abb9b742fee4ddc89e3d47626349dcfbadb59e5c
[dockapps.git] / wmpager / src / wmpager.c
blobabb9b742fee4ddc89e3d47626349dcfbadb59e5c
1 /* $Id: wmpager.c,v 1.4 2002/08/16 17:22:26 essmann Exp $
3 * Copyright (c) 2001 Bruno Essmann <essmann@users.sourceforge.net>
4 * All rights reserved.
5 */
7 #include <X11/Xlib.h>
8 #include <X11/Xutil.h>
9 #include <X11/Xatom.h>
10 #include <X11/xpm.h>
11 #include <X11/extensions/shape.h>
12 #include <sys/time.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
20 #include "buttons.xpm"
21 #include "screen.xpm"
24 * Constants
27 #define AUTHOR "Bruno Essmann <essmann@users.sourceforge.net>"
28 #define APPLICATION "wmpager"
29 #define VERSION "1.2"
30 #define BUILD_REV "$Revision: 1.4 $"
31 #define BUILD_DATE "$Date: 2002/08/16 17:22:26 $"
33 #define XA_WIN_WORKSPACE "_WIN_WORKSPACE"
34 #define XA_WIN_WORKSPACE_NAMES "_WIN_WORKSPACE_NAMES"
36 #define WMPAGER_ENV "WMPAGER"
37 #define WMPAGER_DEFAULT_INSTALL_DIR "/usr/local/share/wmpager/"
38 #define WMPAGER_USER_DIR ".wmpager/"
41 * Prototypes
44 void usage (int bVerbose);
45 void info ();
46 void setVerbose (int bVerbose);
47 int isVerbose ();
49 void initApplicationName (char* szApplicationName);
50 char* getApplicationName ();
52 void initDisplay (char* szDisplay);
53 void destroyDisplay ();
54 Display* getDisplay ();
56 Pixel getWhitePixel ();
57 Pixel getBlackPixel ();
58 int getDefaultScreen ();
59 int getDefaultDepth ();
60 void initWindow (int nArgc, char** szArgv);
61 void destroyWindow ();
62 GC getWindowGraphics ();
63 GC getMainGraphics ();
64 void initWindowMask (char* szInstallDir, char* szButtonTheme);
65 void redrawWindow ();
66 void getWindowOrigin (Window w, int* nX, int* nY);
68 void loop ();
70 void initButtons (int nButtons, int nColumns, int nRows);
71 int getButtonCount ();
72 int getButtonRowCount ();
73 int getButtonColumnCount ();
74 int getButtonWidth ();
75 int getButtonHeight ();
76 int getButtonAt (int nLocationX, int nLocationY);
77 void getButtonLocation (int nButton, int* nLocationX, int* nLocationY);
79 void initTime ();
80 long currentTimeMillis ();
82 void initScreens ();
83 int getScreenCount ();
84 char* getScreenName (int nScreen);
85 int getCurrentScreen ();
86 void setCurrentScreen (int nCurrentScreen);
87 void gotoScreen (int nWorkspace);
90 * Main
93 int main (int nArgc, char** szArgv) {
94 char* szDisplay= NULL;
95 char* szTheme= NULL;
96 char* szInstallDir= NULL;
97 int nWorkspaces= -1;
98 int bVerbose= 0;
99 int nSizeX= -1, nSizeY= -1;
100 int i;
101 initApplicationName(szArgv[0]);
102 /* we no longer use the WMPAGER environment variable
103 * szInstallDir= (char*) getenv(WMPAGER_ENV);
104 * instead we simply use a default installation directory
106 szInstallDir= WMPAGER_DEFAULT_INSTALL_DIR;
107 i= 1;
108 while (i < nArgc) {
109 if (strcmp("-h", szArgv[i]) == 0 || strcmp("--help", szArgv[i]) == 0) {
110 usage(1);
111 } else if (strcmp("-v", szArgv[i]) == 0 || strcmp("--verbose", szArgv[i]) == 0) {
112 bVerbose= 1;
113 } else if (strcmp("-w", szArgv[i]) == 0 || strcmp("--workspaces", szArgv[i]) == 0) {
114 i+= 1;
115 if (i < nArgc) {
116 sscanf(szArgv[i], "%d", &nWorkspaces);
117 if (nWorkspaces <= 0 || nWorkspaces > 9) {
118 fprintf(stderr, "%s: illegal number of workspaces '%s' for option '%s' (has to be 1-9)\n\n", getApplicationName(), szArgv[i], szArgv[i-1]);
119 usage(0);
121 } else {
122 fprintf(stderr, "%s: workspace count expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
123 usage(0);
125 } else if (strcmp("-s", szArgv[i]) == 0 || strcmp("--size", szArgv[i]) == 0) {
126 i+= 1;
127 if (i < nArgc) {
128 sscanf(szArgv[i], "%dx%d", &nSizeX, &nSizeY);
129 if (nSizeX <= 0 || nSizeX > 3 || nSizeY <= 0 || nSizeY > 3) {
130 fprintf(stderr, "%s: illegal size '%s' for option '%s' (has to be 1x1 .. 3x3)\n\n", getApplicationName(), szArgv[i], szArgv[i-1]);
131 usage(0);
133 } else {
134 fprintf(stderr, "%s: size argument expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
135 usage(0);
137 } else if (strcmp("-i", szArgv[i]) == 0 || strcmp("--installdir", szArgv[i]) == 0) {
138 i+= 1;
139 if (i < nArgc) {
140 struct stat buf;
141 szInstallDir= szArgv[i];
142 if (stat(szInstallDir, &buf) != 0) {
143 fprintf(stderr, "%s: cannot access installation directory '%s'\n\n", getApplicationName(), szArgv[i]);
144 usage(0);
146 } else {
147 fprintf(stderr, "%s: display argument expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
148 usage(0);
150 } else if (strcmp("-d", szArgv[i]) == 0 || strcmp("--display", szArgv[i]) == 0) {
151 i+= 1;
152 if (i < nArgc) {
153 szDisplay= szArgv[i];
154 } else {
155 fprintf(stderr, "%s: display argument expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
156 usage(0);
158 } else if (strcmp("-t", szArgv[i]) == 0 || strcmp("--theme", szArgv[i]) == 0) {
159 i+= 1;
160 if (i < nArgc) {
161 szTheme= szArgv[i];
162 } else {
163 fprintf(stderr, "%s: theme argument expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
164 usage(0);
166 } else {
167 fprintf(stderr, "%s: unknown option '%s'\n\n", getApplicationName(), szArgv[i]);
168 usage(0);
170 i+= 1;
172 setVerbose(bVerbose);
173 if (isVerbose()) {
174 char* szRealDisplay= (szDisplay == NULL) ? (char*) getenv("DISPLAY") : szDisplay;
175 if (szRealDisplay == NULL) {
176 szRealDisplay= "localhost:0.0";
178 info();
179 fprintf(
180 stdout,
181 "[ ] startup options:\n" \
182 "[ ] - verbose= true\n" \
183 "[ ] - display= '%s'\n" \
184 "[ ] - installdir= '%s'\n" \
185 "[ ] - theme= '%s'\n" \
186 "[ ] - workspaces= '%d'\n" \
187 "[ ] - size= '%dx%d'\n",
188 szRealDisplay,
189 szInstallDir == NULL ? "<undefined>" : szInstallDir,
190 szTheme == NULL ? "<built-in>" : szTheme,
191 nWorkspaces,
192 nSizeX, nSizeY
195 initTime();
196 initDisplay(szDisplay);
197 initWindow(nArgc, szArgv);
198 initScreens();
199 initButtons(nWorkspaces, nSizeX, nSizeY);
200 initWindowMask(szInstallDir, szTheme);
201 loop();
202 return 0;
206 * Verbose
209 static int _bVerbose;
211 void setVerbose (int bVerbose) {
212 _bVerbose= bVerbose;
215 int isVerbose () {
216 return _bVerbose;
220 * Usage
223 #define USAGE \
224 "usage: %s [options]\n\n" \
225 "where options include:\n" \
226 " -h --help display usage and version information\n" \
227 " -v --verbose verbose message output\n" \
228 " -d --display <name> the display to use (defaults to the\n" \
229 " 'DISPLAY' environment variable)\n" \
230 " -s --size <w>x<h> number of buttons (default depends on the\n" \
231 " number of workspaces you have, i.e. 2x2 for 4\n" \
232 " workspaces, 2x3 for 6, maximum is 3x3)\n" \
233 " -w --workspaces <count> number of workspace buttons to display\n" \
234 " (default is the number of workspaces you have,\n" \
235 " maximum is 9)\n" \
236 " -t --theme <theme.xpm> the button theme to use, extension\n" \
237 " '.xpm' is optional, for more information about\n" \
238 " themes see docu (default is the built-in theme)\n" \
239 " -i --installdir <dir> specifies the installation directory location,\n" \
240 " this location is automatically searched for themes\n" \
241 " (defaults to the '/usr/local/share/wmpager/'\n" \
242 " and the user specific '~/.wmpager' directory)\n"
244 void usage (int bVerbose) {
245 if (bVerbose) {
246 info();
247 fprintf(stdout, USAGE, getApplicationName());
248 exit(0);
249 } else {
250 fprintf(stderr, USAGE, getApplicationName());
251 exit(-1);
255 void info () {
256 char* szRev= strdup(BUILD_REV);
257 char* szDate= strdup(BUILD_DATE);
258 szRev= &szRev[11];
259 szRev[strlen(szRev) - 2]= '\0';
260 szDate= &szDate[7];
261 szDate[strlen(szDate) - 2]= '\0';
262 fprintf(stdout, "%s %s (build %s, %s)\n\n", APPLICATION, VERSION, szRev, szDate);
266 * Application
269 static char* _szApplicationName;
271 char* getApplicationName () {
272 return _szApplicationName;
275 void initApplicationName (char* szApplicationName) {
276 if (szApplicationName == NULL) {
277 _szApplicationName= APPLICATION;
278 } else {
279 _szApplicationName= strdup(szApplicationName);
284 * Display
287 static Display* _display;
289 Display* getDisplay () {
290 return _display;
293 void destroyDisplay () {
294 XCloseDisplay(getDisplay());
297 void initDisplay (char* szDisplay) {
298 if (szDisplay == NULL && ((char*) getenv("DISPLAY")) == NULL) {
299 szDisplay= ":0.0";
301 if (isVerbose()) {
302 char* szRealDisplay= (szDisplay == NULL) ? (char*) getenv("DISPLAY") : szDisplay;
303 if (szRealDisplay == NULL) {
304 szRealDisplay= "localhost:0.0";
306 fprintf(stdout, "[%8ld] initializing display '%s'\n", currentTimeMillis(), szRealDisplay);
308 _display= XOpenDisplay(szDisplay);
309 if (_display == NULL) {
310 fprintf(
311 stderr,
312 "%s: couldn't open display '%s'.\n",
313 getApplicationName(),
314 (szDisplay == NULL) ? ((char*) getenv("DISPLAY")) : szDisplay
316 exit(-1);
321 * Window
324 static int _nDefaultScreen, _nDefaultDepth;
325 static Window _wRoot, _wMain, _wIcon;
326 static GC _gcMain, _gcWindow;
327 static XpmAttributes _attrButtonTheme;
328 static Pixmap _pButtonTheme, _pButtonThemeMask;
329 static XpmAttributes _attrWindow;
330 static Pixmap _pWindow, _pWindowMask;
331 static Pixel _pWhite, _pBlack;
333 Pixel getWhitePixel () {
334 return _pWhite;
337 Pixel getBlackPixel () {
338 return _pBlack;
341 int getDefaultScreen () {
342 return _nDefaultScreen;
345 int getDefaultDepth () {
346 return _nDefaultDepth;
349 Window getRootWindow () {
350 return _wRoot;
353 Window getMainWindow () {
354 return _wMain;
357 Window getIconWindow () {
358 return _wIcon;
361 GC getMainGraphics () {
362 return _gcMain;
365 GC getWindowGraphics () {
366 return _gcWindow;
369 void initWindow (int nArgc, char** szArgv) {
370 char* szApplicationName= getApplicationName();
371 Display* display= getDisplay();
372 XSizeHints *xsizehints;
373 XWMHints* xwmhints;
374 XClassHint* xclasshint;
375 XTextProperty* xtApplication;
376 XGCValues xgcMain;
378 if (isVerbose()) {
379 fprintf(stdout, "[%8ld] initializing application window\n", currentTimeMillis());
382 _nDefaultScreen= DefaultScreen(display);
383 _nDefaultDepth= DefaultDepth(display, _nDefaultScreen);
384 _wRoot= RootWindow(display, _nDefaultScreen);
386 XSelectInput(display, _wRoot, PropertyChangeMask);
388 _pWhite= WhitePixel(display, _nDefaultScreen);
389 _pBlack= BlackPixel(display, _nDefaultScreen);
391 xsizehints= XAllocSizeHints();
392 xsizehints->flags= USSize | USPosition;
393 xsizehints->width= xsizehints->height= 64;
395 _wMain= XCreateSimpleWindow(display, _wRoot, 0, 0, 64, 64, 5, _pWhite, _pBlack);
396 if (_wMain == 0) {
397 fprintf(stderr, "Cannot create main window.\n");
398 exit(-1);
401 _wIcon= XCreateSimpleWindow(display, _wMain, 0, 0, 64, 64, 5, _pWhite, _pBlack);
402 if (_wIcon == 0) {
403 fprintf(stderr, "Cannot create icon window.\n");
404 exit(-1);
407 xwmhints= XAllocWMHints();
408 xwmhints->flags= WindowGroupHint | IconWindowHint | StateHint;
409 xwmhints->icon_window= _wIcon;
410 xwmhints->window_group= _wMain;
411 xwmhints->initial_state= WithdrawnState;
412 XSetWMHints(display, _wMain, xwmhints);
414 xclasshint= XAllocClassHint();
415 xclasshint->res_name= APPLICATION;
416 xclasshint->res_class= APPLICATION;
417 XSetClassHint(display, _wMain, xclasshint);
419 XSetWMNormalHints(display, _wMain, xsizehints);
421 xtApplication= (XTextProperty*) malloc(sizeof(XTextProperty));
422 if (XStringListToTextProperty(&szApplicationName, 1, xtApplication) == 0) {
423 fprintf(stderr, "Cannot set window title.\n");
424 exit(-1);
426 XSetWMName(display, _wMain, xtApplication);
428 _gcMain= XCreateGC(display, _wMain, (GCForeground | GCBackground), &xgcMain);
429 if (_gcMain == NULL) {
430 fprintf(stderr, "Cannot create graphics context.\n");
431 exit(-1);
434 XSelectInput(display, _wMain, ExposureMask | ButtonPressMask | PointerMotionMask | StructureNotifyMask | LeaveWindowMask);
435 XSelectInput(display, _wIcon, ExposureMask | ButtonPressMask | PointerMotionMask | StructureNotifyMask | LeaveWindowMask);
437 XSetCommand(display, _wMain, szArgv, nArgc);
439 XMapWindow(display, _wMain);
442 void destroyWindow () {
443 XFreeGC(getDisplay(), getWindowGraphics());
444 XFreeGC(getDisplay(), getMainGraphics());
445 XDestroyWindow(getDisplay(), getMainWindow());
446 XDestroyWindow(getDisplay(), getIconWindow());
449 void initWindowMask (char* szInstallDir, char* szButtonTheme) {
450 Display* display= getDisplay();
451 GC gc;
452 Window wRoot= getRootWindow();
453 Window wMain= getMainWindow();
454 Window wIcon= getIconWindow();
455 XGCValues xgc, xgcWindow;
456 Pixmap pOpaque, pTransparent, pMask;
457 char* mask= (char*) malloc(512);
458 int i;
460 if (isVerbose()) {
461 fprintf(stdout, "[%8ld] initializing window mask\n", currentTimeMillis());
463 for (i= 0; i < 512; i++) {
464 mask[i]= 0x00;
466 pTransparent= XCreateBitmapFromData(display, wRoot, mask, 64, 64);
467 if (pTransparent == 0) {
468 fprintf(stderr, "%s: couldn't create window mask (transparent).\n", getApplicationName());
469 exit(-1);
471 pMask= XCreateBitmapFromData(display, wRoot, mask, 64, 64);
472 if (pMask == 0) {
473 fprintf(stderr, "%s: couldn't create window mask (mask buffer).\n", getApplicationName());
474 exit(-1);
477 for (i= 0; i < 512; i++) {
478 mask[i]= 0xff;
480 pOpaque= XCreateBitmapFromData(display, wRoot, mask, 64, 64);
481 if (pOpaque == 0) {
482 fprintf(stderr, "%s: couldn't create window mask (opaque).\n", getApplicationName());
483 exit(-1);
486 gc= XCreateGC(display, pMask, (GCForeground | GCBackground), &xgc);
487 if (gc == NULL) {
488 fprintf(stderr, "%s: couldn't create window mask (mask graphics).\n", getApplicationName());
489 exit(-1);
491 for (i= 0; i < getButtonCount(); i++) {
492 int nButtonX, nButtonY;
493 getButtonLocation(i, &nButtonX, &nButtonY);
494 XCopyArea(display, pOpaque, pMask, gc, nButtonX, nButtonY, getButtonWidth(), getButtonHeight(), nButtonX, nButtonY);
497 XFreePixmap(display, pOpaque);
498 XFreePixmap(display, pTransparent);
499 XFreeGC(display, gc);
501 XShapeCombineMask(display, wMain, ShapeBounding, 0, 0, pMask, ShapeSet);
502 XShapeCombineMask(display, wIcon, ShapeBounding, 0, 0, pMask, ShapeSet);
504 if (isVerbose()) {
505 fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(),
506 szButtonTheme == NULL ? "<built-in>" : szButtonTheme);
509 _attrButtonTheme.valuemask|= (XpmReturnPixels | XpmReturnExtensions);
510 if (szButtonTheme == NULL) {
511 if (
512 XpmCreatePixmapFromData(
513 display, wRoot, buttons_xpm, &_pButtonTheme, &_pButtonThemeMask, &_attrButtonTheme
514 ) != XpmSuccess
516 fprintf(stderr, "%s: couldn't create button theme.\n", getApplicationName());
517 exit(-1);
519 } else {
520 int bCheckAgain= 0;
521 struct stat buf;
522 /* check for absolute button theme pathname */
523 if (stat(szButtonTheme, &buf) == -1) {
524 char* szNewTheme= (char*) malloc(strlen(szButtonTheme) + 4);
525 strcpy(szNewTheme, szButtonTheme);
526 strcat(szNewTheme, ".xpm");
527 if (isVerbose()) {
528 fprintf(stdout, "[%8ld] theme file '%s' not found, trying '%s'\n", currentTimeMillis(), szButtonTheme, szNewTheme);
530 /* check for absolute button theme pathname (with .xpm added) */
531 if (stat(szNewTheme, &buf) == 0) {
532 szButtonTheme= szNewTheme;
533 if (isVerbose()) {
534 fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme);
536 } else {
537 bCheckAgain= 1;
538 free(szNewTheme);
541 if (bCheckAgain && szInstallDir != NULL) {
542 char* szNewTheme= (char*) malloc(strlen(szInstallDir) + strlen(szButtonTheme) + 5);
543 strcpy(szNewTheme, szInstallDir);
544 if (szNewTheme[strlen(szNewTheme) - 1] != '/') {
545 strcat(szNewTheme, "/");
547 strcat(szNewTheme, szButtonTheme);
548 if (stat(szNewTheme, &buf) == 0) {
549 bCheckAgain= 0;
550 szButtonTheme= szNewTheme;
551 if (isVerbose()) {
552 fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme);
554 } else {
555 strcat(szNewTheme, ".xpm");
556 if (stat(szNewTheme, &buf) == 0) {
557 bCheckAgain= 0;
558 szButtonTheme= szNewTheme;
559 if (isVerbose()) {
560 fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme);
565 if (bCheckAgain) {
566 /* as a goody check the ~/.wmpager directory if it exists */
567 char* szHome= (char*) getenv("HOME");
568 if (szHome) {
569 /* one really shouldn't copy&paste but hey this is a q&d tool */
570 char* szNewTheme= (char*) malloc(strlen(szHome) + strlen(szButtonTheme) + strlen(WMPAGER_USER_DIR) + 5);
571 strcpy(szNewTheme, szHome);
572 if (szNewTheme[strlen(szNewTheme) - 1] != '/') {
573 strcat(szNewTheme, "/");
575 strcat(szNewTheme, WMPAGER_USER_DIR);
576 strcat(szNewTheme, szButtonTheme);
577 if (stat(szNewTheme, &buf) == 0) {
578 bCheckAgain= 0;
579 szButtonTheme= szNewTheme;
580 if (isVerbose()) {
581 fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme);
583 } else {
584 strcat(szNewTheme, ".xpm");
585 if (stat(szNewTheme, &buf) == 0) {
586 bCheckAgain= 0;
587 szButtonTheme= szNewTheme;
588 if (isVerbose()) {
589 fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme);
595 if (
596 XpmReadFileToPixmap(
597 display, wRoot, szButtonTheme, &_pButtonTheme, &_pButtonThemeMask, &_attrButtonTheme
598 ) != XpmSuccess
600 fprintf(stderr, "%s: couldn't read button theme '%s'.\n", getApplicationName(), szButtonTheme);
601 exit(-1);
605 if (isVerbose()) {
606 fprintf(stdout, "[%8ld] initializing screen buffer\n", currentTimeMillis());
609 _attrWindow.valuemask|= (XpmReturnPixels | XpmReturnExtensions);
610 if (
611 XpmCreatePixmapFromData(
612 display, wRoot, screen_xpm, &_pWindow, &_pWindowMask, &_attrWindow
613 ) != XpmSuccess
615 fprintf(stderr, "%s: couldn't create screen buffer.\n", getApplicationName());
616 exit(-1);
619 _gcWindow= XCreateGC(_display, _pWindow, (GCForeground | GCBackground), &xgcWindow);
620 if (gc == NULL) {
621 fprintf(stderr, "%s: couldn't create screen buffer graphics.\n", getApplicationName());
622 exit(-1);
626 void redrawWindow () {
627 XEvent event;
628 int i;
629 int w= getButtonWidth();
630 int h= getButtonHeight();
631 for (i= 0; i < getButtonCount(); i++) {
632 int x, y, xoff, yoff;
633 xoff= 51;
634 yoff= 10;
635 if (i == getCurrentScreen()) {
636 xoff= 0;
637 yoff= 0;
639 getButtonLocation(i, &x, &y);
640 XSetClipMask(_display, _gcWindow, _pWindowMask);
641 XSetClipOrigin(_display, _gcWindow, 0, 0);
642 XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, xoff + x - 7, y - 7, w, h, x, y);
643 XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, xoff, 0, w, 1, x, y);
644 XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, xoff, 0, 1, h, x, y);
645 XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, xoff + 50, 0, 1, h, x + w - 1, y);
646 XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, xoff, 50, w, 1, x, y + h - 1);
647 XSetClipMask(_display, _gcWindow, _pButtonThemeMask);
648 XSetClipOrigin(_display, _gcWindow, (x + (w - 10) / 2) - i * 10, -51 - yoff + y + (h - 10) / 2);
649 XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, i * 10, 51 + yoff, 10, 10, x + (w - 10) / 2, y + (h - 10) / 2);
651 while (XCheckTypedWindowEvent(_display, _wMain, Expose, &event));
652 XCopyArea(_display, _pWindow, _wMain, _gcMain, 0, 0, 64, 64, 0, 0);
653 while (XCheckTypedWindowEvent(_display, _wIcon, Expose, &event));
654 XCopyArea(_display, _pWindow, _wIcon, _gcMain, 0, 0, 64, 64, 0, 0);
657 void getWindowOrigin (Window w, int* nX, int* nY) {
658 Window wWindow, wParent, wRoot;
659 Window* wChildren;
660 unsigned int nChildren;
661 unsigned int ww, wh, wb, wd;
662 int wx, wy;
664 wParent= w;
665 do {
666 wWindow= wParent;
667 if (!XQueryTree(getDisplay(), wParent, &wRoot, &wParent, &wChildren, &nChildren)) {
668 return;
670 if (wChildren) {
671 XFree(wChildren);
673 } while (wParent != wRoot);
675 if (XGetGeometry(getDisplay(), wWindow, &wRoot, &wx, &wy, &ww, &wh, &wb, &wd)) {
676 if (nX) {
677 *nX= wx;
679 if (nY) {
680 *nY= wy;
686 * Event Loop
689 void loop () {
690 Display* display= getDisplay();
691 XEvent event;
693 if (isVerbose()) {
694 fprintf(stdout, "[%8ld] starting event loop\n", currentTimeMillis());
696 for (;;) {
697 while (XPending(display)) {
698 XNextEvent(display, &event);
699 switch (event.type) {
700 case Expose:
701 if (event.xexpose.count == 0) {
702 redrawWindow();
704 break;
705 case ConfigureNotify:
706 redrawWindow();
707 break;
708 case ButtonPress:
710 int nButton= getButtonAt(event.xbutton.x, event.xbutton.y);
711 if (isVerbose()) {
712 fprintf(stdout, "[%8ld] button %d pressed\n", currentTimeMillis(), nButton);
714 if (nButton != -1) {
715 setCurrentScreen(nButton);
716 gotoScreen(nButton);
719 break;
720 case PropertyNotify:
721 if (strcmp(XA_WIN_WORKSPACE, XGetAtomName(getDisplay(), event.xproperty.atom)) == 0) {
722 setCurrentScreen(-1);
723 if (isVerbose()) {
724 fprintf(stdout, "[%8ld] new current workspace (%d= %s)\n",
725 currentTimeMillis(), getCurrentScreen(), getScreenName(getCurrentScreen()));
727 redrawWindow();
729 break;
730 case DestroyNotify:
731 if (isVerbose()) {
732 fprintf(stdout, "[%8ld] quit application\n", currentTimeMillis());
734 destroyWindow();
735 destroyDisplay();
736 exit(0);
737 break;
740 usleep(50000);
745 * Button Helpers
748 static int _nButtons;
749 static int _nButtonRows, _nButtonColumns;
750 static int _nButtonWidth, _nButtonHeight;
752 int getButtonCount () {
753 return _nButtons;
756 int getButtonRowCount () {
757 return _nButtonRows;
760 int getButtonColumnCount () {
761 return _nButtonColumns;
764 int getButtonWidth () {
765 return _nButtonWidth;
768 int getButtonHeight () {
769 return _nButtonHeight;
772 int getButtonAt (int nLocationX, int nLocationY) {
773 int i, nButtonX, nButtonY;
774 for (i= 0; i < _nButtons; i++) {
775 getButtonLocation(i, &nButtonX, &nButtonY);
776 if (
777 nLocationX >= nButtonX && nLocationX < nButtonX + _nButtonWidth &&
778 nLocationY >= nButtonY && nLocationY < nButtonY + _nButtonHeight
780 return i;
783 return -1;
786 void getButtonLocation (int nButton, int* nLocationX, int* nLocationY) {
787 if (nButton < 0 || nButton > _nButtons) {
788 *nLocationX= *nLocationY= 0;
789 } else {
790 *nLocationX= *nLocationY= 7;
791 while (nButton >= _nButtonColumns) {
792 *nLocationY+= _nButtonHeight + 3;
793 nButton-= _nButtonColumns;
795 while (nButton > 0) {
796 *nLocationX+= _nButtonWidth + 3;
797 nButton--;
802 void initButtons (int nButtons, int nColumns, int nRows) {
803 if (nButtons != -1) {
804 _nButtons= nButtons;
805 } else {
806 _nButtons= getScreenCount();
807 if (_nButtons > 9) {
808 /* only handle nine screens at most */
809 _nButtons= 9;
812 if (nColumns == -1 || nRows == -1) {
813 switch (_nButtons) {
814 case 1:
815 _nButtonRows= _nButtonColumns= 1;
816 break;
817 case 2:
818 _nButtonColumns= 1;
819 _nButtonRows= 2;
820 break;
821 case 3:
822 /* fallthrough */
823 case 4:
824 _nButtonColumns= _nButtonRows= 2;
825 break;
826 case 5:
827 /* fallthrough */
828 case 6:
829 _nButtonColumns= 2;
830 _nButtonRows= 3;
831 break;
832 default:
833 _nButtonColumns= _nButtonRows= 3;
834 break;
836 } else {
837 _nButtonColumns= nColumns;
838 _nButtonRows= nRows;
840 if (_nButtons > _nButtonColumns * _nButtonRows) {
841 _nButtons= _nButtonColumns * _nButtonRows;
843 if (isVerbose()) {
844 fprintf(stdout, "[%8ld] initializing buttons\n", currentTimeMillis());
845 fprintf(stdout, "[%8ld] - %d workspace buttons\n", currentTimeMillis(), _nButtons);
846 fprintf(stdout, "[%8ld] - button layout %dx%d\n", currentTimeMillis(), _nButtonColumns, _nButtonRows);
849 if (_nButtonColumns == 1) {
850 _nButtonWidth= 51;
851 } else if (_nButtonColumns == 2) {
852 _nButtonWidth= 24;
853 } else {
854 _nButtonWidth= 15;
857 if (_nButtonRows == 1) {
858 _nButtonHeight= 51;
859 } else if (_nButtonRows == 2) {
860 _nButtonHeight= 24;
861 } else {
862 _nButtonHeight= 15;
868 * Time
871 static struct timeval _tStart;
873 void initTime () {
874 if (isVerbose()) {
875 fprintf(stdout, "[ ] initializing time\n");
877 gettimeofday(&_tStart, NULL);
880 long currentTimeMillis () {
881 struct timeval tNow;
882 struct timeval tElapsed;
884 gettimeofday(&tNow, NULL);
886 if (_tStart.tv_usec > tNow.tv_usec) {
887 tNow.tv_usec+= 1000000;
888 tNow.tv_sec--;
890 tElapsed.tv_sec= tNow.tv_sec - _tStart.tv_sec;
891 tElapsed.tv_usec= tNow.tv_usec - _tStart.tv_usec;
892 return (tElapsed.tv_sec * 1000) + (tElapsed.tv_usec / 1000);
896 * Screen Handling
899 static Atom _xaWinWorkspace;
900 static Atom _xaWinWorkspaceNames;
901 static int _nScreens;
902 static char** _szScreenNames;
903 static int _nLastScreen;
905 int getScreenCount () {
906 return _nScreens;
909 char* getScreenName (int nScreen) {
910 if (nScreen < 0 || nScreen >= _nScreens) {
911 return NULL;
913 return _szScreenNames[nScreen];
916 void gotoScreen (int nWorkspace) {
917 XEvent event;
918 event.type= ClientMessage;
919 event.xclient.type= ClientMessage;
920 event.xclient.window= getRootWindow();
921 event.xclient.message_type= _xaWinWorkspace;
922 event.xclient.format= 32;
923 event.xclient.data.l[0]= nWorkspace;
924 event.xclient.data.l[1]= currentTimeMillis();
925 XSendEvent(getDisplay(), getRootWindow(), False, SubstructureNotifyMask, (XEvent*) &event);
928 int getCurrentScreen () {
929 return _nLastScreen;
932 void setCurrentScreen (int nCurrentScreen) {
933 if (nCurrentScreen == -1) {
934 long nScreen= _nLastScreen;
935 Atom xaType;
936 int nFormat;
937 unsigned long nItems, nBytesAfter;
938 unsigned char* data;
940 XGetWindowProperty(
941 getDisplay(), getRootWindow(), _xaWinWorkspace,
942 0, 8192, False, XA_CARDINAL, &xaType, &nFormat, &nItems, &nBytesAfter, &data
944 if ((nFormat == 32) && (nItems == 1) && (nBytesAfter == 0)) {
945 nScreen= *(long*) data;
947 if (xaType != None) {
948 XFree(data);
950 _nLastScreen= nScreen;
951 } else {
952 _nLastScreen= nCurrentScreen;
956 void initScreens () {
957 XTextProperty tp;
959 if (isVerbose()) {
960 fprintf(stdout, "[%8ld] initializing window maker communication\n", currentTimeMillis());
962 _xaWinWorkspace= XInternAtom(getDisplay(), XA_WIN_WORKSPACE, False);
963 _xaWinWorkspaceNames= XInternAtom(getDisplay(), XA_WIN_WORKSPACE_NAMES, False);
964 XGetTextProperty(getDisplay(), getRootWindow(), &tp, _xaWinWorkspaceNames);
965 XTextPropertyToStringList(&tp, &_szScreenNames, &_nScreens);
966 _nLastScreen= -1;
967 setCurrentScreen(-1);
968 if (_nLastScreen == -1) {
969 fprintf(
970 stderr,
971 "%s: couldn't determine current workspace.\n" \
972 "Make sure your WindowMaker has Gnome support enabled!\n",
973 getApplicationName()
975 setCurrentScreen(0);
977 if (isVerbose()) {
978 int i;
979 fprintf(stdout, "[%8ld] - %d worspaces found\n", currentTimeMillis(), getScreenCount());
980 for (i= 0; i < getScreenCount(); i++) {
981 fprintf(stdout, "[%8ld] - workspace %d: %s\n", currentTimeMillis(), i, getScreenName(i));
983 fprintf(stdout, "[%8ld] - current workspace is %d (%s)\n", currentTimeMillis(),
984 getCurrentScreen(), getScreenName(getCurrentScreen()));