Friday, September 19, 2008

Screencast

Feltoltottem egy demonstracios videot a jshot weblapjara a korabbi posthoz kapcsolodoan. Megtekintheto itt.

Thursday, September 18, 2008

Widget selection

A JxCapture egy kereskedelmi capture library javahoz. Screenshotot persze alapbol is lehet kesziteni javaban thirdparty lib nelkul (java.awt.Robot-tal), de vannak olyan featureok amiket nem lehet megoldani csak nativ hivasokkal. Az ilyen oprendszer specifikus dolgokhoz ez a lib is JNI-t hasznal de tobbfele platforma letezik implementacioja. A webstartos demo app tartalmaz egy erdekes featuret ami a "Select Window/Object" menupont alatt erheto el.

Ezzel nem csak ablakokat tudunk kivalasztni a kepernyon hanem az azon levo komponenseket is. (Pl.: gombot, textfieldet, paneleket stb) Tehat minden olyat ami az opreracios rendszer szintjen kulon widgetkent van nyilvantartva. Amikor user raviszi az egeret egy ablakra akkor progi kijeloli vagy az egesz ablakot vagy az azon levo widgetet. A dolog annyira megtetszett hogy eldontottem hogy megcsinalom JShotba is.

Tisztan javaban sajnos ezt nem lehet megoldani mert az ablakok manageleset az oprendszer windowmanagere vegzi. A problema megoldasahoz fel kellett frissitenem a mar elegge megkopott c++ es winapi ismereteimet. Amire szuksegunk van az az hogy le tudjam kerdezni az eger kurzor alatt talalhato ablak/widget koordianatajat es meretet. A dolog ugyanugy fog mukodni mint a "region capture", azaz a user egy teljeskepernyos ablakot fog latni rajta a desktoprol keszitett keppel es eger mozgatasra ezen kijelolodik az aktualis widget.

Ehhez 2 native methodra lesz szukseg:

private native int[] getWidgetRectUnderCursor( int x, int y );

private native void takeWidgetStateSnapshot();

Az elso megadja az egerkurzor alatt talalhato widget elhelyezkedeset. A masodik pedig keszit egy "snapshotot" az ablakok elhelyezkedeserol. Erre csak azert van szukseg hogy ne kelljen minden eger mozgataskor ujra lekerdezni melyik ablak hol talalhato. Addig ugysem valtozik semmi mert a felhasznalo csak egy kepet fog latni a desktoprol.

JNI-nel megszokott modon a classbol legeneraljuk header filet. Ez nalam javah -jni hu.jshot.plugins.nativ.WindowUtils

Az alabbi 2 fuggvenyt kell megirunk cpp-ben.

JNIEXPORT void JNICALL Java_hu_jshot_plugins_nativ_WindowUtils_takeWidgetStateSnapshot
(JNIEnv *env, jobject obj) ;


JNIEXPORT jintArray JNICALL Java_hu_jshot_plugins_nativ_WindowUtils_getWidgetRectUnderCursor
(JNIEnv *env, jobject obj, jint px, jint py);

A konkret megvalositas pedig annyi hogy lekerdezzuk a lathato ablakokat megfelelo Z order szerint es az eger kurzor alatti legmagasabb Z orderrel rendelkezo ablakot vesszuk. Ha az ablakon belul tovabbi widgetre mutat a kurzor akkor azt adjuk (ill. ezek kozul a legkisebbet) vissza egyebkent magat az ablakot.

Azt hogy egy ablak lathato-e az IsWindowVisible fgv-vel kerdezhetjuk le. Ez viszont nem azt adja vissza hogy az adott ablak a felhasznalo szamara valoban lathato-e, hanem hogy az ablak vagy annak parentjenek van-e WS_VISIBLE styleja. Vagyis hogy explicit nem hideoltak-e. Ettol meg a felhasznalo szamara nem biztos hogy lathato mert eltakarhatja egy vagy tobb mas ablak.


BOOL IsWindowVisible(
HWND hWnd // handle of window
);

Az talcara letett ablakokat kiszurhetjuk az IsIconic winapi hivassal

