wmbutton dockapp added
[dockapps.git] / wmbutton / wmbutton.c
bloba2e46ac5c924243162f5331316426838515d6f31
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;
99 Pixmap pixmask;
101 int dummy = 0;
102 int N = 1; /* Button number pressed to goto app # */
104 /* Added for Tool Tip Support */
105 long nTooltipShowDelay = TOOLTIP_SHOW_DELAY;
106 long nTooltipReshowDelay = TOOLTIP_RESHOW_DELAY;
107 long nTooltipTimer = -1;
108 long nTooltipHideTimer = -1;
109 long nNow;
110 int nTooltipButton = 0, nTooltipX = 0, nTooltipY = 0;
112 /* Parse Command Line Arguments */
113 parseargs(argc, argv);
115 /* Open Display */
116 if ( (display = XOpenDisplay(Config.Display_str)) == NULL )
117 err_mess(FAILDISP, Config.Display_str);
119 screen = DefaultScreen(display);
120 rootwin = RootWindow(display,screen);
121 depth = DefaultDepth(display, screen);
123 bg_pixel = WhitePixel(display, screen );
124 fg_pixel = BlackPixel(display, screen );
126 xsizehints.flags = USSize | USPosition;
127 xsizehints.width = 64;
128 xsizehints.height = 64;
130 /* Parse Geometry string and fill in sizehints fields */
131 XWMGeometry(display, screen,
132 Config.Geometry_str,
133 NULL,
134 border,
135 &xsizehints,
136 &xsizehints.x,
137 &xsizehints.y,
138 &xsizehints.width,
139 &xsizehints.height,
140 &dummy);
142 if ( (win = XCreateSimpleWindow(display,
143 rootwin,
144 xsizehints.x,
145 xsizehints.y,
146 xsizehints.width,
147 xsizehints.height,
148 border,
149 fg_pixel, bg_pixel) ) == 0 )
150 err_mess(FAILSWIN, NULL);
153 if ( (iconwin = XCreateSimpleWindow(display,
154 win,
155 xsizehints.x,
156 xsizehints.y,
157 xsizehints.width,
158 xsizehints.height,
159 border,
160 fg_pixel, bg_pixel) ) == 0 )
161 err_mess(FAILICON, NULL);
163 /* Set up shaped windows */
164 /*Gives the appicon a border so you can grab and move it. */
166 if ( ( pixmask = XCreateBitmapFromData(display,
167 win,
168 mask_bits,
169 mask_width,
170 mask_height) ) == 0 )
171 err_mess(FAILXPM,NULL);
174 XShapeCombineMask(display, win, ShapeBounding, 0, 0, pixmask, ShapeSet );
175 XShapeCombineMask(display, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet);
177 /* Convert in pixmaps from .xpm includes. */
178 getPixmaps();
180 /* Interclient Communication stuff */
181 /* Appicons don't work with out this stuff */
182 SetWmHints();
183 SetClassHints();
186 XSetWMNormalHints( display, win, &xsizehints );
188 /* Tell window manager what the title bar name is. We never see */
189 /* this anyways in the WithdrawnState */
190 if ( XStringListToTextProperty(&app_name, 1, &app_name_atom) == 0 )
191 err_mess(FAILWNAM,app_name);
192 XSetWMName( display, win, &app_name_atom );
194 /* Create Graphic Context */
195 if (( gc = XCreateGC(display, win,(GCForeground | GCBackground), &xgcValues))
196 == NULL )
197 err_mess(FAILGC,NULL);
199 /* XEvent Masks. We want both window to process X events */
200 XSelectInput(display, win,
201 ExposureMask |
202 ButtonPressMask |
203 ButtonReleaseMask | /* added ButtonReleaseMask *charkins*/
204 PointerMotionMask |
205 StructureNotifyMask |
206 LeaveWindowMask );
207 XSelectInput(display, iconwin,
208 ExposureMask |
209 ButtonPressMask |
210 ButtonReleaseMask | /* added ButtonReleaseMask *charkins*/
211 PointerMotionMask |
212 StructureNotifyMask |
213 LeaveWindowMask );
215 /* Store the 'state' of the application for restarting */
216 XSetCommand( display, win, argv, argc );
218 /* Window won't ever show up until it is mapped.. then drawn after a */
219 /* ConfigureNotify */
220 XMapWindow( display, win );
222 /* Initialize Tooltip Support */
223 initTime();
224 initTooltip(!Config.bTooltipDisable, Config.szTooltipFont, Config.bTooltipSwapColors);
226 /* X Event Loop */
227 while (1) {
228 while (XPending(display) || nTooltipTimer == -1) {
229 XNextEvent(display, &report );
230 switch (report.type) {
231 case Expose:
232 if (report.xexpose.count != 0) {
233 break;
235 if ( Config.Verbose ) fprintf(stdout,"Event: Expose\n");
236 redraw();
237 break;
239 case ConfigureNotify:
240 if ( Config.Verbose ) fprintf(stdout,"Event: ConfigureNotify\n");
241 redraw();
242 break;
244 case MotionNotify:
245 if (hasTooltipSupport()) {
246 if (!hasTooltip()) {
247 nTooltipTimer= currentTimeMillis();
248 nTooltipX= report.xbutton.x;
249 nTooltipY= report.xbutton.y;
250 nTooltipButton= whichButton(report.xbutton.x, report.xbutton.y);
251 } else {
252 int nButton = whichButton(report.xbutton.x, report.xbutton.y);
253 if (nButton != nTooltipButton) {
254 hideTooltip();
255 nTooltipTimer= -1;
256 nTooltipX = report.xbutton.x;
257 nTooltipY = report.xbutton.y;
258 nTooltipButton = nButton;
259 showTooltip(nTooltipButton, nTooltipX, nTooltipY);
263 break;
265 case LeaveNotify:
266 if ( Config.Verbose ) fprintf(stdout,"Event: LeaveNotify\n");
267 if (hasTooltip()) {
268 hideTooltip();
269 nTooltipHideTimer= currentTimeMillis();
271 nTooltipTimer= -1;
272 break;
274 case ButtonPress: /* draw button pressed, don't launch *charkins*/
275 if (hasTooltip()) {
276 hideTooltip();
277 nTooltipHideTimer= currentTimeMillis();
278 } switch (report.xbutton.button) {
279 case Button1:
280 N = whichButton(report.xbutton.x, report.xbutton.y );
281 if ( (N >= 0) && (N <= NUMB_OF_APPS) ) {
282 button_pressed = N + LMASK;
283 redraw();
286 if ( Config.Verbose )
287 fprintf(stdout,"Button 1:x=%d y=%d N=%d\n",
288 report.xbutton.x, report.xbutton.y, N+LMASK);
290 break;
291 case Button2:
292 if (Config.mmouse) {
293 N = whichButton(report.xbutton.x, report.xbutton.y );
294 if ( (N >= 0) && (N <= NUMB_OF_APPS) ) {
295 button_pressed = N + MMASK;
296 redraw();
299 if ( Config.Verbose )
300 fprintf(stdout,"Button 2:x=%d y=%d N=%d\n",
301 report.xbutton.x, report.xbutton.y, N+MMASK);
304 break;
305 case Button3:
306 N = whichButton(report.xbutton.x, report.xbutton.y );
307 if ( (N >= 0) && (N <= NUMB_OF_APPS) ) {
308 button_pressed = N + RMASK;
309 redraw();
312 if ( Config.Verbose )
313 fprintf(stdout,"Button 3:x=%d y=%d N=%d\n",
314 report.xbutton.x, report.xbutton.y, N+RMASK);
316 break;
318 break;
319 case ButtonRelease: /* launch app here if still over button *charkins*/
320 switch (report.xbutton.button) {
321 case Button1:
322 N = whichButton(report.xbutton.x, report.xbutton.y );
323 if ( (N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed))
324 RunAppN( N + LMASK);
325 button_pressed=-1;
326 redraw();
328 if ( Config.Verbose )
329 fprintf(stdout,"Button 1:x=%d y=%d N=%d\n",
330 report.xbutton.x, report.xbutton.y, N+LMASK);
332 break;
333 case Button2:
334 if (Config.mmouse) {
335 N = whichButton(report.xbutton.x, report.xbutton.y );
336 if ( (N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed))
337 RunAppN( N + MMASK);
338 button_pressed=-1;
339 redraw();
341 if ( Config.Verbose )
342 fprintf(stdout,"Button 2:x=%d y=%d N=%d\n",
343 report.xbutton.x, report.xbutton.y, N+MMASK);
346 break;
347 case Button3:
348 N = whichButton(report.xbutton.x, report.xbutton.y );
349 if ( (N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed))
350 RunAppN( N + RMASK);
351 button_pressed=-1;
352 redraw();
354 if ( Config.Verbose )
355 fprintf(stdout,"Button 3:x=%d y=%d N=%d\n",
356 report.xbutton.x, report.xbutton.y, N+RMASK);
358 break;
360 break;
361 case DestroyNotify:
363 if ( Config.Verbose ) fprintf(stdout, "Bye\n");
365 destroyTooltip();
366 XFreeGC(display, gc);
367 XDestroyWindow(display,win);
368 XDestroyWindow(display,iconwin);
369 XCloseDisplay(display);
370 exit(0);
371 break;
375 usleep(50000);
376 nNow = currentTimeMillis();
377 if ( nTooltipTimer != -1 &&
378 ( (nNow > nTooltipTimer + nTooltipShowDelay) || (nNow < nTooltipHideTimer + nTooltipReshowDelay) ) ) {
379 showTooltip(nTooltipButton, nTooltipX, nTooltipY);
380 nTooltipTimer = -1;
385 return (0);
386 }/***********************************************************************/
388 /***********************************************************************
389 * redraw
391 * Map the button region coordinates.
393 * Draw the appropriate number of buttons on the 'visible' Pixmap
394 * using data from the 'buttons' pixmap.
396 * Then, copy the 'visible' pixmap to the two windows ( the withdrawn
397 * main window and the icon window which is the main window's icon image.)
398 ***********************************************************************/
399 void redraw() {
400 int n;
401 int i,j;
402 int dest_x, dest_y;
403 int space;
404 int offset;
405 int bsize = 18;
407 if ( Config.Verbose ) fprintf(stdout,"In Redraw()\n");
408 space = 0;
409 offset = 5;
410 XCopyArea(display, template.pixmap, visible.pixmap, gc, 0, 0,
411 template.attributes.width, template.attributes.height, 0, 0 );
413 for ( j=0; j < 3; j++ ) {
414 for ( i=0; i < 3; i++ ) {
415 n = i + j * 3;
416 dest_x = i*(bsize + space) + offset + space;
417 dest_y = j*(bsize + space) + offset + space;
419 /* Define button mouse coords */
420 button_region[n].x = dest_x;
421 button_region[n].y = dest_y;
422 button_region[n].i = dest_x + bsize - 1;
423 button_region[n].j = dest_y + bsize - 1;
425 /* Copy button images for valid apps */
426 if ( (n + 1) <= NUMB_OF_APPS ) {
427 XCopyArea(display, buttons.pixmap, visible.pixmap, gc,
428 i * bsize, j * bsize, bsize, bsize, dest_x, dest_y);
433 if ( button_pressed>0 ) { /* draw pressed button *charkins*/
434 if(button_pressed>RMASK) button_pressed-=RMASK;
435 else if(button_pressed>MMASK) button_pressed-=MMASK;
436 else if(button_pressed>LMASK) button_pressed-=LMASK;
437 i = (button_pressed-1) % 3; /* get col of button */
438 j = (button_pressed-1) / 3; /* get row of button */
439 dest_x = i * (bsize + space) + offset + space;
440 dest_y = j * (bsize + space) + offset + space;
441 XSetForeground(display, gc, bg_pixel);
442 XDrawLine(display, visible.pixmap, gc,
443 dest_x+1, dest_y+bsize-1, dest_x+bsize-1, dest_y+bsize-1);
444 XDrawLine(display, visible.pixmap, gc,
445 dest_x+bsize-1, dest_y+bsize-1, dest_x+bsize-1, dest_y+1);
446 XSetForeground(display, gc, fg_pixel);
447 XDrawLine(display, visible.pixmap, gc,
448 dest_x, dest_y, dest_x+bsize-2, dest_y);
449 XDrawLine(display, visible.pixmap, gc,
450 dest_x, dest_y, dest_x, dest_y+bsize-2);
451 } /*charkins*/
453 flush_expose( win );
454 XCopyArea(display, visible.pixmap, win, gc, 0, 0,
455 visible.attributes.width, visible.attributes.height, 0, 0 );
456 flush_expose( iconwin );
457 XCopyArea(display, visible.pixmap, iconwin, gc, 0, 0,
458 visible.attributes.width, visible.attributes.height, 0, 0 );
460 }/***********************************************************************/
462 /***********************************************************************
463 * whichButton
465 * Return the button that at the x,y coordinates. The button need not
466 * be visible ( drawn ). Return -1 if no button match.
467 ***********************************************************************/
468 int whichButton( int x, int y ) {
469 int index;
471 for ( index=0; index < NUMB_OF_APPS; index++ ) {
472 if ( x >= button_region[index].x &&
473 x <= button_region[index].i &&
474 y >= button_region[index].y &&
475 y <= button_region[index].j ) {
476 return( index + 1);
479 return(-1);
480 }/***********************************************************************/
483 /***********************************************************************
484 * getPixmaps
486 * Load XPM data into X Pixmaps.
488 * Pixmap template contains the untouched window backdrop image.
489 * Pixmap visible is the template pixmap with buttons drawn on it.
490 * -- what is seen by the user.
491 * Pixmap buttons holds the images for individual buttons that are
492 * later copied onto Pixmap visible.
493 ***********************************************************************/
494 void getPixmaps() {
495 int loaded = 0;
496 template.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
497 visible.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
498 buttons.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
501 if (Config.Verbose) fprintf(stdout, "In getPixmaps\n");
502 /* Template Pixmap. Never Drawn To. */
503 if ( XpmCreatePixmapFromData( display, rootwin, backdrop_xpm,
504 &template.pixmap, &template.mask,
505 &template.attributes) != XpmSuccess )
506 err_mess(FAILTMPL, NULL);
508 /* Visible Pixmap. Copied from template Pixmap and then drawn to. */
509 if ( XpmCreatePixmapFromData( display, rootwin, backdrop_xpm,
510 &visible.pixmap, &visible.mask,
511 &visible.attributes) != XpmSuccess )
512 err_mess(FAILVIS, NULL);
514 /* Button Pixmap. */
515 if ( access( Config.buttonfile, R_OK ) == 0 ) {
516 /* load buttons from file */
517 if ( XpmReadFileToPixmap( display, rootwin, Config.buttonfile,
518 &buttons.pixmap, &buttons.mask,
519 &buttons.attributes) != XpmSuccess ) {
520 err_mess(FAILBUT, NULL);
521 } else {
522 loaded = 1;
525 if (! loaded) {
526 /* Use Builtin Button Pixmap. */
527 if (Config.Verbose) fprintf(stdout, "Using builtin buttons pixmap\n");
528 if ( XpmCreatePixmapFromData( display, rootwin, buttons_xpm,
529 &buttons.pixmap, &buttons.mask,
530 &buttons.attributes) != XpmSuccess )
531 err_mess(FAILBUT, NULL);
533 if (Config.Verbose) fprintf(stdout, "Leaving getPixmaps\n");
535 }/*********************************************************************/
537 void SetWmHints() {
538 XWMHints *xwmhints;
540 xwmhints = XAllocWMHints();
541 xwmhints->flags = WindowGroupHint | IconWindowHint | StateHint;
542 xwmhints->icon_window = iconwin;
543 xwmhints->window_group = win;
544 xwmhints->initial_state = WithdrawnState;
545 XSetWMHints( display, win, xwmhints );
546 XFree(xwmhints);
547 xwmhints = NULL;
550 void SetClassHints() {
551 XClassHint xclasshint;
553 xclasshint.res_name = "wmbutton";
554 xclasshint.res_class = "Wmbutton";
555 XSetClassHint( display, win, &xclasshint );