wmail: added command-line option to specify a different config-file.
[dockapps.git] / wmbutton / wmb_libs.c
blobedfbd2699c5a3e5f40de1b83f5ab4113288530ea
1 /* wmb_libs.c - Edward H. Flora - ehf_dockapps@cox.net */
2 /* Last Modified: 4/3/04 */
3 /*
4 * These functions are designed to work with wmbutton.
5 */
7 /* PORTABILITY:
8 ******************
9 * Coded in ANSI C, using ANSI prototypes.
12 /****** Include Files *************************************************/
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include "wmbutton.h"
18 /****** ToolTip Globals ***********************************************/
20 static struct timeval _tStart;
22 extern struct Config_t Config;
23 int _bTooltip = 0;
24 XFontStruct* _fTooltip;
25 int _nFontHeight, _nFontY;
26 int _nScreenWidth, _nScreenHeight;
27 GC _gcMono = 0;
28 Window _wTooltip;
30 /****** Parse Command Line ********************************************/
31 void parseargs(int argc, char **argv)
33 int current;
34 char *Home = getenv("HOME");
36 while (-1 != (current = getopt(argc, argv, "vhnmsF:b:g:d:f:"))) {
37 switch (current) {
38 case 'v':
39 Config.Verbose = 1;
40 break;
41 case '?':
42 case 'h':
43 show_usage();
44 break;
45 case 'm':
46 Config.mmouse = 1;
47 break;
48 case 'n':
49 Config.bTooltipDisable = 1;
50 break;
51 case 's':
52 Config.bTooltipSwapColors = 1;
53 break;
54 case 'g':
55 Config.Geometry_str = strdup(optarg);
56 break;
57 case 'd':
58 Config.Display_str = strdup(optarg);
59 break;
60 case 'f':
61 Config.configfile = strdup(optarg);
62 break;
63 case 'F':
64 Config.szTooltipFont = strdup(optarg);
65 break;
66 case 'b':
67 Config.buttonfile = strdup(optarg);
68 break;
72 if (!Config.configfile) {
73 if (Home != NULL) {
74 Config.configfile = malloc(strlen(Home) +
75 strlen(CONFFILENAME) + 1);
76 sprintf(Config.configfile, "%s%s", Home, CONFFILENAME);
80 if (!Config.buttonfile) {
81 if (Home != NULL) {
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");
124 exit(0);
126 /***********************************************************************/
128 /****** Error Handler Routine *****************************************/
129 void err_mess(int err, char *str)
131 switch (err) {
132 case FAILDISP:
133 fprintf(stderr, "Fail: XOpenDisplay for %s\n", str);
134 exit(err);
135 case FAILSWIN:
136 fprintf(stderr, "Fail: XCreateSimpleWindow\n");
137 exit(err);
138 case FAILICON:
139 fprintf(stderr, "Fail: XCreateSimpleWindow\n");
140 exit(err);
141 case FAILXPM:
142 fprintf(stderr, "Fail: XCreateBitmapFromData\n");
143 break;
144 case FAILWNAM:
145 fprintf(stderr, "%s: Can't set up window name\n", str);
146 exit(err);
147 case FAILGC:
148 fprintf(stderr, "Fail: XCreateGC\n");
149 exit(err);
150 case FAILCONF:
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);
154 exit(err);
155 case FAILTMPL:
156 fprintf(stderr, "Fail: Can't Create 'template' Pixmap\n");
157 exit(err);
158 case FAILVIS:
159 fprintf(stderr, "Fail: Can't Create 'visible' Pixmap\n");
160 exit(err);
161 case FAILBUT:
162 fprintf(stderr, "Fail: Can't Create 'buttons' Pixmap\n");
163 exit(err);
164 default:
165 fprintf(stderr, "Fail: UnSpecified Error: %d\n", err);
166 fprintf(stderr, "Fail: %s\n", str);
167 exit(err);
170 /***********************************************************************/
172 /***********************************************************************
173 * RunAppN(int app)
175 * Run the command given in the configuration file 'configfile'
176 ***********************************************************************/
177 void RunAppN(int app)
179 char *cmndstr;
180 extern struct Config_t Config;
182 cmndstr = Parse(app); /* Get command to pass to system */
184 if (Config.Verbose)
185 fprintf(stderr, "Command String: %s", cmndstr);
187 if (cmndstr != NULL) {
188 system(cmndstr); /* if there's a command, run it */
189 free(cmndstr);
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)
201 FILE *fp;
203 if ((fp = fopen(path, "r")) == NULL)
204 return 0;
205 else {
206 fclose(fp);
207 return 1;
211 /***********************************************************************
212 * Parse(int app)
214 * Parses the file 'configfile' for command to execute.
215 ***********************************************************************/
216 char *Parse(int app)
218 FILE *fp;
219 char Buf[BUFFER_SIZE];
220 char *Ptr;
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)
228 break;
231 fclose(fp);
233 if (!Ptr)
234 return Ptr;
236 Ptr = strchr(Buf, '\t'); /* find first tab */
237 if (Ptr == NULL)
238 Ptr = strchr(Buf, ' '); /* or space charater */
240 if (Ptr == NULL)
241 return(NULL);
243 Ptr++;
244 Ptr = strdup(Ptr);
246 return Ptr;
248 /**********************************************************************/
250 /***********************************************************************
251 * initTime
253 * Copyright (c) 2001 Bruno Essmann <essmann@users.sourceforge.net>
254 ***********************************************************************/
256 void initTime(void)
258 extern struct Config_t Config;
260 if (Config.Verbose)
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;
275 tNow.tv_sec--;
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;
288 Window* wChildren;
289 unsigned int nChildren, ww, wh, wb, wd;
290 int wx, wy;
292 wParent = w;
293 do {
294 wWindow = wParent;
295 if (!XQueryTree(display, wParent, &wRoot, &wParent, &wChildren, &nChildren))
296 return;
298 if (wChildren)
299 XFree(wChildren);
301 } while (wParent != wRoot);
303 if (XGetGeometry(display, wWindow, &wRoot, &wx, &wy, &ww, &wh, &wb, &wd)) {
304 if (nX)
305 *nX = wx;
307 if (nY)
308 *nY = wy;
311 /**********************************************************************/
313 /***********************************************************************
314 * getButtonLocation
316 * compute location for each button's tooltip (not perfect)
317 ***********************************************************************/
318 void getButtonLocation (int nButton, int *nLocationX, int *nLocationY)
320 *nLocationX = 0;
321 *nLocationY = 8;
323 while (nButton > BUTTON_COLS) {
324 *nLocationY += BUTTON_SIZE;
325 nButton -= BUTTON_COLS;
328 while (nButton > 0) {
329 *nLocationX += BUTTON_SIZE - 1;
330 nButton--;
333 /**********************************************************************/
335 /* SkipWord & SkipSpaces: utility functions for getNicenedString */
336 char *SkipWord(char *Text) {
337 char *Result = Text;
339 while ((*Result != ' ') && (*Result != '\t') &&
340 (*Result != '\n') && (*Result != 0x00))
341 Result++;
343 return Result;
346 char *SkipSpaces(char *Text) {
347 char *Result = Text;
349 while ((*Result == ' ') || (*Result == '\t') || (*Result == '\n'))
350 Result++;
352 return Result;
355 /***********************************************************************
356 * getNicenedString
358 * nicen the parsed command from the .wmbutton config file
359 * - cut if too long
360 * - remove parameters, whitespace and the '&'...
361 ***********************************************************************/
362 char *getNicenedString(char *old, int andAddSeparator)
364 char *WorkStr, *WorkStrEnd, *StartPtr, *EndPtr, *RetStr;
366 if (!old) {
367 if (andAddSeparator)
368 return strdup("-- | ");
369 else
370 return strdup("--");
373 RetStr = malloc(strlen(old) + 3 + 1); /* 3 for Seperator */
374 *RetStr = 0x00;
376 WorkStr = strdup(old);
377 WorkStrEnd = strchr(WorkStr, 0x00);
378 StartPtr = WorkStr;
380 while (StartPtr < WorkStrEnd) {
381 StartPtr = SkipSpaces(StartPtr);
382 EndPtr = SkipWord(StartPtr);
383 *EndPtr = 0x00;
385 if ((*StartPtr == '&') || (*StartPtr == '-'))
386 break;
388 strcat(RetStr, StartPtr);
389 strcat(RetStr, " ");
390 StartPtr = EndPtr + 1;
393 free(WorkStr);
395 if (andAddSeparator)
396 strcat(RetStr, "| ");
398 return RetStr;
401 /***********************************************************************
402 * getButtonAppNames
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);
418 strcat(str, tmp2);
419 free(tmp1);
420 free(tmp2);
422 tmp1 = Parse(nButton + MMASK);
423 tmp2 = getNicenedString(tmp1, 1);
424 strcat(str, tmp2);
425 free(tmp1);
426 free(tmp2);
428 tmp1 = Parse(nButton + RMASK);
429 tmp2 = getNicenedString(tmp1, 0);
430 strcat(str, tmp2);
431 free(tmp1);
432 free(tmp2);
435 return str;
437 /**********************************************************************/
440 int hasTooltipSupport(void)
442 return !Config.bTooltipDisable;
444 /**********************************************************************/
446 void showTooltip (int nButton, int nMouseX, int nMouseY)
448 Pixmap pixmap, mask;
449 int nMainWinX, nMainWinY;
450 int nButtonX = 0, nButtonY = 0, nButtonWidth = 0, nButtonHeight = 0;
451 int nTextY, nX, nY, nWidth, nHeight, nSide;
452 char* szText;
453 extern struct Config_t Config;
454 extern Window iconwin;
455 extern Pixel bg_pixel, fg_pixel;
456 extern Display *display;
457 extern GC gc;
459 if (Config.bTooltipDisable || nButton == -1)
460 return;
462 if (_bTooltip)
463 hideTooltip();
465 if (Config.Verbose)
466 fprintf(stdout,
467 "[%8ld] showing tooltip for button %d at %d, %d\n",
468 currentTimeMillis(), nButton, nMouseX, nMouseY);
470 szText = getButtonAppNames(nButton);
471 if(!szText)
472 return;
474 _bTooltip = 1;
476 nWidth = XTextWidth(_fTooltip, szText, strlen(szText)) + 16;
477 nHeight = _nFontHeight + 4;
478 if (nHeight < 16)
479 nHeight = 16;
481 if (nWidth < nHeight)
482 nWidth = nHeight;
484 if (Config.Verbose)
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;
498 if (nX < 0)
499 nX = 0;
500 } else {
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;
512 } else {
513 nSide |= TOOLTIP_BOTTOM;
514 nY = nButtonY - (nHeight + TOOLTIP_SPACE);
515 nTextY = 0;
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);
535 free(szText);
537 /**********************************************************************/
539 void hideTooltip(void)
541 extern struct Config_t Config;
542 extern Display *display;
544 if (Config.bTooltipDisable)
545 return;
547 if (_bTooltip) {
548 if (Config.Verbose)
549 fprintf(stdout, "[%8ld] hiding tooltip\n", currentTimeMillis());
551 XUnmapWindow(display, _wTooltip);
552 _bTooltip = 0;
555 /**********************************************************************/
557 int hasTooltip(void)
559 if (Config.bTooltipDisable)
560 return 0;
562 return _bTooltip;
564 /**********************************************************************/
566 void initTooltip(void)
568 XSetWindowAttributes attribs;
569 unsigned long vmask;
570 extern Display *display;
571 extern char *app_name;
572 extern int screen;
573 extern Window rootwin, win;
575 if (Config.bTooltipDisable) {
576 if (Config.Verbose)
577 fprintf(stdout, "[%8ld] initializing tooltips (disabled)\n",
578 currentTimeMillis());
580 return;
582 if (Config.Verbose)
583 fprintf(stdout, "[%8ld] initializing tooltips\n", currentTimeMillis());
585 _fTooltip = XLoadQueryFont(display, Config.szTooltipFont);
586 if (!_fTooltip) {
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);
590 exit(-1);
593 _nFontHeight = _fTooltip->ascent + _fTooltip->descent;
594 _nFontY = _fTooltip->ascent;
595 _nScreenWidth = WidthOfScreen(ScreenOfDisplay(display, screen));
596 _nScreenHeight = HeightOfScreen(ScreenOfDisplay(display, screen));
597 if (Config.Verbose)
598 fprintf(stdout, "[%8ld] configuring tooltip font:\n" \
599 "[%8ld] - '%s'\n" \
600 "[%8ld] - font-height= %d, font-ascent= %d\n" \
601 "[%8ld] configuring screen size: %dx%d\n",
602 currentTimeMillis(),
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);
615 if (win == 0) {
616 fprintf(stderr, "Cannot create tooltip window.\n");
617 exit(-1);
620 /**********************************************************************/
622 void destroyTooltip(void)
624 extern Display *display;
626 if (Config.bTooltipDisable)
627 return;
629 if (_gcMono) {
630 XFreeGC(display, _gcMono);
631 _gcMono = 0;
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;
642 XPoint pt[3];
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) {
654 pt[0].y = y + h - 1;
655 pt[1].y = y + h - 1 + TOOLTIP_SPACE;
656 pt[2].y = y + h - 1;
657 } else {
658 pt[0].y = y;
659 pt[1].y = y-TOOLTIP_SPACE;
660 pt[2].y = y;
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;
667 } else {
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;
680 extern GC gc;
681 extern Pixel bg_pixel, fg_pixel;
682 extern int depth;
683 extern Window rootwin;
684 Pixmap bitmap, pixmap;
685 int x, y;
687 bitmap = XCreatePixmap(display, rootwin,
688 width+TOOLTIP_SPACE, height+TOOLTIP_SPACE, 1);
690 if (!_gcMono)
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)
704 y = 0;
705 else
706 y = TOOLTIP_SPACE;
708 x = 0;
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);
715 *mask = bitmap;
717 return pixmap;
719 /***********************************************************************/
722 /***********************************************************************
723 * flush_expose
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;
730 XEvent dummy;
731 int i = 0;
733 while (XCheckTypedWindowEvent(display, w, Expose, &dummy))
734 i++;
736 return i;
738 /***********************************************************************/