wmclockmon: handle fgets NULL returns and zero-length lines
[dockapps.git] / wmbutton / wmbutton.c
blob8e1d6780fdbe1a83b6929c392501eeb3ebeabc27
1 /***********************************************************************
2 * Code is based on wmppp, wmload, wmtime, wmcp, and asbutton
3 * Author: Edward H. Flora <ehflora@ksu.edu>
5 * Contributors:
6 * Christian 'Greek0' Aichinger <Greek0@gmx.net>
7 * Did some code cleanup and fixed several memory leaks.
8 * Ralf Horstmann <ralf.horstmann@gmx.de>
9 * Added ability to load pixmaps at startup,
10 * without having to re-compile
11 * Michael Cohrs <camico@users.sourceforge.net>
12 * Added Tool Tips, and updated graphics
13 * Bruno Essmann <essmann@users.sourceforge.net>)
14 * Creator of wmpager
15 * Casey Harkins <charkins@cs.wisc.edu>
16 * Bug fix reading config file path - 3/6/99
17 * Added button-presses, and other - denoted by *charkins*
18 * Ben Cohen <buddog@aztec.asu.edu>
19 * original author of wmcp (et al.)
20 * Thomas Nemeth <tnemeth@multimania.com>
21 * contributor to wmcp
22 * Michael Henderson <mghenderson@lanl.gov>
23 * Application ideas, suggestions
24 * Ryan ?? <pancake@mindspring.com>
25 * Modified wmbutton to asbutton.
26 * Note: asbutton is a seperate program, not associated
27 * with wmbutton (just as wmbutton is not associated
28 * with wmcp)
29 * Jon Bruno
30 * Web Page Development
31 * The contributors listed above are not necessarily involved with the
32 * development of wmbutton. I'm listing them here partially as thanks for
33 * helping out, catching bugs in the code, etc.
34 ***********************************************************************/
35 #include <stdio.h>
36 #include <math.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <unistd.h>
42 #include "wmbutton.h"
44 #include "backdrop.xpm" /* background graphic */
45 #include "buttons.xpm" /* graphic of 9 buttons */
46 #include "mask.xbm" /* Border Graphic */
48 /*************** Function Prototypes ***********************************/
49 void redraw(void);
50 void getPixmaps(void);
51 int whichButton(int x, int y); // determine which button has been pressed
52 void SetWmHints();
53 void SetClassHints();
55 /***********************************************************************
56 * Globals.. OK.. there's too many globals.
57 * Feel free and fix it, if you'd like.
58 ***********************************************************************/
59 Display *display;
60 int screen;
61 Window rootwin, win, iconwin;
62 GC gc;
63 int depth;
64 Pixel bg_pixel, fg_pixel;
66 struct Config_t Config;
68 typedef struct _XpmIcon {
69 Pixmap pixmap;
70 Pixmap mask;
71 XpmAttributes attributes;
72 } XpmIcon;
74 typedef struct _button_region {
75 int x, y;
76 int i, j;
77 } ButtonArea;
79 ButtonArea button_region[9];
81 XpmIcon template, visible, buttons;
83 int border = 0;
84 int button_pressed = -1; /* button to be drawn pressed *charkins*/
86 char *app_name = "wmbutton";
88 /***********************************************************************
89 * Main
90 ***********************************************************************/
91 int main(int argc, char **argv)
93 XEvent report;
94 XGCValues xgcValues;
95 XTextProperty app_name_atom;
96 XSizeHints xsizehints;
97 Pixmap pixmask;
99 int dummy = 0;
100 int N = 1; /* Button number pressed to goto app # */
102 /* Added for Tool Tip Support */
103 long nTooltipShowDelay = TOOLTIP_SHOW_DELAY;
104 long nTooltipReshowDelay = TOOLTIP_RESHOW_DELAY;
105 long nTooltipTimer = -1;
106 long nTooltipHideTimer = -1;
107 long nNow;
108 int nTooltipButton = 0, nTooltipX = 0, nTooltipY = 0;
110 /* Parse Command Line Arguments */
111 parseargs(argc, argv);
113 /* Catch fire if no configuration file exists */
114 if (!canOpenFile(Config.configfile)) {
115 if(!canOpenFile(CONFIGGLOBAL)) {
116 err_mess(FAILCONF, Config.configfile);
117 return (1);
121 /* Open Display */
122 if ((display = XOpenDisplay(Config.Display_str)) == NULL)
123 err_mess(FAILDISP, Config.Display_str);
125 screen = DefaultScreen(display);
126 rootwin = RootWindow(display, screen);
127 depth = DefaultDepth(display, screen);
129 bg_pixel = WhitePixel(display, screen);
130 fg_pixel = BlackPixel(display, screen);
132 xsizehints.flags = USSize | USPosition;
133 xsizehints.width = 64;
134 xsizehints.height = 64;
136 /* Parse Geometry string and fill in sizehints fields */
137 XWMGeometry(display, screen,
138 Config.Geometry_str,
139 NULL,
140 border,
141 &xsizehints,
142 &xsizehints.x,
143 &xsizehints.y,
144 &xsizehints.width,
145 &xsizehints.height,
146 &dummy);
148 if ((win = XCreateSimpleWindow(display,
149 rootwin,
150 xsizehints.x,
151 xsizehints.y,
152 xsizehints.width,
153 xsizehints.height,
154 border,
155 fg_pixel, bg_pixel)) == 0)
156 err_mess(FAILSWIN, NULL);
158 if ((iconwin = XCreateSimpleWindow(display,
159 win,
160 xsizehints.x,
161 xsizehints.y,
162 xsizehints.width,
163 xsizehints.height,
164 border,
165 fg_pixel, bg_pixel)) == 0)
167 err_mess(FAILICON, NULL);
169 /* Set up shaped windows */
170 /* Gives the appicon a border so you can grab and move it. */
171 if ((pixmask = XCreateBitmapFromData(display,
172 win,
173 mask_bits,
174 mask_width,
175 mask_height)) == 0)
176 err_mess(FAILXPM, NULL);
178 XShapeCombineMask(display, win, ShapeBounding, 0, 0, pixmask, ShapeSet);
179 XShapeCombineMask(display, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet);
181 /* Convert in pixmaps from .xpm includes. */
182 getPixmaps();
184 /* Interclient Communication stuff */
185 /* Appicons don't work with out this stuff */
186 SetWmHints();
187 SetClassHints();
189 XSetWMNormalHints(display, win, &xsizehints);
191 /* Tell window manager what the title bar name is. We never see */
192 /* this anyways in the WithdrawnState */
193 if (XStringListToTextProperty(&app_name, 1, &app_name_atom) == 0)
194 err_mess(FAILWNAM, app_name);
196 XSetWMName(display, win, &app_name_atom);
198 /* Create Graphic Context */
199 if ((gc = XCreateGC(display, win, (GCForeground | GCBackground),
200 &xgcValues)) == NULL)
201 err_mess(FAILGC, NULL);
203 /* XEvent Masks. We want both window to process X events */
204 XSelectInput(display, win,
205 ExposureMask |
206 ButtonPressMask |
207 ButtonReleaseMask | /* added ButtonReleaseMask *charkins*/
208 PointerMotionMask |
209 StructureNotifyMask |
210 LeaveWindowMask);
212 XSelectInput(display, iconwin,
213 ExposureMask |
214 ButtonPressMask |
215 ButtonReleaseMask | /* added ButtonReleaseMask *charkins*/
216 PointerMotionMask |
217 StructureNotifyMask |
218 LeaveWindowMask);
220 /* Store the 'state' of the application for restarting */
221 XSetCommand(display, win, argv, argc);
223 /* Window won't ever show up until it is mapped.. then drawn after a */
224 /* ConfigureNotify */
225 XMapWindow(display, win);
227 /* Initialize Tooltip Support */
228 initTime();
229 initTooltip();
231 /* X Event Loop */
232 while (1) {
233 while (XPending(display) || nTooltipTimer == -1) {
234 XNextEvent(display, &report);
236 switch (report.type) {
237 case Expose:
238 if (report.xexpose.count != 0)
239 break;
241 if (Config.Verbose)
242 fprintf(stdout, "Event: Expose\n");
244 redraw();
245 break;
247 case ConfigureNotify:
248 if (Config.Verbose)
249 fprintf(stdout, "Event: ConfigureNotify\n");
251 redraw();
252 break;
254 case MotionNotify:
255 if (hasTooltipSupport()) {
256 if (!hasTooltip()) {
257 nTooltipTimer = currentTimeMillis();
258 nTooltipX = report.xbutton.x;
259 nTooltipY = report.xbutton.y;
260 nTooltipButton = whichButton(report.xbutton.x, report.xbutton.y);
261 } else {
262 int nButton = whichButton(report.xbutton.x, report.xbutton.y);
263 if (nButton != nTooltipButton) {
264 hideTooltip();
265 nTooltipTimer = -1;
266 nTooltipX = report.xbutton.x;
267 nTooltipY = report.xbutton.y;
268 nTooltipButton = nButton;
269 showTooltip(nTooltipButton, nTooltipX, nTooltipY);
273 break;
275 case LeaveNotify:
276 if (Config.Verbose)
277 fprintf(stdout, "Event: LeaveNotify\n");
279 if (hasTooltip()) {
280 hideTooltip();
281 nTooltipHideTimer = currentTimeMillis();
283 nTooltipTimer = -1;
284 break;
286 case ButtonPress: /* draw button pressed, don't launch *charkins*/
287 if (hasTooltip()) {
288 hideTooltip();
289 nTooltipHideTimer = currentTimeMillis();
292 switch (report.xbutton.button) {
293 case Button1:
294 N = whichButton(report.xbutton.x, report.xbutton.y);
295 if ((N >= 0) && (N <= NUMB_OF_APPS)) {
296 button_pressed = N + LMASK;
297 redraw();
300 if (Config.Verbose)
301 fprintf(stdout, "Button 1:x=%d y=%d N=%d\n",
302 report.xbutton.x, report.xbutton.y, N+LMASK);
303 break;
305 case Button2:
306 if (!Config.mmouse) {
307 N = whichButton(report.xbutton.x, report.xbutton.y);
308 if ((N >= 0) && (N <= NUMB_OF_APPS)) {
309 button_pressed = N + MMASK;
310 redraw();
313 if (Config.Verbose)
314 fprintf(stdout, "Button 2:x=%d y=%d N=%d\n",
315 report.xbutton.x, report.xbutton.y, N+MMASK);
317 break;
319 case Button3:
320 N = whichButton(report.xbutton.x, report.xbutton.y);
321 if ((N >= 0) && (N <= NUMB_OF_APPS)) {
322 button_pressed = N + RMASK;
323 redraw();
326 if (Config.Verbose)
327 fprintf(stdout, "Button 3:x=%d y=%d N=%d\n",
328 report.xbutton.x, report.xbutton.y, N+RMASK);
329 break;
331 break;
333 case ButtonRelease: /* launch app here if still over button *charkins*/
334 switch (report.xbutton.button) {
335 case Button1:
336 N = whichButton(report.xbutton.x, report.xbutton.y);
337 if ((N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed))
338 RunAppN(N + LMASK);
340 button_pressed = -1;
341 redraw();
343 if (Config.Verbose)
344 fprintf(stdout, "Button 1:x=%d y=%d N=%d\n",
345 report.xbutton.x, report.xbutton.y, N+LMASK);
346 break;
348 case Button2:
349 if (!Config.mmouse) {
350 N = whichButton(report.xbutton.x, report.xbutton.y);
351 if ((N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed))
352 RunAppN(N + MMASK);
354 button_pressed = -1;
355 redraw();
357 if (Config.Verbose)
358 fprintf(stdout, "Button 2:x=%d y=%d N=%d\n",
359 report.xbutton.x, report.xbutton.y, N+MMASK);
361 break;
363 case Button3:
364 N = whichButton(report.xbutton.x, report.xbutton.y);
365 if ((N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed))
366 RunAppN(N + RMASK);
368 button_pressed = -1;
369 redraw();
371 if (Config.Verbose)
372 fprintf(stdout, "Button 3:x=%d y=%d N=%d\n",
373 report.xbutton.x, report.xbutton.y, N+RMASK);
374 break;
376 break;
378 case DestroyNotify:
379 if (Config.Verbose)
380 fprintf(stdout, "Bye\n");
382 destroyTooltip();
383 XFreeGC(display, gc);
384 XDestroyWindow(display, win);
385 XDestroyWindow(display, iconwin);
386 XCloseDisplay(display);
387 exit(0);
388 break;
392 usleep(50000);
393 nNow = currentTimeMillis();
394 if (nTooltipTimer != -1 &&
395 ((nNow > nTooltipTimer + nTooltipShowDelay) ||
396 (nNow < nTooltipHideTimer + nTooltipReshowDelay))) {
397 showTooltip(nTooltipButton, nTooltipX, nTooltipY);
398 nTooltipTimer = -1;
402 return (0);
404 /***********************************************************************/
406 /***********************************************************************
407 * redraw
409 * Map the button region coordinates.
411 * Draw the appropriate number of buttons on the 'visible' Pixmap
412 * using data from the 'buttons' pixmap.
414 * Then, copy the 'visible' pixmap to the two windows ( the withdrawn
415 * main window and the icon window which is the main window's icon image.)
416 ***********************************************************************/
417 void redraw() {
418 int n, i, j, dest_x, dest_y, space, offset, bsize = 18;
420 if (Config.Verbose)
421 fprintf(stdout, "In Redraw()\n");
423 space = 0;
424 offset = 5;
425 XCopyArea(display, template.pixmap, visible.pixmap, gc, 0, 0,
426 template.attributes.width, template.attributes.height, 0, 0);
428 for (j = 0; j < 3; j++) {
429 for (i = 0; i < 3; i++) {
430 n = i + j * 3;
431 dest_x = i * (bsize + space) + offset + space;
432 dest_y = j * (bsize + space) + offset + space;
434 /* Define button mouse coords */
435 button_region[n].x = dest_x;
436 button_region[n].y = dest_y;
437 button_region[n].i = dest_x + bsize - 1;
438 button_region[n].j = dest_y + bsize - 1;
440 /* Copy button images for valid apps */
441 if ((n + 1) <= NUMB_OF_APPS)
442 XCopyArea(display, buttons.pixmap, visible.pixmap, gc,
443 i * bsize, j * bsize, bsize, bsize, dest_x, dest_y);
447 if (button_pressed > 0) { /* draw pressed button *charkins*/
448 if (button_pressed > RMASK)
449 button_pressed -= RMASK;
450 else if (button_pressed > MMASK)
451 button_pressed -= MMASK;
452 else if (button_pressed > LMASK)
453 button_pressed -= LMASK;
455 i = (button_pressed - 1) % 3; /* get col of button */
456 j = (button_pressed - 1) / 3; /* get row of button */
457 dest_x = i * (bsize + space) + offset + space;
458 dest_y = j * (bsize + space) + offset + space;
459 XSetForeground(display, gc, bg_pixel);
460 XDrawLine(display, visible.pixmap, gc,
461 dest_x + 1, dest_y + bsize - 1,
462 dest_x + bsize - 1, dest_y + bsize - 1);
463 XDrawLine(display, visible.pixmap, gc,
464 dest_x + bsize - 1, dest_y + bsize - 1,
465 dest_x + bsize - 1, dest_y + 1);
466 XSetForeground(display, gc, fg_pixel);
467 XDrawLine(display, visible.pixmap, gc,
468 dest_x, dest_y, dest_x + bsize - 2, dest_y);
469 XDrawLine(display, visible.pixmap, gc,
470 dest_x, dest_y, dest_x, dest_y + bsize - 2);
471 } /*charkins*/
473 flush_expose(win);
474 XCopyArea(display, visible.pixmap, win, gc, 0, 0,
475 visible.attributes.width, visible.attributes.height, 0, 0);
476 flush_expose(iconwin);
477 XCopyArea(display, visible.pixmap, iconwin, gc, 0, 0,
478 visible.attributes.width, visible.attributes.height, 0, 0);
480 /***********************************************************************/
482 /***********************************************************************
483 * whichButton
485 * Return the button that at the x,y coordinates. The button need not
486 * be visible ( drawn ). Return -1 if no button match.
487 ***********************************************************************/
488 int whichButton(int x, int y)
490 int index;
492 for (index = 0; index < NUMB_OF_APPS; index++) {
493 if (x >= button_region[index].x &&
494 x <= button_region[index].i &&
495 y >= button_region[index].y &&
496 y <= button_region[index].j)
497 return(index + 1);
499 return -1;
501 /***********************************************************************/
504 /***********************************************************************
505 * getPixmaps
507 * Load XPM data into X Pixmaps.
509 * Pixmap template contains the untouched window backdrop image.
510 * Pixmap visible is the template pixmap with buttons drawn on it.
511 * -- what is seen by the user.
512 * Pixmap buttons holds the images for individual buttons that are
513 * later copied onto Pixmap visible.
514 ***********************************************************************/
515 void getPixmaps()
517 int loaded = 0;
518 template.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
519 visible.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
520 buttons.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
522 if (Config.Verbose)
523 fprintf(stdout, "In getPixmaps\n");
525 /* Template Pixmap. Never Drawn To. */
526 if (XpmCreatePixmapFromData(display, rootwin, backdrop_xpm,
527 &template.pixmap, &template.mask,
528 &template.attributes) != XpmSuccess)
529 err_mess(FAILTMPL, NULL);
531 /* Visible Pixmap. Copied from template Pixmap and then drawn to. */
532 if (XpmCreatePixmapFromData(display, rootwin, backdrop_xpm,
533 &visible.pixmap, &visible.mask,
534 &visible.attributes) != XpmSuccess)
535 err_mess(FAILVIS, NULL);
537 /* Button Pixmap. */
538 if (access(Config.buttonfile, R_OK) == 0) {
539 /* load buttons from file */
540 if (XpmReadFileToPixmap(display, rootwin, Config.buttonfile,
541 &buttons.pixmap, &buttons.mask,
542 &buttons.attributes) != XpmSuccess)
543 err_mess(FAILBUT, NULL);
544 else
545 loaded = 1;
548 if (!loaded) {
549 /* Use Builtin Button Pixmap. */
550 if (Config.Verbose)
551 fprintf(stdout, "Using builtin buttons pixmap\n");
553 if (XpmCreatePixmapFromData(display, rootwin, buttons_xpm,
554 &buttons.pixmap, &buttons.mask,
555 &buttons.attributes) != XpmSuccess)
556 err_mess(FAILBUT, NULL);
559 if (Config.Verbose)
560 fprintf(stdout, "Leaving getPixmaps\n");
563 /*********************************************************************/
565 void SetWmHints()
567 XWMHints *xwmhints;
569 xwmhints = XAllocWMHints();
570 xwmhints->flags = WindowGroupHint | IconWindowHint | StateHint;
571 xwmhints->icon_window = iconwin;
572 xwmhints->window_group = win;
573 xwmhints->initial_state = WithdrawnState;
574 XSetWMHints(display, win, xwmhints);
575 XFree(xwmhints);
576 xwmhints = NULL;
579 void SetClassHints()
581 XClassHint xclasshint;
583 xclasshint.res_name = "wmbutton";
584 xclasshint.res_class = "Wmbutton";
585 XSetClassHint(display, win, &xclasshint);