BOOL IsIconic(
HWND hWnd // handle of window
);

A fentebb emlitett problema nem jelent igazan gondot ha ugyis az eger kurzor alatti legnagyobb Z orderrel rendelkezo ablakot valasztjuk. Akkor a takarasban levo
ugysem fog kivalasztodni mert ha van felette vmi akkor annak biztos nagyobb a Z ordere is. Ha csak felig van takarasban akkor ki lehet valasztani de az nem is baj.

Az ablakokat egyszeruen le lehet kerdezi az EnumWindows fgv-vel. Ez egy callbacket ker elso parameterkent ami minden ablak handlejevel meg fog hivodni. A masodik parameterben meg atadhatunk pl egy listat amibe eltaroljuk a hwnd-ket.

BOOL EnumWindows(
WNDENUMPROC lpEnumFunc, // pointer to callback function
LPARAM lParam // application-defined value
);


BOOL CALLBACK EnumWindowsProc(

HWND hwnd, // handle to parent window
LPARAM lParam // application-defined value
);

A child windowkat teljesen hasonloan kerdezhetjuk le az EnumChildWindows fgv-vel. Csak a fenti paremetereken kivul a parent hwndjet is meg kell adnunk.

BOOL EnumChildWindows(

HWND hWndParent, // handle to parent window
WNDENUMPROC lpEnumFunc, // pointer to callback function
LPARAM lParam // application-defined value
);


Az EnumWindows csokkeno Z orderben kapjuk az ablakokat
Az ablak meretet es koordinatait a GetWindowRect fuggvennyel kerdezhetjuk le.

BOOL GetWindowRect(

HWND hWnd, // handle of window
LPRECT lpRect // address of structure for window coordinates
);

Igy mar minden megvan a megvalositashoz amit most nem fogok egy az egyben bepastelni csak par reszletet.

A StateSnapshot tartalmaz egy vector<widget>-et. Tegyuk fel hogy az ablakok mar ki vannak gyujtve ebben. Ahol a widget tartalmazza a handlet, RECT-et es a child komponenskere mutato listat valamint meg tudja mondani egy tetszoleges pontrol hogy az az ablakon belul helyezkedik-e el, es hogy milyen child komponensen van eppen a kurzor.

A lathato ablakokbol kivalasztjuk azt ami az eger kurzor alatt van.

Widget* StateSnapshot::getWindowUnderPoint( int x, int y ) {

Widget::WidgetList *lst = getVisible();
Widget *widget = NULL;

for ( int i = 0; i Widget *w = lst->at(i);
if ( w->pointInside( x, y) ) {
widget = w;
break;
}
}
delete lst;

return widget;
}

A legkisebb teruletu child komponens kivalasztasa:

Widget* Widget::getChildUnderPoint( int x, int y ) {
int area = -1;
Widget *widget = NULL;

for ( int i = 0; i < childList.size(); ++i ) {

Widget *w = childList[ i ];

if ( w->pointInside( x, y ) ) {
if ( area == -1 || w->area() < area ) {
area = w->area();
widget = w;
}
}
}

return widget;
}

Ez pedig az amit a JNI fuggvenyunk ( getWidgetRectUnderCursor ) hivni fog. Eloszor megkeresi melyik ablakra mutat a kurzor. Majd megnezni hogy milyen widget van az ablakon belul azon a helyen. Ha semmi akkor visszater az ablakkal egyebkent a child widgettel.

Widget* StateSnapshot::getWidgetUnderPoint( int x, int y) {
Widget *w = getWindowUnderPoint( x, y );

if ( w == NULL ) {
return NULL;
}

Widget *child = w->getChildUnderPoint( x, y );

if ( child == NULL ) {
return w;
}

return child;
}

Erdemes kiprobalni tobbfele ablakkal a featuret. Ha megnezzuk pl NB-vel (vagy barmilyen mas swinges alkalmazassal) erdekes eredmenyre jutunk. Semmilyen child widgetet nem fogunk tudni kivalasztani csak magat az ablakot, mivel a swing a komponenseit sajat maga rendereli le. Eclipsenel viszont siman megy a gombok es panelek kivalasztasa mivel SWT mar az OS widgetjeit hasznalja. Vannak persze nativ alkalmazasok is ahol nem tudunk mindent kivalasztani egyenkent mert sajat komponenseket hasznalnak. De az ezeket magabafoglalo widget mar kijelolheto.

