Initial dockapps git repo
[dockapps.git] / wmpager-1.2 / src / wmpager.c
blobfd3ae26592e6d058da7a6166aaa480161fa89371
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/"
40 #define TOOLTIP_SUPPORT 1
41 #define TOOLTIP_FONT "-*-helvetica-bold-r-normal-*-12-*-*-*-*-*-*-*"
42 #define TOOLTIP_OUTSIDE 0
43 #define TOOLTIP_SHOW_DELAY 750
44 #define TOOLTIP_RESHOW_DELAY 1500
46 #define TOOLTIP_SPACE 12
47 #define TOOLTIP_TOP 0
48 #define TOOLTIP_BOTTOM 1
49 #define TOOLTIP_LEFT 0
50 #define TOOLTIP_RIGHT 2
53 * Prototypes
56 void usage (int bVerbose);
57 void info ();
58 void setVerbose (int bVerbose);
59 int isVerbose ();
61 void initApplicationName (char* szApplicationName);
62 char* getApplicationName ();
64 void initDisplay (char* szDisplay);
65 void destroyDisplay ();
66 Display* getDisplay ();
68 Pixel getWhitePixel ();
69 Pixel getBlackPixel ();
70 int getDefaultScreen ();
71 int getDefaultDepth ();
72 void initWindow (int nArgc, char** szArgv);
73 void destroyWindow ();
74 GC getWindowGraphics ();
75 GC getMainGraphics ();
76 void initWindowMask (char* szInstallDir, char* szButtonTheme);
77 void redrawWindow ();
78 void getWindowOrigin (Window w, int* nX, int* nY);
80 void loop (long nTooltipShowDelay, long nTooltipReshowDelay);
82 void initButtons (int nButtons, int nColumns, int nRows);
83 int getButtonCount ();
84 int getButtonRowCount ();
85 int getButtonColumnCount ();
86 int getButtonWidth ();
87 int getButtonHeight ();
88 int getButtonAt (int nLocationX, int nLocationY);
89 void getButtonLocation (int nButton, int* nLocationX, int* nLocationY);
91 void initTime ();
92 long currentTimeMillis ();
94 void initScreens ();
95 int getScreenCount ();
96 char* getScreenName (int nScreen);
97 int getCurrentScreen ();
98 void setCurrentScreen (int nCurrentScreen);
99 void gotoScreen (int nWorkspace);
101 void initTooltip (int bTooltipSupport, char* szFontName, int bTooltipOutside);
102 void destroyTooltip ();
103 int hasTooltipSupport ();
104 void showTooltip (int nButton, int nMouseX, int nMouseY);
105 void hideTooltip ();
106 int hasTooltip ();
107 void drawTooltipBalloon (Pixmap pix, GC gc, int x, int y, int w, int h, int side);
108 Pixmap createTooltipPixmap (int width, int height, int side, Pixmap *mask);
111 * Main
114 int main (int nArgc, char** szArgv) {
115 char* szDisplay= NULL;
116 char* szTheme= NULL;
117 char* szInstallDir= NULL;
118 char* szTooltipFont= TOOLTIP_FONT;
119 long nTooltipShowDelay= TOOLTIP_SHOW_DELAY;
120 long nTooltipReshowDelay= TOOLTIP_RESHOW_DELAY;
121 int nWorkspaces= -1;
122 int bVerbose= 0;
123 int nSizeX= -1, nSizeY= -1;
124 int bTooltipSupport= TOOLTIP_SUPPORT;
125 int bTooltipOutside= TOOLTIP_OUTSIDE;
126 int i;
127 initApplicationName(szArgv[0]);
128 /* we no longer use the WMPAGER environment variable
129 * szInstallDir= (char*) getenv(WMPAGER_ENV);
130 * instead we simply use a default installation directory
132 szInstallDir= WMPAGER_DEFAULT_INSTALL_DIR;
133 i= 1;
134 while (i < nArgc) {
135 if (strcmp("-h", szArgv[i]) == 0 || strcmp("--help", szArgv[i]) == 0) {
136 usage(1);
137 } else if (strcmp("-v", szArgv[i]) == 0 || strcmp("--verbose", szArgv[i]) == 0) {
138 bVerbose= 1;
139 } else if (strcmp("-w", szArgv[i]) == 0 || strcmp("--workspaces", szArgv[i]) == 0) {
140 i+= 1;
141 if (i < nArgc) {
142 sscanf(szArgv[i], "%d", &nWorkspaces);
143 if (nWorkspaces <= 0 || nWorkspaces > 9) {
144 fprintf(stderr, "%s: illegal number of workspaces '%s' for option '%s' (has to be 1-9)\n\n", getApplicationName(), szArgv[i], szArgv[i-1]);
145 usage(0);
147 } else {
148 fprintf(stderr, "%s: workspace count expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
149 usage(0);
151 } else if (strcmp("-s", szArgv[i]) == 0 || strcmp("--size", szArgv[i]) == 0) {
152 i+= 1;
153 if (i < nArgc) {
154 sscanf(szArgv[i], "%dx%d", &nSizeX, &nSizeY);
155 if (nSizeX <= 0 || nSizeX > 3 || nSizeY <= 0 || nSizeY > 3) {
156 fprintf(stderr, "%s: illegal size '%s' for option '%s' (has to be 1x1 .. 3x3)\n\n", getApplicationName(), szArgv[i], szArgv[i-1]);
157 usage(0);
159 } else {
160 fprintf(stderr, "%s: size argument expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
161 usage(0);
163 } else if (strcmp("-i", szArgv[i]) == 0 || strcmp("--installdir", szArgv[i]) == 0) {
164 i+= 1;
165 if (i < nArgc) {
166 struct stat buf;
167 szInstallDir= szArgv[i];
168 if (stat(szInstallDir, &buf) != 0) {
169 fprintf(stderr, "%s: cannot access installation directory '%s'\n\n", getApplicationName(), szArgv[i]);
170 usage(0);
172 } else {
173 fprintf(stderr, "%s: display argument expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
174 usage(0);
176 } else if (strcmp("--disable-tooltips", szArgv[i]) == 0) {
177 bTooltipSupport= 0;
178 } else if (strcmp("--tooltip-outside", szArgv[i]) == 0) {
179 bTooltipOutside= 1;
180 } else if (strcmp("--tooltip-font", szArgv[i]) == 0) {
181 i+= 1;
182 if (i < nArgc) {
183 szTooltipFont= szArgv[i];
184 } else {
185 fprintf(stderr, "%s: font argument expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
186 usage(0);
188 } else if (strcmp("--tooltip-delay", szArgv[i]) == 0) {
189 i+= 1;
190 if (i < nArgc) {
191 long nDelay= -1;
192 sscanf(szArgv[i], "%ld", &nDelay);
193 if (nDelay < 0) {
194 fprintf(stderr, "%s: illegal tooltip delay '%s' for option '%s'\n\n", getApplicationName(), szArgv[i], szArgv[i-1]);
195 usage(0);
197 nTooltipShowDelay= nDelay;
198 } else {
199 fprintf(stderr, "%s: delay argument expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
200 usage(0);
202 } else if (strcmp("--tooltip-reshow", szArgv[i]) == 0) {
203 i+= 1;
204 if (i < nArgc) {
205 long nDelay= -1;
206 sscanf(szArgv[i], "%ld", &nDelay);
207 if (nDelay < 0) {
208 fprintf(stderr, "%s: illegal tooltip delay '%s' for option '%s'\n\n", getApplicationName(), szArgv[i], szArgv[i-1]);
209 usage(0);
211 nTooltipReshowDelay= nDelay;
212 } else {
213 fprintf(stderr, "%s: delay argument expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
214 usage(0);
216 } else if (strcmp("-d", szArgv[i]) == 0 || strcmp("--display", szArgv[i]) == 0) {
217 i+= 1;
218 if (i < nArgc) {
219 szDisplay= szArgv[i];
220 } else {
221 fprintf(stderr, "%s: display argument expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
222 usage(0);
224 } else if (strcmp("-t", szArgv[i]) == 0 || strcmp("--theme", szArgv[i]) == 0) {
225 i+= 1;
226 if (i < nArgc) {
227 szTheme= szArgv[i];
228 } else {
229 fprintf(stderr, "%s: theme argument expected for '%s'\n\n", getApplicationName(), szArgv[i-1]);
230 usage(0);
232 } else {
233 fprintf(stderr, "%s: unknown option '%s'\n\n", getApplicationName(), szArgv[i]);
234 usage(0);
236 i+= 1;
238 setVerbose(bVerbose);
239 if (isVerbose()) {
240 char* szRealDisplay= (szDisplay == NULL) ? (char*) getenv("DISPLAY") : szDisplay;
241 if (szRealDisplay == NULL) {
242 szRealDisplay= "localhost:0.0";
244 info();
245 fprintf(
246 stdout,
247 "[ ] startup options:\n" \
248 "[ ] - verbose= true\n" \
249 "[ ] - display= '%s'\n" \
250 "[ ] - installdir= '%s'\n" \
251 "[ ] - theme= '%s'\n" \
252 "[ ] - workspaces= '%d'\n" \
253 "[ ] - size= '%dx%d'\n" \
254 "[ ] - tooltip support= %s\n" \
255 "[ ] - tooltip font= %s\n" \
256 "[ ] - tooltip show delay= %ld\n" \
257 "[ ] - tooltip reshow delay= %ld\n" \
258 "[ ] - tooltip outside= %s\n",
259 szRealDisplay,
260 szInstallDir == NULL ? "<undefined>" : szInstallDir,
261 szTheme == NULL ? "<built-in>" : szTheme,
262 nWorkspaces,
263 nSizeX, nSizeY,
264 bTooltipSupport ? "true" : "false",
265 szTooltipFont,
266 nTooltipShowDelay, nTooltipReshowDelay,
267 bTooltipOutside ? "true" : "false"
270 initTime();
271 initDisplay(szDisplay);
272 initWindow(nArgc, szArgv);
273 initScreens();
274 initButtons(nWorkspaces, nSizeX, nSizeY);
275 initWindowMask(szInstallDir, szTheme);
276 initTooltip(bTooltipSupport, szTooltipFont, bTooltipOutside);
277 loop(nTooltipShowDelay, nTooltipReshowDelay);
278 return 0;
282 * Verbose
285 static int _bVerbose;
287 void setVerbose (int bVerbose) {
288 _bVerbose= bVerbose;
291 int isVerbose () {
292 return _bVerbose;
296 * Usage
299 #define USAGE \
300 "usage: %s [options]\n\n" \
301 "where options include:\n" \
302 " -h --help display usage and version information\n" \
303 " -v --verbose verbose message output\n" \
304 " -d --display <name> the display to use (defaults to the\n" \
305 " 'DISPLAY' environment variable)\n" \
306 " -s --size <w>x<h> number of buttons (default depends on the\n" \
307 " number of workspaces you have, i.e. 2x2 for 4\n" \
308 " workspaces, 2x3 for 6, maximum is 3x3)\n" \
309 " -w --workspaces <count> number of workspace buttons to display\n" \
310 " (default is the number of workspaces you have,\n" \
311 " maximum is 9)\n" \
312 " -t --theme <theme.xpm> the button theme to use, extension\n" \
313 " '.xpm' is optional, for more information about\n" \
314 " themes see docu (default is the built-in theme)\n" \
315 " -i --installdir <dir> specifies the installation directory location,\n" \
316 " this location is automatically searched for themes\n" \
317 " (defaults to the '/usr/local/share/wmpager/'\n" \
318 " and the user specific '~/.wmpager' directory)\n" \
319 " --disable-tooltips do not display any tooltip windows\n" \
320 " --tooltip-font <font> use the specified font as tooltip font\n" \
321 " (default is helvetica, bold, roman, 12 point)\n" \
322 " --tooltip-delay <millis> set the delay before the tooltip window\n" \
323 " is popped up (default is 750 milliseconds)\n" \
324 " --tooltip-reshow <millis> set the tooltip reshow delay (triggered\n" \
325 " when moving from button to button (default is\n" \
326 " 1500 milliseconds)\n" \
327 " --tooltip-outside display tooltip window outside of docklet\n"
329 void usage (int bVerbose) {
330 if (bVerbose) {
331 info();
332 fprintf(stdout, USAGE, getApplicationName());
333 exit(0);
334 } else {
335 fprintf(stderr, USAGE, getApplicationName());
336 exit(-1);
340 void info () {
341 char* szRev= strdup(BUILD_REV);
342 char* szDate= strdup(BUILD_DATE);
343 szRev= &szRev[11];
344 szRev[strlen(szRev) - 2]= '\0';
345 szDate= &szDate[7];
346 szDate[strlen(szDate) - 2]= '\0';
347 fprintf(stdout, "%s %s (build %s, %s)\n\n", APPLICATION, VERSION, szRev, szDate);
351 * Application
354 static char* _szApplicationName;
356 char* getApplicationName () {
357 return _szApplicationName;
360 void initApplicationName (char* szApplicationName) {
361 if (szApplicationName == NULL) {
362 _szApplicationName= APPLICATION;
363 } else {
364 _szApplicationName= strdup(szApplicationName);
369 * Display
372 static Display* _display;
374 Display* getDisplay () {
375 return _display;
378 void destroyDisplay () {
379 XCloseDisplay(getDisplay());
382 void initDisplay (char* szDisplay) {
383 if (szDisplay == NULL && ((char*) getenv("DISPLAY")) == NULL) {
384 szDisplay= ":0.0";
386 if (isVerbose()) {
387 char* szRealDisplay= (szDisplay == NULL) ? (char*) getenv("DISPLAY") : szDisplay;
388 if (szRealDisplay == NULL) {
389 szRealDisplay= "localhost:0.0";
391 fprintf(stdout, "[%8ld] initializing display '%s'\n", currentTimeMillis(), szRealDisplay);
393 _display= XOpenDisplay(szDisplay);
394 if (_display == NULL) {
395 fprintf(
396 stderr,
397 "%s: couldn't open display '%s'.\n",
398 getApplicationName(),
399 (szDisplay == NULL) ? ((char*) getenv("DISPLAY")) : szDisplay
401 exit(-1);
406 * Window
409 static int _nDefaultScreen, _nDefaultDepth;
410 static Window _wRoot, _wMain, _wIcon;
411 static GC _gcMain, _gcWindow;
412 static XpmAttributes _attrButtonTheme;
413 static Pixmap _pButtonTheme, _pButtonThemeMask;
414 static XpmAttributes _attrWindow;
415 static Pixmap _pWindow, _pWindowMask;
416 static Pixel _pWhite, _pBlack;
418 Pixel getWhitePixel () {
419 return _pWhite;
422 Pixel getBlackPixel () {
423 return _pBlack;
426 int getDefaultScreen () {
427 return _nDefaultScreen;
430 int getDefaultDepth () {
431 return _nDefaultDepth;
434 Window getRootWindow () {
435 return _wRoot;
438 Window getMainWindow () {
439 return _wMain;
442 Window getIconWindow () {
443 return _wIcon;
446 GC getMainGraphics () {
447 return _gcMain;
450 GC getWindowGraphics () {
451 return _gcWindow;
454 void initWindow (int nArgc, char** szArgv) {
455 char* szApplicationName= getApplicationName();
456 Display* display= getDisplay();
457 XSizeHints *xsizehints;
458 XWMHints* xwmhints;
459 XClassHint* xclasshint;
460 XTextProperty* xtApplication;
461 XGCValues xgcMain;
463 if (isVerbose()) {
464 fprintf(stdout, "[%8ld] initializing application window\n", currentTimeMillis());
467 _nDefaultScreen= DefaultScreen(display);
468 _nDefaultDepth= DefaultDepth(display, _nDefaultScreen);
469 _wRoot= RootWindow(display, _nDefaultScreen);
471 XSelectInput(display, _wRoot, PropertyChangeMask);
473 _pWhite= WhitePixel(display, _nDefaultScreen);
474 _pBlack= BlackPixel(display, _nDefaultScreen);
476 xsizehints= XAllocSizeHints();
477 xsizehints->flags= USSize | USPosition;
478 xsizehints->width= xsizehints->height= 64;
480 _wMain= XCreateSimpleWindow(display, _wRoot, 0, 0, 64, 64, 5, _pWhite, _pBlack);
481 if (_wMain == 0) {
482 fprintf(stderr, "Cannot create main window.\n");
483 exit(-1);
486 _wIcon= XCreateSimpleWindow(display, _wMain, 0, 0, 64, 64, 5, _pWhite, _pBlack);
487 if (_wIcon == 0) {
488 fprintf(stderr, "Cannot create icon window.\n");
489 exit(-1);
492 xwmhints= XAllocWMHints();
493 xwmhints->flags= WindowGroupHint | IconWindowHint | StateHint;
494 xwmhints->icon_window= _wIcon;
495 xwmhints->window_group= _wMain;
496 xwmhints->initial_state= WithdrawnState;
497 XSetWMHints(display, _wMain, xwmhints);
499 xclasshint= XAllocClassHint();
500 xclasshint->res_name= APPLICATION;
501 xclasshint->res_class= APPLICATION;
502 XSetClassHint(display, _wMain, xclasshint);
504 XSetWMNormalHints(display, _wMain, xsizehints);
506 xtApplication= (XTextProperty*) malloc(sizeof(XTextProperty));
507 if (XStringListToTextProperty(&szApplicationName, 1, xtApplication) == 0) {
508 fprintf(stderr, "Cannot set window title.\n");
509 exit(-1);
511 XSetWMName(display, _wMain, xtApplication);
513 _gcMain= XCreateGC(display, _wMain, (GCForeground | GCBackground), &xgcMain);
514 if (_gcMain == NULL) {
515 fprintf(stderr, "Cannot create graphics context.\n");
516 exit(-1);
519 XSelectInput(display, _wMain, ExposureMask | ButtonPressMask | PointerMotionMask | StructureNotifyMask | LeaveWindowMask);
520 XSelectInput(display, _wIcon, ExposureMask | ButtonPressMask | PointerMotionMask | StructureNotifyMask | LeaveWindowMask);
522 XSetCommand(display, _wMain, szArgv, nArgc);
524 XMapWindow(display, _wMain);
527 void destroyWindow () {
528 XFreeGC(getDisplay(), getWindowGraphics());
529 XFreeGC(getDisplay(), getMainGraphics());
530 XDestroyWindow(getDisplay(), getMainWindow());
531 XDestroyWindow(getDisplay(), getIconWindow());
534 void initWindowMask (char* szInstallDir, char* szButtonTheme) {
535 Display* display= getDisplay();
536 GC gc;
537 Window wRoot= getRootWindow();
538 Window wMain= getMainWindow();
539 Window wIcon= getIconWindow();
540 XGCValues xgc, xgcWindow;
541 Pixmap pOpaque, pTransparent, pMask;
542 char* mask= (char*) malloc(512);
543 int i;
545 if (isVerbose()) {
546 fprintf(stdout, "[%8ld] initializing window mask\n", currentTimeMillis());
548 for (i= 0; i < 512; i++) {
549 mask[i]= 0x00;
551 pTransparent= XCreateBitmapFromData(display, wRoot, mask, 64, 64);
552 if (pTransparent == 0) {
553 fprintf(stderr, "%s: couldn't create window mask (transparent).\n", getApplicationName());
554 exit(-1);
556 pMask= XCreateBitmapFromData(display, wRoot, mask, 64, 64);
557 if (pMask == 0) {
558 fprintf(stderr, "%s: couldn't create window mask (mask buffer).\n", getApplicationName());
559 exit(-1);
562 for (i= 0; i < 512; i++) {
563 mask[i]= 0xff;
565 pOpaque= XCreateBitmapFromData(display, wRoot, mask, 64, 64);
566 if (pOpaque == 0) {
567 fprintf(stderr, "%s: couldn't create window mask (opaque).\n", getApplicationName());
568 exit(-1);
571 gc= XCreateGC(display, pMask, (GCForeground | GCBackground), &xgc);
572 if (gc == NULL) {
573 fprintf(stderr, "%s: couldn't create window mask (mask graphics).\n", getApplicationName());
574 exit(-1);
576 for (i= 0; i < getButtonCount(); i++) {
577 int nButtonX, nButtonY;
578 getButtonLocation(i, &nButtonX, &nButtonY);
579 XCopyArea(display, pOpaque, pMask, gc, nButtonX, nButtonY, getButtonWidth(), getButtonHeight(), nButtonX, nButtonY);
582 XFreePixmap(display, pOpaque);
583 XFreePixmap(display, pTransparent);
584 XFreeGC(display, gc);
586 XShapeCombineMask(display, wMain, ShapeBounding, 0, 0, pMask, ShapeSet);
587 XShapeCombineMask(display, wIcon, ShapeBounding, 0, 0, pMask, ShapeSet);
589 if (isVerbose()) {
590 fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(),
591 szButtonTheme == NULL ? "<built-in>" : szButtonTheme);
594 _attrButtonTheme.valuemask|= (XpmReturnPixels | XpmReturnExtensions);
595 if (szButtonTheme == NULL) {
596 if (
597 XpmCreatePixmapFromData(
598 display, wRoot, buttons_xpm, &_pButtonTheme, &_pButtonThemeMask, &_attrButtonTheme
599 ) != XpmSuccess
601 fprintf(stderr, "%s: couldn't create button theme.\n", getApplicationName());
602 exit(-1);
604 } else {
605 int bCheckAgain= 0;
606 struct stat buf;
607 /* check for absolute button theme pathname */
608 if (stat(szButtonTheme, &buf) == -1) {
609 char* szNewTheme= (char*) malloc(strlen(szButtonTheme) + 4);
610 strcpy(szNewTheme, szButtonTheme);
611 strcat(szNewTheme, ".xpm");
612 if (isVerbose()) {
613 fprintf(stdout, "[%8ld] theme file '%s' not found, trying '%s'\n", currentTimeMillis(), szButtonTheme, szNewTheme);
615 /* check for absolute button theme pathname (with .xpm added) */
616 if (stat(szNewTheme, &buf) == 0) {
617 szButtonTheme= szNewTheme;
618 if (isVerbose()) {
619 fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme);
621 } else {
622 bCheckAgain= 1;
623 free(szNewTheme);
626 if (bCheckAgain && szInstallDir != NULL) {
627 char* szNewTheme= (char*) malloc(strlen(szInstallDir) + strlen(szButtonTheme) + 5);
628 strcpy(szNewTheme, szInstallDir);
629 if (szNewTheme[strlen(szNewTheme) - 1] != '/') {
630 strcat(szNewTheme, "/");
632 strcat(szNewTheme, szButtonTheme);
633 if (stat(szNewTheme, &buf) == 0) {
634 bCheckAgain= 0;
635 szButtonTheme= szNewTheme;
636 if (isVerbose()) {
637 fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme);
639 } else {
640 strcat(szNewTheme, ".xpm");
641 if (stat(szNewTheme, &buf) == 0) {
642 bCheckAgain= 0;
643 szButtonTheme= szNewTheme;
644 if (isVerbose()) {
645 fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme);
650 if (bCheckAgain) {
651 /* as a goody check the ~/.wmpager directory if it exists */
652 char* szHome= (char*) getenv("HOME");
653 if (szHome) {
654 /* one really shouldn't copy&paste but hey this is a q&d tool */
655 char* szNewTheme= (char*) malloc(strlen(szHome) + strlen(szButtonTheme) + strlen(WMPAGER_USER_DIR) + 5);
656 strcpy(szNewTheme, szHome);
657 if (szNewTheme[strlen(szNewTheme) - 1] != '/') {
658 strcat(szNewTheme, "/");
660 strcat(szNewTheme, WMPAGER_USER_DIR);
661 strcat(szNewTheme, szButtonTheme);
662 if (stat(szNewTheme, &buf) == 0) {
663 bCheckAgain= 0;
664 szButtonTheme= szNewTheme;
665 if (isVerbose()) {
666 fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme);
668 } else {
669 strcat(szNewTheme, ".xpm");
670 if (stat(szNewTheme, &buf) == 0) {
671 bCheckAgain= 0;
672 szButtonTheme= szNewTheme;
673 if (isVerbose()) {
674 fprintf(stdout, "[%8ld] initializing button theme '%s'\n", currentTimeMillis(), szButtonTheme);
680 if (
681 XpmReadFileToPixmap(
682 display, wRoot, szButtonTheme, &_pButtonTheme, &_pButtonThemeMask, &_attrButtonTheme
683 ) != XpmSuccess
685 fprintf(stderr, "%s: couldn't read button theme '%s'.\n", getApplicationName(), szButtonTheme);
686 exit(-1);
690 if (isVerbose()) {
691 fprintf(stdout, "[%8ld] initializing screen buffer\n", currentTimeMillis());
694 _attrWindow.valuemask|= (XpmReturnPixels | XpmReturnExtensions);
695 if (
696 XpmCreatePixmapFromData(
697 display, wRoot, screen_xpm, &_pWindow, &_pWindowMask, &_attrWindow
698 ) != XpmSuccess
700 fprintf(stderr, "%s: couldn't create screen buffer.\n", getApplicationName());
701 exit(-1);
704 _gcWindow= XCreateGC(_display, _pWindow, (GCForeground | GCBackground), &xgcWindow);
705 if (gc == NULL) {
706 fprintf(stderr, "%s: couldn't create screen buffer graphics.\n", getApplicationName());
707 exit(-1);
711 void redrawWindow () {
712 XEvent event;
713 int i;
714 int w= getButtonWidth();
715 int h= getButtonHeight();
716 for (i= 0; i < getButtonCount(); i++) {
717 int x, y, xoff, yoff;
718 xoff= 51;
719 yoff= 10;
720 if (i == getCurrentScreen()) {
721 xoff= 0;
722 yoff= 0;
724 getButtonLocation(i, &x, &y);
725 XSetClipMask(_display, _gcWindow, _pWindowMask);
726 XSetClipOrigin(_display, _gcWindow, 0, 0);
727 XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, xoff + x - 7, y - 7, w, h, x, y);
728 XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, xoff, 0, w, 1, x, y);
729 XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, xoff, 0, 1, h, x, y);
730 XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, xoff + 50, 0, 1, h, x + w - 1, y);
731 XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, xoff, 50, w, 1, x, y + h - 1);
732 XSetClipMask(_display, _gcWindow, _pButtonThemeMask);
733 XSetClipOrigin(_display, _gcWindow, (x + (w - 10) / 2) - i * 10, -51 - yoff + y + (h - 10) / 2);
734 XCopyArea(_display, _pButtonTheme, _pWindow, _gcWindow, i * 10, 51 + yoff, 10, 10, x + (w - 10) / 2, y + (h - 10) / 2);
736 while (XCheckTypedWindowEvent(_display, _wMain, Expose, &event));
737 XCopyArea(_display, _pWindow, _wMain, _gcMain, 0, 0, 64, 64, 0, 0);
738 while (XCheckTypedWindowEvent(_display, _wIcon, Expose, &event));
739 XCopyArea(_display, _pWindow, _wIcon, _gcMain, 0, 0, 64, 64, 0, 0);
742 void getWindowOrigin (Window w, int* nX, int* nY) {
743 Window wWindow, wParent, wRoot;
744 Window* wChildren;
745 unsigned int nChildren;
746 unsigned int ww, wh, wb, wd;
747 int wx, wy;
749 wParent= w;
750 do {
751 wWindow= wParent;
752 if (!XQueryTree(getDisplay(), wParent, &wRoot, &wParent, &wChildren, &nChildren)) {
753 return;
755 if (wChildren) {
756 XFree(wChildren);
758 } while (wParent != wRoot);
760 if (XGetGeometry(getDisplay(), wWindow, &wRoot, &wx, &wy, &ww, &wh, &wb, &wd)) {
761 if (nX) {
762 *nX= wx;
764 if (nY) {
765 *nY= wy;
771 * Event Loop
774 void loop (long nTooltipShowDelay, long nTooltipReshowDelay) {
775 Display* display= getDisplay();
776 XEvent event;
777 long nTooltipTimer= -1, nTooltipHideTimer= -1, nNow;
778 int nTooltipButton, nTooltipX, nTooltipY;
780 if (isVerbose()) {
781 fprintf(stdout, "[%8ld] starting event loop\n", currentTimeMillis());
783 for (;;) {
784 while (XPending(display) || (nTooltipTimer == -1)) {
785 XNextEvent(display, &event);
786 switch (event.type) {
787 case Expose:
788 if (event.xexpose.count == 0) {
789 redrawWindow();
791 break;
792 case ConfigureNotify:
793 redrawWindow();
794 break;
795 case MotionNotify:
796 if (hasTooltipSupport()) {
797 if (!hasTooltip()) {
798 nTooltipTimer= currentTimeMillis();
799 nTooltipX= event.xbutton.x;
800 nTooltipY= event.xbutton.y;
801 nTooltipButton= getButtonAt(event.xbutton.x, event.xbutton.y);
802 } else {
803 int nButton= getButtonAt(event.xbutton.x, event.xbutton.y);
804 if (nButton != nTooltipButton) {
805 hideTooltip();
806 nTooltipTimer= -1;
807 nTooltipX= event.xbutton.x;
808 nTooltipY= event.xbutton.y;
809 nTooltipButton= nButton;
810 showTooltip(nTooltipButton, nTooltipX, nTooltipY);
814 break;
815 case LeaveNotify:
816 if (hasTooltip()) {
817 hideTooltip();
818 nTooltipHideTimer= currentTimeMillis();
820 nTooltipTimer= -1;
821 break;
822 case ButtonPress:
824 int nButton= getButtonAt(event.xbutton.x, event.xbutton.y);
825 if (isVerbose()) {
826 fprintf(stdout, "[%8ld] button %d pressed\n", currentTimeMillis(), nButton);
828 if (nButton != -1) {
829 if (hasTooltip()) {
830 hideTooltip();
831 nTooltipHideTimer= currentTimeMillis();
833 setCurrentScreen(nButton);
834 gotoScreen(nButton);
837 break;
838 case PropertyNotify:
839 if (strcmp(XA_WIN_WORKSPACE, XGetAtomName(getDisplay(), event.xproperty.atom)) == 0) {
840 setCurrentScreen(-1);
841 if (isVerbose()) {
842 fprintf(stdout, "[%8ld] new current workspace (%d= %s)\n",
843 currentTimeMillis(), getCurrentScreen(), getScreenName(getCurrentScreen()));
845 redrawWindow();
847 break;
848 case DestroyNotify:
849 if (isVerbose()) {
850 fprintf(stdout, "[%8ld] quit application\n", currentTimeMillis());
852 destroyTooltip();
853 destroyWindow();
854 destroyDisplay();
855 exit(0);
856 break;
859 usleep(50000);
860 nNow= currentTimeMillis();
861 if (
862 nTooltipTimer != -1 &&
864 (nNow > nTooltipTimer + nTooltipShowDelay) ||
865 (nNow < nTooltipHideTimer + nTooltipReshowDelay)
868 showTooltip(nTooltipButton, nTooltipX, nTooltipY);
869 nTooltipTimer= -1;
875 * Button Helpers
878 static int _nButtons;
879 static int _nButtonRows, _nButtonColumns;
880 static int _nButtonWidth, _nButtonHeight;
882 int getButtonCount () {
883 return _nButtons;
886 int getButtonRowCount () {
887 return _nButtonRows;
890 int getButtonColumnCount () {
891 return _nButtonColumns;
894 int getButtonWidth () {
895 return _nButtonWidth;
898 int getButtonHeight () {
899 return _nButtonHeight;
902 int getButtonAt (int nLocationX, int nLocationY) {
903 int i, nButtonX, nButtonY;
904 for (i= 0; i < _nButtons; i++) {
905 getButtonLocation(i, &nButtonX, &nButtonY);
906 if (
907 nLocationX >= nButtonX && nLocationX < nButtonX + _nButtonWidth &&
908 nLocationY >= nButtonY && nLocationY < nButtonY + _nButtonHeight
910 return i;
913 return -1;
916 void getButtonLocation (int nButton, int* nLocationX, int* nLocationY) {
917 if (nButton < 0 || nButton > _nButtons) {
918 *nLocationX= *nLocationY= 0;
919 } else {
920 *nLocationX= *nLocationY= 7;
921 while (nButton >= _nButtonColumns) {
922 *nLocationY+= _nButtonHeight + 3;
923 nButton-= _nButtonColumns;
925 while (nButton > 0) {
926 *nLocationX+= _nButtonWidth + 3;
927 nButton--;
932 void initButtons (int nButtons, int nColumns, int nRows) {
933 if (nButtons != -1) {
934 _nButtons= nButtons;
935 } else {
936 _nButtons= getScreenCount();
937 if (_nButtons > 9) {
938 /* only handle nine screens at most */
939 _nButtons= 9;
942 if (nColumns == -1 || nRows == -1) {
943 switch (_nButtons) {
944 case 1:
945 _nButtonRows= _nButtonColumns= 1;
946 break;
947 case 2:
948 _nButtonColumns= 1;
949 _nButtonRows= 2;
950 break;
951 case 3:
952 /* fallthrough */
953 case 4:
954 _nButtonColumns= _nButtonRows= 2;
955 break;
956 case 5:
957 /* fallthrough */
958 case 6:
959 _nButtonColumns= 2;
960 _nButtonRows= 3;
961 break;
962 default:
963 _nButtonColumns= _nButtonRows= 3;
964 break;
966 } else {
967 _nButtonColumns= nColumns;
968 _nButtonRows= nRows;
970 if (_nButtons > _nButtonColumns * _nButtonRows) {
971 _nButtons= _nButtonColumns * _nButtonRows;
973 if (isVerbose()) {
974 fprintf(stdout, "[%8ld] initializing buttons\n", currentTimeMillis());
975 fprintf(stdout, "[%8ld] - %d workspace buttons\n", currentTimeMillis(), _nButtons);
976 fprintf(stdout, "[%8ld] - button layout %dx%d\n", currentTimeMillis(), _nButtonColumns, _nButtonRows);
979 if (_nButtonColumns == 1) {
980 _nButtonWidth= 51;
981 } else if (_nButtonColumns == 2) {
982 _nButtonWidth= 24;
983 } else {
984 _nButtonWidth= 15;
987 if (_nButtonRows == 1) {
988 _nButtonHeight= 51;
989 } else if (_nButtonRows == 2) {
990 _nButtonHeight= 24;
991 } else {
992 _nButtonHeight= 15;
998 * Time
1001 static struct timeval _tStart;
1003 void initTime () {
1004 if (isVerbose()) {
1005 fprintf(stdout, "[ ] initializing time\n");
1007 gettimeofday(&_tStart, NULL);
1010 long currentTimeMillis () {
1011 struct timeval tNow;
1012 struct timeval tElapsed;
1014 gettimeofday(&tNow, NULL);
1016 if (_tStart.tv_usec > tNow.tv_usec) {
1017 tNow.tv_usec+= 1000000;
1018 tNow.tv_sec--;
1020 tElapsed.tv_sec= tNow.tv_sec - _tStart.tv_sec;
1021 tElapsed.tv_usec= tNow.tv_usec - _tStart.tv_usec;
1022 return (tElapsed.tv_sec * 1000) + (tElapsed.tv_usec / 1000);
1026 * Screen Handling
1029 static Atom _xaWinWorkspace;
1030 static Atom _xaWinWorkspaceNames;
1031 static int _nScreens;
1032 static char** _szScreenNames;
1033 static int _nLastScreen;
1035 int getScreenCount () {
1036 return _nScreens;
1039 char* getScreenName (int nScreen) {
1040 if (nScreen < 0 || nScreen >= _nScreens) {
1041 return NULL;
1043 return _szScreenNames[nScreen];
1046 void gotoScreen (int nWorkspace) {
1047 XEvent event;
1048 event.type= ClientMessage;
1049 event.xclient.type= ClientMessage;
1050 event.xclient.window= getRootWindow();
1051 event.xclient.message_type= _xaWinWorkspace;
1052 event.xclient.format= 32;
1053 event.xclient.data.l[0]= nWorkspace;
1054 event.xclient.data.l[1]= currentTimeMillis();
1055 XSendEvent(getDisplay(), getRootWindow(), False, SubstructureNotifyMask, (XEvent*) &event);
1058 int getCurrentScreen () {
1059 return _nLastScreen;
1062 void setCurrentScreen (int nCurrentScreen) {
1063 if (nCurrentScreen == -1) {
1064 long nScreen= _nLastScreen;
1065 Atom xaType;
1066 int nFormat;
1067 unsigned long nItems, nBytesAfter;
1068 unsigned char* data;
1070 XGetWindowProperty(
1071 getDisplay(), getRootWindow(), _xaWinWorkspace,
1072 0, 8192, False, XA_CARDINAL, &xaType, &nFormat, &nItems, &nBytesAfter, &data
1074 if ((nFormat == 32) && (nItems == 1) && (nBytesAfter == 0)) {
1075 nScreen= *(long*) data;
1077 if (xaType != None) {
1078 XFree(data);
1080 _nLastScreen= nScreen;
1081 } else {
1082 _nLastScreen= nCurrentScreen;
1086 void initScreens () {
1087 XTextProperty tp;
1089 if (isVerbose()) {
1090 fprintf(stdout, "[%8ld] initializing window maker communication\n", currentTimeMillis());
1092 _xaWinWorkspace= XInternAtom(getDisplay(), XA_WIN_WORKSPACE, False);
1093 _xaWinWorkspaceNames= XInternAtom(getDisplay(), XA_WIN_WORKSPACE_NAMES, False);
1094 XGetTextProperty(getDisplay(), getRootWindow(), &tp, _xaWinWorkspaceNames);
1095 XTextPropertyToStringList(&tp, &_szScreenNames, &_nScreens);
1096 _nLastScreen= -1;
1097 setCurrentScreen(-1);
1098 if (_nLastScreen == -1) {
1099 fprintf(
1100 stderr,
1101 "%s: couldn't determine current workspace.\n" \
1102 "Make sure your WindowMaker has Gnome support enabled!\n",
1103 getApplicationName()
1105 setCurrentScreen(0);
1107 if (isVerbose()) {
1108 int i;
1109 fprintf(stdout, "[%8ld] - %d worspaces found\n", currentTimeMillis(), getScreenCount());
1110 for (i= 0; i < getScreenCount(); i++) {
1111 fprintf(stdout, "[%8ld] - workspace %d: %s\n", currentTimeMillis(), i, getScreenName(i));
1113 fprintf(stdout, "[%8ld] - current workspace is %d (%s)\n", currentTimeMillis(),
1114 getCurrentScreen(), getScreenName(getCurrentScreen()));
1119 * Tooltip
1122 int _bTooltip= 0, _bTooltipSupport, _bTooltipOutside;
1123 XFontStruct* _fTooltip;
1124 int _nFontHeight, _nFontY;
1125 int _nScreenWidth, _nScreenHeight;
1126 GC _gcMono= 0;
1127 Window _wTooltip;
1129 int hasTooltipSupport () {
1130 return _bTooltipSupport;
1133 void showTooltip (int nButton, int nMouseX, int nMouseY) {
1134 Pixmap pixmap, mask;
1135 int nMainWinX, nMainWinY;
1136 int nButtonX, nButtonY, nButtonWidth, nButtonHeight;
1137 int nTextY, nX, nY, nWidth, nHeight, nSide;
1138 char* szText;
1140 if (!_bTooltipSupport) {
1141 return;
1143 if (_bTooltip) {
1144 hideTooltip();
1146 _bTooltip= 1;
1147 if (isVerbose()) {
1148 fprintf(stdout, "[%8ld] showing tooltip for button %d (%s) at %d, %d\n", currentTimeMillis(),
1149 nButton, getScreenName(nButton), nMouseX, nMouseY);
1152 szText= strdup(getScreenName(nButton));
1153 nWidth= XTextWidth(_fTooltip, szText, strlen(szText)) + 16;
1154 nHeight= _nFontHeight + 4;
1155 if (nHeight < 16) {
1156 nHeight= 16;
1158 if (nWidth < nHeight) {
1159 nWidth= nHeight;
1161 if (isVerbose()) {
1162 fprintf(stdout, "[%8ld] tooltip size: %d, %d\n", currentTimeMillis(), nWidth, nHeight);
1165 getWindowOrigin(getIconWindow(), &nMainWinX, &nMainWinY);
1166 if (_bTooltipOutside) {
1167 nButtonX= nMainWinX;
1168 nButtonY= nMainWinY;
1169 nButtonWidth= 64;
1170 nButtonHeight= 64;
1171 } else {
1172 getButtonLocation(nButton, &nButtonX, &nButtonY);
1173 nButtonX+= nMainWinX;
1174 nButtonY+= nMainWinY;
1175 nButtonWidth= getButtonWidth();
1176 nButtonHeight= getButtonHeight();
1179 if (nButtonX + nWidth > _nScreenWidth) {
1180 nSide= TOOLTIP_RIGHT;
1181 nX= nButtonX - nWidth + nButtonWidth / 2;
1182 if (nX < 0) {
1183 nX= 0;
1185 } else {
1186 nSide= TOOLTIP_LEFT;
1187 nX= nButtonX + nButtonWidth / 2;
1189 if (nX + nWidth > _nScreenWidth) {
1190 nX= _nScreenWidth - nWidth;
1193 if (nButtonY - (nHeight + TOOLTIP_SPACE) < 0) {
1194 nSide|= TOOLTIP_TOP;
1195 nY= nButtonY + nButtonHeight - 1;
1196 nTextY= TOOLTIP_SPACE;
1197 } else {
1198 nSide|= TOOLTIP_BOTTOM;
1199 nY= nButtonY - (nHeight + TOOLTIP_SPACE);
1200 nTextY= 0;
1203 pixmap= createTooltipPixmap(nWidth, nHeight, nSide, &mask);
1205 XSetForeground(getDisplay(), getMainGraphics(), getBlackPixel());
1206 XSetFont(getDisplay(), getMainGraphics(), _fTooltip->fid);
1207 XDrawString(getDisplay(), pixmap, getMainGraphics(),
1208 8, nTextY + (nHeight - _nFontHeight) / 2 + _nFontY, szText, strlen(szText));
1210 XSetWindowBackgroundPixmap(getDisplay(), _wTooltip, pixmap);
1212 XResizeWindow(getDisplay(), _wTooltip, nWidth, nHeight + TOOLTIP_SPACE);
1213 XShapeCombineMask(getDisplay(), _wTooltip, ShapeBounding, 0, 0, mask, ShapeSet);
1214 XFreePixmap(getDisplay(), mask);
1215 XMoveWindow(getDisplay(), _wTooltip, nX, nY);
1216 XMapRaised(getDisplay(), _wTooltip);
1217 XFreePixmap(getDisplay(), pixmap);
1219 free(szText);
1222 void hideTooltip () {
1223 if (!_bTooltipSupport) {
1224 return;
1226 if (_bTooltip) {
1227 if (isVerbose()) {
1228 fprintf(stdout, "[%8ld] hiding tooltip\n", currentTimeMillis());
1230 XUnmapWindow(getDisplay(), _wTooltip);
1231 _bTooltip= 0;
1235 int hasTooltip () {
1236 if (!_bTooltipSupport) {
1237 return 0;
1239 return _bTooltip;
1242 void initTooltip (int bTooltipSupport, char* szFontName, int bTooltipOutside) {
1243 XSetWindowAttributes attribs;
1244 unsigned long vmask;
1246 _bTooltipSupport= bTooltipSupport;
1247 if (!_bTooltipSupport) {
1248 if (isVerbose()) {
1249 fprintf(stdout, "[%8ld] initializing tooltips (disabled)\n", currentTimeMillis());
1251 return;
1253 if (isVerbose()) {
1254 fprintf(stdout, "[%8ld] initializing tooltips\n", currentTimeMillis());
1256 _bTooltipOutside= bTooltipOutside;
1257 _fTooltip= XLoadQueryFont(getDisplay(), szFontName);
1258 if (!_fTooltip) {
1259 fprintf(stderr, "%s: couldn't allocate font '%s'.\n", getApplicationName(), szFontName);
1260 exit(-1);
1262 _nFontHeight= _fTooltip->ascent + _fTooltip->descent;
1263 _nFontY= _fTooltip->ascent;
1264 _nScreenWidth= WidthOfScreen(ScreenOfDisplay(getDisplay(), getDefaultScreen()));
1265 _nScreenHeight= HeightOfScreen(ScreenOfDisplay(getDisplay(), getDefaultScreen()));
1266 if (isVerbose()) {
1267 fprintf(stdout, "[%8ld] configuring tooltip font:\n" \
1268 "[%8ld] - '%s'\n[%8ld] - font-height= %d, font-ascent= %d\n" \
1269 "[%8ld] configuring screen size: %dx%d\n",
1270 currentTimeMillis(), currentTimeMillis(), szFontName, currentTimeMillis(), _nFontHeight, _nFontY,
1271 currentTimeMillis(), _nScreenWidth, _nScreenHeight
1275 vmask= CWSaveUnder | CWOverrideRedirect | CWBorderPixel;
1276 attribs.save_under= True;
1277 attribs.override_redirect= True;
1278 attribs.border_pixel= 0;
1279 _wTooltip= XCreateWindow(getDisplay(), getRootWindow(), 1, 1, 10, 10, 1,
1280 CopyFromParent, CopyFromParent, CopyFromParent, vmask, &attribs);
1281 if (_wMain == 0) {
1282 fprintf(stderr, "Cannot create tooltip window.\n");
1283 exit(-1);
1287 void destroyTooltip () {
1288 if (!_bTooltipSupport) {
1289 return;
1291 if (_gcMono) {
1292 XFreeGC(getDisplay(), _gcMono);
1293 _gcMono= 0;
1295 XDestroyWindow(getDisplay(), _wTooltip);
1298 void drawTooltipBalloon (Pixmap pix, GC gc, int x, int y, int w, int h, int side) {
1299 Display* display= getDisplay();
1300 int rad = h*3/10;
1301 XPoint pt[3];
1303 XFillArc(display, pix, gc, x, y, rad, rad, 90*64, 90*64);
1304 XFillArc(display, pix, gc, x, y+h-1-rad, rad, rad, 180*64, 90*64);
1306 XFillArc(display, pix, gc, x+w-1-rad, y, rad, rad, 0*64, 90*64);
1307 XFillArc(display, pix, gc, x+w-1-rad, y+h-1-rad, rad, rad, 270*64, 90*64);
1309 XFillRectangle(display, pix, gc, x, y+rad/2, w, h-rad);
1310 XFillRectangle(display, pix, gc, x+rad/2, y, w-rad, h);
1312 if (side & TOOLTIP_BOTTOM) {
1313 pt[0].y = y+h-1;
1314 pt[1].y = y+h-1+TOOLTIP_SPACE;
1315 pt[2].y = y+h-1;
1316 } else {
1317 pt[0].y = y;
1318 pt[1].y = y-TOOLTIP_SPACE;
1319 pt[2].y = y;
1321 if (side & TOOLTIP_RIGHT) {
1322 pt[0].x = x+w-h+2*h/16;
1323 pt[1].x = x+w-h+11*h/16;
1324 pt[2].x = x+w-h+7*h/16;
1325 } else {
1326 pt[0].x = x+h-2*h/16;
1327 pt[1].x = x+h-11*h/16;
1328 pt[2].x = x+h-7*h/16;
1330 XFillPolygon(display, pix, gc, pt, 3, Convex, CoordModeOrigin);
1333 Pixmap createTooltipPixmap (int width, int height, int side, Pixmap *mask) {
1334 Display* display= getDisplay();
1335 Window wRoot= getRootWindow();
1336 GC gc= getMainGraphics();
1337 Pixmap bitmap;
1338 Pixmap pixmap;
1339 int x, y;
1341 bitmap = XCreatePixmap(display, wRoot, width+TOOLTIP_SPACE, height+TOOLTIP_SPACE, 1);
1343 if (!_gcMono) {
1344 _gcMono= XCreateGC(display, bitmap, 0, NULL);
1346 XSetForeground(display, _gcMono, 0);
1347 XFillRectangle(display, bitmap, _gcMono, 0, 0, width+TOOLTIP_SPACE, height+TOOLTIP_SPACE);
1349 pixmap = XCreatePixmap(display, wRoot, width+TOOLTIP_SPACE, height+TOOLTIP_SPACE, getDefaultDepth());
1350 XSetForeground(display, gc, getBlackPixel());
1351 XFillRectangle(display, pixmap, gc, 0, 0, width+TOOLTIP_SPACE, height+TOOLTIP_SPACE);
1353 if (side & TOOLTIP_BOTTOM) {
1354 y = 0;
1355 } else {
1356 y = TOOLTIP_SPACE;
1358 x = 0;
1360 XSetForeground(display, _gcMono, 1);
1361 drawTooltipBalloon(bitmap, _gcMono, x, y, width, height, side);
1362 XSetForeground(display, gc, getWhitePixel());
1363 drawTooltipBalloon(pixmap, gc, x+1, y+1, width-2, height-2, side);
1365 *mask = bitmap;
1367 return pixmap;