Masarykova univerzita Fakulta}w¡¢£¤¥¦§¨  informatiky !"#$%&'()+,-./012345

Multiplatformní knihovna pro interakci s grafickým uživatelským prostředím

Bakalářská práce

Jaromír Kala

Brno, 2014 Prohlášení

Prohlašuji, že tato bakalářská práce je mým původním autorským dílem, které jsem vypracoval samostatně. Všechny zdroje, prameny a literaturu, které jsem při vypracování používal nebo z nich čerpal, v práci řádně cituji s uvedením úplného odkazu na příslušný zdroj.

Jaromír Kala

Vedoucí práce: RNDr. Pavel Troubil

ii Poděkování

Rád bych poděkoval RNDr. Pavlu Troubilovi za cenné rady, věcné připomínky a ochotu při konzultacích a vypracování bakalářské práce.

iii Shrnutí

Cílem bakalářské práce bylo vytvořit multiplatformní knihovnu pro manipulaci s grafickým uživatelským rozhraním. Vzniklá knihovna WDDMan podporuje detekci připojených monitorů a jejich rozlišení, zjištění otevřených oken a manipulaci s nimi (zavření, změny velikostí a přesuny) a detekci virtuálních ploch. Knihovna WDDMan funguje na operačních systémech skupiny Windows, Linux a Mac OS. Kni- hovna s podobnou funkcionalitou doposud nebyla k dispozici a bude použita v middleware CoUniverse pro manipulaci s objekty videokon- ferenčních nástrojů. Prostředí CoUniverse se využije pro vzdálené tlu- močení přednášek pro Středisko pro pomoc studentům se specifickými nároky Masarykovy univerzity. Knihovna WDDMan bude zveřejněna pod otevřenou licencí k volnému užití. Součástí knihovny je i anglická dokumentace a ukázkový a testovací příklad.

iv Klíčová slova

CoUniverse, Windows API, XLib, JNA, AppleScript, GUI

v Obsah

1 Úvod ...... 2 2 Popis použitých technologií ...... 4 2.1 Native Access ...... 4 2.1.1 Popis knihovny Java Native Access ...... 4 2.1.2 Použití JNA v knihovně WDDMan ...... 7 2.2 Windows API ...... 8 2.3 X Window System a Xlib ...... 9 2.4 AppleScript ...... 10 2.4.1 Přehled jazyka ...... 10 2.4.2 Použití jazyka AppleScript v knihovně WDDMan 12 3 Dokumentace knihovny WDDMan ...... 14 3.1 Úvod ...... 14 3.2 Přehled souborů knihovny ...... 15 3.3 Třída WDDMan ...... 17 3.3.1 Konstruktory ...... 17 3.3.2 Funkce pro práci s okny ...... 18 3.3.3 Funkce pro práci s plochami ...... 19 3.3.4 Funkce pro práci s monitory ...... 22 3.3.5 Další funkce ...... 24 3.4 Rozhraní Window ...... 24 3.4.1 Funkce pro zjištění informací o okně ...... 25 3.4.2 Funkce pro manipulaci s oknem ...... 28 3.5 Rozhraní Desktop ...... 30 3.6 Třída Display ...... 31 3.7 Výčtový typ OperatingSystem ...... 32 3.8 Výjimky ...... 33 4 Testování knihovny WDDMan ...... 34 5 Závěr ...... 36 A Seznam příloh ...... 38

1 1 Úvod

Laboratoř pokročilých síťových technologií vyvíjí prostředí pro vzdálené tlumočení přednášek a cvičení do znakového jazyka pro Středisko pro pomoc studentům se specifickými nároky (používá se i název Středisko Teiresiás) Masarykovy univerzity. Pří vzdáleném tlumočení přednášek a cvičení není tlumočník do znakové řeči ve stejné místnosti jako studenti. Vzdálené tlumočení je nutné kvůli nedostatku tlumočníků do odborného znakového jazyka. Aplikační middleware CoUniverse1 se bude používat k řízení tohoto prostředí, protože umožňuje budování, ovládání a samoorganizaci rozsáh- lých kolaborativních prostředí skládajících se z množství komponent [1]. Při použití prostředí CoUniverse pro vzdálené tlumočení přednášek do znakové řeči je potřeba manipulace s grafickým uživatelským rozhraním pro zobrazení používaných videokonferenčních nástrojů. Manipulace s objekty používaných videokonferenčních nástrojů je potřeba kvůli přes- ným požadavkům na vzhled aplikace pro vzdálené tlumočení. Použitým videokonferenčním nástrojem bude UltraGrid2, který umožňuje nízko- latenční přenos videa ve vysokém rozlišení. Popis požadavků na vzhled aplikace a popis použití technologií se nachází v bakalářské práci Milana Semana3. Cílem bakalářské práce bylo navrhnout a implementovat multiplat- formní (pro operační systémy skupiny Windows, Linux a Mac OS) knihovnu napsanou v jazyce Java (protože prostředí CoUniverse je vyví- jeno v programovacím jazyce Java) pro manipulaci s objekty grafického uživatelského prostředí. Měla podporovat detekci připojených monitorů a jejich rozlišení, zjištění otevřených oken a základní manipulaci s nimi (zavření, změnu velikosti a přesunutí). Knihovna v jazyce Java s touto funkcionalitou dosud neexistovala. Ostatní uživatelé, kteří řešili podobné problémy, nejčastěji sami napro- gramovali potřebné řešení pro jejich operační systém, vizte například

1. https://www.sitola.cz/CoUniverse/index.php/CoUniverse 2. http://www.ultragrid.cz/en 3. https://is.muni.cz/th/374487/fi_b

2 1. Úvod získání oken na operačních systémech Windows4, Mac OS5 nebo Linux6. Bakalářská práce je rozdělena do čtyř kapitol. V druhé kapitole popisuji použité technologie a jejich použití při vývoji knihovny WDDMan. V její první sekci knihovnu Java Native Access (JNA), která umo- žňuje jednoduché volání nativních funkcí z programovacího jazyka Java. V další sekci Windows API, které se používá ke komunikaci s operačními systémy skupiny Windows. Knihovna WDDMan volá funkce WinAPI přes JNA k manipulaci s grafickým uživatelským rozhraním na oper- ačním systémech skupiny Windows. V třetí sekci popisuji okenní systém X Window System používaný na operačních systémech skupiny Linux a knihovnu Xlib, kterou knihovna WDDMan používá skrz JNA k manip- ulaci s GUI na operačních systémech skupiny Linux. V poslední sekci se věnuji skriptovacímu jazyku AppleScript podporovanému operačními systémy skupiny Mac OS. AppleScript používá knihovna WDDMan k manipulaci s GUI na operačních systémech Mac OS. Třetí kapitola je dokumentací ke knihovně WDDMan. Nejprve jsou v ní popsány podporované operační systémy a nutné programové vy- bavení k fungování knihovny, následuje stručný popis souborů, ze kterých je knihovna složena a v poslední části kapitoly je dokumentace veřejných tříd, rozhraní, výčtových typů a výjimek knihovny. Ve čtvrté kapitole popisuji, jak jsem testoval funkčnost knihovny testovací aplikací WDDManDemo.

4. http://stackoverflow.com/questions/3188484/ windows-how-to-get-a-list-of-all-visible-windows 5. http://stackoverflow.com/questions/1606321/ how-do-i-get-a-list-of-the-window-titles-on-the-mac-osx 6. http://stackoverflow.com/questions/15638885/ linux-how-to-get-a-list-of-all-visible-windows

3 2 Popis použitých technologií

2.1 Java Native Access

2.1.1 Popis knihovny Java Native Access Java Native Access (JNA) je knihovna pro programovací jazyk Java. JNA umožňuje volání funkcí sdílených knihoven napsaných v jazyce přímo z kódu v jazyce Java bez psaní nativního kódu. JNA nepodporuje volání C++ funkcí, je potřeba napsat v jazyce C rozhraní, které bude odpovídající C++ funkce volat. JNA je zkompilovatelné a funkční na operačních systémech Windows, Linux, Mac OS, Android, a dalších. Při vývoji knihovny JNA není výkon prioritou [2]. Při testování se ukázalo, že jsou výkonnější způsoby volání nativních funkcí (například JNI), ale zároveň byla knihovna JNA nejpohodlnější k použití [3]. Tipy k zlepšení výkonui při používání knihovny JNA jsou v dokumentaci1. Pro volání nativních funkcí používá JNA knihovnu libffi2, která umožňuje volání nativních funkcí za běhu programu. Součástí knihovny JNA je i platformně specifická knihovna, která obsahuje některé nativní funkce a struktury pro různé operační systémy (například některé funkce z WinAPI či Xlib) již namapované. Rovněž je součástí platformně specifické knihovny sada nástrojů, které fungují na OS Windows, Linux a Mac OS. Sada nástrojů obsahuje následující třídy:

