1 /* wmb_libs.c - Edward H. Flora - ehf_dockapps@cox.net */
2 /* Last Modified: 4/3/04 */
4 * These functions are designed to work with wmbutton.
9 * Coded in ANSI C, using ANSI prototypes.
12 /****** Include Files *************************************************/
18 /****** ToolTip Globals ***********************************************/
20 static struct timeval _tStart
;
22 extern struct Config_t Config
;
24 XFontStruct
* _fTooltip
;
25 int _nFontHeight
, _nFontY
;
26 int _nScreenWidth
, _nScreenHeight
;
30 /****** Parse Command Line ********************************************/
31 void parseargs(int argc
, char **argv
)
34 char *Home
= getenv("HOME");
36 while (-1 != (current
= getopt(argc
, argv
, "vhnmsF:b:g:d:f:"))) {
49 Config
.bTooltipDisable
= 1;
52 Config
.bTooltipSwapColors
= 1;
55 Config
.Geometry_str
= strdup(optarg
);
58 Config
.Display_str
= strdup(optarg
);
61 Config
.configfile
= strdup(optarg
);
64 Config
.szTooltipFont
= strdup(optarg
);
67 Config
.buttonfile
= strdup(optarg
);
72 if (!Config
.configfile
) {
74 Config
.configfile
= malloc(strlen(Home
) +
75 strlen(CONFFILENAME
) + 1);
76 sprintf(Config
.configfile
, "%s%s", Home
, CONFFILENAME
);
80 if (!Config
.buttonfile
) {
82 Config
.buttonfile
= malloc(strlen(Home
) +
83 strlen(BUTTONFILENAME
) + 1);
84 sprintf(Config
.buttonfile
, "%s%s", Home
, BUTTONFILENAME
);
88 if (!Config
.Geometry_str
)
89 Config
.Geometry_str
= "64x64+0+0";
91 if (!Config
.Display_str
)
92 Config
.Display_str
= "";
94 if (!Config
.szTooltipFont
)
95 Config
.szTooltipFont
= TOOLTIP_FONT
;
97 if (!Config
.bTooltipDisable
)
98 Config
.bTooltipDisable
= !TOOLTIP_SUPPORT
;
102 /****** Show Usage Information ****************************************/
103 void show_usage(void)
105 extern char *app_name
;
107 fprintf(stderr
, "\n");
108 fprintf(stderr
, "usage: %s [-g geom] [-d dpy] [-f cfgfile] [-b btnfile] "\
109 "[-F <font>] [-v] [-s] [-n]\n",app_name
);
110 fprintf(stderr
, "\n");
111 fprintf(stderr
, " wmbutton version %s\n", PACKAGE_VERSION
);
112 fprintf(stderr
, "\n");
113 fprintf(stderr
, "-g <geometry> Window Geometry - ie: 64x64+10+10\n");
114 fprintf(stderr
, "-d <display> Display - ie: 127.0.0.1:0.0\n");
115 fprintf(stderr
, "-f <filename> Full path to configuration file.\n");
116 fprintf(stderr
, "-b <filename> Full path to button xpm.\n");
117 fprintf(stderr
, "-F <font> Custom tooltip font (e.g. -b\\&h-lucidatypewriter-medium-*-*-*-12-*)\n");
118 fprintf(stderr
, "-v Verbose Mode.\n");
119 fprintf(stderr
, "-h Help. This message.\n");
120 fprintf(stderr
, "-m Disable Middle Mouse functionality.\n");
121 fprintf(stderr
, "-s Swap tooltip colors.\n");
122 fprintf(stderr
, "-n Turn off tooltips.\n");
123 fprintf(stderr
, "\n");
126 /***********************************************************************/
128 /****** Error Handler Routine *****************************************/
129 void err_mess(int err
, char *str
)
133 fprintf(stderr
, "Fail: XOpenDisplay for %s\n", str
);
136 fprintf(stderr
, "Fail: XCreateSimpleWindow\n");
139 fprintf(stderr
, "Fail: XCreateSimpleWindow\n");
142 fprintf(stderr
, "Fail: XCreateBitmapFromData\n");
145 fprintf(stderr
, "%s: Can't set up window name\n", str
);
148 fprintf(stderr
, "Fail: XCreateGC\n");
151 fprintf(stderr
, "Fail: Can't Find user or system configuration file.\n");
152 fprintf(stderr
, "Fail: User Config: '%s'\n", str
);
153 fprintf(stderr
, "Fail: System Config: '%s'\n", CONFIGGLOBAL
);
156 fprintf(stderr
, "Fail: Can't Create 'template' Pixmap\n");
159 fprintf(stderr
, "Fail: Can't Create 'visible' Pixmap\n");
162 fprintf(stderr
, "Fail: Can't Create 'buttons' Pixmap\n");
165 fprintf(stderr
, "Fail: UnSpecified Error: %d\n", err
);
166 fprintf(stderr
, "Fail: %s\n", str
);
170 /***********************************************************************/
172 /***********************************************************************
175 * Run the command given in the configuration file 'configfile'
176 ***********************************************************************/
177 void RunAppN(int app
)
180 extern struct Config_t Config
;
182 cmndstr
= Parse(app
); /* Get command to pass to system */
185 fprintf(stderr
, "Command String: %s", cmndstr
);
187 if (cmndstr
!= NULL
) {
188 system(cmndstr
); /* if there's a command, run it */
192 /***********************************************************************/
194 /***********************************************************************
195 * canOpenFile(const char *path)
197 * Check if the file at a given path can be opened.
198 ***********************************************************************/
199 int canOpenFile(const char *path
)
203 if ((fp
= fopen(path
, "r")) == NULL
)
211 /***********************************************************************
214 * Parses the file 'configfile' for command to execute.
215 ***********************************************************************/
219 char Buf
[BUFFER_SIZE
];
222 if ((fp
= fopen(Config
.configfile
, "r")) == NULL
)
223 if ((fp
= fopen(CONFIGGLOBAL
, "r")) == NULL
)
224 err_mess(FAILCONF
,Config
.configfile
);
226 while ((Ptr
= fgets(Buf
, BUFFER_SIZE
, fp
))) {
227 if (atoi(Buf
) == app
)
236 Ptr
= strchr(Buf
, '\t'); /* find first tab */
238 Ptr
= strchr(Buf
, ' '); /* or space charater */
248 /**********************************************************************/
250 /***********************************************************************
253 * Copyright (c) 2001 Bruno Essmann <essmann@users.sourceforge.net>
254 ***********************************************************************/
258 extern struct Config_t Config
;
261 fprintf(stdout
, "[ ] initializing time\n");
263 gettimeofday(&_tStart
, NULL
);
265 /**********************************************************************/
267 long currentTimeMillis(void)
269 struct timeval tNow
, tElapsed
;
271 gettimeofday(&tNow
, NULL
);
273 if (_tStart
.tv_usec
> tNow
.tv_usec
) {
274 tNow
.tv_usec
+= 1000000;
278 tElapsed
.tv_sec
= tNow
.tv_sec
- _tStart
.tv_sec
;
279 tElapsed
.tv_usec
= tNow
.tv_usec
- _tStart
.tv_usec
;
280 return (tElapsed
.tv_sec
* 1000) + (tElapsed
.tv_usec
/ 1000);
282 /**********************************************************************/
284 void getWindowOrigin(Window w
, int *nX
, int *nY
)
286 extern Display
*display
;
287 Window wWindow
, wParent
, wRoot
;
289 unsigned int nChildren
, ww
, wh
, wb
, wd
;
295 if (!XQueryTree(display
, wParent
, &wRoot
, &wParent
, &wChildren
, &nChildren
))
301 } while (wParent
!= wRoot
);
303 if (XGetGeometry(display
, wWindow
, &wRoot
, &wx
, &wy
, &ww
, &wh
, &wb
, &wd
)) {
311 /**********************************************************************/
313 /***********************************************************************
316 * compute location for each button's tooltip (not perfect)
317 ***********************************************************************/
318 void getButtonLocation (int nButton
, int *nLocationX
, int *nLocationY
)
323 while (nButton
> BUTTON_COLS
) {
324 *nLocationY
+= BUTTON_SIZE
;
325 nButton
-= BUTTON_COLS
;
328 while (nButton
> 0) {
329 *nLocationX
+= BUTTON_SIZE
- 1;
333 /**********************************************************************/
335 /* SkipWord & SkipSpaces: utility functions for getNicenedString */
336 char *SkipWord(char *Text
) {
339 while ((*Result
!= ' ') && (*Result
!= '\t') &&
340 (*Result
!= '\n') && (*Result
!= 0x00))
346 char *SkipSpaces(char *Text
) {
349 while ((*Result
== ' ') || (*Result
== '\t') || (*Result
== '\n'))
355 /***********************************************************************
358 * nicen the parsed command from the .wmbutton config file
360 * - remove parameters, whitespace and the '&'...
361 ***********************************************************************/
362 char *getNicenedString(char *old
, int andAddSeparator
)
364 char *WorkStr
, *WorkStrEnd
, *StartPtr
, *EndPtr
, *RetStr
;
368 return strdup("-- | ");
373 RetStr
= malloc(strlen(old
) + 3 + 1); /* 3 for Seperator */
376 WorkStr
= strdup(old
);
377 WorkStrEnd
= strchr(WorkStr
, 0x00);
380 while (StartPtr
< WorkStrEnd
) {
381 StartPtr
= SkipSpaces(StartPtr
);
382 EndPtr
= SkipWord(StartPtr
);
385 if ((*StartPtr
== '&') || (*StartPtr
== '-'))
388 strcat(RetStr
, StartPtr
);
390 StartPtr
= EndPtr
+ 1;
396 strcat(RetStr
, "| ");
401 /***********************************************************************
404 *returns the 1..3 application names / commands to be shown in tooltip
405 ***********************************************************************/
406 char *getButtonAppNames(int nButton
)
408 char *tmp1
, *tmp2
, *str
= NULL
;
410 if (!( nButton
< 0 || nButton
> 9 )) {
412 /* FIXME: _Might_ overflow, but it's unlikely.
413 * Perhaps one should fix this sometime ;) */
414 str
= (char*) calloc (sizeof(char), BUFFER_SIZE
);
416 tmp1
= Parse(nButton
+ LMASK
);
417 tmp2
= getNicenedString(tmp1
, 1);
422 tmp1
= Parse(nButton
+ MMASK
);
423 tmp2
= getNicenedString(tmp1
, 1);
428 tmp1
= Parse(nButton
+ RMASK
);
429 tmp2
= getNicenedString(tmp1
, 0);
437 /**********************************************************************/
440 int hasTooltipSupport(void)
442 return !Config
.bTooltipDisable
;
444 /**********************************************************************/
446 void showTooltip (int nButton
, int nMouseX
, int nMouseY
)
449 int nMainWinX
, nMainWinY
;
450 int nButtonX
= 0, nButtonY
= 0, nButtonWidth
= 0, nButtonHeight
= 0;
451 int nTextY
, nX
, nY
, nWidth
, nHeight
, nSide
;
453 extern struct Config_t Config
;
454 extern Window iconwin
;
455 extern Pixel bg_pixel
, fg_pixel
;
456 extern Display
*display
;
459 if (Config
.bTooltipDisable
|| nButton
== -1)
467 "[%8ld] showing tooltip for button %d at %d, %d\n",
468 currentTimeMillis(), nButton
, nMouseX
, nMouseY
);
470 szText
= getButtonAppNames(nButton
);
476 nWidth
= XTextWidth(_fTooltip
, szText
, strlen(szText
)) + 16;
477 nHeight
= _nFontHeight
+ 4;
481 if (nWidth
< nHeight
)
485 fprintf(stdout
, "[%8ld] tooltip size: %d, %d\n",
486 currentTimeMillis(), nWidth
, nHeight
);
488 getWindowOrigin(iconwin
, &nMainWinX
, &nMainWinY
);
489 getButtonLocation(nButton
, &nButtonX
, &nButtonY
);
490 nButtonX
+= nMainWinX
;
491 nButtonY
+= nMainWinY
;
492 nButtonWidth
= BUTTON_SIZE
;
493 nButtonHeight
= BUTTON_SIZE
;
495 if (nButtonX
+ nWidth
> _nScreenWidth
) {
496 nSide
= TOOLTIP_RIGHT
;
497 nX
= nButtonX
- nWidth
+ nButtonWidth
/ 2;
501 nSide
= TOOLTIP_LEFT
;
502 nX
= nButtonX
+ nButtonWidth
/ 2;
505 if (nX
+ nWidth
> _nScreenWidth
)
506 nX
= _nScreenWidth
- nWidth
;
508 if (nButtonY
- (nHeight
+ TOOLTIP_SPACE
) < 0) {
509 nSide
|= TOOLTIP_TOP
;
510 nY
= nButtonY
+ nButtonHeight
- 1;
511 nTextY
= TOOLTIP_SPACE
;
513 nSide
|= TOOLTIP_BOTTOM
;
514 nY
= nButtonY
- (nHeight
+ TOOLTIP_SPACE
);
518 pixmap
= createTooltipPixmap(nWidth
, nHeight
, nSide
, &mask
);
520 XSetForeground(display
, gc
, Config
.bTooltipSwapColors
? fg_pixel
: bg_pixel
);
521 XSetFont(display
, gc
, _fTooltip
->fid
);
522 XDrawString(display
, pixmap
, gc
,
523 8, nTextY
+ (nHeight
- _nFontHeight
) / 2 + _nFontY
,
524 szText
, strlen(szText
));
526 XSetWindowBackgroundPixmap(display
, _wTooltip
, pixmap
);
528 XResizeWindow(display
, _wTooltip
, nWidth
, nHeight
+ TOOLTIP_SPACE
);
529 XShapeCombineMask(display
, _wTooltip
, ShapeBounding
, 0, 0, mask
, ShapeSet
);
530 XFreePixmap(display
, mask
);
531 XMoveWindow(display
, _wTooltip
, nX
, nY
);
532 XMapRaised(display
, _wTooltip
);
533 XFreePixmap(display
, pixmap
);
537 /**********************************************************************/
539 void hideTooltip(void)
541 extern struct Config_t Config
;
542 extern Display
*display
;
544 if (Config
.bTooltipDisable
)
549 fprintf(stdout
, "[%8ld] hiding tooltip\n", currentTimeMillis());
551 XUnmapWindow(display
, _wTooltip
);
555 /**********************************************************************/
559 if (Config
.bTooltipDisable
)
564 /**********************************************************************/
566 void initTooltip(void)
568 XSetWindowAttributes attribs
;
570 extern Display
*display
;
571 extern char *app_name
;
573 extern Window rootwin
, win
;
575 if (Config
.bTooltipDisable
) {
577 fprintf(stdout
, "[%8ld] initializing tooltips (disabled)\n",
578 currentTimeMillis());
583 fprintf(stdout
, "[%8ld] initializing tooltips\n", currentTimeMillis());
585 _fTooltip
= XLoadQueryFont(display
, Config
.szTooltipFont
);
587 fprintf(stderr
, "%s: couldn't allocate font '%s'.\n", app_name
, Config
.szTooltipFont
);
588 if (!strcmp(Config
.szTooltipFont
, TOOLTIP_FONT
))
589 fprintf(stderr
, "%s: Use option -F <font>\n", app_name
);
593 _nFontHeight
= _fTooltip
->ascent
+ _fTooltip
->descent
;
594 _nFontY
= _fTooltip
->ascent
;
595 _nScreenWidth
= WidthOfScreen(ScreenOfDisplay(display
, screen
));
596 _nScreenHeight
= HeightOfScreen(ScreenOfDisplay(display
, screen
));
598 fprintf(stdout
, "[%8ld] configuring tooltip font:\n" \
600 "[%8ld] - font-height= %d, font-ascent= %d\n" \
601 "[%8ld] configuring screen size: %dx%d\n",
603 currentTimeMillis(), Config
.szTooltipFont
,
604 currentTimeMillis(), _nFontHeight
, _nFontY
,
605 currentTimeMillis(), _nScreenWidth
, _nScreenHeight
);
607 vmask
= CWSaveUnder
| CWOverrideRedirect
| CWBorderPixel
;
608 attribs
.save_under
= True
;
609 attribs
.override_redirect
= True
;
610 attribs
.border_pixel
= 0;
611 _wTooltip
= XCreateWindow(display
, rootwin
, 1, 1, 10, 10, 1,
612 CopyFromParent
, CopyFromParent
,
613 CopyFromParent
, vmask
, &attribs
);
616 fprintf(stderr
, "Cannot create tooltip window.\n");
620 /**********************************************************************/
622 void destroyTooltip(void)
624 extern Display
*display
;
626 if (Config
.bTooltipDisable
)
630 XFreeGC(display
, _gcMono
);
634 XDestroyWindow(display
, _wTooltip
);
636 /**********************************************************************/
638 void drawTooltipBalloon(Pixmap pix
, GC gc
, int x
, int y
, int w
, int h
, int side
)
640 extern Display
*display
;
641 int rad
= h
* 3 / 10;
644 XFillArc(display
, pix
, gc
, x
, y
, rad
, rad
, 90 * 64, 90 * 64);
645 XFillArc(display
, pix
, gc
, x
, y
+ h
- 1 - rad
, rad
, rad
, 180 * 64, 90 * 64);
647 XFillArc(display
, pix
, gc
, x
+ w
- 1 - rad
, y
, rad
, rad
, 0 * 64, 90 * 64);
648 XFillArc(display
, pix
, gc
, x
+ w
- 1 - rad
, y
+ h
- 1 - rad
, rad
, rad
, 270 * 64, 90 * 64);
650 XFillRectangle(display
, pix
, gc
, x
, y
+ rad
/ 2, w
, h
- rad
);
651 XFillRectangle(display
, pix
, gc
, x
+ rad
/ 2, y
, w
- rad
, h
);
653 if (side
& TOOLTIP_BOTTOM
) {
655 pt
[1].y
= y
+ h
- 1 + TOOLTIP_SPACE
;
659 pt
[1].y
= y
-TOOLTIP_SPACE
;
663 if (side
& TOOLTIP_RIGHT
) {
664 pt
[0].x
= x
+ w
- h
+ 2 * h
/ 16;
665 pt
[1].x
= x
+ w
- h
+ 11 * h
/ 16;
666 pt
[2].x
= x
+ w
- h
+ 7 * h
/ 16;
668 pt
[0].x
= x
+ h
- 2 * h
/16;
669 pt
[1].x
= x
+ h
- 11 * h
/16;
670 pt
[2].x
= x
+ h
- 7 * h
/16;
673 XFillPolygon(display
, pix
, gc
, pt
, 3, Convex
, CoordModeOrigin
);
675 /**********************************************************************/
677 Pixmap
createTooltipPixmap(int width
, int height
, int side
, Pixmap
*mask
)
679 extern Display
*display
;
681 extern Pixel bg_pixel
, fg_pixel
;
683 extern Window rootwin
;
684 Pixmap bitmap
, pixmap
;
687 bitmap
= XCreatePixmap(display
, rootwin
,
688 width
+TOOLTIP_SPACE
, height
+TOOLTIP_SPACE
, 1);
691 _gcMono
= XCreateGC(display
, bitmap
, 0, NULL
);
693 XSetForeground(display
, _gcMono
, 0);
694 XFillRectangle(display
, bitmap
, _gcMono
, 0, 0,
695 width
+TOOLTIP_SPACE
, height
+TOOLTIP_SPACE
);
697 pixmap
= XCreatePixmap(display
, rootwin
, width
+TOOLTIP_SPACE
,
698 height
+TOOLTIP_SPACE
, depth
);
699 XSetForeground(display
, gc
, Config
.bTooltipSwapColors
? fg_pixel
: bg_pixel
);
700 XFillRectangle(display
, pixmap
, gc
, 0, 0, width
+TOOLTIP_SPACE
,
701 height
+TOOLTIP_SPACE
);
703 if (side
& TOOLTIP_BOTTOM
)
710 XSetForeground(display
, _gcMono
, 1);
711 drawTooltipBalloon(bitmap
, _gcMono
, x
, y
, width
, height
, side
);
712 XSetForeground(display
, gc
, Config
.bTooltipSwapColors
? bg_pixel
: fg_pixel
);
713 drawTooltipBalloon(pixmap
, gc
, x
+1, y
+1, width
-2, height
-2, side
);
719 /***********************************************************************/
722 /***********************************************************************
725 * Everyone else has one of these... Can't hurt to throw it in.
726 ***********************************************************************/
727 int flush_expose(Window w
)
729 extern Display
*display
;
733 while (XCheckTypedWindowEvent(display
, w
, Expose
, &dummy
))
738 /***********************************************************************/