Category Archives: Projekti

Sedaj načrtujem objektni del predmetov:

Vsak predmet bo sestavljen iz objekta TShape. V primeru je izpostavljen predmet za črto. Ta predmet tudi vsebuje dve točki za urejanje njene dolžine in položaja. Takšna točka se imenuje “handle” in je sestavljena iz objekta ShapeHandle. Razvidno je, da je objekt TShape kot TShapeHandle izpeljana iz glavnega objekta GObject.

Predmet TCanvas pa je glavni gradnik, ki izrisuje ostale predmete in zato ima seznam predmetov, katere naj izriše. Izpeljan pa je iz objekta GtkDrawingArea.

Ponovno sem začel s Teuthido. Tokrat bo dizajn zelo objektno naravnan za čimbolšo obdelavo predmetov. Ustvaril sem si git repozitorij na github. Repozitorij najdete tukaj. In še slika najnovejšega builda:

Shrani.si

Na tem naslovu si lahko prenesete popravek za gnome-system-monitor različico 2.24.1. Patch potrdite z ukazom

cd gnome-system-monitor-2.24.1
cat /mesto/popravka/gnome-system-monitor-2.24.1-users_tab.patch | patch -p1

In dalje skompajlate in namestite nadzornika sistema.

Ponovno sem spisal popravek za program Gnome System Monitor, ki omogoča pregled nad prijavljenimi uporabniki v sistemu. Še screenshot:

Patch bom objavil jutri, če bo kdo želel preizkusiti.

Danes popoldne sem se poigral z WebKit pogonom. Zastavil sem si cilj narediti nekakšen proof-of-concept browser, ki je po delovanju nekoliko podoben Google Chrome brskalniku.

Torej je eno glavno okno, ki ponuja ustvarjanej novih zavihkov. Ko se proces ustvarjanja sproži, se najprej požene drug proces, kjer biva WebKit pogon. Nato Ta drug proces ustvari nek medprocesni kanal na katerega se glavno okno poveže. Potem izmenjata nekatere informacije. Ko je vse kočano, se v drugem procesu ustvari WebKit gradnik, glavno okno pa poveže ta gradnik v nov zavihek. In valla, imamo prikazano stran.

Še screenshot:
Shrani.si
V konzoli je prikazan seznam procesov, kjer se tudi opazijo trije pognani procesi za tri zavihke. Bom videl koliko časa bom kaj imel in stvar še naprej preučeval.

Razmišljal sem, kako bi ponovno napisal glavno komponento Teuthide. Trenutna delovna površina, ki prikazuje predmete, je Gtk+ gradnik, podedovan od gradnika GtkDrawingArea. Delovna površina ima notranji seznam vseh predmetov, ki nato spreminjajo svoj položaj, obliko in ostale lastnosti. Vendar predmet je običajna struktura in ima zato nekaj pomanjkljivosti:

  • koda za obdelavo predmetov je nepregledna,
  • vsa dejanja nad predmeti mora opraviti delovna površina

Zato sem razmišljal v smeri, da bi delovna površina bila kontejner, mogoče kar izpeljan iz GtkFixed, ki že omogoča poljubni položaj. Predmeti pa bi bili ali Gtk gradniki. Vendar tukaj je težko najdit gradniki, ki bi ustrezal predmetom. Najbolje bi bilo, da bi predmet bil izpeljanka gradnika GtkDrawingArea z vključenimi dogodki. Če bi predmet bil Gtk+ gradnik, bi lahko zelo enostavno povezoval dogodke in pisati odzivne funkcije.

Sedaj resnično nimam veliko prostega časa za razvoj Teuthide. Veliko dela je v službi in pridem pozno popoldne domov. Med vikendom pa ponavadi počivam. No sedaj sem si vzel malo časa za moj projekt. Malo pogledal kaj je narejenega in kaj manjka.

Izvorna koda ima dobrih 5000 vrstic, ki omogočajo:

  • ustvarjanje delovne površine poljubne velikosti,
  • pomanjšava, povečava delovne površine,
  • premikanje, brisanje, ustvarjanje predmetov,
  • spreminjanje velikosti predmetov (ima še malenkost napak),
  • spreminjanje lastnosti predmetov – barva ospredja, barva ozadja, besedilo,
  • urejanje povezave med predmeti, izgled povezav, napis povezave, barva povezave,
  • izvoz delovne površine v PNG sliko,
  • shranjevanje in nalaganje delovne površine.

In ravno zadnja točka potrebuje popolno predelavo. Sedaj se delovna površina shrani v XML zapis. V tem zapisu je pa vsak element na površini zapisan kot kopija vseh točk, ki ga opisuje. Se pravi, če imamo nek predmet, ki je izrisan iz sedmih, točk, morajo vse te točke imeti svoj zapis v obliki XY koordinat. In to za vsak predmet. Če imamo na površini 12 takšnih predmetov, pomeni to 84 XY zapisov za vse te predmete. In menim, da se ta problem lahko reši veliko bolj elegantno.

