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>
11 #include <X11/extensions/shape.h>
13 #include <sys/types.h>
14 #include <sys/select.h>
21 #include "buttons.xpm"
28 #define AUTHOR "Bruno Essmann <essmann@users.sourceforge.net>"
29 #define APPLICATION "wmpager"
32 #define XA_NET_NUMBER_OF_DESKTOPS "_NET_NUMBER_OF_DESKTOPS"
33 #define XA_NET_CURRENT_DESKTOP "_NET_CURRENT_DESKTOP"
34 #define XA_NET_DESKTOP_NAMES "_NET_DESKTOP_NAMES"
36 #define WMPAGER_ENV "WMPAGER"
37 #ifndef WMPAGER_DEFAULT_INSTALL_DIR
38 #define WMPAGER_DEFAULT_INSTALL_DIR "/usr/local/share/wmpager/"
40 #define WMPAGER_USER_DIR ".wmpager/"
46 void usage (int bVerbose
);
48 void setVerbose (int bVerbose
);
51 void initApplicationName (char* szApplicationName
);
52 char* getApplicationName ();
54 void initDisplay (char* szDisplay
);
55 void destroyDisplay ();
56 Display
* getDisplay ();
58 Pixel
getWhitePixel ();
59 Pixel
getBlackPixel ();
60 int getDefaultScreen ();
61 int getDefaultDepth ();
62 void initWindow (int nArgc
, char** szArgv
);
63 void destroyWindow ();
64 GC
getWindowGraphics ();
65 GC
getMainGraphics ();
66 void initWindowMask (char* szInstallDir
, char* szButtonTheme
);
68 void getWindowOrigin (Window w
, int* nX
, int* nY
);
72 void initButtons (int nButtons
, int nColumns
, int nRows
);
73 int getButtonCount ();
74 int getButtonRowCount ();
75 int getButtonColumnCount ();
76 int getButtonWidth ();
77 int getButtonHeight ();
78 int getButtonAt (int nLocationX
, int nLocationY
);
79 void getButtonLocation (int nButton
, int* nLocationX
, int* nLocationY
);
82 long currentTimeMillis ();
85 int getScreenCount ();
86 char* getScreenName (int nScreen
);
87 int getCurrentScreen ();
88 void setCurrentScreen (int nCurrentScreen
);
89 void gotoScreen (int nWorkspace
);
95 int main (int nArgc
, char** szArgv
) {
96 char* szDisplay
= NULL
;
98 char* szInstallDir
= NULL
;
101 int nSizeX
= -1, nSizeY
= -1;
103 initApplicationName(szArgv
[0]);
104 /* we no longer use the WMPAGER environment variable
105 * szInstallDir= (char*) getenv(WMPAGER_ENV);
106 * instead we simply use a default installation directory
108 szInstallDir
= WMPAGER_DEFAULT_INSTALL_DIR
;
111 if (strcmp("-h", szArgv
[i
]) == 0 || strcmp("--help", szArgv
[i
]) == 0) {
113 } else if (strcmp("-v", szArgv
[i
]) == 0 || strcmp("--verbose", szArgv
[i
]) == 0) {
115 } else if (strcmp("-w", szArgv
[i
]) == 0 || strcmp("--workspaces", szArgv
[i
]) == 0) {
118 sscanf(szArgv
[i
], "%d", &nWorkspaces
);
119 if (nWorkspaces
<= 0 || nWorkspaces
> 9) {
120 fprintf(stderr
, "%s: illegal number of workspaces '%s' for option '%s' (has to be 1-9)\n\n", getApplicationName(), szArgv
[i
], szArgv
[i
-1]);
124 fprintf(stderr
, "%s: workspace count expected for '%s'\n\n", getApplicationName(), szArgv
[i
-1]);
127 } else if (strcmp("-s", szArgv
[i
]) == 0 || strcmp("--size", szArgv
[i
]) == 0) {
130 sscanf(szArgv
[i
], "%dx%d", &nSizeX
, &nSizeY
);
131 if (nSizeX
<= 0 || nSizeX
> 3 || nSizeY
<= 0 || nSizeY
> 3) {
132 fprintf(stderr
, "%s: illegal size '%s' for option '%s' (has to be 1x1 .. 3x3)\n\n", getApplicationName(), szArgv
[i
], szArgv
[i
-1]);
136 fprintf(stderr
, "%s: size argument expected for '%s'\n\n", getApplicationName(), szArgv
[i
-1]);
139 } else if (strcmp("-i", szArgv
[i
]) == 0 || strcmp("--installdir", szArgv
[i
]) == 0) {
143 szInstallDir
= szArgv
[i
];
144 if (stat(szInstallDir
, &buf
) != 0) {
145 fprintf(stderr
, "%s: cannot access installation directory '%s'\n\n", getApplicationName(), szArgv
[i
]);
149 fprintf(stderr
, "%s: display argument expected for '%s'\n\n", getApplicationName(), szArgv
[i
-1]);
152 } else if (strcmp("-d", szArgv
[i
]) == 0 || strcmp("--display", szArgv
[i
]) == 0) {
155 szDisplay
= szArgv
[i
];
157 fprintf(stderr
, "%s: display argument expected for '%s'\n\n", getApplicationName(), szArgv
[i
-1]);
160 } else if (strcmp("-t", szArgv
[i
]) == 0 || strcmp("--theme", szArgv
[i
]) == 0) {
163 szTheme
= strdup(szArgv
[i
]);
165 fprintf(stderr
, "%s: theme argument expected for '%s'\n\n", getApplicationName(), szArgv
[i
-1]);
169 fprintf(stderr
, "%s: unknown option '%s'\n\n", getApplicationName(), szArgv
[i
]);
174 setVerbose(bVerbose
);
176 char* szRealDisplay
= (szDisplay
== NULL
) ? (char*) getenv("DISPLAY") : szDisplay
;
177 if (szRealDisplay
== NULL
) {
178 szRealDisplay
= "localhost:0.0";
183 "[ ] startup options:\n" \
184 "[ ] - verbose= true\n" \
185 "[ ] - display= '%s'\n" \
186 "[ ] - installdir= '%s'\n" \
187 "[ ] - theme= '%s'\n" \
188 "[ ] - workspaces= '%d'\n" \
189 "[ ] - size= '%dx%d'\n",
191 szInstallDir
== NULL
? "<undefined>" : szInstallDir
,
192 szTheme
== NULL
? "<built-in>" : szTheme
,
198 initDisplay(szDisplay
);
199 initWindow(nArgc
, szArgv
);
201 initButtons(nWorkspaces
, nSizeX
, nSizeY
);
202 initWindowMask(szInstallDir
, szTheme
);
211 static int _bVerbose
;
213 void setVerbose (int bVerbose
) {
226 "usage: %s [options]\n\n" \
227 "where options include:\n" \
228 " -h --help display usage and version information\n" \
229 " -v --verbose verbose message output\n" \
230 " -d --display <name> the display to use (defaults to the\n" \
231 " 'DISPLAY' environment variable)\n" \
232 " -s --size <w>x<h> number of buttons (default depends on the\n" \
233 " number of workspaces you have, i.e. 2x2 for 4\n" \
234 " workspaces, 2x3 for 6, maximum is 3x3)\n" \
235 " -w --workspaces <count> number of workspace buttons to display\n" \
236 " (default is the number of workspaces you have,\n" \
238 " -t --theme <theme.xpm> the button theme to use, extension\n" \
239 " '.xpm' is optional, for more information about\n" \
240 " themes see docu (default is the built-in theme)\n" \
241 " -i --installdir <dir> specifies the installation directory location,\n" \
242 " this location is automatically searched for themes\n" \
243 " (defaults to the '/usr/local/share/wmpager/'\n" \
244 " and the user specific '~/.wmpager' directory)\n"
246 void usage (int bVerbose
) {
249 fprintf(stdout
, USAGE
, getApplicationName());
252 fprintf(stderr
, USAGE
, getApplicationName());
258 fprintf(stdout
, "%s %s\n\n", APPLICATION
, VERSION
);
265 static char* _szApplicationName
;
267 char* getApplicationName () {
268 return _szApplicationName
;
271 void initApplicationName (char* szApplicationName
) {
272 if (szApplicationName
== NULL
) {
273 _szApplicationName
= APPLICATION
;
275 _szApplicationName
= strdup(szApplicationName
);
283 static Display
* _display
;
286 Display
* getDisplay () {
290 void destroyDisplay () {
291 XCloseDisplay(getDisplay());
294 void initDisplay (char* szDisplay
) {
295 if (szDisplay
== NULL
&& ((char*) getenv("DISPLAY")) == NULL
) {
299 char* szRealDisplay
= (szDisplay
== NULL
) ? (char*) getenv("DISPLAY") : szDisplay
;
300 if (szRealDisplay
== NULL
) {
301 szRealDisplay
= "localhost:0.0";
303 fprintf(stdout
, "[%8ld] initializing display '%s'\n", currentTimeMillis(), szRealDisplay
);
305 _display
= XOpenDisplay(szDisplay
);
306 if (_display
== NULL
) {
309 "%s: couldn't open display '%s'.\n",
310 getApplicationName(),
311 (szDisplay
== NULL
) ? ((char*) getenv("DISPLAY")) : szDisplay
315 _xfd
= XConnectionNumber(_display
);
322 static int _nDefaultScreen
, _nDefaultDepth
;
323 static Window _wRoot
, _wMain
, _wIcon
;
324 static GC _gcMain
, _gcWindow
;
325 static XpmAttributes _attrButtonTheme
;
326 static Pixmap _pButtonTheme
, _pButtonThemeMask
;
327 static XpmAttributes _attrWindow
;
328 static Pixmap _pWindow
, _pWindowMask
;
329 static Pixel _pWhite
, _pBlack
;
331 Pixel
getWhitePixel () {
335 Pixel
getBlackPixel () {
339 int getDefaultScreen () {
340 return _nDefaultScreen
;
343 int getDefaultDepth () {
344 return _nDefaultDepth
;
347 Window
getRootWindow () {
351 Window
getMainWindow () {
355 Window
getIconWindow () {
359 GC
getMainGraphics () {
363 GC
getWindowGraphics () {
367 void initWindow (int nArgc
, char** szArgv
) {
368 char* szApplicationName
= getApplicationName();
369 Display
* display
= getDisplay();
370 XSizeHints
*xsizehints
;
372 XClassHint
* xclasshint
;
373 XTextProperty xtApplication
;
376 fprintf(stdout
, "[%8ld] initializing application window\n", currentTimeMillis());
379 _nDefaultScreen
= DefaultScreen(display
);
380 _nDefaultDepth
= DefaultDepth(display
, _nDefaultScreen
);
381 _wRoot
= RootWindow(display
, _nDefaultScreen
);
383 XSelectInput(display
, _wRoot
, PropertyChangeMask
);
385 _pWhite
= WhitePixel(display
, _nDefaultScreen
);
386 _pBlack
= BlackPixel(display
, _nDefaultScreen
);
388 xsizehints
= XAllocSizeHints();
389 xsizehints
->flags
= USSize
| USPosition
;
390 xsizehints
->width
= xsizehints
->height
= 64;
392 _wMain
= XCreateSimpleWindow(display
, _wRoot
, 0, 0, 64, 64, 5, _pWhite
, _pBlack
);
394 fprintf(stderr
, "Cannot create main window.\n");
398 _wIcon
= XCreateSimpleWindow(display
, _wMain
, 0, 0, 64, 64, 5, _pWhite
, _pBlack
);
400 fprintf(stderr
, "Cannot create icon window.\n");
404 xwmhints
= XAllocWMHints();
405 xwmhints
->flags
= WindowGroupHint
| IconWindowHint
| StateHint
;
406 xwmhints
->icon_window
= _wIcon
;
407 xwmhints
->window_group
= _wMain
;
408 xwmhints
->initial_state
= WithdrawnState
;
409 XSetWMHints(display
, _wMain
, xwmhints
);
411 xclasshint
= XAllocClassHint();
412 xclasshint
->res_name
= APPLICATION
;
413 xclasshint
->res_class
= APPLICATION
;
414 XSetClassHint(display
, _wMain
, xclasshint
);
416 XSetWMNormalHints(display
, _wMain
, xsizehints
);
422 if (XStringListToTextProperty(&szApplicationName
, 1, &xtApplication
) == 0) {
423 fprintf(stderr
, "Cannot set window title.\n");
426 XSetWMName(display
, _wMain
, &xtApplication
);
427 XFree(xtApplication
.value
);
429 _gcMain
= XCreateGC(display
, _wMain
, 0L, NULL
);
430 if (_gcMain
== NULL
) {
431 fprintf(stderr
, "Cannot create graphics context.\n");
435 XSelectInput(display
, _wMain
, ExposureMask
| ButtonPressMask
| PointerMotionMask
| StructureNotifyMask
| LeaveWindowMask
);
436 XSelectInput(display
, _wIcon
, ExposureMask
| ButtonPressMask
| PointerMotionMask
| StructureNotifyMask
| LeaveWindowMask
);
438 XSetCommand(display
, _wMain
, szArgv
, nArgc
);
440 XMapWindow(display
, _wMain
);
443 void destroyWindow () {
444 XFreeGC(getDisplay(), getWindowGraphics());
445 XFreeGC(getDisplay(), getMainGraphics());
446 XDestroyWindow(getDisplay(), getMainWindow());
447 XDestroyWindow(getDisplay(), getIconWindow());
450 void initWindowMask (char* szInstallDir
, char* szButtonTheme
) {
451 Display
* display
= getDisplay();
453 Window wRoot
= getRootWindow();
454 Window wMain
= getMainWindow();
455 Window wIcon
= getIconWindow();
456 Pixmap pOpaque
, pTransparent
, pMask
;
457 char* mask
= (char*) malloc(512);
461 fprintf(stdout
, "[%8ld] initializing window mask\n", currentTimeMillis());
463 for (i
= 0; i
< 512; i
++) {
466 pTransparent
= XCreateBitmapFromData(display
, wRoot
, mask
, 64, 64);
467 if (pTransparent
== 0) {
468 fprintf(stderr
, "%s: couldn't create window mask (transparent).\n", getApplicationName());
471 pMask
= XCreateBitmapFromData(display
, wRoot
, mask
, 64, 64);
473 fprintf(stderr
, "%s: couldn't create window mask (mask buffer).\n", getApplicationName());
477 for (i
= 0; i
< 512; i
++) {
480 pOpaque
= XCreateBitmapFromData(display
, wRoot
, mask
, 64, 64);
482 fprintf(stderr
, "%s: couldn't create window mask (opaque).\n", getApplicationName());
486 gc
= XCreateGC(display
, pMask
, 0L, NULL
);
488 fprintf(stderr
, "%s: couldn't create window mask (mask graphics).\n", getApplicationName());
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
);
498 XFreePixmap(display
, pOpaque
);
499 XFreePixmap(display
, pTransparent
);
500 XFreeGC(display
, gc
);
502 XShapeCombineMask(display
, wMain
, ShapeBounding
, 0, 0, pMask
, ShapeSet
);
503 XShapeCombineMask(display
, wIcon
, ShapeBounding
, 0, 0, pMask
, ShapeSet
);
506 fprintf(stdout
, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(),
507 szButtonTheme
== NULL
? "<built-in>" : szButtonTheme
);
510 _attrButtonTheme
.valuemask
|= (XpmReturnPixels
| XpmReturnExtensions
);
511 if (szButtonTheme
== NULL
) {
513 XpmCreatePixmapFromData(
514 display
, wRoot
, buttons_xpm
, &_pButtonTheme
, &_pButtonThemeMask
, &_attrButtonTheme
517 fprintf(stderr
, "%s: couldn't create button theme.\n", getApplicationName());
523 /* check for absolute button theme pathname */
524 if (stat(szButtonTheme
, &buf
) == -1) {
525 char* szNewTheme
= (char*) malloc(strlen(szButtonTheme
) + 5);
526 strcpy(szNewTheme
, szButtonTheme
);
527 strcat(szNewTheme
, ".xpm");
529 fprintf(stdout
, "[%8ld] theme file '%s' not found, trying '%s'\n", currentTimeMillis(), szButtonTheme
, szNewTheme
);
531 /* check for absolute button theme pathname (with .xpm added) */
532 if (stat(szNewTheme
, &buf
) == 0) {
534 szButtonTheme
= szNewTheme
;
536 fprintf(stdout
, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme
);
543 if (bCheckAgain
&& szInstallDir
!= NULL
) {
544 char* szNewTheme
= (char*) malloc(strlen(szInstallDir
) + strlen(szButtonTheme
) + 6);
545 strcpy(szNewTheme
, szInstallDir
);
546 if (szNewTheme
[strlen(szNewTheme
) - 1] != '/') {
547 strcat(szNewTheme
, "/");
549 strcat(szNewTheme
, szButtonTheme
);
550 if (stat(szNewTheme
, &buf
) == 0) {
553 szButtonTheme
= szNewTheme
;
555 fprintf(stdout
, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme
);
558 strcat(szNewTheme
, ".xpm");
559 if (stat(szNewTheme
, &buf
) == 0) {
562 szButtonTheme
= szNewTheme
;
564 fprintf(stdout
, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme
);
572 /* as a goody check the ~/.wmpager directory if it exists */
573 char* szHome
= (char*) getenv("HOME");
575 /* one really shouldn't copy&paste but hey this is a q&d tool */
576 char* szNewTheme
= (char*) malloc(strlen(szHome
) + strlen(szButtonTheme
) + strlen(WMPAGER_USER_DIR
) + 6);
577 strcpy(szNewTheme
, szHome
);
578 if (szNewTheme
[strlen(szNewTheme
) - 1] != '/') {
579 strcat(szNewTheme
, "/");
581 strcat(szNewTheme
, WMPAGER_USER_DIR
);
582 strcat(szNewTheme
, szButtonTheme
);
583 if (stat(szNewTheme
, &buf
) == 0) {
586 szButtonTheme
= szNewTheme
;
588 fprintf(stdout
, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme
);
591 strcat(szNewTheme
, ".xpm");
592 if (stat(szNewTheme
, &buf
) == 0) {
595 szButtonTheme
= szNewTheme
;
597 fprintf(stdout
, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme
);
607 display
, wRoot
, szButtonTheme
, &_pButtonTheme
, &_pButtonThemeMask
, &_attrButtonTheme
610 fprintf(stderr
, "%s: couldn't read button theme '%s'.\n", getApplicationName(), szButtonTheme
);
618 fprintf(stdout
, "[%8ld] initializing screen buffer\n", currentTimeMillis());
621 _attrWindow
.valuemask
|= (XpmReturnPixels
| XpmReturnExtensions
);
623 XpmCreatePixmapFromData(
624 display
, wRoot
, screen_xpm
, &_pWindow
, &_pWindowMask
, &_attrWindow
627 fprintf(stderr
, "%s: couldn't create screen buffer.\n", getApplicationName());
631 _gcWindow
= XCreateGC(_display
, _pWindow
, 0L, NULL
);
632 if (_gcWindow
== NULL
) {
633 fprintf(stderr
, "%s: couldn't create screen buffer graphics.\n", getApplicationName());
638 void redrawWindow () {
641 int w
= getButtonWidth();
642 int h
= getButtonHeight();
643 for (i
= 0; i
< getButtonCount(); i
++) {
644 int x
, y
, xoff
, yoff
;
647 if (i
== getCurrentScreen()) {
651 getButtonLocation(i
, &x
, &y
);
652 XSetClipMask(_display
, _gcWindow
, _pWindowMask
);
653 XSetClipOrigin(_display
, _gcWindow
, 0, 0);
654 XCopyArea(_display
, _pButtonTheme
, _pWindow
, _gcWindow
, xoff
+ x
- 7, y
- 7, w
, h
, x
, y
);
655 XCopyArea(_display
, _pButtonTheme
, _pWindow
, _gcWindow
, xoff
, 0, w
, 1, x
, y
);
656 XCopyArea(_display
, _pButtonTheme
, _pWindow
, _gcWindow
, xoff
, 0, 1, h
, x
, y
);
657 XCopyArea(_display
, _pButtonTheme
, _pWindow
, _gcWindow
, xoff
+ 50, 0, 1, h
, x
+ w
- 1, y
);
658 XCopyArea(_display
, _pButtonTheme
, _pWindow
, _gcWindow
, xoff
, 50, w
, 1, x
, y
+ h
- 1);
659 XSetClipMask(_display
, _gcWindow
, _pButtonThemeMask
);
660 XSetClipOrigin(_display
, _gcWindow
, (x
+ (w
- 10) / 2) - i
* 10, -51 - yoff
+ y
+ (h
- 10) / 2);
661 XCopyArea(_display
, _pButtonTheme
, _pWindow
, _gcWindow
, i
* 10, 51 + yoff
, 10, 10, x
+ (w
- 10) / 2, y
+ (h
- 10) / 2);
663 while (XCheckTypedWindowEvent(_display
, _wMain
, Expose
, &event
));
664 XCopyArea(_display
, _pWindow
, _wMain
, _gcMain
, 0, 0, 64, 64, 0, 0);
665 while (XCheckTypedWindowEvent(_display
, _wIcon
, Expose
, &event
));
666 XCopyArea(_display
, _pWindow
, _wIcon
, _gcMain
, 0, 0, 64, 64, 0, 0);
669 void getWindowOrigin (Window w
, int* nX
, int* nY
) {
670 Window wWindow
, wParent
, wRoot
;
672 unsigned int nChildren
;
673 unsigned int ww
, wh
, wb
, wd
;
679 if (!XQueryTree(getDisplay(), wParent
, &wRoot
, &wParent
, &wChildren
, &nChildren
)) {
685 } while (wParent
!= wRoot
);
687 if (XGetGeometry(getDisplay(), wWindow
, &wRoot
, &wx
, &wy
, &ww
, &wh
, &wb
, &wd
)) {
702 Display
* display
= getDisplay();
709 fprintf(stdout
, "[%8ld] starting event loop\n", currentTimeMillis());
712 while (XPending(display
)) {
713 XNextEvent(display
, &event
);
714 switch (event
.type
) {
716 if (event
.xexpose
.count
== 0) {
720 case ConfigureNotify
:
725 int nButton
= getButtonAt(event
.xbutton
.x
, event
.xbutton
.y
);
727 fprintf(stdout
, "[%8ld] button %d pressed\n", currentTimeMillis(), nButton
);
730 setCurrentScreen(nButton
);
736 atom_name
= XGetAtomName(getDisplay(), event
.xproperty
.atom
);
737 if (atom_name
== NULL
)
739 if (strcmp(XA_NET_CURRENT_DESKTOP
, atom_name
) == 0) {
740 setCurrentScreen(-1);
742 fprintf(stdout
, "[%8ld] new current workspace (%d= %s)\n",
743 currentTimeMillis(), getCurrentScreen(), getScreenName(getCurrentScreen()));
751 fprintf(stdout
, "[%8ld] quit application\n", currentTimeMillis());
761 tv
.tv_usec
= 500000UL;
764 select(_xfd
+ 1, &fds
, NULL
, NULL
, &tv
);
772 static int _nButtons
;
773 static int _nButtonRows
, _nButtonColumns
;
774 static int _nButtonWidth
, _nButtonHeight
;
776 int getButtonCount () {
780 int getButtonRowCount () {
784 int getButtonColumnCount () {
785 return _nButtonColumns
;
788 int getButtonWidth () {
789 return _nButtonWidth
;
792 int getButtonHeight () {
793 return _nButtonHeight
;
796 int getButtonAt (int nLocationX
, int nLocationY
) {
797 int i
, nButtonX
, nButtonY
;
798 for (i
= 0; i
< _nButtons
; i
++) {
799 getButtonLocation(i
, &nButtonX
, &nButtonY
);
801 nLocationX
>= nButtonX
&& nLocationX
< nButtonX
+ _nButtonWidth
&&
802 nLocationY
>= nButtonY
&& nLocationY
< nButtonY
+ _nButtonHeight
810 void getButtonLocation (int nButton
, int* nLocationX
, int* nLocationY
) {
811 if (nButton
< 0 || nButton
> _nButtons
) {
812 *nLocationX
= *nLocationY
= 0;
814 *nLocationX
= *nLocationY
= 7;
815 while (nButton
>= _nButtonColumns
) {
816 *nLocationY
+= _nButtonHeight
+ 3;
817 nButton
-= _nButtonColumns
;
819 while (nButton
> 0) {
820 *nLocationX
+= _nButtonWidth
+ 3;
826 void initButtons (int nButtons
, int nColumns
, int nRows
) {
827 if (nButtons
!= -1) {
830 _nButtons
= getScreenCount();
832 /* only handle nine screens at most */
836 if (nColumns
== -1 || nRows
== -1) {
839 _nButtonRows
= _nButtonColumns
= 1;
848 _nButtonColumns
= _nButtonRows
= 2;
857 _nButtonColumns
= _nButtonRows
= 3;
861 _nButtonColumns
= nColumns
;
864 if (_nButtons
> _nButtonColumns
* _nButtonRows
) {
865 _nButtons
= _nButtonColumns
* _nButtonRows
;
868 fprintf(stdout
, "[%8ld] initializing buttons\n", currentTimeMillis());
869 fprintf(stdout
, "[%8ld] - %d workspace buttons\n", currentTimeMillis(), _nButtons
);
870 fprintf(stdout
, "[%8ld] - button layout %dx%d\n", currentTimeMillis(), _nButtonColumns
, _nButtonRows
);
873 if (_nButtonColumns
== 1) {
875 } else if (_nButtonColumns
== 2) {
881 if (_nButtonRows
== 1) {
883 } else if (_nButtonRows
== 2) {
895 static struct timeval _tStart
;
899 fprintf(stdout
, "[ ] initializing time\n");
901 gettimeofday(&_tStart
, NULL
);
904 long currentTimeMillis () {
906 struct timeval tElapsed
;
908 gettimeofday(&tNow
, NULL
);
910 if (_tStart
.tv_usec
> tNow
.tv_usec
) {
911 tNow
.tv_usec
+= 1000000;
914 tElapsed
.tv_sec
= tNow
.tv_sec
- _tStart
.tv_sec
;
915 tElapsed
.tv_usec
= tNow
.tv_usec
- _tStart
.tv_usec
;
916 return (tElapsed
.tv_sec
* 1000) + (tElapsed
.tv_usec
/ 1000);
923 static Atom _xaNetNumberOfDesktops
;
924 static Atom _xaNetCurrentDesktop
;
925 static Atom _xaNetDesktopNames
;
926 static int _nScreens
;
927 static char** _szScreenNames
;
928 static int _nDesktopNames
;
929 static int _nLastScreen
;
931 int getScreenCount () {
935 char* getScreenName (int nScreen
) {
936 if (nScreen
< 0 || nScreen
>= _nDesktopNames
) {
939 return _szScreenNames
[nScreen
];
942 void gotoScreen (int nWorkspace
) {
944 event
.type
= ClientMessage
;
945 event
.xclient
.type
= ClientMessage
;
946 event
.xclient
.window
= getRootWindow();
947 event
.xclient
.message_type
= _xaNetCurrentDesktop
;
948 event
.xclient
.format
= 32;
949 event
.xclient
.data
.l
[0]= nWorkspace
;
950 event
.xclient
.data
.l
[1]= currentTimeMillis();
951 XSendEvent(getDisplay(), getRootWindow(), False
, SubstructureNotifyMask
, (XEvent
*) &event
);
954 int getCurrentScreen () {
958 void setCurrentScreen (int nCurrentScreen
) {
959 if (nCurrentScreen
== -1) {
960 long nScreen
= _nLastScreen
;
963 unsigned long nItems
, nBytesAfter
;
967 getDisplay(), getRootWindow(), _xaNetCurrentDesktop
,
968 0, 8192, False
, XA_CARDINAL
, &xaType
, &nFormat
, &nItems
, &nBytesAfter
, &data
970 if ((nFormat
== 32) && (nItems
== 1) && (nBytesAfter
== 0)) {
971 nScreen
= *(long*) data
;
974 _nLastScreen
= nScreen
;
976 _nLastScreen
= nCurrentScreen
;
980 void initScreens () {
984 unsigned long nItems
, nBytesAfter
;
988 fprintf(stdout
, "[%8ld] initializing window maker communication\n", currentTimeMillis());
990 _xaNetNumberOfDesktops
= XInternAtom(getDisplay(), XA_NET_NUMBER_OF_DESKTOPS
, False
);
991 _xaNetCurrentDesktop
= XInternAtom(getDisplay(), XA_NET_CURRENT_DESKTOP
, False
);
992 _xaNetDesktopNames
= XInternAtom(getDisplay(), XA_NET_DESKTOP_NAMES
, False
);
995 getDisplay(), getRootWindow(), _xaNetNumberOfDesktops
,
996 0, 8192, False
, XA_CARDINAL
, &xaType
, &nFormat
, &nItems
, &nBytesAfter
, &data
998 if ((nFormat
== 32) && (nItems
== 1) && (nBytesAfter
== 0)) {
999 _nScreens
= *(long*) data
;
1003 XGetTextProperty(getDisplay(), getRootWindow(), &tp
, _xaNetDesktopNames
);
1004 Xutf8TextPropertyToTextList(getDisplay(), &tp
, &_szScreenNames
, &_nDesktopNames
);
1008 setCurrentScreen(-1);
1009 if (_nLastScreen
== -1) {
1012 "%s: couldn't determine current workspace.\n" \
1013 "Make sure your WindowMaker has EWMH support enabled!\n",
1014 getApplicationName()
1016 setCurrentScreen(0);
1020 fprintf(stdout
, "[%8ld] - %d worspaces found\n", currentTimeMillis(), getScreenCount());
1021 for (i
= 0; i
< getScreenCount(); i
++) {
1022 fprintf(stdout
, "[%8ld] - workspace %d: %s\n", currentTimeMillis(), i
, getScreenName(i
));
1024 fprintf(stdout
, "[%8ld] - current workspace is %d (%s)\n", currentTimeMillis(),
1025 getCurrentScreen(), getScreenName(getCurrentScreen()));