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", VER_STR
);
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 /***********************************************************************
197 * Parses the file 'configfile' for command to execute.
198 ***********************************************************************/
202 char Buf
[BUFFER_SIZE
];
205 if ((fp
= fopen(Config
.configfile
, "r")) == NULL
)
206 if ((fp
= fopen(CONFIGGLOBAL
, "r")) == NULL
)
207 err_mess(FAILCONF
,Config
.configfile
);
209 while ((Ptr
= fgets(Buf
, BUFFER_SIZE
, fp
))) {
210 if (atoi(Buf
) == app
)
219 Ptr
= strchr(Buf
, '\t'); /* find first tab */
221 Ptr
= strchr(Buf
, ' '); /* or space charater */
231 /**********************************************************************/
233 /***********************************************************************
236 * Copyright (c) 2001 Bruno Essmann <essmann@users.sourceforge.net>
237 ***********************************************************************/
241 extern struct Config_t Config
;
244 fprintf(stdout
, "[ ] initializing time\n");
246 gettimeofday(&_tStart
, NULL
);
248 /**********************************************************************/
250 long currentTimeMillis(void)
252 struct timeval tNow
, tElapsed
;
254 gettimeofday(&tNow
, NULL
);
256 if (_tStart
.tv_usec
> tNow
.tv_usec
) {
257 tNow
.tv_usec
+= 1000000;
261 tElapsed
.tv_sec
= tNow
.tv_sec
- _tStart
.tv_sec
;
262 tElapsed
.tv_usec
= tNow
.tv_usec
- _tStart
.tv_usec
;
263 return (tElapsed
.tv_sec
* 1000) + (tElapsed
.tv_usec
/ 1000);
265 /**********************************************************************/
267 void getWindowOrigin(Window w
, int *nX
, int *nY
)
269 extern Display
*display
;
270 Window wWindow
, wParent
, wRoot
;
272 unsigned int nChildren
, ww
, wh
, wb
, wd
;
278 if (!XQueryTree(display
, wParent
, &wRoot
, &wParent
, &wChildren
, &nChildren
))
284 } while (wParent
!= wRoot
);
286 if (XGetGeometry(display
, wWindow
, &wRoot
, &wx
, &wy
, &ww
, &wh
, &wb
, &wd
)) {
294 /**********************************************************************/
296 /***********************************************************************
299 * compute location for each button's tooltip (not perfect)
300 ***********************************************************************/
301 void getButtonLocation (int nButton
, int *nLocationX
, int *nLocationY
)
306 while (nButton
> BUTTON_COLS
) {
307 *nLocationY
+= BUTTON_SIZE
;
308 nButton
-= BUTTON_COLS
;
311 while (nButton
> 0) {
312 *nLocationX
+= BUTTON_SIZE
- 1;
316 /**********************************************************************/
318 /* SkipWord & SkipSpaces: utility functions for getNicenedString */
319 char *SkipWord(char *Text
) {
322 while ((*Result
!= ' ') && (*Result
!= '\t') &&
323 (*Result
!= '\n') && (*Result
!= 0x00))
329 char *SkipSpaces(char *Text
) {
332 while ((*Result
== ' ') || (*Result
== '\t') || (*Result
== '\n'))
338 /***********************************************************************
341 * nicen the parsed command from the .wmbutton config file
343 * - remove parameters, whitespace and the '&'...
344 ***********************************************************************/
345 char *getNicenedString(char *old
, int andAddSeparator
)
347 char *WorkStr
, *WorkStrEnd
, *StartPtr
, *EndPtr
, *RetStr
;
351 return strdup("-- | ");
356 RetStr
= malloc(strlen(old
) + 3 + 1); /* 3 for Seperator */
359 WorkStr
= strdup(old
);
360 WorkStrEnd
= strchr(WorkStr
, 0x00);
363 while (StartPtr
< WorkStrEnd
) {
364 StartPtr
= SkipSpaces(StartPtr
);
365 EndPtr
= SkipWord(StartPtr
);
368 if ((*StartPtr
== '&') || (*StartPtr
== '-'))
371 strcat(RetStr
, StartPtr
);
373 StartPtr
= EndPtr
+ 1;
379 strcat(RetStr
, "| ");
384 /***********************************************************************
387 *returns the 1..3 application names / commands to be shown in tooltip
388 ***********************************************************************/
389 char *getButtonAppNames(int nButton
)
391 char *tmp1
, *tmp2
, *str
= NULL
;
393 if (!( nButton
< 0 || nButton
> 9 )) {
395 /* FIXME: _Might_ overflow, but it's unlikely.
396 * Perhaps one should fix this sometime ;) */
397 str
= (char*) calloc (sizeof(char), BUFFER_SIZE
);
399 tmp1
= Parse(nButton
+ LMASK
);
400 tmp2
= getNicenedString(tmp1
, 1);
405 tmp1
= Parse(nButton
+ MMASK
);
406 tmp2
= getNicenedString(tmp1
, 1);
411 tmp1
= Parse(nButton
+ RMASK
);
412 tmp2
= getNicenedString(tmp1
, 0);
420 /**********************************************************************/
423 int hasTooltipSupport(void)
425 return !Config
.bTooltipDisable
;
427 /**********************************************************************/
429 void showTooltip (int nButton
, int nMouseX
, int nMouseY
)
432 int nMainWinX
, nMainWinY
;
433 int nButtonX
= 0, nButtonY
= 0, nButtonWidth
= 0, nButtonHeight
= 0;
434 int nTextY
, nX
, nY
, nWidth
, nHeight
, nSide
;
436 extern struct Config_t Config
;
437 extern Window iconwin
;
438 extern Pixel bg_pixel
, fg_pixel
;
439 extern Display
*display
;
442 if (Config
.bTooltipDisable
|| nButton
== -1)
450 "[%8ld] showing tooltip for button %d at %d, %d\n",
451 currentTimeMillis(), nButton
, nMouseX
, nMouseY
);
453 szText
= getButtonAppNames(nButton
);
459 nWidth
= XTextWidth(_fTooltip
, szText
, strlen(szText
)) + 16;
460 nHeight
= _nFontHeight
+ 4;
464 if (nWidth
< nHeight
)
468 fprintf(stdout
, "[%8ld] tooltip size: %d, %d\n",
469 currentTimeMillis(), nWidth
, nHeight
);
471 getWindowOrigin(iconwin
, &nMainWinX
, &nMainWinY
);
472 getButtonLocation(nButton
, &nButtonX
, &nButtonY
);
473 nButtonX
+= nMainWinX
;
474 nButtonY
+= nMainWinY
;
475 nButtonWidth
= BUTTON_SIZE
;
476 nButtonHeight
= BUTTON_SIZE
;
478 if (nButtonX
+ nWidth
> _nScreenWidth
) {
479 nSide
= TOOLTIP_RIGHT
;
480 nX
= nButtonX
- nWidth
+ nButtonWidth
/ 2;
484 nSide
= TOOLTIP_LEFT
;
485 nX
= nButtonX
+ nButtonWidth
/ 2;
488 if (nX
+ nWidth
> _nScreenWidth
)
489 nX
= _nScreenWidth
- nWidth
;
491 if (nButtonY
- (nHeight
+ TOOLTIP_SPACE
) < 0) {
492 nSide
|= TOOLTIP_TOP
;
493 nY
= nButtonY
+ nButtonHeight
- 1;
494 nTextY
= TOOLTIP_SPACE
;
496 nSide
|= TOOLTIP_BOTTOM
;
497 nY
= nButtonY
- (nHeight
+ TOOLTIP_SPACE
);
501 pixmap
= createTooltipPixmap(nWidth
, nHeight
, nSide
, &mask
);
503 XSetForeground(display
, gc
, Config
.bTooltipSwapColors
? fg_pixel
: bg_pixel
);
504 XSetFont(display
, gc
, _fTooltip
->fid
);
505 XDrawString(display
, pixmap
, gc
,
506 8, nTextY
+ (nHeight
- _nFontHeight
) / 2 + _nFontY
,
507 szText
, strlen(szText
));
509 XSetWindowBackgroundPixmap(display
, _wTooltip
, pixmap
);
511 XResizeWindow(display
, _wTooltip
, nWidth
, nHeight
+ TOOLTIP_SPACE
);
512 XShapeCombineMask(display
, _wTooltip
, ShapeBounding
, 0, 0, mask
, ShapeSet
);
513 XFreePixmap(display
, mask
);
514 XMoveWindow(display
, _wTooltip
, nX
, nY
);
515 XMapRaised(display
, _wTooltip
);
516 XFreePixmap(display
, pixmap
);
520 /**********************************************************************/
522 void hideTooltip(void)
524 extern struct Config_t Config
;
525 extern Display
*display
;
527 if (Config
.bTooltipDisable
)
532 fprintf(stdout
, "[%8ld] hiding tooltip\n", currentTimeMillis());
534 XUnmapWindow(display
, _wTooltip
);
538 /**********************************************************************/
542 if (Config
.bTooltipDisable
)
547 /**********************************************************************/
549 void initTooltip(void)
551 XSetWindowAttributes attribs
;
553 extern Display
*display
;
554 extern char *app_name
;
556 extern Window rootwin
, win
;
558 if (Config
.bTooltipDisable
) {
560 fprintf(stdout
, "[%8ld] initializing tooltips (disabled)\n",
561 currentTimeMillis());
566 fprintf(stdout
, "[%8ld] initializing tooltips\n", currentTimeMillis());
568 _fTooltip
= XLoadQueryFont(display
, Config
.szTooltipFont
);
570 fprintf(stderr
, "%s: couldn't allocate font '%s'.\n", app_name
, Config
.szTooltipFont
);
571 if (!strcmp(Config
.szTooltipFont
, TOOLTIP_FONT
))
572 fprintf(stderr
, "%s: Use option -F <font>\n", app_name
);
576 _nFontHeight
= _fTooltip
->ascent
+ _fTooltip
->descent
;
577 _nFontY
= _fTooltip
->ascent
;
578 _nScreenWidth
= WidthOfScreen(ScreenOfDisplay(display
, screen
));
579 _nScreenHeight
= HeightOfScreen(ScreenOfDisplay(display
, screen
));
581 fprintf(stdout
, "[%8ld] configuring tooltip font:\n" \
583 "[%8ld] - font-height= %d, font-ascent= %d\n" \
584 "[%8ld] configuring screen size: %dx%d\n",
586 currentTimeMillis(), Config
.szTooltipFont
,
587 currentTimeMillis(), _nFontHeight
, _nFontY
,
588 currentTimeMillis(), _nScreenWidth
, _nScreenHeight
);
590 vmask
= CWSaveUnder
| CWOverrideRedirect
| CWBorderPixel
;
591 attribs
.save_under
= True
;
592 attribs
.override_redirect
= True
;
593 attribs
.border_pixel
= 0;
594 _wTooltip
= XCreateWindow(display
, rootwin
, 1, 1, 10, 10, 1,
595 CopyFromParent
, CopyFromParent
,
596 CopyFromParent
, vmask
, &attribs
);
599 fprintf(stderr
, "Cannot create tooltip window.\n");
603 /**********************************************************************/
605 void destroyTooltip(void)
607 extern Display
*display
;
609 if (Config
.bTooltipDisable
)
613 XFreeGC(display
, _gcMono
);
617 XDestroyWindow(display
, _wTooltip
);
619 /**********************************************************************/
621 void drawTooltipBalloon(Pixmap pix
, GC gc
, int x
, int y
, int w
, int h
, int side
)
623 extern Display
*display
;
624 int rad
= h
* 3 / 10;
627 XFillArc(display
, pix
, gc
, x
, y
, rad
, rad
, 90 * 64, 90 * 64);
628 XFillArc(display
, pix
, gc
, x
, y
+ h
- 1 - rad
, rad
, rad
, 180 * 64, 90 * 64);
630 XFillArc(display
, pix
, gc
, x
+ w
- 1 - rad
, y
, rad
, rad
, 0 * 64, 90 * 64);
631 XFillArc(display
, pix
, gc
, x
+ w
- 1 - rad
, y
+ h
- 1 - rad
, rad
, rad
, 270 * 64, 90 * 64);
633 XFillRectangle(display
, pix
, gc
, x
, y
+ rad
/ 2, w
, h
- rad
);
634 XFillRectangle(display
, pix
, gc
, x
+ rad
/ 2, y
, w
- rad
, h
);
636 if (side
& TOOLTIP_BOTTOM
) {
638 pt
[1].y
= y
+ h
- 1 + TOOLTIP_SPACE
;
642 pt
[1].y
= y
-TOOLTIP_SPACE
;
646 if (side
& TOOLTIP_RIGHT
) {
647 pt
[0].x
= x
+ w
- h
+ 2 * h
/ 16;
648 pt
[1].x
= x
+ w
- h
+ 11 * h
/ 16;
649 pt
[2].x
= x
+ w
- h
+ 7 * h
/ 16;
651 pt
[0].x
= x
+ h
- 2 * h
/16;
652 pt
[1].x
= x
+ h
- 11 * h
/16;
653 pt
[2].x
= x
+ h
- 7 * h
/16;
656 XFillPolygon(display
, pix
, gc
, pt
, 3, Convex
, CoordModeOrigin
);
658 /**********************************************************************/
660 Pixmap
createTooltipPixmap(int width
, int height
, int side
, Pixmap
*mask
)
662 extern Display
*display
;
664 extern Pixel bg_pixel
, fg_pixel
;
666 extern Window rootwin
;
667 Pixmap bitmap
, pixmap
;
670 bitmap
= XCreatePixmap(display
, rootwin
,
671 width
+TOOLTIP_SPACE
, height
+TOOLTIP_SPACE
, 1);
674 _gcMono
= XCreateGC(display
, bitmap
, 0, NULL
);
676 XSetForeground(display
, _gcMono
, 0);
677 XFillRectangle(display
, bitmap
, _gcMono
, 0, 0,
678 width
+TOOLTIP_SPACE
, height
+TOOLTIP_SPACE
);
680 pixmap
= XCreatePixmap(display
, rootwin
, width
+TOOLTIP_SPACE
,
681 height
+TOOLTIP_SPACE
, depth
);
682 XSetForeground(display
, gc
, Config
.bTooltipSwapColors
? fg_pixel
: bg_pixel
);
683 XFillRectangle(display
, pixmap
, gc
, 0, 0, width
+TOOLTIP_SPACE
,
684 height
+TOOLTIP_SPACE
);
686 if (side
& TOOLTIP_BOTTOM
)
693 XSetForeground(display
, _gcMono
, 1);
694 drawTooltipBalloon(bitmap
, _gcMono
, x
, y
, width
, height
, side
);
695 XSetForeground(display
, gc
, Config
.bTooltipSwapColors
? bg_pixel
: fg_pixel
);
696 drawTooltipBalloon(pixmap
, gc
, x
+1, y
+1, width
-2, height
-2, side
);
702 /***********************************************************************/
705 /***********************************************************************
708 * Everyone else has one of these... Can't hurt to throw it in.
709 ***********************************************************************/
710 int flush_expose(Window w
)
712 extern Display
*display
;
716 while (XCheckTypedWindowEvent(display
, w
, Expose
, &dummy
))
721 /***********************************************************************/