Zato premišljujem o sistemu, ki bi izrazil obliko nekega predmeta brez XY koordinat. Verjetno bo potrebno izdelati nek nov XML zapis posebej za predmete, ki bo poleg SVG zapisa vključeval še dodatne informacije. Delnoma je to že narejeno preko dodatne datoteke, ki jo ima vsak predmet, vendar se mi to zdi grda rešitev.

Ah da še to omenim: v podjetju iščemo kompetentne sodelavce z Python ali Ruby ali Enterprise Java znanjem za razvoj web aplikacij. Če je kdo zainteresiran, naj se mi javi na mail ali pa na pošto, ki jo najdete na domači strani podjetja.

V prvem delu smo se razjasnili glede izrisa gradnikov in poiskali kodo, ki sproži izris glavnega okna. Sedaj pa bomo pogledali dejansko kodo, ki izriše okno.

Ko program želi prikazati okno, ga ne mora direktno izrisati na zaslon, ampak kliče posebno funkcijo za X strežnik, ta pa ustvari novo “površino” in jo prikaže. Upravitelj oken pa poskrbi za okvir in naslovnico okoli okna. Tukaj Gtk+ nima vpliva razen tega, da je sprožil to dogajanje. Torej X strežnik oz. odjemalska knjižnica Xlib poskrbi da ima gtk+ neko površino, na katero ima dovoljenje za risanje. Tukaj se pa nato sproži “expose” signal okna, ki nato izriše njegovo ozadje. Nato se sproži rekurzivna funkcija, ki še hierarhično izrisuje vse otroke (gradnike znotraj okna) in sprožuje njihov “expose” signal.

Ker pa ne želimo stikati po gtk+ izvorni kodi, si raje izberemo pogon, ki ga bomo spremenili. Pa vzemimo pogon Murrine. Ta pogon vse izrise opravlja preko cairo vektorske knjižnice in trenutno velja za najbolj prilagosdljiv pogon.

V pogonu sedaj iščemo funkcijo , ki pripada klicu draw_flat_box(). V izvorni kodi jo najdemo v datoteki murrine_style.c pod imenom murrine_style_draw_flat_box(). Nekje v vrstici 1551 v isti datoteki pa tudi vidimo, kako pogon prevzame klice na funkcijo draw_flat_box() z:

style_class->draw_flat_box = murrine_style_draw_flat_box;

Torej omenjeno funkcijo bodo klicali vsi gradniki, ki bodo potrebovali nek pobarvan okvir. Mi pa želimo gladke robove omejiti samo na okna, zato moramo preverjati, da bo izris robov samo pri gradnikih vrste GtkWindow. Pogon murrine ima že spisano funkcijo, ki z cairo funkcijami ustvari pravokotnik z glajenimi robovi. Zato to tudi uporabimo. Pred koncem funkcije vstavimo naslednjo kodo:


if (GTK_IS_WINDOW(widget)) {
cairo_t *cr = murrine_begin_paint (window, area);
int x, y, w, h, d;

cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
gdk_window_get_geometry(window, &x, &y, &w, &h, &d);
clearlooks_rounded_rectangle (cr, 0, 0, w, h, 20.0, MRN_CORNER_TOPLEFT | MRN_CORNER_TOPRIGHT | MRN_CORNER_BOTTOMRIGHT | MRN_CORNER_BOTTOMLEFT);

cairo_fill(cr);
cairo_destroy (cr);
}

Tukaj smo najprej preverili, če je funkcijo murrine_style_draw_flat_box() klicalo glavno okno. Nato iz okna pridobimo cairo podlago za risanje. Nastavimo barvo na sivo in narišemo pravokotnik. Spremenjen pogon prevedemo in namestimo (make && sudo make install). In kar takoj, ko temo uveljavimo, vidimo spremembe:
Shrani.si

Se pravi da smo na pravi poti. Gladki robovi se res izrišejo. Sedaj pa je potrebno tisti preostanek pri robovih odstraniti, da bo skozi vidno ozadje.

Nadaljevanje v tretjem delu.

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:
mockup

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.

Že kar preveč časa je minilo odkar sem se posvetil mojemu grande projektu Teuthida. Tokrat sem se potrudil in izdal prvi release candidate za verzijo 0.1alpha3. Res je kar mal pretirano to označevanje vendar vse novosti, ki spadajo pod alpha3 izdajo še niso implementirane.

Glavne novosti te RC izdaje pa so:

  • oblike sedaj imajo sence,
  • uporabnik lahko spreminja barvo ospredja in ozadja oblike.

Izvorno kodo te RC1 izdaje pa dobite tukaj.