FileMonitor notifikace o změnách souborů.

FileUtils funkce se soubory, které nejsou obsaženy přímo v jazyce Java (například přesunutí souboru do koše).

KeyboardUtils informace o stavu klávesnice

WindowUtils další funkce pro okna.

1. http://twall.github.io/jna/4.0/javadoc/overview-summary.html# performance 2. http://sourceware.org/libffi/

4 2. Popis použitých technologií Základní použití knihovny JNA ukáži na příkladu, kdy ze souboru priklad.c zavolám funkci secti z jazyka Java. Soubor priklad.c napsaný v programovacím jazyce C vypadající následně:

int secti(int x, int y) { return (x + y); }

je potřeba standardním způsobem přeložit do sdílené knihovny, na- příklad na operačním systému Linux a kompilátoru GCC příkazem gcc -o libpriklad.so -shared priklad.c. Následně se vytvoří nové rozhraní Priklad.java v jazyce Java vypadající:

import com.sun.jna.;

public interface Priklad extends Library { public int secti(int x, int y); }

Rozhraní musí rozšířit rozhraní Library a každá funkce, která je volána z jazyka Java, musí být v rozhraní specifikována – musí se jmenovat stejně jako v původním C souboru a datové typy se převádějí podle tabulky 2.1. Pointer a NativeLong jsou třídy knihovny JNA. Knihovna Java Native Access podporuje i složitější datové typy. Pole se převádějí přímo na pole v jazyce Java. Struktury a unie se převedou vytvořením nové třídy, která rozšíří třídu Structure, respektive Union, knihovny JNA. Kompletní popis, jak převést struktury a unie je v dokumentaci3. Načtení knihovny a zavolání funkce secti se v souboru Secti.java provede následně.