Remelhetoleg xlibbel is hasonloan egyszeruen megoldhato. A kovetkezo (wines) JShot verzio mar tartalmazni fogja a featuret ami hamarosan letoltheto lesz.

Thursday, July 31, 2008

jshot.info

A JShot weblapja ezentul a http://jshot.info cimen erheto el. Felraktam par screencastot, shotot meg eztazt.

Saturday, July 26, 2008

Swing, JShot etc

Egy picit el lett hanyagolva az utobbi idoben a blog de itt a nyar - meg amennyi maradt belole - ugyhogy igyekszek irni par postot.

Egy korabbi bejegyezesben mar irtam egy JShot nevezetu ScreenCapture utilityrol. Kicsit felelevenitve ez egy javas screenshot keszito es uploader utility amivel az elkeszitett screenshotot feltolthetjuk az elore beallitott helyre. Tobbfele feltolto plugin van hozza. Pl ftp, http (ami a kepfeltoltes.hu-ra tolti), skype file sender. Az elobbi ketto feltoltes utan megjeleniti es a vagolapra masolja az urlt is. Az egesznek annyi a lenyege hogy ha meg akarjuk mutatni a kepernyo egy reszet vkinek akkor upload es mar pastelhetjuk a linket.

A proginak elkeszult az elso publikus teszt verzioja. Letoltheto egyelore innen.

Feature lista:

  • Teljes kepernyo, desktop, aktiv window, taskbar capture. (az utobbi 3 csak jni-vel win alatt)
  • Area capture user alatal kivalasztott terulet
  • Editalasi es rajzolasi funkciok (alakzatok, szabadkezi, szoveg, copy/cut/paste, radir, floodfill, effektek, rotate, flip, crop, merge, stb)
  • Uploader pluginok: ftp/http/skype mindegyikhez kulon profileok hozhatok letre
  • Alakzatok tulajdonsagainak allitasa
  • Feltoltesek egylepesben systemtrayrol
  • Undo/Redo

Ami remlehetoleg meg jon:

  • Vmi IPC a tray app es a futo app kozott, az azonos peldanyban valo kep megnyitashoz pl.
  • Hotkeyek (keyboard hook jni-vel, nem igerem hogy minden platformra de winre biztos)
Irnek par szot a fejlesztes soran szerzett tapasztalatokrol. A java igazabol nem olyan eros a desktop vonalon ezzel gondolom nem mondtam ujat. Viszont imho meg igyis nagyobb produktivitas erheto el vele mint pl cpp+egy nativ guitoolkit-tel, pusztan a managed kodbol szarmazo elonyok miatt. Az elonyok es hatranyok targyalasanal viszont nem art kulonvalasztani hogy mi az ami a fejlesztesi szempontbol jo vagy rossz illetve a felhasznalonak jo vagy rossz.

User szemszogebol a a swinges alkalmazas csunya es lassu. Legalabbis sokan mondjak. Plusz azontul hogy csunya nagyon elut a kinezete a operendszeren futo nativ alkalmazasoktol. Ez utobbi imho hulyeseg. Vannak eleg latvanyos Look and feel-el is (pl liquid). Az hogy mashogy nez ki mint egy nativ alkalmazas meg nem feltetlen hatrany, sot teljesen szokvanyos. Rengeteg alkalamzas van ami nagy szamban hasznal sajat renderelesu komponenseket, es a userek is szeretik cserelgeni a skineket ha van ra lehetoseguk. Eleg megnezni az official msn klienst win alatt, kb semmi nem emlekeztet belole win32-es widgetekre. Ez a bongeszokre ugyanugy igaz. Az operanal se a Windos Native az alapertelemzett skin hanem valami egeszen csicsas kinezet van defaultbol beallitva. Nem beszelve arrol hogy sokan hasznalnak crossplatformos (pl gtk-s xchat, gimp) programokat, amiknek ugyanugy elut a kinezete az alap widgetektol mint egy swinges progie. Tehat egyaltalan nem lenne problema ez, csak sajnos az alapertelmezett Metal/Ocean laf tenyleg nem olyan tetszetos.

