Základní aplikace v GDK
7.10.2020
Knihovna GDK představuje relativně nízkoúrovňovou mezivrstvu mezi knihovnou GTK a okenním serverem. To však neznamená že v určitých případech nemůže být použita samostatně, pokud nechceme nebo nemůžeme mít aplikaci závislou na relativně velké a komplexní knihovně GTK a na druhé straně psát uživatelské rozhraní v Xlib nebo xcb nám přijde příliš nízkoúrovňové.
Okno vytvoříme pomocí funkce gdk_window_new, která nám v případě úspěchu vrátí ukazatel na typ GdkWindow. Parametry funkce jsou rodičovské okno, adresa struktury v jejíchž prvcích nastavíme požadované parametry okna a maska ve které určíme, které z parametrů této struktury jsou platné a mají být použity. Po vytvoření okno zobrazíme pomocí funkce gdk_window_show.
GdkWindow* window; /*globální proměnná*/ GdkWindowAttr attributes; gint attr_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_TITLE | GDK_WA_WMCLASS; if (!gdk_init_check(&argc, &argv)) return EXIT_FAILURE; memset(&attributes, 0, sizeof(attributes)); attributes.window_type = GDK_WINDOW_TOPLEVEL; attributes.x = 100; attributes.y = 50; attributes.event_mask = GDK_ALL_EVENTS_MASK; attributes.width = 440; attributes.height = 480; attributes.title = "GDK základní okno"; attributes.wclass = GDK_INPUT_OUTPUT; gdk_event_handler_set(on_gdk_event, NULL, NULL); window = gdk_window_new(NULL, &attributes, attr_mask); gdk_window_show(window);
Po vytvoření a zobrazení okna musíme realizovat smyčku událostí, ve které aplikace poběží dokud z této smyčky nevyskočíme nebo aplikaci neukončíme "natvrdo". K tomu využijeme knihovnu GLib, nad kterou je GDK postavena. Zbývající kód funkce main bude vypadat následovně.
main_loop = g_main_loop_new(NULL, FALSE); g_main_loop_run(main_loop); g_main_loop_unref(main_loop); return EXIT_SUCCESS;
kde globální proměnná main_loop je definovaná takto:
GMainLoop* main_loop;
Nyní zbývá napsat obslužnou funkci událostí nastavenou ve výše uvedeném kódu funkcí gdk_event_handler_set.
void on_gdk_event(GdkEvent* event, gpointer data)
{
if (event->type == GDK_EXPOSE)
{
on_expose((GdkEventExpose*)event);
}
else if (event->type == GDK_DELETE)
{
on_end_app();
}
}
Jak vidíme, v tomto nejjednodušším případě stačí obsloužit událost překreslení okna (GDK_EXPOSE) a zrušení okna (GDK_DELETE).
Při požadavku na překreslení okna zatím nebudeme nic vykreslovat (to si necháme na další pokračování), ale měli bychom zavolat funkce gdk_window_begin_draw_frame a gdk_window_end_draw_frame, čímž řekneme správci oken (jako je X11) že je okno překresleno.
void on_expose(GdkEventExpose* ev)
{
if (ev->region == NULL)
return;
GdkDrawingContext* dc = gdk_window_begin_draw_frame(
ev->window, ev->region);
gdk_window_end_draw_frame(ev->window, dc);
}
V reakci na zrušení hlavního okna aplikace musíme korektně ukončit smyčku událostí, jinak by totiž i po zrušení okna proces zůstal běžet až do jeho ukončení zvenku.
void on_end_app()
{
gdk_window_destroy(window);
g_main_loop_quit(main_loop);
}
Tím máme kompletní základ aplikace v GDK. V příštím pokračovaní si ukážeme jak kreslit a vypisovat text do okna a následně si vytvoříme jednoduchý a rychlý prohlížeč obrázků ve stylu programu feh.
Na závěr celý výpis programu, který lze sestavit překladačem GCC následujícím příkazem (pro ladicí sestavení):
gcc gdk-okno.c -Wall -g `pkg-config --cflags --libs gdk-3.0` -ogdk-okno
#include <gdk/gdk.h>
GMainLoop* main_loop;
GdkWindow* window;
void on_end_app()
{
gdk_window_destroy(window);
g_main_loop_quit(main_loop);
}
void on_expose(GdkEventExpose* ev)
{
if (ev->region == NULL)
return;
GdkDrawingContext* dc = gdk_window_begin_draw_frame(
ev->window, ev->region);
gdk_window_end_draw_frame(ev->window, dc);
}
void on_gdk_event(GdkEvent* event, gpointer data)
{
if (event->type == GDK_EXPOSE)
{
on_expose((GdkEventExpose*)event);
}
else if (event->type == GDK_DELETE)
{
on_end_app();
}
}
int main(int argc, char** argv)
{
GdkWindowAttr attributes;
gint attr_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_TITLE | GDK_WA_WMCLASS;
if (!gdk_init_check(&argc, &argv))
return EXIT_FAILURE;
memset(&attributes, 0, sizeof(attributes));
attributes.window_type = GDK_WINDOW_TOPLEVEL;
attributes.x = 100;
attributes.y = 50;
attributes.event_mask = GDK_ALL_EVENTS_MASK;
attributes.width = 440;
attributes.height = 480;
attributes.title = "GDK základní okno";
attributes.wclass = GDK_INPUT_OUTPUT;
gdk_event_handler_set(on_gdk_event, NULL, NULL);
window = gdk_window_new(NULL, &attributes, attr_mask);
gdk_window_show(window);
main_loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(main_loop);
g_main_loop_unref(main_loop);
return EXIT_SUCCESS;
}