wmbiff: Use unsigned data type for port number.
[dockapps.git] / wmbutton / wmbutton.c
blob6d4dd26cd1e45ec93e3ff08914c8174cddba24b9
1 /***********************************************************************
2 * Code is based on wmppp, wmload, wmtime, wmcp, and asbutton
3 * Author: Edward H. Flora <ehflora@ksu.edu>
4 * Ver 0 Rel 6.1 Jan 23, 2005
6 * Contributors:
7 * Christian 'Greek0' Aichinger <Greek0@gmx.net>
8 * Did some code cleanup and fixed several memory leaks.
9 * Ralf Horstmann <ralf.horstmann@gmx.de>
10 * Added ability to load pixmaps at startup,
11 * without having to re-compile
12 * Michael Cohrs <camico@users.sourceforge.net>
13 * Added Tool Tips, and updated graphics
14 * Bruno Essmann <essmann@users.sourceforge.net>)
15 * Creator of wmpager
16 * Casey Harkins <charkins@cs.wisc.edu>
17 * Bug fix reading config file path - 3/6/99
18 * Added button-presses, and other - denoted by *charkins*
19 * Ben Cohen <buddog@aztec.asu.edu>
20 * original author of wmcp (et al.)
21 * Thomas Nemeth <tnemeth@multimania.com>
22 * contributor to wmcp
23 * Michael Henderson <mghenderson@lanl.gov>
24 * Application ideas, suggestions
25 * Ryan ?? <pancake@mindspring.com>
26 * Modified wmbutton to asbutton.
27 * Note: asbutton is a seperate program, not associated
28 * with wmbutton (just as wmbutton is not associated
29 * with wmcp)
30 * Jon Bruno
31 * Web Page Development
32 * The contributors listed above are not necessarily involved with the
33 * development of wmbutton. I'm listing them here partially as thanks for
34 * helping out, catching bugs in the code, etc.
35 ***********************************************************************/
36 #include <stdio.h>
37 #include <math.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <ctype.h>
41 #include <unistd.h>
43 #include "wmbutton.h"
45 #include "backdrop.xpm" /* background graphic */
46 #include "buttons.xpm" /* graphic of 9 buttons */
47 #include "mask.xbm" /* Border Graphic */
49 /*************** Function Prototypes ***********************************/
50 void redraw(void);
51 void getPixmaps(void);
52 int whichButton(int x, int y); // determine which button has been pressed
53 void SetWmHints();
54 void SetClassHints();
56 /***********************************************************************
57 * Globals.. OK.. there's too many globals.
58 * Feel free and fix it, if you'd like.
59 ***********************************************************************/
60 Display *display;
61 int screen;
62 Window rootwin, win, iconwin;
63 GC gc;
64 int depth;
65 Pixel bg_pixel, fg_pixel;
67 struct Config_t Config;
69 typedef struct _XpmIcon {
70 Pixmap pixmap;
71 Pixmap mask;
72 XpmAttributes attributes;
73 } XpmIcon;
75 typedef struct _button_region {
76 int x, y;
77 int i, j;
78 } ButtonArea;
80 ButtonArea button_region[9];
82 XpmIcon template, visible, buttons;
84 int border = 0;
85 int button_pressed = -1; /* button to be drawn pressed *charkins*/
87 char *app_name = "wmbutton";
89 /***********************************************************************
90 * Main
91 ***********************************************************************/
92 int main(int argc, char **argv)
94 XEvent report;
95 XGCValues xgcValues;
96 XTextProperty app_name_atom;
97 XSizeHints xsizehints;
98 Pixmap pixmask;
100 int dummy = 0;
101 int N = 1; /* Button number pressed to goto app # */
103 /* Added for Tool Tip Support */
104 long nTooltipShowDelay = TOOLTIP_SHOW_DELAY;
105 long nTooltipReshowDelay = TOOLTIP_RESHOW_DELAY;
106 long nTooltipTimer = -1;
107 long nTooltipHideTimer = -1;
108 long nNow;
109 int nTooltipButton = 0, nTooltipX = 0, nTooltipY = 0;
111 /* Parse Command Line Arguments */
112 parseargs(argc, argv);
114 /* Catch fire if no configuration file exists */
115 if (!canOpenFile(Config.configfile)) {
116 if(!canOpenFile(CONFIGGLOBAL)) {
117 err_mess(FAILCONF, Config.configfile);
118 return (1);
122 /* Open Display */
123 if ((display = XOpenDisplay(Config.Display_str)) == NULL)
124 err_mess(FAILDISP, Config.Display_str);
126 screen = DefaultScreen(display);
127 rootwin = RootWindow(display, screen);
128 depth = DefaultDepth(display, screen);
130 bg_pixel = WhitePixel(display, screen);
131 fg_pixel = BlackPixel(display, screen);
133 xsizehints.flags = USSize | USPosition;
134 xsizehints.width = 64;
135 xsizehints.height = 64;
137 /* Parse Geometry string and fill in sizehints fields */
138 XWMGeometry(display, screen,
139 Config.Geometry_str,
140 NULL,
141 border,
142 &xsizehints,
143 &xsizehints.x,
144 &xsizehints.y,
145 &xsizehints.width,
146 &xsizehints.height,
147 &dummy);
149 if ((win = XCreateSimpleWindow(display,
150 rootwin,
151 xsizehints.x,
152 xsizehints.y,
153 xsizehints.width,
154 xsizehints.height,
155 border,
156 fg_pixel, bg_pixel)) == 0)
157 err_mess(FAILSWIN, NULL);
159 if ((iconwin = XCreateSimpleWindow(display,
160 win,
161 xsizehints.x,
162 xsizehints.y,
163 xsizehints.width,
164 xsizehints.height,
165 border,
166 fg_pixel, bg_pixel)) == 0)
168 err_mess(FAILICON, NULL);
170 /* Set up shaped windows */
171 /* Gives the appicon a border so you can grab and move it. */
172 if ((pixmask = XCreateBitmapFromData(display,
173 win,
174 mask_bits,
175 mask_width,
176 mask_height)) == 0)
177 err_mess(FAILXPM, NULL);
179 XShapeCombineMask(display, win, ShapeBounding, 0, 0, pixmask, ShapeSet);
180 XShapeCombineMask(display, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet);
182 /* Convert in pixmaps from .xpm includes. */
183 getPixmaps();
185 /* Interclient Communication stuff */
186 /* Appicons don't work with out this stuff */
187 SetWmHints();
188 SetClassHints();
190 XSetWMNormalHints(display, win, &xsizehints);
192 /* Tell window manager what the title bar name is. We never see */
193 /* this anyways in the WithdrawnState */
194 if (XStringListToTextProperty(&app_name, 1, &app_name_atom) == 0)
195 err_mess(FAILWNAM, app_name);
197 XSetWMName(display, win, &app_name_atom);
199 /* Create Graphic Context */
200 if ((gc = XCreateGC(display, win, (GCForeground | GCBackground),
201 &xgcValues)) == NULL)
202 err_mess(FAILGC, NULL);
204 /* XEvent Masks. We want both window to process X events */
205 XSelectInput(display, win,
206 ExposureMask |
207 ButtonPressMask |
208 ButtonReleaseMask | /* added ButtonReleaseMask *charkins*/
209 PointerMotionMask |
210 StructureNotifyMask |
211 LeaveWindowMask);
213 XSelectInput(display, iconwin,
214 ExposureMask |
215 ButtonPressMask |
216 ButtonReleaseMask | /* added ButtonReleaseMask *charkins*/
217 PointerMotionMask |
218 StructureNotifyMask |
219 LeaveWindowMask);
221 /* Store the 'state' of the application for restarting */
222 XSetCommand(display, win, argv, argc);
224 /* Window won't ever show up until it is mapped.. then drawn after a */
225 /* ConfigureNotify */
226 XMapWindow(display, win);
228 /* Initialize Tooltip Support */
229 initTime();
230 initTooltip();
232 /* X Event Loop */
233 while (1) {
234 while (XPending(display) || nTooltipTimer == -1) {
235 XNextEvent(display, &report);
237 switch (report.type) {
238 case Expose:
239 if (report.xexpose.count != 0)
240 break;
242 if (Config.Verbose)
243 fprintf(stdout, "Event: Expose\n");
245 redraw();
246 break;
248 case ConfigureNotify:
249 if (Config.Verbose)
250 fprintf(stdout, "Event: ConfigureNotify\n");
252 redraw();
253 break;
255 case MotionNotify:
256 if (hasTooltipSupport()) {
257 if (!hasTooltip()) {
258 nTooltipTimer = currentTimeMillis();
259 nTooltipX = report.xbutton.x;
260 nTooltipY = report.xbutton.y;
261 nTooltipButton = whichButton(report.xbutton.x, report.xbutton.y);
262 } else {
263 int nButton = whichButton(report.xbutton.x, report.xbutton.y);
264 if (nButton != nTooltipButton) {
265 hideTooltip();
266 nTooltipTimer = -1;
267 nTooltipX = report.xbutton.x;
268 nTooltipY = report.xbutton.y;
269 nTooltipButton = nButton;
270 showTooltip(nTooltipButton, nTooltipX, nTooltipY);
274 break;
276 case LeaveNotify:
277 if (Config.Verbose)
278 fprintf(stdout, "Event: LeaveNotify\n");
280 if (hasTooltip()) {
281 hideTooltip();
282 nTooltipHideTimer = currentTimeMillis();
284 nTooltipTimer = -1;
285 break;
287 case ButtonPress: /* draw button pressed, don't launch *charkins*/
288 if (hasTooltip()) {
289 hideTooltip();
290 nTooltipHideTimer = currentTimeMillis();
293 switch (report.xbutton.button) {
294 case Button1:
295 N = whichButton(report.xbutton.x, report.xbutton.y);
296 if ((N >= 0) && (N <= NUMB_OF_APPS)) {
297 button_pressed = N + LMASK;
298 redraw();
301 if (Config.Verbose)
302 fprintf(stdout, "Button 1:x=%d y=%d N=%d\n",
303 report.xbutton.x, report.xbutton.y, N+LMASK);
304 break;
306 case Button2:
307 if (!Config.mmouse) {
308 N = whichButton(report.xbutton.x, report.xbutton.y);
309 if ((N >= 0) && (N <= NUMB_OF_APPS)) {
310 button_pressed = N + MMASK;
311 redraw();
314 if (Config.Verbose)
315 fprintf(stdout, "Button 2:x=%d y=%d N=%d\n",
316 report.xbutton.x, report.xbutton.y, N+MMASK);
318 break;
320 case Button3:
321 N = whichButton(report.xbutton.x, report.xbutton.y);
322 if ((N >= 0) && (N <= NUMB_OF_APPS)) {
323 button_pressed = N + RMASK;
324 redraw();
327 if (Config.Verbose)
328 fprintf(stdout, "Button 3:x=%d y=%d N=%d\n",
329 report.xbutton.x, report.xbutton.y, N+RMASK);
330 break;
332 break;
334 case ButtonRelease: /* launch app here if still over button *charkins*/
335 switch (report.xbutton.button) {
336 case Button1:
337 N = whichButton(report.xbutton.x, report.xbutton.y);
338 if ((N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed))
339 RunAppN(N + LMASK);
341 button_pressed = -1;
342 redraw();
344 if (Config.Verbose)
345 fprintf(stdout, "Button 1:x=%d y=%d N=%d\n",
346 report.xbutton.x, report.xbutton.y, N+LMASK);
347 break;
349 case Button2:
350 if (!Config.mmouse) {
351 N = whichButton(report.xbutton.x, report.xbutton.y);
352 if ((N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed))
353 RunAppN(N + MMASK);
355 button_pressed = -1;
356 redraw();
358 if (Config.Verbose)
359 fprintf(stdout, "Button 2:x=%d y=%d N=%d\n",
360 report.xbutton.x, report.xbutton.y, N+MMASK);
362 break;
364 case Button3:
365 N = whichButton(report.xbutton.x, report.xbutton.y);
366 if ((N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed))
367 RunAppN(N + RMASK);
369 button_pressed = -1;
370 redraw();
372 if (Config.Verbose)
373 fprintf(stdout, "Button 3:x=%d y=%d N=%d\n",
374 report.xbutton.x, report.xbutton.y, N+RMASK);
375 break;
377 break;
379 case DestroyNotify:
380 if (Config.Verbose)
381 fprintf(stdout, "Bye\n");
383 destroyTooltip();
384 XFreeGC(display, gc);
385 XDestroyWindow(display, win);
386 XDestroyWindow(display, iconwin);
387 XCloseDisplay(display);
388 exit(0);
389 break;
393 usleep(50000);
394 nNow = currentTimeMillis();
395 if (nTooltipTimer != -1 &&
396 ((nNow > nTooltipTimer + nTooltipShowDelay) ||
397 (nNow < nTooltipHideTimer + nTooltipReshowDelay))) {
398 showTooltip(nTooltipButton, nTooltipX, nTooltipY);
399 nTooltipTimer = -1;
403 return (0);
405 /***********************************************************************/
407 /***********************************************************************
408 * redraw
410 * Map the button region coordinates.
412 * Draw the appropriate number of buttons on the 'visible' Pixmap
413 * using data from the 'buttons' pixmap.
415 * Then, copy the 'visible' pixmap to the two windows ( the withdrawn
416 * main window and the icon window which is the main window's icon image.)
417 ***********************************************************************/
418 void redraw() {
419 int n, i, j, dest_x, dest_y, space, offset, bsize = 18;
421 if (Config.Verbose)
422 fprintf(stdout, "In Redraw()\n");
424 space = 0;
425 offset = 5;
426 XCopyArea(display, template.pixmap, visible.pixmap, gc, 0, 0,
427 template.attributes.width, template.attributes.height, 0, 0);
429 for (j = 0; j < 3; j++) {
430 for (i = 0; i < 3; i++) {
431 n = i + j * 3;
432 dest_x = i * (bsize + space) + offset + space;
433 dest_y = j * (bsize + space) + offset + space;
435 /* Define button mouse coords */
436 button_region[n].x = dest_x;
437 button_region[n].y = dest_y;
438 button_region[n].i = dest_x + bsize - 1;
439 button_region[n].j = dest_y + bsize - 1;
441 /* Copy button images for valid apps */
442 if ((n + 1) <= NUMB_OF_APPS)
443 XCopyArea(display, buttons.pixmap, visible.pixmap, gc,
444 i * bsize, j * bsize, bsize, bsize, dest_x, dest_y);
448 if (button_pressed > 0) { /* draw pressed button *charkins*/
449 if (button_pressed > RMASK)
450 button_pressed -= RMASK;
451 else if (button_pressed > MMASK)
452 button_pressed -= MMASK;
453 else if (button_pressed > LMASK)
454 button_pressed -= LMASK;
456 i = (button_pressed - 1) % 3; /* get col of button */
457 j = (button_pressed - 1) / 3; /* get row of button */
458 dest_x = i * (bsize + space) + offset + space;
459 dest_y = j * (bsize + space) + offset + space;
460 XSetForeground(display, gc, bg_pixel);
461 XDrawLine(display, visible.pixmap, gc,
462 dest_x + 1, dest_y + bsize - 1,
463 dest_x + bsize - 1, dest_y + bsize - 1);
464 XDrawLine(display, visible.pixmap, gc,
465 dest_x + bsize - 1, dest_y + bsize - 1,
466 dest_x + bsize - 1, dest_y + 1);
467 XSetForeground(display, gc, fg_pixel);
468 XDrawLine(display, visible.pixmap, gc,
469 dest_x, dest_y, dest_x + bsize - 2, dest_y);
470 XDrawLine(display, visible.pixmap, gc,
471 dest_x, dest_y, dest_x, dest_y + bsize - 2);
472 } /*charkins*/
474 flush_expose(win);
475 XCopyArea(display, visible.pixmap, win, gc, 0, 0,
476 visible.attributes.width, visible.attributes.height, 0, 0);
477 flush_expose(iconwin);
478 XCopyArea(display, visible.pixmap, iconwin, gc, 0, 0,
479 visible.attributes.width, visible.attributes.height, 0, 0);
481 /***********************************************************************/
483 /***********************************************************************
484 * whichButton
486 * Return the button that at the x,y coordinates. The button need not
487 * be visible ( drawn ). Return -1 if no button match.
488 ***********************************************************************/
489 int whichButton(int x, int y)
491 int index;
493 for (index = 0; index < NUMB_OF_APPS; index++) {
494 if (x >= button_region[index].x &&
495 x <= button_region[index].i &&
496 y >= button_region[index].y &&
497 y <= button_region[index].j)
498 return(index + 1);
500 return -1;
502 /***********************************************************************/
505 /***********************************************************************
506 * getPixmaps
508 * Load XPM data into X Pixmaps.
510 * Pixmap template contains the untouched window backdrop image.
511 * Pixmap visible is the template pixmap with buttons drawn on it.
512 * -- what is seen by the user.
513 * Pixmap buttons holds the images for individual buttons that are
514 * later copied onto Pixmap visible.
515 ***********************************************************************/
516 void getPixmaps()
518 int loaded = 0;
519 template.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
520 visible.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
521 buttons.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
523 if (Config.Verbose)
524 fprintf(stdout, "In getPixmaps\n");
526 /* Template Pixmap. Never Drawn To. */
527 if (XpmCreatePixmapFromData(display, rootwin, backdrop_xpm,
528 &template.pixmap, &template.mask,
529 &template.attributes) != XpmSuccess)
530 err_mess(FAILTMPL, NULL);
532 /* Visible Pixmap. Copied from template Pixmap and then drawn to. */
533 if (XpmCreatePixmapFromData(display, rootwin, backdrop_xpm,
534 &visible.pixmap, &visible.mask,
535 &visible.attributes) != XpmSuccess)
536 err_mess(FAILVIS, NULL);
538 /* Button Pixmap. */
539 if (access(Config.buttonfile, R_OK) == 0) {
540 /* load buttons from file */
541 if (XpmReadFileToPixmap(display, rootwin, Config.buttonfile,
542 &buttons.pixmap, &buttons.mask,
543 &buttons.attributes) != XpmSuccess)
544 err_mess(FAILBUT, NULL);
545 else
546 loaded = 1;
549 if (!loaded) {
550 /* Use Builtin Button Pixmap. */
551 if (Config.Verbose)
552 fprintf(stdout, "Using builtin buttons pixmap\n");
554 if (XpmCreatePixmapFromData(display, rootwin, buttons_xpm,
555 &buttons.pixmap, &buttons.mask,
556 &buttons.attributes) != XpmSuccess)
557 err_mess(FAILBUT, NULL);
560 if (Config.Verbose)
561 fprintf(stdout, "Leaving getPixmaps\n");
564 /*********************************************************************/
566 void SetWmHints()
568 XWMHints *xwmhints;
570 xwmhints = XAllocWMHints();
571 xwmhints->flags = WindowGroupHint | IconWindowHint | StateHint;
572 xwmhints->icon_window = iconwin;
573 xwmhints->window_group = win;
574 xwmhints->initial_state = WithdrawnState;
575 XSetWMHints(display, win, xwmhints);
576 XFree(xwmhints);
577 xwmhints = NULL;
580 void SetClassHints()
582 XClassHint xclasshint;
584 xclasshint.res_name = "wmbutton";
585 xclasshint.res_class = "Wmbutton";
586 XSetClassHint(display, win, &xclasshint);