Ami a lassusagot illeti a startup tenyleg lehetne joval gyorsabb, de ez az ami csak bizonyos alkalmazasoknal fontos. Vannak olyan programok ahol a user elvarja hogy kattintasra azonnal bejojjon. Egy lightweight editor vagy kepnezegeto pl ilyen. Egy screencapture utilitinel is ez az elvaras. Ennek en ugy probaltam megfelelni hogy kulon valasztottam a main appot, es egy a systemtrayen futo kis alkalmazast. Ez memoria hasznalat szemontjabol is kevezobb. Amikor a user ki akarja valasztni a kepernyo egy reszet akkor duplakattint a systrayes ikonra vagy menubol kivalasztja az area capturet. Ekkor bejon egy awt-s ablak rajta egy canvassal ami kirajzolja screenshotot. Azert awt-s mert ezt lehet fullscreenre rakni es eleg gyors ahhoz
hogy azonnal bejojjon. Igy az egesznek olyan hatasa van kb mintha a kepernyon jelone ki a felhasznalo kepreszletet. A kep feltolteset vagy editalasat mar a main app vegzi el. Igy annak startuptimeja adodik hozza a feltoltesi idohoz, amihez kepest a startup mar elhanyagolhato.

Fejlesztesi szempontjabol swing szerintem egy jol felepitett osztalykonyvtar. A komponensek konnyen kiterjeszthtok. Ami elonye hogy ez tenyleg full platformfuggetlen, a komponensek ugyanugy viselkednek es ugyanugy neznek ki mindenhol. Ez a nativ crossplatform guitoolkitekrol altalban nem mondhato el. Viszont alapbol nagyon keves komponens van. Szerintem mar delphi 1.0-ba is tobb volt. Amig ott egy 10 tabos lapozhato widgetre voltak kipakolva, addig az osszes swinges kompi elfer egyetlen JPanelen. Nincs pl calendar, statusbar, datetimepicker. Valamint viszonylag alap dolgokhoz is sokat kell kodolni.

Nem igazan ismerek jol hasznalhato rad gui buildert hozza. Bar a matisse kisebb nagyobb hibai ellenere jol hasznalhato dialogok es static formok megtervezesere.

Ami meg feltunt hogy van par idegesito memoria felszabaditasi hiba ami mar igen regota megvan es sajnos nem nagyon akarjak javitani. Ez abbol adodik hogy a swingben jopar helyen van olyan static referencia ami a sajat komponenseinkre mutathat. A gc az ilyeneket nem fogja tudni felszabaditani, se azokat amikre ez a widget hivatkozik. Megoldas az hogy disposekor kezzel leszedjuk az osszes komponenst rola plusz kulso objectre mutato fieldek nullozzuk. Igy csak az ures widget marad bent a memoriaban a rajta levo stuffok legalabb mar nem. Vagy valami dummy komponenst letrehozunk hogy kiusse a static referencet. Ez nalam jelentkezett a drag and drop-nal hasznalt TransferHandler-ben ahol a SwingDragGestureRecognizer static valtozo hivatkozott a komponemsemre. Persze a kovetkezo muveletkor ezt felulirja egy uj referenciaval, de valami mindig maradni fog benne. JInternalFramnel szinten van memoria felszabaditasi problema. Ha letrehozunk egy framet majd disposeoljuk, nem fogja tudni felszabaditani csak ha csinalunk egy kovetkezot is. A legutolso viszont mindig bent fog maradni a memoriaban. Ami megrosszabb hogy nem csak JInternalFrame-re hanem sima JFram-re is mukodik.

Szoval osszessegeben lenne meg hova fejlodnie a dolognak. De biztos vagyok benne hogy ha SWT-ben vagy .NET-ben csinaltam volna akkor is lenne ehhez hasonlo szivas lista csak mas jellegu problemakkal. Az ember mindig azt szidja amivel eppen dolgozik :)

