wmbutton: Middle button enabled by default
[dockapps.git] / wmbutton / wmbutton.c
blob14831fd2f91ed0e0a64d764c36da7271e424cc68
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 /* Open Display */
115 if ((display = XOpenDisplay(Config.Display_str)) == NULL)
116 err_mess(FAILDISP, Config.Display_str);
118 screen = DefaultScreen(display);
119 rootwin = RootWindow(display, screen);
120 depth = DefaultDepth(display, screen);
122 bg_pixel = WhitePixel(display, screen);
123 fg_pixel = BlackPixel(display, screen);
125 xsizehints.flags = USSize | USPosition;
126 xsizehints.width = 64;
127 xsizehints.height = 64;
129 /* Parse Geometry string and fill in sizehints fields */
130 XWMGeometry(display, screen,
131 Config.Geometry_str,
132 NULL,
133 border,
134 &xsizehints,
135 &xsizehints.x,
136 &xsizehints.y,
137 &xsizehints.width,
138 &xsizehints.height,
139 &dummy);
141 if ((win = XCreateSimpleWindow(display,
142 rootwin,
143 xsizehints.x,
144 xsizehints.y,
145 xsizehints.width,
146 xsizehints.height,
147 border,
148 fg_pixel, bg_pixel)) == 0)
149 err_mess(FAILSWIN, NULL);
151 if ((iconwin = XCreateSimpleWindow(display,
152 win,
153 xsizehints.x,
154 xsizehints.y,
155 xsizehints.width,
156 xsizehints.height,
157 border,
158 fg_pixel, bg_pixel)) == 0)
160 err_mess(FAILICON, NULL);
162 /* Set up shaped windows */
163 /* Gives the appicon a border so you can grab and move it. */
164 if ((pixmask = XCreateBitmapFromData(display,
165 win,
166 mask_bits,
167 mask_width,
168 mask_height)) == 0)
169 err_mess(FAILXPM, NULL);
171 XShapeCombineMask(display, win, ShapeBounding, 0, 0, pixmask, ShapeSet);
172 XShapeCombineMask(display, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet);
174 /* Convert in pixmaps from .xpm includes. */
175 getPixmaps();
177 /* Interclient Communication stuff */
178 /* Appicons don't work with out this stuff */
179 SetWmHints();
180 SetClassHints();
182 XSetWMNormalHints(display, win, &xsizehints);
184 /* Tell window manager what the title bar name is. We never see */
185 /* this anyways in the WithdrawnState */
186 if (XStringListToTextProperty(&app_name, 1, &app_name_atom) == 0)
187 err_mess(FAILWNAM, app_name);
189 XSetWMName(display, win, &app_name_atom);
191 /* Create Graphic Context */
192 if ((gc = XCreateGC(display, win, (GCForeground | GCBackground),
193 &xgcValues)) == NULL)
194 err_mess(FAILGC, NULL);
196 /* XEvent Masks. We want both window to process X events */
197 XSelectInput(display, win,
198 ExposureMask |
199 ButtonPressMask |
200 ButtonReleaseMask | /* added ButtonReleaseMask *charkins*/
201 PointerMotionMask |
202 StructureNotifyMask |
203 LeaveWindowMask);
205 XSelectInput(display, iconwin,
206 ExposureMask |
207 ButtonPressMask |
208 ButtonReleaseMask | /* added ButtonReleaseMask *charkins*/
209 PointerMotionMask |
210 StructureNotifyMask |
211 LeaveWindowMask);
213 /* Store the 'state' of the application for restarting */
214 XSetCommand(display, win, argv, argc);
216 /* Window won't ever show up until it is mapped.. then drawn after a */
217 /* ConfigureNotify */
218 XMapWindow(display, win);
220 /* Initialize Tooltip Support */
221 initTime();
222 initTooltip(!Config.bTooltipDisable, Config.szTooltipFont, Config.bTooltipSwapColors);
224 /* X Event Loop */
225 while (1) {
226 while (XPending(display) || nTooltipTimer == -1) {
227 XNextEvent(display, &report);
229 switch (report.type) {
230 case Expose:
231 if (report.xexpose.count != 0)
232 break;
234 if (Config.Verbose)
235 fprintf(stdout, "Event: Expose\n");
237 redraw();
238 break;
240 case ConfigureNotify:
241 if (Config.Verbose)
242 fprintf(stdout, "Event: ConfigureNotify\n");
244 redraw();
245 break;
247 case MotionNotify:
248 if (hasTooltipSupport()) {
249 if (!hasTooltip()) {
250 nTooltipTimer = currentTimeMillis();
251 nTooltipX = report.xbutton.x;
252 nTooltipY = report.xbutton.y;
253 nTooltipButton = whichButton(report.xbutton.x, report.xbutton.y);
254 } else {
255 int nButton = whichButton(report.xbutton.x, report.xbutton.y);
256 if (nButton != nTooltipButton) {
257 hideTooltip();
258 nTooltipTimer = -1;
259 nTooltipX = report.xbutton.x;
260 nTooltipY = report.xbutton.y;
261 nTooltipButton = nButton;
262 showTooltip(nTooltipButton, nTooltipX, nTooltipY);
266 break;
268 case LeaveNotify:
269 if (Config.Verbose)
270 fprintf(stdout, "Event: LeaveNotify\n");
272 if (hasTooltip()) {
273 hideTooltip();
274 nTooltipHideTimer = currentTimeMillis();
276 nTooltipTimer = -1;
277 break;
279 case ButtonPress: /* draw button pressed, don't launch *charkins*/
280 if (hasTooltip()) {
281 hideTooltip();
282 nTooltipHideTimer = currentTimeMillis();
285 switch (report.xbutton.button) {
286 case Button1:
287 N = whichButton(report.xbutton.x, report.xbutton.y);
288 if ((N >= 0) && (N <= NUMB_OF_APPS)) {
289 button_pressed = N + LMASK;
290 redraw();
293 if (Config.Verbose)
294 fprintf(stdout, "Button 1:x=%d y=%d N=%d\n",
295 report.xbutton.x, report.xbutton.y, N+LMASK);
296 break;
298 case Button2:
299 if (!Config.mmouse) {
300 N = whichButton(report.xbutton.x, report.xbutton.y);
301 if ((N >= 0) && (N <= NUMB_OF_APPS)) {
302 button_pressed = N + MMASK;
303 redraw();
306 if (Config.Verbose)
307 fprintf(stdout, "Button 2:x=%d y=%d N=%d\n",
308 report.xbutton.x, report.xbutton.y, N+MMASK);
310 break;
312 case Button3:
313 N = whichButton(report.xbutton.x, report.xbutton.y);
314 if ((N >= 0) && (N <= NUMB_OF_APPS)) {
315 button_pressed = N + RMASK;
316 redraw();
319 if (Config.Verbose)
320 fprintf(stdout, "Button 3:x=%d y=%d N=%d\n",
321 report.xbutton.x, report.xbutton.y, N+RMASK);
322 break;
324 break;
326 case ButtonRelease: /* launch app here if still over button *charkins*/
327 switch (report.xbutton.button) {
328 case Button1:
329 N = whichButton(report.xbutton.x, report.xbutton.y);
330 if ((N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed))
331 RunAppN(N + LMASK);
333 button_pressed = -1;
334 redraw();
336 if (Config.Verbose)
337 fprintf(stdout, "Button 1:x=%d y=%d N=%d\n",
338 report.xbutton.x, report.xbutton.y, N+LMASK);
339 break;
341 case Button2:
342 if (!Config.mmouse) {
343 N = whichButton(report.xbutton.x, report.xbutton.y);
344 if ((N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed))
345 RunAppN(N + MMASK);
347 button_pressed = -1;
348 redraw();
350 if (Config.Verbose)
351 fprintf(stdout, "Button 2:x=%d y=%d N=%d\n",
352 report.xbutton.x, report.xbutton.y, N+MMASK);
354 break;
356 case Button3:
357 N = whichButton(report.xbutton.x, report.xbutton.y);
358 if ((N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed))
359 RunAppN(N + RMASK);
361 button_pressed = -1;
362 redraw();
364 if (Config.Verbose)
365 fprintf(stdout, "Button 3:x=%d y=%d N=%d\n",
366 report.xbutton.x, report.xbutton.y, N+RMASK);
367 break;
369 break;
371 case DestroyNotify:
372 if (Config.Verbose)
373 fprintf(stdout, "Bye\n");
375 destroyTooltip();
376 XFreeGC(display, gc);
377 XDestroyWindow(display, win);
378 XDestroyWindow(display, iconwin);
379 XCloseDisplay(display);
380 exit(0);
381 break;
385 usleep(50000);
386 nNow = currentTimeMillis();
387 if (nTooltipTimer != -1 &&
388 ((nNow > nTooltipTimer + nTooltipShowDelay) ||
389 (nNow < nTooltipHideTimer + nTooltipReshowDelay))) {
390 showTooltip(nTooltipButton, nTooltipX, nTooltipY);
391 nTooltipTimer = -1;
395 return (0);
397 /***********************************************************************/
399 /***********************************************************************
400 * redraw
402 * Map the button region coordinates.
404 * Draw the appropriate number of buttons on the 'visible' Pixmap
405 * using data from the 'buttons' pixmap.
407 * Then, copy the 'visible' pixmap to the two windows ( the withdrawn
408 * main window and the icon window which is the main window's icon image.)
409 ***********************************************************************/
410 void redraw() {
411 int n, i, j, dest_x, dest_y, space, offset, bsize = 18;
413 if (Config.Verbose)
414 fprintf(stdout, "In Redraw()\n");
416 space = 0;
417 offset = 5;
418 XCopyArea(display, template.pixmap, visible.pixmap, gc, 0, 0,
419 template.attributes.width, template.attributes.height, 0, 0);
421 for (j = 0; j < 3; j++) {
422 for (i = 0; i < 3; i++) {
423 n = i + j * 3;
424 dest_x = i * (bsize + space) + offset + space;
425 dest_y = j * (bsize + space) + offset + space;
427 /* Define button mouse coords */
428 button_region[n].x = dest_x;
429 button_region[n].y = dest_y;
430 button_region[n].i = dest_x + bsize - 1;
431 button_region[n].j = dest_y + bsize - 1;
433 /* Copy button images for valid apps */
434 if ((n + 1) <= NUMB_OF_APPS)
435 XCopyArea(display, buttons.pixmap, visible.pixmap, gc,
436 i * bsize, j * bsize, bsize, bsize, dest_x, dest_y);
440 if (button_pressed > 0) { /* draw pressed button *charkins*/
441 if (button_pressed > RMASK)
442 button_pressed -= RMASK;
443 else if (button_pressed > MMASK)
444 button_pressed -= MMASK;
445 else if (button_pressed > LMASK)
446 button_pressed -= LMASK;
448 i = (button_pressed - 1) % 3; /* get col of button */
449 j = (button_pressed - 1) / 3; /* get row of button */
450 dest_x = i * (bsize + space) + offset + space;
451 dest_y = j * (bsize + space) + offset + space;
452 XSetForeground(display, gc, bg_pixel);
453 XDrawLine(display, visible.pixmap, gc,
454 dest_x + 1, dest_y + bsize - 1,
455 dest_x + bsize - 1, dest_y + bsize - 1);
456 XDrawLine(display, visible.pixmap, gc,
457 dest_x + bsize - 1, dest_y + bsize - 1,
458 dest_x + bsize - 1, dest_y + 1);
459 XSetForeground(display, gc, fg_pixel);
460 XDrawLine(display, visible.pixmap, gc,
461 dest_x, dest_y, dest_x + bsize - 2, dest_y);
462 XDrawLine(display, visible.pixmap, gc,
463 dest_x, dest_y, dest_x, dest_y + bsize - 2);
464 } /*charkins*/
466 flush_expose(win);
467 XCopyArea(display, visible.pixmap, win, gc, 0, 0,
468 visible.attributes.width, visible.attributes.height, 0, 0);
469 flush_expose(iconwin);
470 XCopyArea(display, visible.pixmap, iconwin, gc, 0, 0,
471 visible.attributes.width, visible.attributes.height, 0, 0);
473 /***********************************************************************/
475 /***********************************************************************
476 * whichButton
478 * Return the button that at the x,y coordinates. The button need not
479 * be visible ( drawn ). Return -1 if no button match.
480 ***********************************************************************/
481 int whichButton(int x, int y)
483 int index;
485 for (index = 0; index < NUMB_OF_APPS; index++) {
486 if (x >= button_region[index].x &&
487 x <= button_region[index].i &&
488 y >= button_region[index].y &&
489 y <= button_region[index].j)
490 return(index + 1);
492 return -1;
494 /***********************************************************************/
497 /***********************************************************************
498 * getPixmaps
500 * Load XPM data into X Pixmaps.
502 * Pixmap template contains the untouched window backdrop image.
503 * Pixmap visible is the template pixmap with buttons drawn on it.
504 * -- what is seen by the user.
505 * Pixmap buttons holds the images for individual buttons that are
506 * later copied onto Pixmap visible.
507 ***********************************************************************/
508 void getPixmaps()
510 int loaded = 0;
511 template.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
512 visible.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
513 buttons.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
515 if (Config.Verbose)
516 fprintf(stdout, "In getPixmaps\n");
518 /* Template Pixmap. Never Drawn To. */
519 if (XpmCreatePixmapFromData(display, rootwin, backdrop_xpm,
520 &template.pixmap, &template.mask,
521 &template.attributes) != XpmSuccess)
522 err_mess(FAILTMPL, NULL);
524 /* Visible Pixmap. Copied from template Pixmap and then drawn to. */
525 if (XpmCreatePixmapFromData(display, rootwin, backdrop_xpm,
526 &visible.pixmap, &visible.mask,
527 &visible.attributes) != XpmSuccess)
528 err_mess(FAILVIS, NULL);
530 /* Button Pixmap. */
531 if (access(Config.buttonfile, R_OK) == 0) {
532 /* load buttons from file */
533 if (XpmReadFileToPixmap(display, rootwin, Config.buttonfile,
534 &buttons.pixmap, &buttons.mask,
535 &buttons.attributes) != XpmSuccess)
536 err_mess(FAILBUT, NULL);
537 else
538 loaded = 1;
541 if (!loaded) {
542 /* Use Builtin Button Pixmap. */
543 if (Config.Verbose)
544 fprintf(stdout, "Using builtin buttons pixmap\n");
546 if (XpmCreatePixmapFromData(display, rootwin, buttons_xpm,
547 &buttons.pixmap, &buttons.mask,
548 &buttons.attributes) != XpmSuccess)
549 err_mess(FAILBUT, NULL);
552 if (Config.Verbose)
553 fprintf(stdout, "Leaving getPixmaps\n");
556 /*********************************************************************/
558 void SetWmHints()
560 XWMHints *xwmhints;
562 xwmhints = XAllocWMHints();
563 xwmhints->flags = WindowGroupHint | IconWindowHint | StateHint;
564 xwmhints->icon_window = iconwin;
565 xwmhints->window_group = win;
566 xwmhints->initial_state = WithdrawnState;
567 XSetWMHints(display, win, xwmhints);
568 XFree(xwmhints);
569 xwmhints = NULL;
572 void SetClassHints()
574 XClassHint xclasshint;
576 xclasshint.res_name = "wmbutton";
577 xclasshint.res_class = "Wmbutton";
578 XSetClassHint(display, win, &xclasshint);