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