Kot sem že v mojem prejšnjem postu omenu, se na Ubuntu straneh nahaja zelo dober predlog za GTK+ temo nove generacije. Pa si bom od avtorja malce sposodil sliko.
Poglejmo si, kakšni bi bilo pogovorno okno za vnos administratorskega gesla, kadar želimo pognati program, ki potrebuje sistemske privilegije:

Kar odstopa, so glajeni robovi okna in rahel metalski preliv kot ozadje. Ko se gtk+ program prikazuje, se najprej naloži t.i. pogon izrisa (theme engine), ki vsebuje funkcije za izris posameznih gradnikov. Namreč gradniki v gtk+ so implementirani tako, da kadar se mora gradnik izrisati, se kliče signal, ki je dejansko kazalec na neko funkcijo, ki upravi izris. Če pogon ne implementira te funkcije, izris gradnika prevzame gtk+ z lastno implementacijo. Vsak pogon pa lahko še ima stile (gtkrc styles), ki lahko določajo npr. barve in robove.
Izris hipotetičnega gumba:
Gumb -> [klic "expose" signala za ponoven izris] -> [klic pogona] -> [branje stila] -> izris na zaslon
če pogona ni, tudi pogonskega dela ni:
Gumb -> [klic "expose" signala za ponoven izris] -> [klic notranje Gtk+ funkcije] -> izris na zaslon
Vsak gradnik, ki je izrisljiv, ima posebno strukturo, ki se imenuje GdkWindow in vsebuje poleg bitne slike gradnika še dodatne informacije npr. stil teme. Najbolj pomembna signala za izrisljive gradnike sta “realize”, ki prvič ustvari GdkWindow strukturo “expose”, ki se samodejno kliče vsakič, ko Gtk+ ugotovi, da je izrisano področje gradnika na zaslonu “poškodovano” in potrebuje osvežitev.
Če želimo karkoli izrisati na katerikoli gradnik, ki se prikaže, moramo najprej pridobiti njegovo GdkWindow strukturo. In ta je na voljo ravno pri signali “expose” in “realize”. Sedaj če pogledamo v Gtk+ izvorno kodo, bomo našli imenik gtk, kjer se nahaja koda za vsak gradnik, izrisljiv in neizrisljiv. Mi pa iščemo glavno okno, torej GtkWindow. Če v kodi iščemo za signal “expose”, ga kar kmalu najdemo. Zgleda pa takole:
static gint
gtk_window_expose (GtkWidget *widget,
GdkEventExpose *event)
{
if (!GTK_WIDGET_APP_PAINTABLE (widget))
gtk_window_paint (widget, &event->area);
if (GTK_WIDGET_CLASS (gtk_window_parent_class)->expose_event)
return GTK_WIDGET_CLASS (gtk_window_parent_class)->expose_event (widget, event);
return FALSE;
}
To je privzeta funkcija za signal “expose”, ki bo izrisovala okno. Ta privzeti dogodek lahko prepišemo z lastnim. Vendar to ne želimo. V tej funkciji še ni nobene kode za risanje, torej gremo dalje. Funckija gtk_window_paint() se nahaja še v enaki datoteki, vsebina pa je:
static void
gtk_window_paint (GtkWidget *widget,
GdkRectangle *area)
{
gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL,
GTK_SHADOW_NONE, area, widget, "base", 0, 0, -1, -1);
}
Tudi ta funkcija ne vsebuje kode za risanje. Dalje s funkcijo gtk_paint_flat_box. Tukaj si pomagamo z orodjem grep, ki ugotovi, da je funkcija v datoteki gtkstyle.c. Sedaj pa v funkciji opazimo to, o čemer sem govoril. Funkcija gtk_paint_flat_box() kliče funkcijo draw_flat_box(), ki bi jo moral ponujati pogon:
GTK_STYLE_GET_CLASS (style)->draw_flat_box (style, window, state_type, shadow_type,
(GdkRectangle *) area, widget, detail,
x, y, width, height);
Nadaljujemo v drugem delu.