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 *************************************************/
19 /****** ToolTip Globals ***********************************************/
21 static struct timeval _tStart
;
23 extern struct Config_t Config
;
25 XFontStruct
* _fTooltip
;
26 int _nFontHeight
, _nFontY
;
27 int _nScreenWidth
, _nScreenHeight
;
31 /****** Parse Command Line ********************************************/
32 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(
75 strlen(Home
) + strlen(CONFFILENAME
) + 1);
76 sprintf(Config
.configfile
, "%s%s", Home
, CONFFILENAME
);
80 if (!Config
.buttonfile
) {
82 Config
.buttonfile
= malloc(
83 strlen(Home
) + 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 ****************************************/
104 extern char *app_name
;
106 fprintf(stderr
,"\n");
107 fprintf(stderr
,"usage: %s [-g geom] [-d dpy] [-f cfgfile] [-b btnfile] "\
108 "[-F <font>] [-v] [-s] [-n]\n",app_name
);
109 fprintf(stderr
,"\n");
110 fprintf(stderr
," wmbutton version %s\n", VER_STR
);
111 fprintf(stderr
,"\n");
112 fprintf(stderr
,"-g <geometry> Window Geometry - ie: 64x64+10+10\n");
113 fprintf(stderr
,"-d <display> Display - ie: 127.0.0.1:0.0\n");
114 fprintf(stderr
,"-f <filename> Full path to configuration file.\n");
115 fprintf(stderr
,"-b <filename> Full path to button xpm.\n");
116 fprintf(stderr
,"-F <font> Custom tooltip font (e.g. -b\\&h-lucidatypewriter-medium-*-*-*-12-*)\n");
117 fprintf(stderr
,"-v Verbose Mode.\n");
118 fprintf(stderr
,"-h Help. This message.\n");
119 fprintf(stderr
,"-m Disable Middle Mouse functionality.\n");
120 fprintf(stderr
,"-s Swap tooltip colors.\n");
121 fprintf(stderr
,"-n Turn off tooltips.\n");
122 fprintf(stderr
,"\n");
124 }/***********************************************************************/
127 /****** Error Handler Routine *****************************************/
128 void err_mess(int err
, char *str
) {
132 fprintf(stderr
,"Fail: XOpenDisplay for %s\n", str
);
135 fprintf(stderr
,"Fail: XCreateSimpleWindow\n");
138 fprintf(stderr
,"Fail: XCreateSimpleWindow\n");
141 fprintf(stderr
,"Fail: XCreateBitmapFromData\n");
144 fprintf(stderr
,"%s: Can't set up window name\n", str
);
147 fprintf(stderr
,"Fail: XCreateGC\n");
150 fprintf(stderr
, "Fail: Can't Find user or system configuration file.\n");
151 fprintf(stderr
, "Fail: User Config: '%s'\n", str
);
152 fprintf(stderr
, "Fail: System Config: '%s'\n", CONFIGGLOBAL
);
155 fprintf(stderr
, "Fail: Can't Create 'template' Pixmap\n");
158 fprintf(stderr
, "Fail: Can't Create 'visible' Pixmap\n");
161 fprintf(stderr
, "Fail: Can't Create 'buttons' Pixmap\n");
164 fprintf(stderr
, "Fail: UnSpecified Error: %d\n",err
);
165 fprintf(stderr
, "Fail: %s\n",str
);
169 }/***********************************************************************/
171 /***********************************************************************
174 * Run the command given in the configuration file 'configfile'
175 ***********************************************************************/
176 void RunAppN( int app
) {
178 extern struct Config_t Config
;
180 cmndstr
= Parse(app
); // Get command to pass to system
182 if (Config
.Verbose
) fprintf(stderr
, "Command String: %s", cmndstr
);
184 if (cmndstr
!= NULL
) {
185 system(cmndstr
); // if there's a command, run it
188 }/***********************************************************************/
190 /***********************************************************************
193 * Parses the file 'configfile' for command to execute.
194 ***********************************************************************/
195 char *Parse(int app
) {
197 char Buf
[BUFFER_SIZE
];
200 if ((fp
= fopen(Config
.configfile
, "r")) == NULL
)
201 if ((fp
= fopen(CONFIGGLOBAL
, "r")) == NULL
)
202 err_mess(FAILCONF
,Config
.configfile
);
204 while ((Ptr
= fgets(Buf
, BUFFER_SIZE
, fp
))) {
205 if (atoi(Buf
) == app
)
214 Ptr
= strchr(Buf
, '\t'); // find first tab
215 if (Ptr
== NULL
) Ptr
= strchr(Buf
, ' '); // or space charater
216 if (Ptr
== NULL
) return(NULL
);
222 }/**********************************************************************/
224 /***********************************************************************
227 * Copyright (c) 2001 Bruno Essmann <essmann@users.sourceforge.net>
228 ***********************************************************************/
231 extern struct Config_t Config
;
233 if (Config
.Verbose
) {
234 fprintf(stdout
, "[ ] initializing time\n");
237 gettimeofday(&_tStart
, NULL
);
238 }/**********************************************************************/
240 long currentTimeMillis () {
242 struct timeval tElapsed
;
244 gettimeofday(&tNow
, NULL
);
246 if (_tStart
.tv_usec
> tNow
.tv_usec
) {
247 tNow
.tv_usec
+= 1000000;
250 tElapsed
.tv_sec
= tNow
.tv_sec
- _tStart
.tv_sec
;
251 tElapsed
.tv_usec
= tNow
.tv_usec
- _tStart
.tv_usec
;
252 return (tElapsed
.tv_sec
* 1000) + (tElapsed
.tv_usec
/ 1000);
253 }/**********************************************************************/
256 void getWindowOrigin (Window w
, int* nX
, int* nY
) {
257 extern Display
*display
;
258 Window wWindow
, wParent
, wRoot
;
260 unsigned int nChildren
;
261 unsigned int ww
, wh
, wb
, wd
;
267 if (!XQueryTree(display
, wParent
, &wRoot
, &wParent
, &wChildren
, &nChildren
))
273 } while (wParent
!= wRoot
);
275 if (XGetGeometry(display
, wWindow
, &wRoot
, &wx
, &wy
, &ww
, &wh
, &wb
, &wd
)) {
283 }/**********************************************************************/
285 /***********************************************************************
288 * compute location for each button's tooltip (not perfect)
289 ***********************************************************************/
290 void getButtonLocation (int nButton
, int* nLocationX
, int* nLocationY
) {
293 while (nButton
> BUTTON_COLS
) {
294 *nLocationY
+= BUTTON_SIZE
;
295 nButton
-= BUTTON_COLS
;
297 while (nButton
> 0) {
298 *nLocationX
+= BUTTON_SIZE
- 1;
301 }/**********************************************************************/
303 /* SkipWord & SkipSpaces: utility functions for getNicenedString */
304 char *SkipWord(char *Text
) {
307 while ((*Result
!= ' ')&&(*Result
!= '\t')&&
308 (*Result
!= '\n')&&(*Result
!= 0x00))
313 char *SkipSpaces(char *Text
) {
316 while ((*Result
== ' ')||(*Result
== '\t')||(*Result
== '\n'))
321 /***********************************************************************
324 * nicen the parsed command from the .wmbutton config file
326 * - remove parameters, whitespace and the '&'...
327 ***********************************************************************/
328 char* getNicenedString (char *old
, int andAddSeparator
) {
338 return strdup("-- | ");
343 RetStr
= malloc(strlen(old
) + 3 + 1); // 3 for Seperator
346 WorkStr
= strdup(old
);
347 WorkStrEnd
= strchr(WorkStr
, 0x00);
350 while(StartPtr
< WorkStrEnd
) {
351 StartPtr
= SkipSpaces(StartPtr
);
352 EndPtr
= SkipWord(StartPtr
);
355 if ((*StartPtr
== '&')||(*StartPtr
== '-'))
358 strcat(RetStr
, StartPtr
);
365 if (andAddSeparator
) {
366 strcat(RetStr
, "| ");
372 /***********************************************************************
375 * returns the 1..3 application names / commands to be shown in tooltip
376 ***********************************************************************/
377 char* getButtonAppNames (int nButton
) {
381 if (!( nButton
< 0 || nButton
> 9 )) {
383 // FIXME: _Might_ overflow, but it's unlikely.
384 // Perhaps one should fix this sometime ;)
385 str
= (char*) calloc (sizeof(char), BUFFER_SIZE
);
387 tmp1
= Parse(nButton
+ LMASK
);
388 tmp2
= getNicenedString(tmp1
, 1);
393 tmp1
= Parse(nButton
+ MMASK
);
394 tmp2
= getNicenedString(tmp1
, 1);
399 tmp1
= Parse(nButton
+ RMASK
);
400 tmp2
= getNicenedString(tmp1
, 0);
407 }/**********************************************************************/
410 int hasTooltipSupport () {
411 return !Config
.bTooltipDisable
;
412 }/**********************************************************************/
414 void showTooltip (int nButton
, int nMouseX
, int nMouseY
) {
416 int nMainWinX
, nMainWinY
;
417 int nButtonX
= 0, nButtonY
= 0, nButtonWidth
= 0, nButtonHeight
= 0;
418 int nTextY
, nX
, nY
, nWidth
, nHeight
, nSide
;
420 extern struct Config_t Config
;
421 extern Window iconwin
;
422 extern Pixel bg_pixel
, fg_pixel
;
423 extern Display
*display
;
426 if (Config
.bTooltipDisable
|| nButton
== -1) {
434 if (Config
.Verbose
) {
435 fprintf(stdout
, "[%8ld] showing tooltip for button %d at %d, %d\n",
437 nButton
, nMouseX
, nMouseY
);
440 szText
= getButtonAppNames(nButton
);
446 nWidth
= XTextWidth(_fTooltip
, szText
, strlen(szText
)) + 16;
447 nHeight
= _nFontHeight
+ 4;
451 if (nWidth
< nHeight
) {
454 if (Config
.Verbose
) {
455 fprintf(stdout
, "[%8ld] tooltip size: %d, %d\n",
456 currentTimeMillis(), nWidth
, nHeight
);
459 getWindowOrigin(iconwin
, &nMainWinX
, &nMainWinY
);
460 getButtonLocation(nButton
, &nButtonX
, &nButtonY
);
461 nButtonX
+= nMainWinX
;
462 nButtonY
+= nMainWinY
;
463 nButtonWidth
= BUTTON_SIZE
;
464 nButtonHeight
= BUTTON_SIZE
;
466 if (nButtonX
+ nWidth
> _nScreenWidth
) {
467 nSide
= TOOLTIP_RIGHT
;
468 nX
= nButtonX
- nWidth
+ nButtonWidth
/ 2;
474 nX
= nButtonX
+ nButtonWidth
/ 2;
476 if (nX
+ nWidth
> _nScreenWidth
) {
477 nX
= _nScreenWidth
- nWidth
;
480 if (nButtonY
- (nHeight
+ TOOLTIP_SPACE
) < 0) {
482 nY
= nButtonY
+ nButtonHeight
- 1;
483 nTextY
= TOOLTIP_SPACE
;
485 nSide
|= TOOLTIP_BOTTOM
;
486 nY
= nButtonY
- (nHeight
+ TOOLTIP_SPACE
);
490 pixmap
= createTooltipPixmap(nWidth
, nHeight
, nSide
, &mask
);
492 XSetForeground(display
, gc
, Config
.bTooltipSwapColors
? fg_pixel
: bg_pixel
);
493 XSetFont(display
, gc
, _fTooltip
->fid
);
494 XDrawString(display
, pixmap
, gc
,
495 8, nTextY
+ (nHeight
- _nFontHeight
) / 2 + _nFontY
,
496 szText
, strlen(szText
));
498 XSetWindowBackgroundPixmap(display
, _wTooltip
, pixmap
);
500 XResizeWindow(display
, _wTooltip
, nWidth
, nHeight
+ TOOLTIP_SPACE
);
501 XShapeCombineMask(display
, _wTooltip
, ShapeBounding
, 0, 0, mask
, ShapeSet
);
502 XFreePixmap(display
, mask
);
503 XMoveWindow(display
, _wTooltip
, nX
, nY
);
504 XMapRaised(display
, _wTooltip
);
505 XFreePixmap(display
, pixmap
);
508 }/**********************************************************************/
510 void hideTooltip () {
511 extern struct Config_t Config
;
512 extern Display
*display
;
514 if (Config
.bTooltipDisable
) {
518 if (Config
.Verbose
) {
519 fprintf(stdout
, "[%8ld] hiding tooltip\n", currentTimeMillis());
521 XUnmapWindow(display
, _wTooltip
);
524 }/**********************************************************************/
527 if (Config
.bTooltipDisable
) {
531 }/**********************************************************************/
533 void initTooltip () {
534 XSetWindowAttributes attribs
;
536 extern Display
*display
;
537 extern char *app_name
;
539 extern Window rootwin
, win
;
541 if (Config
.bTooltipDisable
) {
542 if (Config
.Verbose
) {
543 fprintf(stdout
, "[%8ld] initializing tooltips (disabled)\n",
544 currentTimeMillis());
549 if (Config
.Verbose
) {
550 fprintf(stdout
, "[%8ld] initializing tooltips\n", currentTimeMillis());
552 _fTooltip
= XLoadQueryFont(display
, Config
.szTooltipFont
);
554 fprintf(stderr
, "%s: couldn't allocate font '%s'.\n", app_name
, Config
.szTooltipFont
);
555 if (!strcmp(Config
.szTooltipFont
, TOOLTIP_FONT
))
556 fprintf(stderr
, "%s: Use option -F <font>\n", app_name
);
559 _nFontHeight
= _fTooltip
->ascent
+ _fTooltip
->descent
;
560 _nFontY
= _fTooltip
->ascent
;
561 _nScreenWidth
= WidthOfScreen(ScreenOfDisplay(display
, screen
));
562 _nScreenHeight
= HeightOfScreen(ScreenOfDisplay(display
, screen
));
563 if (Config
.Verbose
) {
564 fprintf(stdout
, "[%8ld] configuring tooltip font:\n" \
566 "[%8ld] - font-height= %d, font-ascent= %d\n" \
567 "[%8ld] configuring screen size: %dx%d\n",
569 currentTimeMillis(), Config
.szTooltipFont
,
570 currentTimeMillis(), _nFontHeight
, _nFontY
,
571 currentTimeMillis(), _nScreenWidth
, _nScreenHeight
);
574 vmask
= CWSaveUnder
| CWOverrideRedirect
| CWBorderPixel
;
575 attribs
.save_under
= True
;
576 attribs
.override_redirect
= True
;
577 attribs
.border_pixel
= 0;
578 _wTooltip
= XCreateWindow(display
, rootwin
, 1, 1, 10, 10, 1,
579 CopyFromParent
, CopyFromParent
,
580 CopyFromParent
, vmask
, &attribs
);
582 fprintf(stderr
, "Cannot create tooltip window.\n");
585 }/**********************************************************************/
587 void destroyTooltip () {
588 extern Display
*display
;
590 if (Config
.bTooltipDisable
) {
594 XFreeGC(display
, _gcMono
);
597 XDestroyWindow(display
, _wTooltip
);
598 }/**********************************************************************/
600 void drawTooltipBalloon (Pixmap pix
, GC gc
, int x
, int y
, int w
, int h
, int side
) {
601 extern Display
*display
;
605 XFillArc(display
, pix
, gc
, x
, y
, rad
, rad
, 90*64, 90*64);
606 XFillArc(display
, pix
, gc
, x
, y
+h
-1-rad
, rad
, rad
, 180*64, 90*64);
608 XFillArc(display
, pix
, gc
, x
+w
-1-rad
, y
, rad
, rad
, 0*64, 90*64);
609 XFillArc(display
, pix
, gc
, x
+w
-1-rad
, y
+h
-1-rad
, rad
, rad
, 270*64, 90*64);
611 XFillRectangle(display
, pix
, gc
, x
, y
+rad
/2, w
, h
-rad
);
612 XFillRectangle(display
, pix
, gc
, x
+rad
/2, y
, w
-rad
, h
);
614 if (side
& TOOLTIP_BOTTOM
) {
616 pt
[1].y
= y
+h
-1+TOOLTIP_SPACE
;
620 pt
[1].y
= y
-TOOLTIP_SPACE
;
623 if (side
& TOOLTIP_RIGHT
) {
624 pt
[0].x
= x
+w
-h
+2*h
/16;
625 pt
[1].x
= x
+w
-h
+11*h
/16;
626 pt
[2].x
= x
+w
-h
+7*h
/16;
628 pt
[0].x
= x
+h
-2*h
/16;
629 pt
[1].x
= x
+h
-11*h
/16;
630 pt
[2].x
= x
+h
-7*h
/16;
632 XFillPolygon(display
, pix
, gc
, pt
, 3, Convex
, CoordModeOrigin
);
633 }/**********************************************************************/
635 Pixmap
createTooltipPixmap (int width
, int height
, int side
, Pixmap
*mask
) {
636 extern Display
*display
;
638 extern Pixel bg_pixel
, fg_pixel
;
640 extern Window rootwin
;
645 bitmap
= XCreatePixmap(display
, rootwin
,
646 width
+TOOLTIP_SPACE
, height
+TOOLTIP_SPACE
, 1);
649 _gcMono
= XCreateGC(display
, bitmap
, 0, NULL
);
651 XSetForeground(display
, _gcMono
, 0);
652 XFillRectangle(display
, bitmap
, _gcMono
, 0, 0,
653 width
+TOOLTIP_SPACE
, height
+TOOLTIP_SPACE
);
655 pixmap
= XCreatePixmap(display
, rootwin
,
656 width
+TOOLTIP_SPACE
, height
+TOOLTIP_SPACE
, depth
);
657 XSetForeground(display
, gc
, Config
.bTooltipSwapColors
? fg_pixel
: bg_pixel
);
658 XFillRectangle(display
, pixmap
, gc
, 0, 0,
659 width
+TOOLTIP_SPACE
, height
+TOOLTIP_SPACE
);
661 if (side
& TOOLTIP_BOTTOM
) {
668 XSetForeground(display
, _gcMono
, 1);
669 drawTooltipBalloon(bitmap
, _gcMono
, x
, y
, width
, height
, side
);
670 XSetForeground(display
, gc
, Config
.bTooltipSwapColors
? bg_pixel
: fg_pixel
);
671 drawTooltipBalloon(pixmap
, gc
, x
+1, y
+1, width
-2, height
-2, side
);
676 }/***********************************************************************/
679 /***********************************************************************
682 * Everyone else has one of these... Can't hurt to throw it in.
683 ***********************************************************************/
684 int flush_expose(Window w
) {
685 extern Display
*display
;
689 while (XCheckTypedWindowEvent(display
, w
, Expose
, &dummy
)) i
++;
691 }/***********************************************************************/