import com.sun.jna.Native; public class Secti { public static void main(String argv[]) {

3. http://twall.github.io/jna/4.0/javadoc/overview-summary.html# structures

5 2. Popis použitých technologií Datový typ v C Datový typ v jazyce Java int int (může se převést i na boolean) long NativeLong long long long short short float float double double char wchar_t char char* String void* Pointer

Tabulka 2.1: Převod datových typů.

Operační systém Pojmenování knihovny arg1 Linux libpriklad.so priklad Windows priklad.dll priklad Mac OS X libpriklad.dylib priklad

Tabulka 2.2: Pojmenování knihovny.

Priklad priklad = (Priklad)Native.loadLibrary("priklad", Priklad.class); int x = 1; int y = 2; int z = priklad.secti(x, y); System.out.println(z); //vypise 3 } }

První argument funkce loadLibrary je řetězec arg1 odpovídající pojmenování knihovny dle tabulky 2.2. Soubor Secti.java stačí jen spustit se souborem knihovny ve stejné složce.

6 2. Popis použitých technologií 2.1.2 Použití JNA v knihovně WDDMan Knihovna JNA se používá v knihovně WDDMan k volání WinAPI a Xlib funkcí pro většinu operací s grafickým uživatelským rozhraním na operačních systémech Windows a Linux. K volání nativních funkcí z jazyka Java se dají použít i další možnosti. (JNI) je rozhraní, které umožňuje volání na- tivního kódu z jazyka Java i opačným směrem (tedy z nativního kódu volat kód v jazyce Java). Volání nativních funkcí rozhraním JNI vyžaduje psaní nativních funkcí ve speciálním formátu. Simplified Wrapper and Interface Generator (SWIG) je nástroj, který umožňuje propojení (ve smyslu vzájemného volání kódu) C a C++ knihoven a aplikací s řadou jazyků vyšší úrovně, například Java, C#, Go, R, Perl, PHP, Python a Lua. Volání nativních funkcí vyžaduje naprogramovaní speciálního rozhraní. BridJ je knihovna, která umožňuje volání C, C++ a Objective-C funkcí (s jistými omezeními) z jazyka Java. K volání nativních funkcí není potřeba psát nativní kód. Při volání většiny funkcí je rychlejší než knihovna JNA, ale zatím nepodporuje předávání struktur hodnotou [4]. Místo ostatních alternativ jsem se rozhodl pro knihovnu JNA z ná- sledujících důvodů:

• Knihovna JNA je jednoduchá na použití, při jejím používání stačí psát kód v jazyce Java.

• JNA je zavedený projekt, který již využívá řada aplikací. S tím souvisí, že má i dobře napsanou dokumentaci, ukázkové příklady použití a širokou komunitu uživatelů.

• V knihovně WDDMan nepotřebuji volat žádné C++ funkce, proto nevadí, že je JNA nepodporuje.

• Knihovna WDDMan volá poměrně málo nativních funkcí a není tolik významná rychlost, proto není překážkou menší výkon volání nativních funkcí přes JNA než u jiných nástrojů.

• Velkou výhodou knihovny JNA je platformně specifická knihovna (soubor jna-platform.jar), která obsahuje připravené rozhraní pro volání některých funkcí WinAPI a Xlib, které knihovna WDDMan využívá.

7 2. Popis použitých technologií • Součástí ukázkových příkladů knihovny JNA je příklad x114, který ukazuje objektově orientovaný přístup k některým funkcím knihovny Xlib. Knihovna WDDMan používá knihovnu JNA, platformně specifickou knihovnou a příklad x11. Pro volání některých funkcí WinAPI (ze souborů User32.dll a Kernel32.dll) používá již vytvořené rozhraní, které je součástí platformně specifické knihovny.

2.2 Windows API

Windows API (WinAPI) označuje kolekci API dostupnou na operačních systémech Windows. WinAPI používají aplikace pro operační systém Windows k interakci s operačním systémem. Stejné WinAPI funkce jsou dostupné na 32 i 64bitových systémech [5]. Funkce WinAPI se dají rozdělit do následujících kategorií [6]:

Administrace instalace a správa aplikací.

Bezpečnost autentizace, správa účtů a oprávnění.

Diagnostika výkon počítače a řešení problémů s aplikacemi i sys- témem.

Grafika a multimédia grafický (formátovaný text, grafika i videa) a zvukový výstup.

Síť komunikaci po síti a přístup k sdíleným službám (například vzdále- ným úložištím a tiskárnám).

Systémové služby přistupování k zdrojům počítače a operačního sys- tému (například přístup k souborovému manažeru, procesům, vláknům a paměti).

Uživatelské prostředí tvorba uživatelského prostředí od vytvoření okna po jednotlivé grafické prvky (například tlačítka, menu nebo skrolovací lišty) a zpracování vstupních zařízení formou zpráv, které se posílají aplikacím.

4. https://github.com/twall/jna/tree/master/contrib/x11

8 2. Popis použitých technologií V knihovně WDDMan se používají funkce WinAPI ze souborů User32.dll a Kernel32.dll k funkcionalitě na operačních systémech ze skupiny Windows. Knihovna User32.dll obsahuje funkce pro zjištění informací o oknech a monitorech manipulaci s okny. Používané funkce ze souboru User32.dll jsou:

• EnumWindows – pro procházení oken,

• GetWindowInfo – pro zjištění informací o okně,

• GetWindowText – pro zjištění titulku okna,

• IsWindowVisible – pro zjištění, jestli je okno viditelné,

• MoveWindow – pro přesun a změnu velikosti okna,

• DestroyWindow – pro zavření okna,

• GetSystemMetrics – pro zjištění informací o počtu připojených monitorů a rozlišení zobrazovací plochy,

• EnumDisplayMonitors – pro procházení připojených monitorů.

Ze souboru Kernel32.dll (ten obsahuje především funkce pro pří- stup k systémovým službám) se ještě využívá funkce: • GetLastError – pro zjištění toho, jaká chyba nastala, aby byl při vyvolání výjimky přesnější popis chyby. Funkce WinAPI jsou volány přes knihovnu JNA, kde v její platformně specifické části je pro některé funkce již vytvořené rozhraní.

2.3 X Window System a Xlib

X Window System (často se používají zkratky X nebo X11) je okenní systém používaný převážně na systémech podobných operačnímu sys- tému . Ne všechny operační systémy podobné OS Unix používají X Window System, nepoužívají ho například Mac OS X a Android. X podporuje základní operace s grafickým uživatelským rozhraním, například vykreslování a manipulaci s okny (která jsou vykresleny na ploše, ta se nazývá kořenové okno) a plochami (na každé ploše jsou různá

9 2. Popis použitých technologií okna a uživatel může přepínat, kterou plochu má zrovna zobrazenou) a interakci s vstupními zařízeními (myší a klávesnicí). X Window System neurčuje, jak má být grafické uživatelské rozhraní vykresleno (například podobu tlačítek, skrolovacích lišt a menu), proto různé uživatelské prostředí využívající X často vypadají odlišně. Mezi známá uživatelské prostředí, která používají X Window System, patří GNOME, KDE a Xfce. X Window System používá klient-server model. Server (nazývaný X Server) se stará o vstupy (ze zařízení jako klávesnice a myši) a výstupy (zobrazované prostředí přes grafickou kartu) a přes X protokol komunikuje s klienty, což jsou jednotlivé aplikace. XLib je knihovna, která obsahuje funkce pro komunikaci aplikací X serverem přes X protokol. Xlib je napsaná v jazyce C. Xlib obsahuje tři typy funkcí – funkce pro spojení s X serverem, funkce pro komunikaci s X serverem a lokální funkce klienta. V knihovně WDDMan se využívá knihovna Xlib pro interakci s gra- fickým oživatelským rozhraním na operačním systému Linux. Knihovna WDDMan používá knihovnu JNA pro volání většiny funkcí knihovny Xlib a příklad x11, který umožňuje objektivně orientovaný přístup k části funkcí knihovny Xlib.

2.4 AppleScript

2.4.1 Přehled jazyka AppleScript (AS) je skriptovací jazyk podporovaný operačním systé- mem Mac OS od verze System 7 [7] (všechny následující verze Mac OS, včetně Mac OS X, AppleScript podporují). AppleScript se používá ke komunikaci mezi aplikacemi na operačním systému Mac OS přes Apple events. Zprávy můžou být jak nízkoúrovňové, například zpráva zmáčknuta klávesa p, tak i vysokoúrovňové, například zpráva pro uložení souboru nebo zavření programu. Aplikace, které podporují přijímaní zpráv, se nazývají skriptovatelné. Aplikace, které nejsou skrip- tovatelné, můžou posílat zprávy jiným aplikacím. AppleScript skripty se často využívají k zautomatizování často opa- kovaných a nebo komplexních akcí (například pojmenovávání souborů, změnu systémových nastavení nebo připojení k internetu) [8]. Apple- Script skripty jsou k tomu vhodné kvůli tomu, že umožňují jednoduše

10 2. Popis použitých technologií posílat skrze zprávy data mezi více aplikacemi. AppleScript je slabě a dynamicky typovaný jazyk, ve kterém se syntaxe podobá angličtině. Proměnné se nemusí dopředu deklarovat, AS skript set x to 1 vytvoří proměnnou x a nastaví její hodnotu jako celé číslo 1. Podporované základní datové typy jsou celá a reálná čísla, řetězce, seznamy, logické hodnoty, odkazy, záznamy (složený datový typ) a data (ve významu kalendářního data, které může obsahovat i čas) [9]. Na odřádkování příkazů záleží. Podmínky se v AppleScript skriptech zapisují následně:

if logickáHodnota then příkazy else příkazy2 end if

AS podporuje základní cykly (ukázka pro cyklus while):

repeat while logickáHodnota příkazy end repeat

Zprávy aplikacím se posílají příkazem tell následně: tell application "Jméno aplikace" zprávy end tell

U příkazu tell lze použít i zkrácenou verzi: tell application "Jméno aplikace" to zpráva. Pro psaní AppleScript skriptů je v operačním systému Mac OS X Ap- pleScript Editor (do verze OS Mac OS X 10.6 se jmenoval Script Editor). Podporuje psaní skriptů včetně zvýrazňování syntaxe, spouštění skriptů a zobrazení ladících informací. Rovněž umožňuje automatickou tvorbu AppleScript skriptů odpovídajících tomu, co uživatel právě provádí v operačním systému. Takto jde vytvořit skripty pro zautomatizování často používaných akcí u podporovaných aplikací i bez znalosti jazyka AppleScript.

11 2. Popis použitých technologií 2.4.2 Použití jazyka AppleScript v knihovně WDDMan Jazyk AppleScript se v knihovně WDDMan používá pro interakci s ope- račním systémem Mac OS a aplikacemi na něm spuštěnými. Použil jsem ho kvůli tomu, že umožňuje zjišťování informací o aplikacích i manipulaci s nimi a je dobře zdokumentovaný, jednoduchý na používání a dostatečně univerzální (je součástí Mac OS již od verze System 7). Další možnost pro zjištění oken na OS Mac OS je funkce NSWindowList, která je součástí AppKit5. Zjišťovat informace o získa- ných oknech a manipulovat s nimi lze přes funkce z hlavičkového souboru CGSPrivate.h6. Tyto funkce však nejsou nijak oficiálně dokumentované a mohou přestat v dalších verzích Mac OS X fungovat. Z tohoto důvodu jsem tento postup v knihovně WDDMan nepoužil. AppleScript skripty se v knihovně WDDMan příkazem osascript následně: osascript -e ’AppleScript skript’. Vrácená data pak jsou již zpracována přímo v jazyce Java. Aktuální okna se získají posláním zprávy aplikaci System Events:

tell application "System Events" set info to every window of every application process end tell

Aktuální okna, která mají vlastnost visible pravdivou, se získají posláním zprávy:

set info to every window of (every application process whose visible is true)

Pro manipulaci a zjištění informací o okně se skriptovatelné aplikace posílají zprávy (id představuje id okna, které se získá při zjištění oken):

• get the bounds of window id – získání rozměrů okna,

• set bounds of window id to {x1, y1, x2, y2} – nastavení rozměrů okna a

5. https://developer.apple.com/library/mac/documentation/cocoa/ reference/applicationkit/Miscellaneous/AppKit_Functions/Reference/ reference.html#//apple_ref/c/func/NSWindowList 6. http://code.google.com/p/undocumented-goodness/source/browse/ trunk/CoreGraphics/CGSPrivate.h

12 2. Popis použitých technologií • close window id – zavření okna.

Pro manipulaci a zjištění informací o okně aplikace, která není skriptovatelná, se spouští AppleScript skripty (kde proces je proces okna aplikace, jehož rozměry získáváme):

tell application "System Events" to tell application process "proces" zpráva end tell

Kde zpráva je jedna z

• get {position, size} of window id – získání rozměrů okna,

• set {position, size} to {{x, y}, {width, height}} – změna rozměrů okna a

• click (button 1 of window id) – zavření okna.

Rozlišení obrazovky se zjistí posláním zprávy get the bounds of the window of the desktop aplikaci Finder. Při více připojených monitorech je takto vráceno rozlišení celé zobrazovací plochy, Apple- Script skripty neumožňují dostatečně univerzálně zjistit počet a rozlišení jednotlivých připojených monitorů. Knihovna WDDMan tedy zjištění informací o více monitorech na Mac OS nepodporuje.

13 3 Dokumentace knihovny WDDMan

3.1 Úvod

WDDMan je knihovna napsaná v jazyce Java a umožňuje manipulaci s grafickým uživatelským rozhraním. Podporuje zjištění oken, displejů a ploch a základní manipulaci s nimi. Knihovna WDDMan funguje na operačních systémech Windows XP, Windows Vista, Windows 7 a Windows 8, na operačních systémech Linux s podporou X Window System a na Mac OS X. Knihovna WDDMan je napsána v jazyce Java SE 6, pro fungování knihovny je potřeba mít nainstalováno běhové prostředí jazyka Java podporující alespoň verzi SE 6. Pro fungování knihovny WDDMan je potřeba knihovna JNA. Jsou nutné oba soubory knihovny JNA, jak hlavní soubor (obvykle pojmen- ovaný jna-verze.jar), tak soubor platformně specifickými funkcemi (obvykle pojmenovaný jna-platform-verze.jar, do verze knihovny JNA 4.0.0 obvykle pojmenovaný platform-verze.jar). Knihovna WDDMan vyžaduje alespoň verzi JNA 3.5.1 a verzi platformně specifického souboru 3.5.2 (verze 3.5.1 tohoto souboru obsahovala v jedné z používaných funkcí chybu). Pro správné fungování všech funkcí knihovny WDDMan na operač- ním systému Mac OS je potřeba povolit používání pomocných zařízení. Do verze operačního systému Mac OS X 10.9 stačí v nastavení systému v položce Universal Access zatrhnout nastavení Enable access for assistive devices. Ve verzi operačního systému Mac OS X 10.9 je potřeba povolit používání pomocných zařízení pro každou aplikaci jednotlivě, návod se nachází v oficiální nápovědě k operačnímu systému Mac OS X 1. Pro správné fungování detekce displejů (pokud je jich připojeno více než jeden) a zjištění velikosti oken je potřeba na operačním systému Linux mít nainstalované nástroje xrandr a xprop.

1. http://support.apple.com/kb/HT6026

14 3. Dokumentace knihovny WDDMan 3.2 Přehled souborů knihovny

Knihovna je tvořena více soubory. Všechny soubory knihovny (až na soubor X.java) jsou v balíku wddman. Veřejné (běžný uživatel knihovny je používá) třídy, rozhraní, výčtové typy a výjimky jsou: class WDDMan interface Window interface Desktop class Display enum OperatingSystem class WDDManException extends Exception class UnsupportedOperatingSystemException extends Exception Popis veřejných tříd, rozhraní, výčtových typů a výjimek následuje v dalších podčástech. Veřejná rozhraní jsou implementována v souborech: • class LinuxWindow, class MacWindow a class WinWindow – implementují rozhraní Window (reprezentuje okno a umožňuje manipulaci s ním, popis rozhraní v sekci 3.4) pro odpovídající operační systémy.

• class LinuxDesktop, class MacDesktop a class WinDesktop – implementují rozhraní Desktop (reprezentuje plochu a umo- žňuje zjištění informací o ni, popis rozhraní v sekci 3.5) pro odpovídající operační systémy. Třída MacDesktop rozšiřuje třídu WinDesktop, protože funkcionalita na obou operačních systémech je podobná. Neveřejné (běžný uživatel knihovny je nepoužívá) třídy a rozhraní jsou: • interface Windows – obsahuje funkce pro práci s okny, napří- klad zjištění aktuálních oken nebo získání okna podle titulku. Funkce z rozhraní Windows se obvykle volají z třídy WDDMan při volání funkcí pro práci s okny.

• class LinuxWindows, class MacWindows a class WinWindows – implementují rozhraní Windows pro odpovídající operační sys- témy.

15 3. Dokumentace knihovny WDDMan • interface Desktops – rozhraní obsahuje funkce pro práci s vir- tuálními plochami (detekce ploch, získání plochy podle návu). Funkce z rozhraní Desktops se obvykle volají z třídy WDDMan při volání funkcí pro práci s plochami.

• class LinuxDesktops, class MacDesktops a class WinDes- ktops – implementují rozhraní Desktops pro odpovídající oper- ační systémy. Třída MacDesktops rozšiřuje třídu WinDesktops, protože funkcionalita na obou operačních systémech je skoro stejná.

• interface Screen – obsahuje funkce pro práci s monitory, na- příklad zjištění počtu monitorů, získání monitorů nebo velikost zobrazovací plochy. Funkce z rozhraní Screen se obvykle volají z třídy WDDMan při volání funkcí pro práci s monitory. • class LinuxScreen, class MacScreen a class WinScreen – implementují rozhraní Screen pro odpovídající operační systémy. • class Monitor – pomocná třída představující monitor. Používá se k setřízení monitorů podle pořadí zleva doprava při volání funkce pro získání monitorů na operačních systémech Linux a Windows.

• class MonitorComparatorByRealX – komparátor pro třídu Monitor podle pořadí zleva doprava. • class MacHelper – obsahuje statické pomocné funkce, které používá více tříd na operačním systému Mac OS (například zavolání AppleScript skriptu).

• interface User32Extended – rozhraní pro volání WinAPI fun- kcí přes knihovnu JNA.

• interface X11Ext – rozhraní pro volání funkcí Xlib přes kni- hovnu JNA.

• X.java – soubor z ukázkového příkladu knihovny JNA x112, který knihovna WDDMan používá k volání některých funkcí XLib.

2. https://github.com/twall/jna/tree/master/contrib/x11

16 3. Dokumentace knihovny WDDMan Protože je soubor převzatý a nijak jsem ho kvůli licenčním pod- mínkám neupravoval, tak je jediný v jiném balíku – jnacontrib.x11.api. • class XWindowExtended – rozšiřuje třídu Window ze souboru X.java pro použití v knihovně WDDMan. • class XDisplayExtended – rozšiřuje třídu Display ze souboru X.java pro použití v knihovně WDDMan. Soubor WDDManDemo.java obsahuje testovací a ukázkový příklad použití knihovny na vypsání aktuálních oken, ploch a monitorů. Po- drobný popis testovacího souboru je v kapitole 4.

3.3 Třída WDDMan

Třída WDDMan je hlavní třídou knihovny, umožňuje získání oken, ploch a monitorů, informací o nich a manipulaci s nimi.

3.3.1 Konstruktory public WDDMan() throws UnsupportedOperatingSystemException Konstruktor WDDMan() detekuje operační systém zavoláním funkce: System.getProperty("os.name"). Podporovány jsou návratové hodnoty: • Linux, • Windows XP, • Windows Vista, • Windows 7, • Windows 8, • Mac OS X. Při jiné hodnotě vlastnosti os.name (včetně hodnoty null v případě, kdy vlastnost os.name vůbec neexistuje) vyvolá konstruktor WDDMan() výjimku UnsupportedOperatingSystemException, u které je v popisu vypsán detekovaný operační systém. Konstruktor po detekci operačního systému inicializuje vnitřní pro- měnné třídy podle toho, do které skupiny OS patří detekovaný operační systém.

17 3. Dokumentace knihovny WDDMan public WDDMan(OperatingSystem operatingSystem)

Konstruktor WDDMan(OperatingSystem operatingSystem) připraví vnitřní proměnné třídy podle hodnoty parametru operatingSystem. Výčtový typ OperatingSystem může mít hodnoty WINDOWS, LINUX a MACOS. Konstruktor WDDMan(OperatingSystem operatingSystem) nijak neověřuje, jestli je spuštěný operační systém podporovaný. Při použití jiného výčtového typu než odpovídajícího spuštěnému operačnímu sys- tému není chování knihovny nijak specifikováno a pravděpodobně bude vyvolána výjimka. Použít konstruktor WDDMan(OperatingSystem operatingSystem) je tedy vhodné jen v případě používání knihovny na operačním systému, kde hodnota vlastnosti os.name je nerozpoznána, ale patří do jedné ze skupin podporovaných operačních systémů (Windows, Linux a Mac OS). Například při použití knihovny na budoucí verzi OS Windows.

3.3.2 Funkce pro práci s okny

public List getWindows() throws WDDManException

Funkce getWindows() vrátí seznam obsahující všechna aktuální okna. Na operačním systému Windows okna projitá zavoláním funkce EnumWindows. Na OS Linux okna získaná z vlastnosti _NET_CLIENT_LIST na kořenovém okně. Pokud toto zjištění selže, okna se zjistí z vlastnosti _WIN_CLIENT_LIST. Na OS Mac OS okna získána z proměnné info po zavolání Apple- Script skriptu:

tell application System Events, set info to every window of every application process end tell

Pokud dojde k chybě při získání aktuálních oken je vyvolána výjimka WDDManException s popisem chyby.

18 3. Dokumentace knihovny WDDMan public List getVisibleWindows() throws WDDManException Funkce getVisibleWindows() vrátí seznam obsahující všechna aktu- ální viditelná okna. Jde o okna vrácená funkcí getWindows(), která jsou viditelná (popis, kdy je okno viditelné, je v popisu funkce Window.isVisible(), viz 3.4.1). Pokud dojde k chybě při získání aktuálních viditelných oken je vyvolána výjimka WDDManException s popisem chyby. public Window getWindowByTitle(String title) throws WDDManException Funkce getWindowByTitle() najde a vrátí okno, jehož titulek je stejný jako parametr title (záleží i na velikosti písmen). Pokud žádné takové okno neexistuje, getWindowByTitle() vrátí null. Pokud existuje více oken se stejným titulkem title, funkce vrátí jedno z nich. Dojde-li při získání okna podle titulku k chybě, funkce vyvolá vý- jimku WDDManException s popisem chyby.

public List getWindowsByTitle(String title) throws WDDManException Funkce getWindowsByTitle() najde a vrátí seznam oken, jejichž titulek je stejný jako parametr title (záleží i na velikosti písmen). Pokud žádné takové okno neexistuje, getWindowByTitle() vrátí prázdný seznam. Pokud při získání oken podle titulku nastane chyba, funkce vyvolá výjimku WDDManException s popisem chyby.

3.3.3 Funkce pro práci s plochami public List getDesktops() throws WDDManException Funkce getDesktops vrátí seznam obsahující všechny aktuální plochy. Na OS Linux jde o plochy získáné z vlastnosti _NET_DESKTOP_NAMES. Pokud toto zjištění selže, knihovna zjistí plochy z vlastnosti _WIN_WORKSPACE_NAMES. Protože Windows a Mac OS nepodporují více ploch, při zavolání getDesktops() vrátí jedinou plochu pojmenovanou Windows Desktop,

19 3. Dokumentace knihovny WDDMan respektive Mac OS Desktop, a s pozicí (pozice plochy je popsána v úvodu sekce 3.5) nastavenou na 0. Pokud dojde k chybě při získání aktuálních ploch, je vyvolána vý- jimka WDDManException s popisem chyby.

public int getDesktopCount() throws WDDManException Funkce getDesktopCount() vrátí počet ploch. Na OS Linux jde o počet získaný z vlastnosti _NET_NUMBER_OF_DESKTOPS. Pokud toto zavolání selže, kni- hovna zjistí počet z vlastnosti _WIN_WORKSPACE_COUNT. Na OS Windows a Mac OS getDesktopCount() vrátí vždy 1. Pokud dojde k chybě při získání počtu aktuálních ploch, je vyvolána výjimka WDDManException s popisem chyby.

public Desktop getCurrentDesktop() throws WDDManException Funkce getCurrentDesktop() vrátí aktivní plochu. Na OS Linux se pozice aktivní plochy získá z vlastnosti _NET_CURRENT_DESKTOP. Pokud toto zjištění selže, knihovna zjistí pozici z vlastnosti _WIN_WORKSPACE. Následně je pozice převedena na plochu funkcí findDesktopByPosition(). Na OS Windows a Mac OS funkce vrátí vždy jedinou plochu. Pokud dojde k chybě při získání aktivní plochy, je vyvolána výjimka WDDManException s popisem chyby. public Desktop findDesktopByName(String name) throws WDDManException Funkce findDesktopByName() získá všechny plochy zavoláním funkce getDesktops() a potom mezi nimi najde plochu, jejíž název je shodný s parametrem name (záleží i na velikosti písmen). Pokud je více ploch se stejným názvem, funkce vrátí jednu z nich (není nijak specifikováno kterou). Jestliže žádná plocha s názvem name neexistuje, funkce vrátí null. K chybě při získání plochy podle jména může dojít jen tehdy, pokud dojde k chybě při zavolání funkce getDesktops(). Funkce

20 3. Dokumentace knihovny WDDMan findDesktopByName() potom vyvolá výjimku WDDManException s po- pisem chyby.

public Desktop findDesktopByPosition(int position) throws WDDManException Funkce findDesktopByPosition() získá všechny plochy zavoláním funkce getDesktops() a potom mezi nimi najde plochu, jejíž pozice je shodná s parametrem position. Jestliže žádná plocha s pozicí position neexistuje, funkce vrátí null. K chybě při získání plochy podle pozice může dojít jen tehdy, pokud dojde k chybě při zavolání funkce getDesktops(). Funkce findDesktopByPosition() potom vyvolá výjimku WDDManException s popisem chyby.

public boolean changeCurrentDesktopByPosition(int position) throws WDDManException Funkce changeCurrentDesktopByPosition() změní aktuální plochu podle parametru position. Na OS Linux se odešle zpráva _NET_CURRENT_DESKTOP s parametrem position. Na OS Windows a Mac OS funkce neprovede žádnou změnu, protože více ploch není těmito operačními systémy podporovaných. Pokud je hodnota position menší než 0 nebo větší než hodnota získána zavoláním getDesktopCount() - 1, funkce vrátí false, jinak vrátí true. Pokud dojde k chybě při změně aktivní plochy podle pozice, je vyvolána výjimka WDDManException s popisem chyby. public boolean changeCurrentDesktopByName(String name) throws WDDManException Funkce changeCurrentDesktopByName() změní aktuální plochu podle parametru name. Na OS Linux se pošle zpráva _NET_CURRENT_DESKTOP s parametrem pozicí plochy (plocha se vyhledá zavoláním funkce findDesktopByName(name)).

21 3. Dokumentace knihovny WDDMan Na OS Windows a Mac OS funkce neprovede žádnou změnu, protože více ploch není těmito operačními systémy podporovaných. Pokud žádná plocha s názvem name neexistuje, funkce vrátí false, jinak vrátí true. Pokud dojde k chybě při změně aktivní plochy podle jména, je vyvolána výjimka WDDManException s popisem chyby.

public void moveWindowToDesktop(Window window, Desktop desktop) throws WDDManException Funkce moveWindowToDesktop() přesune okno window na plochu desktop. Na OS Linux se pošle zpráva _NET_WM_DESKTOP, kde parametry jsou okno a pozice plochy desktop. Na OS Windows a Mac OS se okno nepřesune, protože více ploch není podporovaných. Pokud dojde k chybě při přesunu okna na plochu, je vyvolána výjimka WDDManException s popisem chyby.

3.3.4 Funkce pro práci s monitory public int getScreenWidth() throws WDDManException Funkce getScreenWidth() vrátí šířku zobrazovací plochy. Na OS Windows jde o výsledek zavolání WinAPI funkce: GetSystemMetrics(SM_CXVIRTUALSCREEN), kde konstanta SM_CXVIRTUALSCREEN je rovna 78. Na OS Linux se zjistí šířka Xlib funkcí XDisplayWidth. Na operačním systému Mac OS se získá šířka z výsledku Apple- Script skriptu tell application "Finder" to get the bounds of the window of the desktop. Pokud dojde k chybě při získání šířky zobrazovací plochy, je vyvolána výjimka WDDManException s popisem chyby.

public int getScreenHeight() throws WDDManException Funkce getScreenHeight() vrátí výšku zobrazovací plochy. Na OS Windows jde o výsledek zavolání WinAPI funkce: GetSystemMetrics(SM_CYVIRTUALSCREEN),

22 3. Dokumentace knihovny WDDMan kde konstanta SM_CYVIRTUALSCREEN je rovna 79. Na OS Linux se zjistí výška Xlib funkcí XDisplayHeight. Na operačním systému Mac OS se získá výška z výsledku Apple- Script skriptu tell application "Finder" to get the bounds of the window of the desktop. Pokud dojde k chybě při získání výšky zobrazovací plochy, je vyvolána výjimka WDDManException s popisem chyby.

public int getDisplaysCount() throws WDDManException Funkce getDisplaysCount() vrátí počet připojených monitorů. Na operačním systému Windows se počet zjistí zavoláním funkce GetSystemMetrics(SM_CMONITORS), kde hodnota konstanty SM_CMONITORS je 80. Na OS Linux funkce getDisplaysCount() získá počet připojených monitorů nástrojem xrandr (příkazem xrandr a z výsledku se zjistí počet připojených monitorů). Je tedy nutné mít tento nástroj na OS Linux nainstalován. Pokud není, funkce vyvolá výjimku WDDManException s informací, že nástroj není nainstalován. Na OS Mac OS nelze AppleScript skriptem, dostatečně podporo- vaným na různých verzích operačního systému Mac OS, zjistit počet připojených monitorů. Funkce tedy vždy vrátí 1. Pokud dojde k chybě při získání počtu monitorů, je vyvolána výjimka WDDManException s popisem chyby. public List getDisplays() throws WDDManException Funkce getDisplays() vrátí seznam aktuálně připojených monitorů, který je seřazený podle polohy monitorů zleva doprava. Nejlevější moni- tor je tedy první v seznamu a nejpravější poslední. Na OS Windows jde o monitory projité zavoláním funkce EnumDisplayMonitors a následně setřízené podle polohy. Na operačním systému Linux se monitory získají nástrojem xrandr. Z výsledku příkazu xrandr se zjistí informace o jednotlivých monitorech a následně se monitory setřídí dle polohy. Je tedy nutné mít tento nástroj na OS Linux nainstalován. Pokud není, funkce vyvolá výjimku WDDManException s informací, že nástroj není nainstalován.

23 3. Dokumentace knihovny WDDMan Na OS Mac OS nelze AppleScript skriptem, dostatečně podporova- ným na různých verzích operačního systému Mac OS, zjistit informace o jednotlivých připojených monitorech. Funkce getDisplays() tedy na OS Mac OS vrátí seznam obsahující jeden monitor, jehož šířka je rovna zavolání funkce getScreenWidth() a výška getScreenHeight() (což odpovídá celé zobrazovací ploše). Pokud dojde k chybě při získání počtu monitorů, je vyvolána výjimka WDDManException s popisem chyby.

3.3.5 Další funkce public OperatingSystem getRunningOperatingSystem() Funkce getRunningOperatingSystem() vrátí hodnotu výčtového typu OperatingSystem podle toho, jaká verze knihovny je používána (jestli verze pro OS Windows, Linux nebo Mac OS). Pokud byla knihovna inicializována konstruktorem WDDMan().getRunningOperatingSystem() vrátí skupinu operačního systému podle detekovaného OS. Při použití kontruktoru WDDMan(OperatingSystem operatingSystem), funkce vrátí hodnotu parametru konstruktoru.

3.4 Rozhraní Window

Rozhraní Window reprezentuje okno. Každé okno je určeno souřadnicemi (přičemž bod [0,0] je v levém horním rohu zobrazovací plochy) a má titulek (který může být prázdný). Dále lze u okna zjistit, na které je ploše a jestli je viditelné, a manipulovat s ním, zavřít a přesouvat ho. Na operačních systémech Windows a Linux je okno určeno trvale a jednoznačně vnitřním ukazatelem na okno. Na operačním systému Mac OS nelze při používání AppleScript skriptů jednoznačně trvale identifikovat okno. Každé okno je určené jménem aplikace, která ho vytvořila, procesem aplikace a id, což před- stavuje pořadí oken aplikace podle hodnoty z souřadnice. Hodnotu id 1 má okno, které je nejvýš ze všech oken aplikace a může překrývat ostatní okna aplikace. Hodnota id se tedy v průběhu mění (stačí, aby uživatel přenesl okno do popředí nebo vyvolal nové okno aplikace). Proto je vhodné před každou manipulací s oknem získat aktuální stav oken.

24 3. Dokumentace knihovny WDDMan V AppleScript skriptech označuje application jméno aplikace, je- jíž rozměry zjišťujeme, id pořadí zjišťovaného okna a proces proces aplikace.

3.4.1 Funkce pro zjištění informací o okně public int getTop() throws WDDManException Funkce getTop() vrátí vzdálenost horního okraje okna od horního okraje zobrazovací plochy. Na operačním systému Wndows se rozměry okna zjístí zavoláním WinAPI funkce GetWindowInfo(windowHandle, windowInfo), kde windowHandle je handle okna a do struktury windowInfo se uloží in- formace o okně. Následně se ze struktury windowInfo zjistí vzdálenost horního okraje okna od horního okraje zobrazovací plochy. Na OS Linux se souřadnice okna získají zavoláním funkce XGetGeometry. Následně se souřadnice okna převedou na souřadnice na zobrazovací ploše zavoláním funkce XTranslateCoordinates. Potom se ze souřadnic získá vzdálenost horního okraje okna od horního okraje zobrazovací plochy. Na operačním systému Mac OS se rozměry okna akriptovatelné aplikace zjistí zavoláním AppleScript skriptu "tell application " + application + " to get the bounds of window " + id". Rozměry okna neskriptovatelné aplikace získáme zavoláním skriptu:

tell application "System Events" to tell application process "proces" get {position, size} of window id end tell

Následně se zpracují rozměry okna a zjistí se vzdálenost horního okraje okna od horního okraje zobrazovací plochy. Používá se cachování výsledků – po prvním zjištění rozměrů okna jsou rozměry jednu sekundu uloženy. Pokud je další zjištění rozměrů okna zavoláno po kratší době než jedna sekunda, tak jsou vráceny uložené hodnoty. Cachování výsledku se používá kvůli zrychlení knihovny při opakovaném volání zjišťování rozměrů na operačním systému Mac OS. Pokud dojde k chybě při získání rozměrů okna, je vyvolána výjimka WDDManException s popisem chyby.

25 3. Dokumentace knihovny WDDMan public int getBottom() throws WDDManException

Funkce getBottom() vrátí vzdálenost dolního okraje okna od horního okraje zobrazovací plochy. Rozměry okna se zjistí stejně jako u funkce getTop(). Pokud dojde k chybě při získání rozměrů okna, je vyvolána výjimka WDDManException s popisem chyby. public int getLeft() throws WDDManException

Funkce getLeft() vrátí vzdálenost levého okraje okna od levého okraje zobrazovací plochy. Rozměry okna se zjistí stejně jako u funkce getTop(). Pokud dojde k chybě při získání rozměrů okna, je vyvolána výjimka WDDManException s popisem chyby. public int getRight() throws WDDManException

Funkce getRight() vrátí vzdálenost pravého okraje okna od levého okraje zobrazovací plochy. Rozměry okna se zjistí stejně jako u funkce getTop(). Pokud dojde k chybě při získání rozměrů okna, je vyvolána výjimka WDDManException s popisem chyby. public int getWidth() throws WDDManException

Funkce getWidth() vrátí šířku okna, což je vzdálenost rovna getRight() - getLeft(). Pokud dojde k chybě při získání rozměrů okna, je vyvolána výjimka WDDManException s popisem chyby. public int getHeight() throws WDDManException

Funkce getHeight() vrátí výšku okna, což je vzdálenost rovna getBottom() - getTop(). Pokud dojde k chybě při získání rozměrů okna, je vyvolána výjimka WDDManException s popisem chyby.

26 3. Dokumentace knihovny WDDMan public String getTitle() throws WDDManException Funkce getTitle() vrátí titulek okna. Na OS Windows se titulek zjistí zavoláním WinAPI funkce GetWindowText(windowHandle, title, 1000), kde windowHandle je handle okna, title pole znaků, do kterého se titulek uloží a 1000 ve- likost pole znaků title (na Windows jde o maximální délku titulku, kterou knihovna podporuje). Pole znaků title se poté převede na řetězec. Na OS Linux se proveden z vlastnosti _NET_WM_NAME. Pokud se nepodaří titulek získat, zjistí se z vlastnosti XA_WM_NAME. Na operačním systému Mac Os je titulek uložený již při vytvoření okna, jen se vrátí. Pokud dojde k chybě při získání titulku okna, je vyvolána výjimka WDDManException s popisem chyby. public boolean isVisible() throws WDDManException Funkce isVisible() vrátí, jestli je okno viditelné. Okno je viditelné, pokud má obdélník určený jeho okraji (tedy zavoláním getLeft(), getTop(), getRight() a getBottom()) neprázdný průnik s obdélníkem určeným okrajem zobrazovací plochy (což je obdélník se souřadnicemi 0, 0, getScreenWidth() a getScreenHeight()) a zároveň na OS Win- dows musí okno při zavolání WinAPI funkce IsWindowVisible vrátit true a na OS Mac OS musí mít vlastnost visible nastavenu na true a jméno procesu nesmí být DashboardClient. Okno tedy může být viditelné i tehdy, pokud ho uživatel nevidí na obrazovce – například když je pod jiným oknem, které ho úplně překrývá. Pokud dojde k chybě při zjištění, jestli je okno viditelné, je vyvolána výjimka WDDManException s popisem chyby.

public Desktop getDesktop() throws WDDManException Funkce getDesktop() vrátí plochu, na které se nachází okno. Pokud okno není na žádné ploše, funkce vrátí null. Na operačním systému Linux se zjistí pozice plochy, na které je okno zjištěním vlastnosti _NET_WM_DESKTOP. Pokud toto zjištění selže, pozice plochy se zjistí vlastností _WIN_WORKSPACE. Následně se pozice převede

27 3. Dokumentace knihovny WDDMan na plochu zavoláním funkce WDDMan.findDesktopByPosition a tato plocha se vrátí. Okno nemusí být na žádné ploše, potom funkce vrátí hodnotu null. Na OS Windows a Mac OS není více ploch podporovaných, pro každé okno se vrátí tedy vždy jediná plocha. Pokud dojde na operačním systému Linux k chybě při zjištění, na které ploše je okno, je vyvolána výjimka WDDManException s popisem chyby.

3.4.2 Funkce pro manipulaci s oknem public void close() throws WDDManException Funkce close() zavře okno. Na operačním systému Windows se zavolá WinAPI funkce DestroyWindow(windowHandle), kde windowHandle je handle okna. Na OS Windows nelze touto funkcí zavřít okno, které vytvořilo jiné vlákno, než které volá funkci DestroyWindow. V tomto případě se okno nezavře a je vyvolána výjimka WDDManException s popisem, že nelze zavřít okno, které vytvořilo jiné vlákno. Na OS Linux se okno zavře posláním zprávy "_NET_CLOSE_WINDOW". Na operačním systému Mac OS se zavře okno skriptovatelné aplikace provedením AppleScript skriptu:

tell application "aplikace" close window "id" end tell

Okno neskriptovatelné aplikace se zavře skriptem:

tell application "System Events" to tell application process "proces" click (button 1 of window id) end tell

Pokud dojde k chybě při získání rozměrů okna, je vyvolána výjimka WDDManException s popisem chyby.

28 3. Dokumentace knihovny WDDMan public void resize(int x, int y, int width, int height) throws WDDManException Funkce resize() nastaví velikost okna tak, že levý horní roh okna bude mít vzdálenost x pixelů od horního okraje zobrazovací plochy a y pixelů od levého okraje zobrazovací plochy, šířku width pixelů a výšku height pixelů. Na operačním systému Windows se zavolá WinAPI funkce MoveWindow(windowHandle, x, y, width, height, true), kde windowHandle je handle odpovídající oknu. Na OS Linux se zavolá funkce XMoveResizeWindow. Na operačním systému Mac OS se provede pro změnu velikosti okna skriptovatelné aplikace AppleScript skript: tell application application activate set bounds of window id to {x, y, (x + width), (y + height)} end tell Pro změnu velikosti okna neskriptovatelné aplikace skript: tell application "System Events" to tell application process "proces" tell window id, set {position, size} to {{x, z}, {width, height}} end tell end tell Pokud dojde k chybě nastavení velikosti okna, je vyvolána výjimka WDDManException s popisem chyby. public void move(int x, int y) throws WDDManException Funkce move() posune okno o x pixelů doprava a y pixelů dolů (hodnoty x a y mohou být i záporné, pak se posun vykoná doleva, respektive nahoru). Na operačním systému Linux se zavolá funkce XMoveWindow. Na OS Windows a Mac OS se zavolá: resize(getLeft() + x, getTop() + y, getWidth(), getHeight()).

29 3. Dokumentace knihovny WDDMan Pokud dojde k chybě při posunu okna, je vyvolána výjimka WDDManException s popisem chyby.

3.5 Rozhraní Desktop

Rozhraní Desktop reprezentuje plochu operačního systému. Každá plo- cha je určená jménem a pozicí. Pozice okna je číslo, zobrazení ploch záleží na okenním manažeru. V některých okenních manažerech odpo- vídá pozice zobrazení ploch zleva doprava. U plochy jde zjistit, jestli je aktivní a získat seznam oken (nebo viditelných oken), které se na ní nacházejí. Tyto informace o ploše se dynamicky mění (například při každém zavolání funkce getWindows() je vrácen seznam oken, které jsou na ploše nyní). Operační systémy Windows a Mac OS více ploch nepodporují, je na nich jediná, stále aktivní, plocha s jménem plochy Windows Desktop, respektive Mac OS Desktop a pozicí 0.

public String getName() Funkce getName() vrátí jméno plochy. Na operačním systému Linux se jméno získá z vlastnosti _NET_DESKTOP_NAMES, pokud zjištění selže, zjistí se jméno z vlastnosti _WIN_WORKSPACE_NAMES. Na OS Windows a Mac OS je jméno plochy Windows Desktop, respektive Mac OS Desktop.

public int getPosition() Funkce getPosition() vrátí pozici plochy, což je číslo mezi 0 a výsledkem getDesktopCount() - 1. Na OS Windows a Mac OS je pozice plochy vždy 0. public boolean isCurrent() throws WDDManException Funkce isCurrent() vrací, jestli je plocha aktivní. Na operačním systému Linux se zjistí pozice aktivní plochy z vlast- nosti _NET_CURRENT_DESKTOP. Pokud toto zjištění selže, kni- hovna zjistí pozici z vlastnosti _WIN_WORKSPACE. Následně je

30 3. Dokumentace knihovny WDDMan pozice aktivní plochy porovnána s pozicí plochy, na které je funkce isCurrent() zavolána. Na OS Windows a Mac OS je jediná plocha vždy aktivní. Pokud dojde k chybě při získání aktivní plochy, je vyvolána výjimka WDDManException s popisem chyby. public List getWindows() throws WDDManException Funkce getWindows() vrátí seznam všech oken, které jsou na ploše. Na operačním systému Linux se projdou všechna okna a vrátí se seznam všech oken, u kterých se plocha získaná zavoláním getDesktop() rovná ploše, na které je volána funkce getWindows(). Na OS Windows a Mac OS jde o všechna okna. Pokud dojde k chybě při získání oken na ploše, je vyvolána výjimka WDDManException s popisem chyby. public List getVisibleWindows() throws WDDManException Funkce getVisibleWindows() vrátí seznam všech viditelných oken, které jsou na ploše. Na operačním systému Linux získají okna na ploše zavoláním funkce getWindows() a vrátí se ty z nich, které při zavolání isVisible() vrátí true. Na OS Windows a Mac OS jsou vrácena všechna viditelná okna. Pokud dojde k chybě při získání viditelných oken na ploše, je vyvolána výjimka WDDManException s popisem chyby.

3.6 Třída Display

Třída Display reprezentuje monitor. Každý monitor má určenou pozici zleva doprava a rozlišení (šířku a výšku). Popsat jiné rozložení displejů (například v mřížce) knihovna WDDMan nyní neumožňuje. Informace o monitorech se dynamicky nemění (nastane-li například změna ro- zlišení monitoru, funkce getWidth() a getHeight() budou stále vracet původní hodnoty). V knihovně WDDMan se nepoužívají (použité me- tody je neumožňují získat) jednoznačné ukazatele na monitor, tudíž se

31 3. Dokumentace knihovny WDDMan informace dynamicky neaktualizuje. Je vhodné si před každým použitím získat aktuální informace o monitorech funkci getDisplays(). Operační systému Mac OS neumožňuje dostatečně univerzálně získat informace o monitorech přes AppleScript skripty. Na OS Mac OS je vždy jen jeden monitor, který má pozici 0 a šířku a výšku odpovídající celé zobrazovací ploše. Popis toho, jak se zjišťují informace o monitoru, je v popisu funkce WDDMan.getDisplays().

public int getPosition()

Funkce getPosition() vrátí pozici monitoru podle toho, kolikátý je monitor zleva doprava. Návratová hodnota může být mezi hodnotou 0 (pro nejlevější monitor) a výsledkem getDisplaysCount() - 1 (pro nejpravější monitor).

public int getWidth()

Funkce getWidth() vrátí šířku monitoru v pixelech dle nastaveného rozlišení.

public int getHeight()

Funkce getHeight() vrátí výšku monitoru v pixelech dle nastaveného rozlišení.

3.7 Výčtový typ OperatingSystem

Výčtový typ operační systém může nabývat hodnot: • WINDOWS, • LINUX, • MACOS. Používá se v konstruktoru: WDDMan.WDDMan(OperatingSystem operatingSystem), ve kterém se specifikuje, jakou verzi má knihovna použít a při zavolání funkce WDDMan.getRunningOperatingSystem().

32 3. Dokumentace knihovny WDDMan 3.8 Výjimky

Knihovna vyvolává 2 různé výjimky:

• UnsupportedOperatingSystemException a

• WDDManException.

Při použití knihovny na nepodporovaném operačním systému je vyvolána výjimka UnsupportedOperatingSystemException, kde je v popisu uve- deno, na kterém OS je knihovna použita. Při jakékoliv jiné chybě při používání knihovny je vyvolána výjimka WDDManException s popisem chyby.

33 4 Testování knihovny WDDMan

Pro testování knihovny WDDMan jsem vytvořil testovací aplikaci WD- DManDemo. WDDManDemo je přímo součástí knihovny v souboru WDDManDemo.java. Tento soubor jako jediný obsahuje funkci main, proto je přes něj knihovna přímo spustitelná příkazem java -jar WDDMan.jar. V složce lib musí být umístěn hlavní sou- bor JNA knihovny (pojmenovaný jna.jar) a platformně specifický soubor (pojmenovaný jna-platform.jar). Testovací aplikaci lze použít i jako ukázkový příklad, jak knihovnu WDDMan používat. Při spuštění vypíše testovací aplikace WDDManDemo základní in- formace, které se dají knihovnou získat, na standardní výstup. Postupně vypíše následující informace:

• skupinu detekovaného operačního systému,

• rozlišení celé zobrazovací plochy,

• počet připojených monitorů a jejich rozlišení,

• počet připojených ploch a jejich jména,

• počet oken,

• viditelná okna, jejich název a rozměry a

• okna, která nejsou viditelná, jejich název a rozměry.

Při spuštění s prvním parametrem manipulation (tedy java -jar WDDMan.jar manipulation) testovací aplikace WDDManDemo otes- tuje i manipulaci s grafickým uživatelským rozhraním. Po výpisu zák- ladních informací provede následujcí kroky (mezi každými dvěma kroky vždy 4 sekundy čeká):

• vytvoří nové okna s titulkem WDDMan Demo (je vytvořeno JFrame okno),

• oknu nastaví rozměry,

• okno posune,

34 4. Testování knihovny WDDMan • pokud je více ploch než 1:

? přepne aktivní plochu na jinou plochu, ? přesune okno na aktivní plochu, ? přepne aktivní plochu na původní,

• okno zavře. Na operačním systému Windows se zavření okna nepovede a skončí vyvoláním výjimky, protože okno vytvořilo jiné vlákno (JFrame okno je otevřeno v novém vlákně). Okno je potom zavřeno funkcí dispose přímo JFrame okna.

Knihovnu WDDMan jsem vyvíjel a testoval na operačních systémech:

• Windows 7 Home Premium SP 1 s verzí JRE 1.7.0_45-b18,

• Fedora release 18 s verzí JRE fedora-2.3.5.3.fc18-x86_64

• Mac OS X 10.6.8 s verzí JRE 1.6.0_65-b14-462-10M4609.

Knihovna WDDMan byla vyvíjena s verzí hlavního souboru knihovny JNA 3.5.1 a s platformně specifickým souborem verze 3.5.2-20130308.202545-5. Tyto verze knihovny JNA byly nejvíce testovány. Verze 3.5.1 platformně specifického souboru obsahovala v jedné z používaných funkcí chybu a nešla použít. Protože v době vývoje knihovny nebyla ještě vydána verze JNA 3.5.2, bylo k vývoji použito aktuální sestavení. Knihovna WDDMan byla otestována testovací aplikací i s verzemi knihovny JNA 3.5.2 a 4.0.0 (k 20. 12. 2013 nejnovější verze) na operačním systému Windows 7.

35 5 Závěr

Ve své bakalářské práci jsem vytvořil knihovnu WDDMan v programo- vacím jazyce Java pro manipulaci s grafickým uživatelským rozhraním na operačních systémech skupiny , Linux a Mac OS. Knihovna WDDMan bude použita při tvorbě aplikace pro vzdálené tlumočení do znakového jazyka pro Středisko pro pomoc studentům se specifickými nároky Masarykovy univerzity. Knihovna s podobnou funkcionalitou doposud neexistovala. Knihovna WDDMan bude zveře- jněna k volnému užití. Knihovna WDDMan umožňuje detekci otevřených oken, informací o nich – titulek, pozici a viditelnost okna a manipulaci s nimi – přesunutí, změnu velikosti a zavření. Dále podporuje zjištění informací o monitorech – celkovou zobrazovací plochu, počet připojených monitorů a jejich rozlišení. Rovněž knihovna umožňuje na operačních systémech skupiny Linux zjištění virtuálních ploch, aktivní plochy a manipulaci s nimi – změnu aktivní plochy a přesun aplikací mezi plochami. Podporovaná funkcionalita se na jednotlivých operačních systémech mírně liší. Operační systémy ze skupiny Mac OS neumožňují dostatečně univerzálně zjistit informace o jednotlivých připojených monitorech. Knihovna WDDMan obsahuje kromě české dokumentace v této ba- kalářské práci i anglickou dokumentaci ve formě Javadoc komentářů. Vygenerovaná anglická dokumentace z Javadoc komentářů v HTML souborech je přílohou práce. Součástí dokumentace je i jednoduchý testovací a ukázkový program v souboru WDDManDemo.java, který vy- píše na standardní výstup informace o aktuálních oknech, plochách i monitorech. Při spuštění s prvním parametrem manipulation otestuje i základní manipulaci s oknem. Ukázkový program se spustí příkazem java -jar WDDManDemo.jar, respektive java -jar WDDManDemo.jar manipulation. Zdrojový kód i dokumentace jsou zveřejněny pod otevřenou licencí „The BSD 3-Clause License“. Knihovnu WDDMan plánuji nadále rozvíjet. Funkcionalita jde dále rozšiřovat, například přidat další funkce pro manipulaci s okny nebo umožnit přesnější popsání pozic monitorů, které jsou umístěny jinak než vedle sebe. Rovněž plánuji reagovat na podněty uživatelů.

36 Reference

[1] LIŠKA, Miloš a Petr HOLUB. CoUniverse: Framework for Build- ing Self-organizing Collaborative Environments Using Extreme- Bandwidth Media Applications. In Lecture Notes in Computer Sci- ence vol. 5415 Euro-Par 2008 Workshops - Parallel Processing. Las Palmas de Gran Canaria, Spain: Springer Berlin / Heidelberg, 2008. s. 339-351, 12 s. ISBN 978-3-642-00954-9. [2] WALL, Timothy. Java Native Access (JNA). In: Twall/jna · GitHub [online]. 2011 [cit. 2013-12-8]. Dostupné z: https://github. com/twall/jna/blob/master/README.md [3] ARCHIBALD, Stuart. JNA, JNI and Raw . In: OpenGamma Developers [online]. 2012 [cit. 2013-12-08]. Dostupné z: http://developers.opengamma.com/blog/2012/05/25/jna-jni- and-raw-java-performance [4] CHAFIK, Olivier. FAQ BridJ’s Frequently Asked Questions. In: Bridj BridJ: Let Java & Scala call C, C++, ObjectiveC, C#... Google Project Hosting [online]. 2013 [cit. 2013-12-09]. Dostupné z: http://code.google.com/p/bridj/wiki/FAQ#JNA [5] MICROSOFT CORPORATION. Windows API. In: Microsoft Developer Network [online]. 2010 [cit. 2013-12-12]. Dostupné z: http: //msdn.microsoft.com/en-us/library/cc433218(VS.85).aspx [6] MICROSOFT CORPORATION. Overview of the Windows API. In: Microsoft Developer Network [online]. 2010 [cit. 2013-12-12]. Dos- tupné z: http://msdn.microsoft.com/en-us/library/aa383723(v= vs.85).aspx [7] BYTNAR, Steven. AppleScript: Introduction. In: MacWarriors AppleScript Workshop [online]. 1996 [cit. 2013-11-26]. Dostupné z: http://www.acm.uiuc.edu/iCal/workshops/applescript/1996/ 1_ introduction.html#WhereDidItComeFrom [8] NYHTHAWK PRODUCTIONS. AppleScript: The Language of Automation. In: Mac OS X Automation [online]. [2009] [cit. 2013-12- 03]. Dostupné z: http://www.macosxautomation.com/applescript/ index.html [9] MAHAFFEY, T.J. Cooking with Data Types - Part 1. In: Ap- plescript Forums [online]. 2003 [cit. 2013-12-03]. Dostupné z: http: //macscripter.net/viewtopic.php?pid=96743#p96743

37 A Seznam příloh

K práci přikládám přílohy:

• WDDMan.jar – knihovna WDDMan.

• WDDMan-javadoc.zip – anglická Javadoc dokumentace knihovny WDDMan.

• WDDMan-source.zip – zdrojové kódy knihovny WDDMan.

38