wmcalc: Add icon for freedesktop.org icon themes.
[dockapps.git] / wmcp / wmcp.c
blob603078dd67bb9dd799be85d54168d9fcbff7d98e
2 /***********************************************************************
3 * Code is stol^H^H^H^Hbased on wmppp, wmload, and wmtme
5 * Author: Ben Cohen <buddog@aztec.asu.edu>
7 * Contributors:
8 * Thomas Nemeth <tnemeth@multimania.com> -- Pushed button highlighting
9 * Craig Maloney <craig@ic.net> -- CTRL + ALT + key option
12 * This program is distributed under the GPL license.
15 * Best viewed with tab = 4 ( in vi set ts=4 )
17 ***********************************************************************/
21 #define VERSION "Ver 1.2.8 -- May 25, 1999"
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
25 #include <X11/xpm.h>
26 #include <X11/extensions/shape.h>
27 #include <X11/keysym.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <math.h>
32 #include "backdrop.xpm"
33 #include "buttons.xpm"
34 #include "pushed_buttons.xpm"
35 #include "mask.xbm"
37 #define NO (0)
38 #define YES (1)
40 #define MAX_X_BUT 4
41 #define MAX_Y_BUT 4
44 /***********************************************************************
45 * Globals.. OK.. there's too many globals.. so sue me.
46 ***********************************************************************/
48 Display * display;
49 int screen;
50 Window rootwin, win, iconwin;
51 GC gc;
52 int depth;
53 Pixel bg_pixel, fg_pixel;
55 XSizeHints xsizehints;
56 XWMHints * xwmhints;
57 XClassHint xclasshint;
60 typedef struct _XpmIcon {
61 Pixmap pixmap;
62 Pixmap mask;
63 XpmAttributes attributes;
64 } XpmIcon;
67 Pixmap pixmask;
69 typedef struct _button_region {
70 int x,y;
71 int i,j;
72 } ButtonArea;
74 ButtonArea button_region[16];
76 XpmIcon template, visible, buttons, pbuttons;
78 unsigned int control = 0;
80 int numb_of_workspaces = 16; /* Number of buttons to display.
81 Initially set high. Changed by
82 -n switch or button 2or3 */
84 int N = 1; /* Button number pressed to goto WS */
85 int B = 1; /* Button number pressed to number WS's */
86 int alt_key_type = 1;
87 int border = 5;
88 int Verbose = 0;
90 char * app_name = "wmcp";
94 /***********************************************************************
95 * Function Prototypes
96 ***********************************************************************/
98 void switchToWorkspaceN( int workspace );
99 void redraw( int xbut, int ybut );
100 void getPixmaps();
101 int whichButton( int x, int y, int xbut, int ybut );
102 int flush_expose(Window w);
103 void show_usage();
110 /***********************************************************************
111 * main
112 ***********************************************************************/
114 int main( int argc, char ** argv )
116 XEvent report;
117 XGCValues xgcValues;
119 XTextProperty app_name_atom;
121 int dummy = 0;
122 int i;
123 int xbut = 2;
124 int ybut = 2;
126 int is_shaped = YES;
127 int window_state = WithdrawnState;
129 char Geometry_str[64] = "64x64+5+5";
130 char Display_str[64] = "";
133 /* Parse Command Line Arguments */
135 for ( i=1; i<argc; i++ ) {
136 if ( *argv[i] == '-' ) {
137 switch ( *(argv[i]+1) ) {
138 case 'v':
139 Verbose = 1;
140 break;
141 case 'g':
142 if ( ++i >= argc ) show_usage();
143 sscanf(argv[i], "%s", Geometry_str);
144 if ( Verbose ) printf("Geometry is: %s\n", Geometry_str);
145 break;
146 case 'd':
147 if ( ++i >= argc ) show_usage();
148 sscanf(argv[i], "%s", Display_str);
149 if ( Verbose ) printf("Display is: %s\n", Display_str);
150 break;
151 case 'n':
152 if ( ++i >= argc ) show_usage();
153 sscanf(argv[i], "%d", &numb_of_workspaces);
154 if ( Verbose )
155 printf("Numb of Workspaces: %d\n", numb_of_workspaces);
156 break;
157 case 's':
158 if ( ++i >= argc ) show_usage();
159 if ( *argv[i] == 'n' ) {
160 is_shaped = NO;
161 } else {
162 is_shaped = YES;
164 break;
165 case 'w':
166 if ( ++i >= argc ) show_usage();
167 switch ( *argv[i] ) {
168 case 'i':
169 window_state = IconicState;
170 break;
171 case 'w':
172 window_state = WithdrawnState;
173 break;
174 case 'n':
175 window_state = NormalState;
176 break;
178 break;
179 case 'x':
180 if ( ++i >= argc ) show_usage();
181 sscanf(argv[i], "%d", &xbut);
182 if ( xbut < 1 || xbut > MAX_X_BUT ) xbut = 3;
183 if ( Verbose ) printf("Num X buttons=%d\n", xbut);
184 break;
185 case 'y':
186 if ( ++i >= argc ) show_usage();
187 sscanf(argv[i], "%d", &ybut);
188 if ( ybut < 1 || ybut > MAX_Y_BUT ) ybut = 3;
189 if ( Verbose ) printf("Num Y buttons=%d\n", ybut);
190 break;
191 case 'a':
192 if ( ++i >= argc ) show_usage();
193 sscanf(argv[i], "%d", &alt_key_type);
194 if ( Verbose ) printf("Alt Key is: %d\n", alt_key_type);
195 break;
196 case 'c':
197 control=ControlMask;
198 if ( Verbose ) printf ("Control Key Modifier added\n");
199 break;
200 case 'h':
201 show_usage();
202 break;
213 if ( (display = XOpenDisplay(Display_str)) == NULL ) {
214 fprintf(stderr,"Fail: XOpenDisplay for %s\n", Display_str);
215 exit(-1);
219 screen = DefaultScreen(display);
220 rootwin = RootWindow(display,screen);
221 depth = DefaultDepth(display, screen);
223 bg_pixel = WhitePixel(display, screen );
224 fg_pixel = BlackPixel(display, screen );
228 xsizehints.flags = USSize | USPosition;
229 xsizehints.width = 64;
230 xsizehints.height = 64;
233 /* Parse Geometry string and fill in sizehints fields */
235 XWMGeometry(display, screen,
236 Geometry_str,
237 NULL,
238 border,
239 &xsizehints,
240 &xsizehints.x,
241 &xsizehints.y,
242 &xsizehints.width,
243 &xsizehints.height,
244 &dummy);
247 if ( (win = XCreateSimpleWindow(
248 display,
249 rootwin,
250 xsizehints.x,
251 xsizehints.y,
252 xsizehints.width,
253 xsizehints.height,
254 border,
255 fg_pixel, bg_pixel) ) == 0 ) {
256 fprintf(stderr,"Fail: XCreateSimpleWindow\n");
257 exit(-1);
260 if ( (iconwin = XCreateSimpleWindow(
261 display,
262 win,
263 xsizehints.x,
264 xsizehints.y,
265 xsizehints.width,
266 xsizehints.height,
267 border,
268 fg_pixel, bg_pixel) ) == 0 ) {
269 fprintf(stderr,"Fail: XCreateSimpleWindow\n");
270 exit(-1);
275 /* Set up shaped windows */
276 /* Gives the appicon a border so you can grab and move it. */
278 if ( is_shaped == YES ) {
279 if ( ( pixmask = XCreateBitmapFromData(display, win,
280 mask_bits, mask_width, mask_height) ) == 0 ) {
281 fprintf(stderr,"Fail: XCreateBitmapFromData\n");
284 XShapeCombineMask(display,win, ShapeBounding,0,0, pixmask,ShapeSet);
285 XShapeCombineMask(display,iconwin,ShapeBounding,0,0, pixmask,ShapeSet);
291 /* Convert in pixmaps from .xpm includes. */
292 getPixmaps();
297 /* Interclient Communication stuff */
298 /* Appicons don't work with out this stuff */
300 xwmhints = XAllocWMHints();
301 xwmhints->flags = WindowGroupHint | IconWindowHint | StateHint;
302 xwmhints->icon_window = iconwin;
303 xwmhints->window_group = win;
304 xwmhints->initial_state = window_state;
307 XSetWMHints( display, win, xwmhints );
309 xclasshint.res_name = "wmcp";
310 xclasshint.res_class = "WMcp";
311 XSetClassHint( display, win, &xclasshint );
313 XSetWMNormalHints( display, win, &xsizehints );
319 /* Tell window manager what the title bar name is. We never see */
320 /* this anyways in the WithdrawnState */
322 if ( XStringListToTextProperty(&app_name, 1, &app_name_atom) == 0 ) {
323 fprintf(stderr,"%s: Can't set up window name\n", app_name);
324 exit(-1);
326 XSetWMName( display, win, &app_name_atom );
330 /* Create Graphic Context */
332 if ( (gc = XCreateGC(
333 display,
334 win,
335 (GCForeground | GCBackground),
336 &xgcValues)) == NULL ) {
337 fprintf(stderr,"Fail: XCreateGC\n");
338 exit(-1);
345 /* XEvent Masks. We want both window to process X events */
347 XSelectInput(
348 display,
349 win,
350 ExposureMask |
351 ButtonPressMask |
352 PointerMotionMask |
353 StructureNotifyMask );
355 XSelectInput(
356 display,
357 iconwin,
358 ExposureMask |
359 ButtonPressMask |
360 PointerMotionMask |
361 StructureNotifyMask );
365 /* Store the 'state' of the application for restarting */
367 XSetCommand( display, win, argv, argc );
370 /* Window won't ever show up until it is mapped.. then drawn after a */
371 /* ConfigureNotify */
373 XMapWindow( display, win );
377 /* X Event Loop */
379 while (1) {
380 XNextEvent(display, &report );
381 switch (report.type) {
384 case Expose:
385 if (report.xexpose.count != 0) {
386 break;
388 if ( Verbose ) fprintf(stdout,"Event: Expose\n");
389 redraw( xbut, ybut );
390 break;
393 case ConfigureNotify:
394 if ( Verbose ) fprintf(stdout,"Event: ConfigureNotify\n");
395 redraw( xbut, ybut );
396 break;
399 case ButtonPress:
400 if ( Verbose )
401 printf ("numb_of_workspaces=%d\n", numb_of_workspaces);
402 switch (report.xbutton.button) {
403 case Button1:
404 N = whichButton(report.xbutton.x, report.xbutton.y, xbut, ybut );
405 if ( N >= 0 && N <= numb_of_workspaces ) {
406 switchToWorkspaceN( N );
407 redraw(xbut, ybut);
409 if ( Verbose )
410 fprintf(stdout,"Button 1:x=%d y=%d N=%d\n",
411 report.xbutton.x, report.xbutton.y, N);
412 break;
414 case Button2:
415 case Button3:
416 B = whichButton(report.xbutton.x, report.xbutton.y, xbut, ybut );
417 if ( B >= 0 && B <= 9 ) {
418 numb_of_workspaces = B;
419 redraw(xbut, ybut);
421 if ( Verbose )
422 fprintf(stdout,"Button 2or3:x=%d y=%d B=%d\n",
423 report.xbutton.x, report.xbutton.y, B);
424 break;
427 break;
430 case DestroyNotify:
431 if ( Verbose )
432 fprintf(stdout, "Bye\n");
433 XFreeGC(display, gc);
434 XDestroyWindow(display,win);
435 XDestroyWindow(display,iconwin);
436 XCloseDisplay(display);
437 if ( Verbose )
438 fprintf(stdout, "Bye\n");
439 exit(0);
440 break;
446 return (0);
451 /***********************************************************************
452 * redraw
454 * Map the button region coordinates.
456 * Draw the appropriate number of buttons on the 'visible' Pixmap
457 * using data from the 'buttons' pixmap.
459 * Then, copy the 'visible' pixmap to the two windows ( the withdrawn
460 * main window and the icon window which is the main window's icon image.)
462 ***********************************************************************/
464 void redraw( int xbut, int ybut )
466 int n;
467 int i,j;
468 int dest_x, dest_y; /* size of a whole button */
469 int step_x, step_y; /* size of half a button for corner copying */
471 int offset = 8; /* skip pixels past the window's border image */
473 int xbut_size;
474 int ybut_size;
477 xbut_size = 48 / xbut;
478 ybut_size = 48 / ybut;
481 XCopyArea( display,
482 template.pixmap, visible.pixmap,
484 0, 0,
485 template.attributes.width,
486 template.attributes.height,
487 0, 0 );
490 for ( j=0; j < ybut; j++ ) {
491 for ( i=0; i < xbut; i++ ) {
492 n = i + j * xbut;
494 dest_x = ( i * xbut_size ) + offset;
495 dest_y = ( j * ybut_size ) + offset;
496 step_x = 24 / xbut;
497 step_y = 24 / ybut;
499 /* Define button mouse coords */
501 button_region[n].x = dest_x;
502 button_region[n].y = dest_y;
503 button_region[n].i = dest_x + xbut_size - 1;
504 button_region[n].j = dest_y + ybut_size - 1;
507 /* Copy button images for valid workspaces */
509 if ( (n + 1) <= numb_of_workspaces ) {
511 /* Draw normal button */
512 /* Edited by Gert Beumer */
513 if ( (n + 1) != N ) {
515 /* upper left */
516 XCopyArea( display,
517 buttons.pixmap,
518 visible.pixmap,
520 0,0,
521 step_x, step_y,
522 dest_x,
523 dest_y);
524 /* lowwer left */
525 XCopyArea( display,
526 buttons.pixmap,
527 visible.pixmap,
529 0,48 - step_y,
530 step_x, step_y,
531 dest_x,
532 dest_y + step_y);
533 /* lowwer right */
534 XCopyArea( display,
535 buttons.pixmap,
536 visible.pixmap,
538 48 - step_x,48 - step_y,
539 step_x, step_y,
540 dest_x + step_x,
541 dest_y + step_y);
542 /* upper right */
543 XCopyArea( display,
544 buttons.pixmap,
545 visible.pixmap,
547 48 - step_x,0,
548 step_x, step_y,
549 dest_x + step_x,
550 dest_y);
552 /* Draw the numbers */
553 XCopyArea( display,
554 buttons.pixmap,
555 visible.pixmap,
557 n * 5,
559 5,5,
560 dest_x + (48 - xbut * 5) / (2 * xbut),
561 dest_y + (48 - ybut * 5) / (2 * ybut));
564 /* Draw pushed button */
565 /* Added by Thomas Nemeth, Edited by Gert Beumer */
566 if ( (n + 1) == N ) {
567 /* draw the four parts */
569 /* upper left */
570 XCopyArea( display,
571 pbuttons.pixmap,
572 visible.pixmap,
574 0,0,
575 step_x, step_y,
576 dest_x,
577 dest_y);
578 /* lowwer left */
579 XCopyArea( display,
580 pbuttons.pixmap,
581 visible.pixmap,
583 0,48 - step_y,
584 step_x, step_y,
585 dest_x,
586 dest_y + step_y);
587 /* lowwer right */
588 XCopyArea( display,
589 pbuttons.pixmap,
590 visible.pixmap,
592 48 - step_x,48 - step_y,
593 step_x, step_y,
594 dest_x + step_x,
595 dest_y + step_y);
596 /* upper right */
597 XCopyArea( display,
598 pbuttons.pixmap,
599 visible.pixmap,
601 48 - step_x,0,
602 step_x, step_y,
603 dest_x + step_x,
604 dest_y);
606 /* Draw the numbers */
607 XCopyArea( display,
608 pbuttons.pixmap,
609 visible.pixmap,
611 n * 5,
613 5,5,
614 dest_x + (48 - xbut * 5) / (2 * xbut),
615 dest_y + (48 - ybut * 5) / (2 * ybut));
623 flush_expose( win );
624 XCopyArea( display,
625 visible.pixmap, win, gc,
626 0, 0,
627 visible.attributes.width,
628 visible.attributes.height,
629 0, 0 );
631 flush_expose( iconwin );
632 XCopyArea( display,
633 visible.pixmap, iconwin, gc,
634 0, 0,
635 visible.attributes.width,
636 visible.attributes.height,
637 0, 0 );
640 if ( Verbose )
641 fprintf(stdout,"In Redraw()\n");
648 /***********************************************************************
649 * whichButton
651 * Return the button that at the x,y coordinates. The button need not
652 * be visible ( drawn ). Return -1 if no button match.
654 ***********************************************************************/
656 int whichButton( int x, int y, int xbut, int ybut )
658 int index;
660 for ( index=0; index< xbut*ybut; index++ ) {
661 if ( x >= button_region[index].x &&
662 x <= button_region[index].i &&
663 y >= button_region[index].y &&
664 y <= button_region[index].j ) {
665 return( index + 1 );
668 return(-1);
675 /***********************************************************************
676 * switchToWorkspaceN()
678 * Send the Synthetic Key Press event with the appropriate
679 * [ meta key + 1-4 key ] combo. Alt seems to usualy be Mod1Mask.
681 ***********************************************************************/
683 void switchToWorkspaceN( int workspace ) {
685 XEvent sendEvent;
687 sendEvent.xkey.type = KeyPress;
688 sendEvent.xkey.window = rootwin;
689 sendEvent.xkey.root = rootwin;
690 sendEvent.xkey.subwindow = 0x0;
691 switch ( alt_key_type ) {
692 case 1:
693 sendEvent.xkey.state = Mod1Mask+control;
694 break;
695 case 2:
696 sendEvent.xkey.state = Mod2Mask+control;
697 break;
698 case 3:
699 sendEvent.xkey.state = Mod3Mask+control;
700 break;
701 case 4:
702 sendEvent.xkey.state = Mod4Mask+control;
703 break;
705 sendEvent.xkey.keycode = XKeysymToKeycode(display, 0x30 + workspace );
706 sendEvent.xkey.same_screen = True;
707 sendEvent.xkey.display = display;
708 sendEvent.xkey.send_event = False;
710 XSendEvent( display, rootwin, True, KeyPressMask, &sendEvent );
714 /***********************************************************************
715 * getPixmaps
717 * Load XPM data into X Pixmaps.
719 * Pixmap template contains the untouched window backdrop image.
720 * Pixmap visible is the template pixmap with buttons drawn on it.
721 * -- what is seen by the user.
722 * Pixmap buttons holds the images for individual buttons that are
723 * later copied onto Pixmap visible.
724 ***********************************************************************/
725 void getPixmaps()
728 template.attributes.valuemask |=
729 (XpmReturnPixels | XpmReturnExtensions);
730 visible.attributes.valuemask |=
731 (XpmReturnPixels | XpmReturnExtensions);
732 buttons.attributes.valuemask |=
733 (XpmReturnPixels | XpmReturnExtensions);
735 /* Template Pixmap. Never Drawn To. */
736 if ( XpmCreatePixmapFromData( display,
737 rootwin,
738 backdrop_xpm,
739 &template.pixmap,
740 &template.mask,
741 &template.attributes) != XpmSuccess ) {
742 fprintf(stderr, "Can't Create 'template' Pixmap");
743 exit(1);
746 /* Visible Pixmap. Copied from template Pixmap and then drawn to. */
747 if ( XpmCreatePixmapFromData( display,
748 rootwin,
749 backdrop_xpm,
750 &visible.pixmap,
751 &visible.mask,
752 &visible.attributes) != XpmSuccess ) {
753 fprintf(stderr, "Can't Create 'visible' Pixmap");
754 exit(1);
757 /* Buttons Pixmap. */
758 if ( XpmCreatePixmapFromData( display,
759 rootwin,
760 buttons_xpm,
761 &buttons.pixmap,
762 &buttons.mask,
763 &buttons.attributes) != XpmSuccess ) {
764 fprintf(stderr, "Can't Create 'buttons' Pixmap");
765 exit(1);
768 /* Pushed Buttons Pixmap. */
769 if ( XpmCreatePixmapFromData( display,
770 rootwin,
771 pushed_buttons_xpm,
772 &pbuttons.pixmap,
773 &pbuttons.mask,
774 &pbuttons.attributes) != XpmSuccess ) {
775 fprintf(stderr, "Can't Create 'pbuttons' Pixmap");
776 exit(1);
784 /***********************************************************************
785 * flush_expose
787 * Everyone else has one of these... Can't hurt to throw it in.
789 ***********************************************************************/
790 int flush_expose(Window w) {
792 XEvent dummy;
793 int i=0;
795 while (XCheckTypedWindowEvent(display, w, Expose, &dummy))
796 i++;
798 return i;
802 /***********************************************************************
803 * show_usage
805 ***********************************************************************/
807 void show_usage()
810 fprintf(stderr,"\n\
812 %s\n\
813 This software is GPL -- do as you wish with it.\n\
815 Origional Author:\n\
816 Ben Cohen <buddog@aztec.asu.edu>\n\
818 Contributors:\n\
819 Thomas Nemeth <tnemeth@multimania.com>\n\
820 Craig Maloney <craig@ic.net>\n\
821 Gert Beumer <Gert@scintilla.utwente.nl>\n\
825 usage: wmcp [-g geometry] [-d dpy] [-n workspaces] [-a alt key] [-v]\n\
826 [-c] [-w i/n/w] [-s y/n] [-x #] [-y #] [-h]\n\
829 -g geometry: ie: 64x64+10+10\n\
830 -d dpy: Display. ie: 127.0.0.1:0.0\n\
831 -n workspaces: How many buttons to start with.\n\
832 -a alt key: integer 1-4 defining ModXMask (default 1 Mod1Mask).\n\
833 -w i/n/w: Window State: Iconic, Normal, Withdrawn (default Withdrawn)\n\
834 -s y/n: Shaped window: yes or no (default y)\n\
835 -c Sends CTRL + ALT + Key (default only sends ALT + key)\n\
836 -v Verbose. 0=off, 1=on (default 0)\n\
837 -x Number of buttons on the x-direction (1,2,3, or 4)\n\
838 -y Number of buttons in the y-direction (1,2,3, or 4)\n\
839 -h Help. This screen.\n\
842 ",VERSION);
844 exit(-1);
849 KeyPress event, serial 13, synthetic NO, window 0x25,
850 root 0x25, subw 0x0, time 3340683384, (37,254), root:(37,254),
851 state 0x8, keycode 10 (keysym 0x31, 1), same_screen YES,
852 XLookupString gives 1 characters: "1"
854 KeyPress event, serial 13, synthetic YES, window 0xbffff9ac,
855 root 0x40009b48, subw 0x4000a670, time 2, (26460,-1352), root:(-1146,7),
856 state 0x7de0, keycode 64 (keysym 0xffe9, Alt_L), same_screen YES,
857 XLookupString gives 0 characters: ""