De attol meg a JShot mukodik - mar amennyira egy developer a sajat alkalmazasat teszteni tudja - minden eszrevetelt szivesen fogadok.

Monday, December 25, 2006

Karacsonyi wish list

Java™ SE 7 wish list

Peter Ahé egy eredekes Java Dolphin-os whishlistet fogalmazott meg blogjaban. Szamomra egy-ket otlet eleg meredeknek tunik, de van olyan is amit szivesen latnek a 7-es javaban.

"Real closures"

Closures-rol mar tobben irtak. Nekem akkor ez egy uj dolog volt mert az altalam hasznalt nyelvek nem igazan tamogatjak. Tulajdonkeppen kodblokk amit egy fuggveny parameterkent adunk meg. Ertelmezesem szerint annyiban tud tobbet mint egy callback/delegate/anonymousinnerclass hogy a blokkon kivuli lokal valtozokat eleri. Tipikusan azt csinalja hogy egy collection minden elemere meghivja a megadott blokkot, az pedig valamilyen muveletet vegez a kapott parameterrel. Ilyesmit lehet csinalni javaban egy anonymous inner class + final tomb referenciaval, de a dolog lenyege inkabb az lenne hogy egy egyszeru szerkezetet szolgaltat amivel roviden megoldhato a dolog.

Rubyban ezzel sokat szoktak operalni. Python mar kevesbe tamogatja de map/filter + lambda-val lehet hasonlo hatast elerni. Amiota bejott a List comprehension, azota amikor csak lehet mindenki azt hasznalja mert sokkal attekinthetobb.

Nem egy olyan dolog ami nelkul ne lehetne elni, de ha valami atlathato syntaxot talalnak ki neki akkor lehet hogy jo lesz.

"Type aliasing"

pl.: "import java.util.List<String> as StringList;"

Ez csak egy aprosag de jol nez ki. Pythonban is van ilyen bar ott ritkan hasznalom, mert viszonylag rovidek es konnyen megjegyezhetoek a modul es package nevek. Javaban viszont a kacifantosabb nevek -foleg igy genericel kombinalva- leroviditesere jol johet. Mivel ugyis csak importban hasznalhato (remelhetoleg) igy nem ront az olvashatosagon.

"Super packages"

Hmm, nekem nincsenek ilyen igenyeim a packagekkel kapcsolatban, de akik nagy meretu frameworkoket fejlesztenek azoknak lehet.

"Shorthand syntax for declaring properties"

Azaz "property String foo"-bol csinal setter/gettert. Ez ebben a formban nem tudom miert jo nekunk. Egyreszt a legtobb IDE ugyis auto generalja, masreszt ha a setter/getterbe sajat kodot akarok rakni akkor nem hasznalhatom. Max olyan formaban lenne ertelme mint ahogy C#-ban van. De akkor meg szvsz a kezdetektol kellett volna alkalmazni, nem utolag belerakni. Szerintem ez igy felesleges.

"Array syntax for collections"

"How sweet is this:
final map = new HashMap<String, Integer>();
map["one"] = 1;"


Na igen, ez tok jo lenne csak sztem egyaltalan nem illik bele a java nyelvezetebe.

"Shorthand syntax for declaring local variables"

Ezen mar akkor is enyhen ledobbentem amikor meglattam hogy C#-nal ilyet akarnak.
Vagyis lokal valtozokat tudok ugy deklaralni hogy nem irom ki a tipust mert az az ertekadas alapjan dol el. Erre tobbfele javaslat is van.

JavaScript-re emlekezteto syntax: (szerintem ez a legrondabb)
var foo = "bar";

Vagy:
final foot = "bar"; (mivel ha final akkor ugyis csak egyszer tudom inicializalni)

Gosling pedig a kovetkezo syntaxot javasolta:
foo := "bar"; // Valaki mar meg is patchelte azota a javac-t hogy elfogadja ezt az ertekadast. Hat igen, GPL.. :)

