1 /*
2 Best viewed with vim5, using ts=4
3
4 wmgeneral was taken from wmppp.
5
6 It has a lot of routines which most of the wm* programs use.
7
8 ------------------------------------------------------------
9
10 Author: Martijn Pieterse (pieterse@xs4all.nl)
11
12 ---
13 CHANGES:
14 ---
15 14/09/1998 (Dave Clark, clarkd@skyia.com)
16 * Updated createXBMfromXPM routine
17 * Now supports >256 colors
18 11/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
19 * Removed a bug from parse_rcfile. You could
20 not use "start" in a command if a label was
21 also start.
22 * Changed the needed geometry string.
23 We don't use window size, and don't support
24 negative positions.
25 03/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
26 * Added parse_rcfile2
27 02/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
28 * Added -geometry support (untested)
29 28/08/1998 (Martijn Pieterse, pieterse@xs4all.nl)
30 * Added createXBMfromXPM routine
31 * Saves a lot of work with changing xpm's.
32 02/05/1998 (Martijn Pieterse, pieterse@xs4all.nl)
33 * changed the read_rc_file to parse_rcfile, as suggested by Marcelo E. Magallon
34 * debugged the parse_rc file.
35 30/04/1998 (Martijn Pieterse, pieterse@xs4all.nl)
36 * Ripped similar code from all the wm* programs,
37 and put them in a single file.
38
39 */
40
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <ctype.h>
49 #include <stdarg.h>
50 #include <assert.h>
51
52 #include <X11/Xlib.h>
53 #ifdef HAVE_X11_XPM_H
54 #include <X11/xpm.h>
55 #endif
56 #ifdef HAVE_XPM_H
57 #include <xpm.h>
58 #endif
59 #include <X11/Xutil.h> /* needed for Region on solaris? */
60 #include <X11/extensions/shape.h>
61
62 #include "wmgeneral.h"
63
64 /*****************/
65 /* X11 Variables */
66 /*****************/
67
68 Display *display;
69 Window Root;
70 int screen;
71 int x_fd;
72 int d_depth;
73 XSizeHints mysizehints;
74 XWMHints mywmhints;
75 Pixel back_pix, fore_pix;
76 // static const char *Geometry = "";
77 Window iconwin, win;
78 GC NormalGC;
79 XpmIcon wmgen_bkg;
80 XpmIcon wmgen_src;
81 Pixmap pixmask;
82
83 /*****************/
84 /* Mouse Regions */
85 /*****************/
86
87 typedef struct {
88 int enable;
89 int top;
90 int bottom;
91 int left;
92 int right;
93 } MOUSE_REGION;
94
95 MOUSE_REGION mouse_region[MAX_MOUSE_REGION];
96
97 /***********************/
98 /* Function Prototypes */
99 /***********************/
100
101 static void GetXPM(XpmIcon *, const char **);
102 Pixel GetColor(const char *);
103 void RedrawWindow(void);
104 int CheckMouseRegion(int, int);
105
106 /*******************************************************************************\
107 |* parse_rcfile *|
108 \*******************************************************************************/
109
parse_rcfile(const char * filename,rckeys * keys)110 void parse_rcfile(const char *filename, rckeys * keys)
111 {
112
113 char *p, *q;
114 char temp[128];
115 const char *tokens = " :\t\n";
116 FILE *fp;
117 int i, key;
118
119 fp = fopen(filename, "r");
120 if (fp) {
121 while (fgets(temp, 128, fp)) {
122 key = 0;
123 char *t = strdup(temp);
124 q = strtok(t, tokens);
125 while (key >= 0 && keys[key].label) {
126 if ((!strcmp(q, keys[key].label))) {
127 p = strstr(temp, keys[key].label);
128 p += strlen(keys[key].label);
129 p += strspn(p, tokens);
130 if ((i = strcspn(p, "#\n")))
131 p[i] = 0;
132 free(*keys[key].var);
133 *keys[key].var = strdup(p);
134 key = -1;
135 } else
136 key++;
137 }
138 free(t);
139 }
140 fclose(fp);
141 }
142 }
143
144 /*******************************************************************************\
145 |* parse_rcfile2 *|
146 \*******************************************************************************/
147
parse_rcfile2(const char * filename,rckeys2 * keys)148 void parse_rcfile2(const char *filename, rckeys2 * keys)
149 {
150
151 char *p;
152 char temp[128];
153 const char *tokens = " :\t\n";
154 FILE *fp;
155 int i, key;
156 char *family = NULL;
157
158 fp = fopen(filename, "r");
159 if (fp) {
160 while (fgets(temp, 128, fp)) {
161 key = 0;
162 while (key >= 0 && keys[key].label) {
163 if ((p = strstr(temp, keys[key].label))) {
164 p += strlen(keys[key].label);
165 p += strspn(p, tokens);
166 if ((i = strcspn(p, "#\n")))
167 p[i] = 0;
168 free(*keys[key].var);
169 *keys[key].var = strdup(p);
170 key = -1;
171 } else
172 key++;
173 }
174 }
175 fclose(fp);
176 }
177 free(family);
178 }
179
180
181 /*******************************************************************************\
182 |* GetXPM *|
183 \*******************************************************************************/
184
GetXPM(XpmIcon * wmgen_local,const char * pixmap_bytes[])185 static void GetXPM(XpmIcon * wmgen_local, const char *pixmap_bytes[])
186 {
187
188 XWindowAttributes attributes;
189 int err;
190
191 /* For the colormap */
192 XGetWindowAttributes(display, Root, &attributes);
193 /* despite the comment, I still don't understand...
194 attributes is subsequently unused in this function -ns 11/2002 */
195
196 wmgen_local->attributes.valuemask |=
197 (XpmReturnPixels | XpmReturnExtensions);
198
199 err = XpmCreatePixmapFromData(display, Root, (char **) pixmap_bytes,
200 &(wmgen_local->pixmap),
201 &(wmgen_local->mask),
202 &(wmgen_local->attributes));
203
204 if (err != XpmSuccess) {
205 fprintf(stderr,
206 "Not enough free colorcells to create pixmap from data (err=%d).\n",
207 err);
208 exit(1);
209 }
210 }
211
212 /*******************************************************************************\
213 |* GetColor *|
214 \*******************************************************************************/
215
GetColor(const char * name)216 Pixel GetColor(const char *name)
217 {
218
219 XColor color;
220 XWindowAttributes attributes;
221
222 XGetWindowAttributes(display, Root, &attributes);
223
224 color.pixel = 0;
225 if (!XParseColor(display, attributes.colormap, name, &color)) {
226 fprintf(stderr, "wm.app: GetColor() can't parse %s.\n", name);
227 } else if (!XAllocColor(display, attributes.colormap, &color)) {
228 fprintf(stderr, "wm.app: GetColor() can't allocate %s.\n", name);
229 }
230 return color.pixel;
231 }
232
233 /*******************************************************************************\
234 |* flush_expose *|
235 \*******************************************************************************/
236
flush_expose(Window w)237 static int flush_expose(Window w)
238 {
239
240 XEvent dummy;
241 int i = 0;
242
243 while (XCheckTypedWindowEvent(display, w, Expose, &dummy))
244 i++;
245
246 return i;
247 }
248
249 /*******************************************************************************\
250 |* RedrawWindow *|
251 \*******************************************************************************/
252
RedrawWindow(void)253 void RedrawWindow(void)
254 {
255
256 flush_expose(iconwin);
257 XCopyArea(display, wmgen_bkg.pixmap, iconwin, NormalGC,
258 0, 0, wmgen_bkg.attributes.width,
259 wmgen_bkg.attributes.height, 0, 0);
260 flush_expose(win);
261 XCopyArea(display, wmgen_bkg.pixmap, win, NormalGC,
262 0, 0, wmgen_bkg.attributes.width,
263 wmgen_bkg.attributes.height, 0, 0);
264 }
265
266 /*******************************************************************************\
267 |* RedrawWindowXY *|
268 \*******************************************************************************/
269
RedrawWindowXY(int x,int y)270 void RedrawWindowXY(int x, int y)
271 {
272
273 flush_expose(iconwin);
274 XCopyArea(display, wmgen_bkg.pixmap, iconwin, NormalGC,
275 x, y, wmgen_bkg.attributes.width,
276 wmgen_bkg.attributes.height, 0, 0);
277 flush_expose(win);
278 XCopyArea(display, wmgen_bkg.pixmap, win, NormalGC,
279 x, y, wmgen_bkg.attributes.width,
280 wmgen_bkg.attributes.height, 0, 0);
281 }
282
283 /*******************************************************************************\
284 |* AddMouseRegion *|
285 \*******************************************************************************/
286
AddMouseRegion(unsigned int region_idx,int left,int top,int right,int bottom)287 void AddMouseRegion(unsigned int region_idx, int left, int top, int right,
288 int bottom)
289 {
290
291 if (region_idx < MAX_MOUSE_REGION) {
292 mouse_region[region_idx].enable = 1;
293 mouse_region[region_idx].top = top;
294 mouse_region[region_idx].left = left;
295 mouse_region[region_idx].bottom = bottom;
296 mouse_region[region_idx].right = right;
297 }
298 }
299
300 /*******************************************************************************\
301 |* CheckMouseRegion *|
302 \*******************************************************************************/
303
CheckMouseRegion(int x,int y)304 int CheckMouseRegion(int x, int y)
305 {
306
307 int i;
308 int found;
309
310 found = 0;
311
312 for (i = 0; i < MAX_MOUSE_REGION && !found; i++) {
313 if (mouse_region[i].enable &&
314 x <= mouse_region[i].right &&
315 x >= mouse_region[i].left &&
316 y <= mouse_region[i].bottom && y >= mouse_region[i].top)
317 found = 1;
318 }
319 if (!found)
320 return -1;
321 return (i - 1);
322 }
323
324 /*******************************************************************************\
325 |* createXBMfromXPM *|
326 \*******************************************************************************/
createXBMfromXPM(char * xbm,const char ** xpm,int sx,int sy)327 void createXBMfromXPM(char *xbm, const char **xpm, int sx, int sy)
328 {
329
330 int i, j, k;
331 int width, height, numcol, depth;
332 int zero = 0;
333 unsigned char bwrite;
334 int bcount;
335 int curpixel;
336
337 sscanf(*xpm, "%d %d %d %d", &width, &height, &numcol, &depth);
338
339
340 for (k = 0; k != depth; k++) {
341 zero <<= 8;
342 zero |= xpm[1][k];
343 }
344
345 for (i = numcol + 1; i < numcol + sy + 1; i++) {
346 bcount = 0;
347 bwrite = 0;
348 for (j = 0; j < sx * depth; j += depth) {
349 bwrite >>= 1;
350
351 curpixel = 0;
352 for (k = 0; k != depth; k++) {
353 curpixel <<= 8;
354 curpixel |= xpm[i][j + k];
355 }
356
357 if (curpixel != zero) {
358 bwrite += 128;
359 }
360 bcount++;
361 if (bcount == 8) {
362 *xbm = bwrite;
363 xbm++;
364 bcount = 0;
365 bwrite = 0;
366 }
367 }
368 }
369 }
370
371 /*******************************************************************************\
372 |* copyXPMArea *|
373 \*******************************************************************************/
374
copyXPMArea(int src_x,int src_y,int width,int height,int dest_x,int dest_y)375 void copyXPMArea(int src_x, int src_y, int width, int height, int dest_x,
376 int dest_y)
377 {
378
379 XCopyArea(display, wmgen_src.pixmap, wmgen_bkg.pixmap, NormalGC, src_x,
380 src_y, width, height, dest_x, dest_y);
381
382 }
383
384 /*******************************************************************************\
385 |* copyXBMArea *|
386 \*******************************************************************************/
387
copyXBMArea(int src_x,int src_y,int width,int height,int dest_x,int dest_y)388 void copyXBMArea(int src_x, int src_y, int width, int height, int dest_x,
389 int dest_y)
390 {
391
392 XCopyArea(display, wmgen_src.mask, wmgen_bkg.pixmap, NormalGC, src_x,
393 src_y, width, height, dest_x, dest_y);
394 }
395
396
397 /* added for wmbiff */
398 XFontStruct *f;
loadFont(const char * fontname)399 int loadFont(const char *fontname)
400 {
401 if (display != NULL) {
402 f = XLoadQueryFont(display, fontname);
403 if (f) {
404 XSetFont(display, NormalGC, f->fid);
405 return 0;
406 } else {
407 printf("couldn't set font!\n");
408 }
409 }
410 return -1;
411 }
412
drawString(int dest_x,int dest_y,const char * string,const char * colorname,const char * bgcolorname,int right_justify)413 void drawString(int dest_x, int dest_y, const char *string,
414 const char *colorname, const char *bgcolorname,
415 int right_justify)
416 {
417 int len = strlen(string);
418 assert(colorname != NULL);
419 XSetForeground(display, NormalGC, GetColor(colorname));
420 XSetBackground(display, NormalGC, GetColor(bgcolorname));
421 if (right_justify)
422 dest_x -= XTextWidth(f, string, len);
423 XDrawImageString(display, wmgen_bkg.pixmap, NormalGC, dest_x, dest_y,
424 string, len);
425 }
426
eraseRect(int x,int y,int x2,int y2,const char * bgcolorname)427 void eraseRect(int x, int y, int x2, int y2, const char *bgcolorname)
428 {
429 XSetForeground(display, NormalGC, GetColor(bgcolorname));
430 XFillRectangle(display, wmgen_bkg.pixmap, NormalGC, x, y, x2 - x,
431 y2 - y);
432 }
433
434 /* end wmbiff additions */
435
436 /*******************************************************************************\
437 |* setMaskXY *|
438 \*******************************************************************************/
439
setMaskXY(int x,int y)440 void setMaskXY(int x, int y)
441 {
442
443 XShapeCombineMask(display, win, ShapeBounding, x, y, pixmask,
444 ShapeSet);
445 XShapeCombineMask(display, iconwin, ShapeBounding, x, y, pixmask,
446 ShapeSet);
447 }
448
449 /*******************************************************************************\
450 |* openXwindow *|
451 \*******************************************************************************/
openXwindow(int argc,const char * argv[],const char * pixmap_bytes_bkg[],const char * pixmap_bytes_src[],char * pixmask_bits,int pixmask_width,int pixmask_height,int notWithdrawn)452 void openXwindow(int argc, const char *argv[],
453 const char *pixmap_bytes_bkg[],
454 const char *pixmap_bytes_src[], char *pixmask_bits,
455 int pixmask_width, int pixmask_height, int notWithdrawn)
456 {
457
458 unsigned int borderwidth = 1;
459 XClassHint classHint;
460 const char *display_name = NULL;
461 char *wname = strdup(argv[0]);
462 XTextProperty name;
463
464 XGCValues gcv;
465 unsigned long gcm;
466
467 const char *geometry = NULL;
468 char default_geometry[128];
469
470 int dummy = 0;
471 int i;
472
473 if (!wname) {
474 fprintf(stderr, "Unable to allocate memory for window name!\n");
475 abort();
476 }
477
478 for (i = 1; argv[i]; i++) {
479 if (!strcmp(argv[i], "-display") && i < argc - 1) {
480 display_name = argv[i + 1];
481 i++;
482 }
483 if (!strcmp(argv[i], "-geometry") && i < argc - 1) {
484 geometry = argv[i + 1];
485 i++;
486 }
487 }
488
489 sprintf(default_geometry, "%dx%d+0+0", pixmask_width, pixmask_height);
490
491 if (!(display = XOpenDisplay(display_name))) {
492 fprintf(stderr, "%s: can't open display %s\n",
493 wname, XDisplayName(display_name));
494 exit(1);
495 }
496 screen = DefaultScreen(display);
497 Root = RootWindow(display, screen);
498 d_depth = DefaultDepth(display, screen);
499 x_fd = XConnectionNumber(display);
500
501 /* Convert XPM to XImage */
502 GetXPM(&wmgen_bkg, pixmap_bytes_bkg);
503 GetXPM(&wmgen_src, pixmap_bytes_src);
504
505 /* Create a window to hold the stuff */
506 mysizehints.flags = USSize | USPosition;
507 mysizehints.x = 0;
508 mysizehints.y = 0;
509
510 back_pix = GetColor("black");
511 fore_pix = GetColor("cyan");
512
513 XWMGeometry(display, screen, geometry, default_geometry, borderwidth,
514 &mysizehints, &mysizehints.x, &mysizehints.y,
515 &mysizehints.width, &mysizehints.height, &dummy);
516
517 mysizehints.width = pixmask_width; /* changed 11/2002 for wmbiff non 64x64-ness */
518 mysizehints.height = pixmask_height; /* was statically 64. */
519
520 win = XCreateSimpleWindow(display, Root, mysizehints.x, mysizehints.y,
521 mysizehints.width, mysizehints.height,
522 borderwidth, fore_pix, back_pix);
523
524 iconwin =
525 XCreateSimpleWindow(display, win, mysizehints.x, mysizehints.y,
526 mysizehints.width, mysizehints.height,
527 borderwidth, fore_pix, back_pix);
528
529 /* Activate hints */
530 XSetWMNormalHints(display, win, &mysizehints);
531 classHint.res_name = wname;
532 classHint.res_class = wname;
533 XSetClassHint(display, win, &classHint);
534
535 /* Was PointerMotionMask instead of KeyPressMask, but pointer motion is irrelevant,
536 and if the user went to the trouble of giving us keypresses, the least we can do
537 is handle em... */
538 XSelectInput(display, win,
539 ButtonPressMask | ExposureMask | ButtonReleaseMask |
540 KeyPressMask | StructureNotifyMask);
541 XSelectInput(display, iconwin,
542 ButtonPressMask | ExposureMask | ButtonReleaseMask |
543 KeyPressMask | StructureNotifyMask);
544
545 /* wname is argv[0] */
546 if (XStringListToTextProperty(&wname, 1, &name) == 0) {
547 fprintf(stderr, "%s: can't allocate window name\n", wname);
548 exit(1);
549 }
550
551 XSetWMName(display, win, &name);
552 XFree(name.value);
553
554 /* Create GC for drawing */
555
556 gcm = GCForeground | GCBackground | GCGraphicsExposures;
557 gcv.foreground = fore_pix;
558 gcv.background = back_pix;
559 gcv.graphics_exposures = 0;
560 NormalGC = XCreateGC(display, Root, gcm, &gcv);
561
562 /* ONLYSHAPE ON */
563
564 pixmask =
565 XCreateBitmapFromData(display, win, pixmask_bits, pixmask_width,
566 pixmask_height);
567
568 XShapeCombineMask(display, win, ShapeBounding, 0, 0, pixmask,
569 ShapeSet);
570 XShapeCombineMask(display, iconwin, ShapeBounding, 0, 0, pixmask,
571 ShapeSet);
572
573 /* ONLYSHAPE OFF */
574
575 mywmhints.initial_state = WithdrawnState;
576 mywmhints.icon_window = iconwin;
577 mywmhints.icon_x = mysizehints.x;
578 mywmhints.icon_y = mysizehints.y;
579 mywmhints.window_group = win;
580 mywmhints.flags =
581 (notWithdrawn ? 0 : StateHint) | IconWindowHint |
582 IconPositionHint | WindowGroupHint;
583
584 XSetWMHints(display, win, &mywmhints);
585
586 XSetCommand(display, win, (char **) argv, argc);
587 XMapWindow(display, win);
588
589 if (geometry) {
590 /* we'll silently drop width and height as well as negative positions */
591 /* mostly because I don't know how to deal with them */
592 /*
593 int wx, wy, x, y;
594 int specified = XParseGeometry(geometry, &x, &y, &wx, &wy);
595 printf("%d %d %d %d\n", x, y, wx, wy);
596 if( specified & XNegative ) {
597 x = DisplayWidth(display, DefaultScreen(display)) - x - pixmask_width;
598 }
599 if( specified & YNegative ) {
600 y = DisplayHeight(display, DefaultScreen(display)) - y - pixmask_height;
601 }
602 if( specified & XValue || specified & YValue ) {
603 XMoveWindow(display, win, x, y);
604 } */
605
606 /*
607 if (sscanf(geometry, "+%d+%d", &wx, &wy) == 2) {
608 XMoveWindow(display, win, wx, wy);
609 } else if (sscanf(geometry, "%dx%d+%d+%d", &x, &y, &wx, &wy) == 4) {
610 XMoveWindow(display, win, wx, wy);
611 } else if (sscanf(geometry, "+%d-%d", &wx, &wy) == 2) {
612 XMoveWindow(display, win, wx, 0 - wy);
613 } else {
614 fprintf(stderr, "Unsupported geometry string '%s'\n",
615 geometry);
616 exit(1);
617 } */
618 }
619
620 if (wname)
621 free(wname);
622 }
623