A "var"-os nal azonkivul hogy JS-re emlekeztet meg uj keywordot is be kell vezetni. Enumnal is volt ilyen hogy 1.4-es sourcban pl valtozonevkent hasznaltak, 1.5-re nem lehetett egyazegyben leforgatni mert ott mar reserved word. De a legfobb ervem az hogy hulyen nez ki (akarcsak pascal styelos operator) :).

Legeloszor a dinamikusan tipusos nyelvekre asszocialtam de ettol meg nyilvan ugyanugy static typing marad.

(Egyebkent meg a dinamukusan tipusos nyelveknek szvsz nem is az az igazi elonye (ami egyesek szerint nagy hatrany is lehet) hogy nem kell kiirni a tipust hanem sokszor egyszeruen nem is erdekel hogy kinek mi a tipusa. Max az hogy mit tud az illeto objektum. Ha egy file objectnek es egy socket objectnek is van read metodusa akkor nekem az egyforman jo hiaba total kulonbozo a ket objektum. Ugyanugy hasznalhatom anelkul hogy kozos interfacet irnek ra benne a read methoddal. Ezert ritkan is lehet olyat latni hogy isinstance, helyette inkabb hasattr-t hasznalnak. Abba nem mennek bele hogy alkalmas-e ilyen nyelv nagy rendszerek fejesztesere mert ebbe nem tudnek allastfoglalni. (mindenesetre van ra pelda boven). Kisebb programok fejlesztesenel viszont ez nagy mertekben novelheti a produktivitast (masok szerint meg a hibalehetoseget:)).

Visszaterve a javahoz, nem tudom hogy van-e a dolgonak azon kivul haszna hogy nem kell leirni par karaktert. Uj keywordot es operatort meg szerintem hanyagolni kene.

Gondolkodtam hogy en milyen featuret latnek szivesen de nem sok ertelmes dolog jutott eszembe. kack viszont ezt javasolta:

catch( Exception1, Exception2, Exception 3 ) { }

Ezt most max ugy lehet hogy kozos parent-et csinalok nekik es azt kapom el. De vegulis elofordulhat hogy logikailag nem illik bele vmelyik Exception egy bizonyos hiearchiaba de attol meg egyuttesen szeretnem elkapni oket.

Nem vagyok az uj featureok ellen, csak az olyanokat nem szeretem amik rontjak az olvashatosagot, vagy nagyon "hackelhetove" teszik a nyelvet. Ez alatt azt ertem hogy ugyanazt a dolgot tobbfelekeppen meg lehet csinalni, pl egy sorban ugyhogy senki nem fogja erteni mit csinal az a sor, vagy tobben es akkor esetleg atlathatobb lesz. Ha a Closures-nek vmi szar syantox talalnak ki akkor abbol lehet ilyen problema. Az olvashatosagot szvsz a tul sok keywordel, tul sok speci operatorral is le lehet rontani. Szoval szerintem mertekkel kene kezelni ezeket a featureoket. 

Monday, December 11, 2006

Java SE 6

Kijott a a JDK 1.6-os verzioja, amit idaig mustang kodneven emlegettek. Jol idozitettek a felev vegere igy nem nagyon van idom megnezegetni. Amit a betas tapasztalatok alapjan tudok hogy sok szep desktop feature kerult bele mint pl systemtray icon, antialiasingos font, splashscreen. NB-t megneztem milyen 1.6al. A textek eddig sem voltak nalam szalkasak egy cleartext utility miatt de most mintha megszebb lenne, bar lehet csak placebo. Sebesseg novekedest majdnem minden verzional igergetnek, de ezt egy desktop appnal annyira nem veszem eszre. Eddig sem volt se tul gyors se tul lassu. De ez majd hosszabb hasznalat utan ugyis kiderul. Ha lesz idom megnezem alaposabban.

Jah es a kedvencem: "java -cp ".;libs/*" Progi"
De vajon miert nem jutott ez mar hamarabb eszukbe? :)

Sunday, November 05, 2006

lol?

ehehe

Sunday, October 01, 2006

LayerTable

Egy kis JShot upgrade. A shapek zorderjet egy LayerTable segitsegevel lehet valtoztatni, drag and droppal.