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 	05/02/2002 (Remi Broemeling, remi@penguinscratch.com)
16 	        * Added check so that -display or -geometry with no arguments at the
17                   end of argv doesn't case a seg fault.
18         14/09/1998 (Dave Clark, clarkd@skyia.com)
19                 * Updated createXBMfromXPM routine
20                 * Now supports >256 colors
21 	11/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
22 		* Removed a bug from parse_rcfile. You could
23 		  not use "start" in a command if a label was
24 		  also start.
25 		* Changed the needed geometry string.
26 		  We don't use window size, and don't support
27 		  negative positions.
28 	03/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
29 		* Added parse_rcfile2
30 	02/09/1998 (Martijn Pieterse, pieterse@xs4all.nl)
31 		* Added -geometry support (untested)
32 	28/08/1998 (Martijn Pieterse, pieterse@xs4all.nl)
33 		* Added createXBMfromXPM routine
34 		* Saves a lot of work with changing xpm's.
35 	02/05/1998 (Martijn Pieterse, pieterse@xs4all.nl)
36 		* changed the read_rc_file to parse_rcfile, as suggested by Marcelo E. Magallon
37 		* debugged the parse_rc file.
38 	30/04/1998 (Martijn Pieterse, pieterse@xs4all.nl)
39 		* Ripped similar code from all the wm* programs,
40 		  and put them in a single file.
41 
42 */
43 
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 
51 #include <X11/Xlib.h>
52 #include <X11/xpm.h>
53 #include <X11/extensions/shape.h>
54 
55 #include "wmgeneral.h"
56 
57   /*****************/
58  /* X11 Variables */
59 /*****************/
60 
61 Window		Root;
62 int			screen;
63 int			x_fd;
64 int			d_depth;
65 XSizeHints	mysizehints;
66 XWMHints	mywmhints;
67 Pixel		back_pix, fore_pix;
68 char		*Geometry = "";
69 Window		iconwin, win;
70 GC			NormalGC;
71 XpmIcon		wmgen;
72 Pixmap		pixmask;
73 
74   /*****************/
75  /* Mouse Regions */
76 /*****************/
77 
78 typedef struct {
79 	int		enable;
80 	int		top;
81 	int		bottom;
82 	int		left;
83 	int		right;
84 } MOUSE_REGION;
85 
86 MOUSE_REGION	mouse_region[MAX_MOUSE_REGION];
87 
88   /***********************/
89  /* Function Prototypes */
90 /***********************/
91 
92 static void GetXPM(XpmIcon *, char **);
93 static Pixel GetColor(char *);
94 void RedrawWindow(void);
95 void AddMouseRegion(int, int, int, int, int);
96 int CheckMouseRegion(int, int);
97 
98 /*******************************************************************************\
99 |* parse_rcfile																   *|
100 \*******************************************************************************/
101 
parse_rcfile(const char * filename,rckeys * keys)102 void parse_rcfile(const char *filename, rckeys *keys) {
103 
104 	char	*p,*q;
105 	char	temp[128];
106 	char	*tokens = " :\t\n";
107 	FILE	*fp;
108 	int		i,key;
109 
110 	fp = fopen(filename, "r");
111 	if (fp) {
112 		while (fgets(temp, 128, fp)) {
113 			key = 0;
114 			q = strdup(temp);
115 			q = strtok(q, tokens);
116 			while (key >= 0 && keys[key].label) {
117 				if ((!strcmp(q, keys[key].label))) {
118 					p = strstr(temp, keys[key].label);
119 					p += strlen(keys[key].label);
120 					p += strspn(p, tokens);
121 					if ((i = strcspn(p, "#\n"))) p[i] = 0;
122 					free(*keys[key].var);
123 					*keys[key].var = strdup(p);
124 					key = -1;
125 				} else key++;
126 			}
127 			free(q);
128 		}
129 		fclose(fp);
130 	}
131 }
132 
133 /*******************************************************************************\
134 |* parse_rcfile2															   *|
135 \*******************************************************************************/
136 
parse_rcfile2(const char * filename,rckeys2 * keys)137 void parse_rcfile2(const char *filename, rckeys2 *keys) {
138 
139 	char	*p;
140 	char	temp[128];
141 	char	*tokens = " :\t\n";
142 	FILE	*fp;
143 	int		i,key;
144 	char	*family = NULL;
145 
146 	fp = fopen(filename, "r");
147 	if (fp) {
148 		while (fgets(temp, 128, fp)) {
149 			key = 0;
150 			while (key >= 0 && keys[key].label) {
151 				if ((p = strstr(temp, keys[key].label))) {
152 					p += strlen(keys[key].label);
153 					p += strspn(p, tokens);
154 					if ((i = strcspn(p, "#\n"))) p[i] = 0;
155 					free(*keys[key].var);
156 					*keys[key].var = strdup(p);
157 					key = -1;
158 				} else key++;
159 			}
160 		}
161 		fclose(fp);
162 	}
163 	free(family);
164 }
165 
166 
167 /*******************************************************************************\
168 |* GetXPM																	   *|
169 \*******************************************************************************/
170 
GetXPM(XpmIcon * wmgen,char * pixmap_bytes[])171 static void GetXPM(XpmIcon *wmgen, char *pixmap_bytes[]) {
172 
173 	XWindowAttributes	attributes;
174 	int					err;
175 
176 	/* For the colormap */
177 	XGetWindowAttributes(display, Root, &attributes);
178 
179 	wmgen->attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
180 
181 	err = XpmCreatePixmapFromData(display, Root, pixmap_bytes, &(wmgen->pixmap),
182 					&(wmgen->mask), &(wmgen->attributes));
183 
184 	if (err != XpmSuccess) {
185 		fprintf(stderr, "Not enough free colorcells.\n");
186 		exit(1);
187 	}
188 }
189 
190 /*******************************************************************************\
191 |* GetColor																	   *|
192 \*******************************************************************************/
193 
GetColor(char * name)194 static Pixel GetColor(char *name) {
195 
196 	XColor				color;
197 	XWindowAttributes	attributes;
198 
199 	XGetWindowAttributes(display, Root, &attributes);
200 
201 	color.pixel = 0;
202 	if (!XParseColor(display, attributes.colormap, name, &color)) {
203 		fprintf(stderr, "wm.app: can't parse %s.\n", name);
204 	} else if (!XAllocColor(display, attributes.colormap, &color)) {
205 		fprintf(stderr, "wm.app: can't allocate %s.\n", name);
206 	}
207 	return color.pixel;
208 }
209 
210 /*******************************************************************************\
211 |* flush_expose																   *|
212 \*******************************************************************************/
213 
flush_expose(Window w)214 static int flush_expose(Window w) {
215 
216 	XEvent 		dummy;
217 	int			i=0;
218 
219 	while (XCheckTypedWindowEvent(display, w, Expose, &dummy))
220 		i++;
221 
222 	return i;
223 }
224 
225 /*******************************************************************************\
226 |* RedrawWindow																   *|
227 \*******************************************************************************/
228 
RedrawWindow(void)229 void RedrawWindow(void) {
230 
231 	flush_expose(iconwin);
232 	XCopyArea(display, wmgen.pixmap, iconwin, NormalGC,
233 				0,0, wmgen.attributes.width, wmgen.attributes.height, 0,0);
234 	flush_expose(win);
235 	XCopyArea(display, wmgen.pixmap, win, NormalGC,
236 				0,0, wmgen.attributes.width, wmgen.attributes.height, 0,0);
237 }
238 
239 /*******************************************************************************\
240 |* RedrawWindowXY															   *|
241 \*******************************************************************************/
242 
RedrawWindowXY(int x,int y)243 void RedrawWindowXY(int x, int y) {
244 
245 	flush_expose(iconwin);
246 	XCopyArea(display, wmgen.pixmap, iconwin, NormalGC,
247 				x,y, wmgen.attributes.width, wmgen.attributes.height, 0,0);
248 	flush_expose(win);
249 	XCopyArea(display, wmgen.pixmap, win, NormalGC,
250 				x,y, wmgen.attributes.width, wmgen.attributes.height, 0,0);
251 }
252 
253 /*******************************************************************************\
254 |* AddMouseRegion															   *|
255 \*******************************************************************************/
256 
AddMouseRegion(int index,int left,int top,int right,int bottom)257 void AddMouseRegion(int index, int left, int top, int right, int bottom) {
258 
259 	if (index < MAX_MOUSE_REGION) {
260 		mouse_region[index].enable = 1;
261 		mouse_region[index].top = top;
262 		mouse_region[index].left = left;
263 		mouse_region[index].bottom = bottom;
264 		mouse_region[index].right = right;
265 	}
266 }
267 
268 /*******************************************************************************\
269 |* CheckMouseRegion															   *|
270 \*******************************************************************************/
271 
CheckMouseRegion(int x,int y)272 int CheckMouseRegion(int x, int y) {
273 
274 	int		i;
275 	int		found;
276 
277 	found = 0;
278 
279 	for (i=0; i<MAX_MOUSE_REGION && !found; i++) {
280 		if (mouse_region[i].enable &&
281 			x <= mouse_region[i].right &&
282 			x >= mouse_region[i].left &&
283 			y <= mouse_region[i].bottom &&
284 			y >= mouse_region[i].top)
285 			found = 1;
286 	}
287 	if (!found) return -1;
288 	return (i-1);
289 }
290 
291 /*******************************************************************************\
292 |* createXBMfromXPM															   *|
293 \*******************************************************************************/
createXBMfromXPM(char * xbm,char ** xpm,int sx,int sy)294 void createXBMfromXPM(char *xbm, char **xpm, int sx, int sy) {
295 
296 	int		i,j,k;
297 	int		width, height, numcol, depth;
298     int 	zero=0;
299 	unsigned char	bwrite;
300     int		bcount;
301     int     curpixel;
302 
303 	sscanf(*xpm, "%d %d %d %d", &width, &height, &numcol, &depth);
304 
305 
306     for (k=0; k!=depth; k++)
307     {
308         zero <<=8;
309         zero |= xpm[1][k];
310     }
311 
312 	for (i=numcol+1; i < numcol+sy+1; i++) {
313 		bcount = 0;
314 		bwrite = 0;
315 		for (j=0; j<sx*depth; j+=depth) {
316             bwrite >>= 1;
317 
318             curpixel=0;
319             for (k=0; k!=depth; k++)
320             {
321                 curpixel <<=8;
322                 curpixel |= xpm[i][j+k];
323             }
324 
325             if ( curpixel != zero ) {
326 				bwrite += 128;
327 			}
328 			bcount++;
329 			if (bcount == 8) {
330 				*xbm = bwrite;
331 				xbm++;
332 				bcount = 0;
333 				bwrite = 0;
334 			}
335 		}
336 	}
337 }
338 
339 /*******************************************************************************\
340 |* copyXPMArea																   *|
341 \*******************************************************************************/
342 
copyXPMArea(int x,int y,int sx,int sy,int dx,int dy)343 void copyXPMArea(int x, int y, int sx, int sy, int dx, int dy) {
344 
345 	XCopyArea(display, wmgen.pixmap, wmgen.pixmap, NormalGC, x, y, sx, sy, dx, dy);
346 
347 }
348 
349 /*******************************************************************************\
350 |* copyXBMArea																   *|
351 \*******************************************************************************/
352 
copyXBMArea(int x,int y,int sx,int sy,int dx,int dy)353 void copyXBMArea(int x, int y, int sx, int sy, int dx, int dy) {
354 
355 	XCopyArea(display, wmgen.mask, wmgen.pixmap, NormalGC, x, y, sx, sy, dx, dy);
356 }
357 
358 
359 /*******************************************************************************\
360 |* setMaskXY																   *|
361 \*******************************************************************************/
362 
setMaskXY(int x,int y)363 void setMaskXY(int x, int y) {
364 
365 	 XShapeCombineMask(display, win, ShapeBounding, x, y, pixmask, ShapeSet);
366 	 XShapeCombineMask(display, iconwin, ShapeBounding, x, y, pixmask, ShapeSet);
367 }
368 
369 /*******************************************************************************\
370 |* openXwindow																   *|
371 \*******************************************************************************/
openXwindow(int argc,char * argv[],char * pixmap_bytes[],char * pixmask_bits,int pixmask_width,int pixmask_height)372 void openXwindow(int argc, char *argv[], char *pixmap_bytes[], char *pixmask_bits, int pixmask_width, int pixmask_height) {
373 
374 	unsigned int	borderwidth = 1;
375 	XClassHint		classHint;
376 	char			*display_name = NULL;
377 	char			*wname = argv[0];
378 	XTextProperty	name;
379 
380 	XGCValues		gcv;
381 	unsigned long	gcm;
382 
383 	char			*geometry = NULL;
384 
385 	int				dummy=0;
386 	int				i, wx, wy;
387 
388 	for (i=1; argv[i]; i++) {
389 		if (!strcmp(argv[i], "-display")) {
390 		  if ((i + 1) < argc) {
391 		    display_name = argv[i+1];
392 		    i++;
393 		  }
394 		}
395 		if (!strcmp(argv[i], "-geometry")) {
396 		  if ((i + 1) < argc) {
397 			geometry = argv[i+1];
398 			i++;
399 		  }
400 		}
401 	}
402 
403 	if (!(display = XOpenDisplay(display_name))) {
404 		fprintf(stderr, "%s: can't open display %s\n",
405 						wname, XDisplayName(display_name));
406 		exit(1);
407 	}
408 	screen  = DefaultScreen(display);
409 	Root    = RootWindow(display, screen);
410 	d_depth = DefaultDepth(display, screen);
411 	x_fd    = XConnectionNumber(display);
412 
413 	/* Convert XPM to XImage */
414 	GetXPM(&wmgen, pixmap_bytes);
415 
416 	/* Create a window to hold the stuff */
417 	mysizehints.flags = USSize | USPosition;
418 	mysizehints.x = 0;
419 	mysizehints.y = 0;
420 
421 	back_pix = GetColor("white");
422 	fore_pix = GetColor("black");
423 
424 	XWMGeometry(display, screen, Geometry, NULL, borderwidth, &mysizehints,
425 				&mysizehints.x, &mysizehints.y,&mysizehints.width,&mysizehints.height, &dummy);
426 
427 	mysizehints.width = 16;
428 	mysizehints.height = 16;
429 
430 	win = XCreateSimpleWindow(display, Root, mysizehints.x, mysizehints.y,
431 				mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix);
432 
433 	iconwin = XCreateSimpleWindow(display, win, mysizehints.x, mysizehints.y,
434 				mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix);
435 
436 	/* Activate hints */
437 	XSetWMNormalHints(display, win, &mysizehints);
438 	classHint.res_name = wname;
439 	classHint.res_class = wname;
440 	XSetClassHint(display, win, &classHint);
441 
442 	XSelectInput(display, win, ButtonPressMask | ExposureMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
443 	XSelectInput(display, iconwin, ButtonPressMask | ExposureMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
444 
445 	if (XStringListToTextProperty(&wname, 1, &name) == 0) {
446 		fprintf(stderr, "%s: can't allocate window name\n", wname);
447 		exit(1);
448 	}
449 
450 	XSetWMName(display, win, &name);
451 
452 	/* Create GC for drawing */
453 
454 	gcm = GCForeground | GCBackground | GCGraphicsExposures;
455 	gcv.foreground = fore_pix;
456 	gcv.background = back_pix;
457 	gcv.graphics_exposures = 0;
458 	NormalGC = XCreateGC(display, Root, gcm, &gcv);
459 
460 	/* ONLYSHAPE ON */
461 
462 	pixmask = XCreateBitmapFromData(display, win, pixmask_bits, pixmask_width, pixmask_height);
463 
464 	XShapeCombineMask(display, win, ShapeBounding, 0, 0, pixmask, ShapeSet);
465 	XShapeCombineMask(display, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet);
466 
467 	/* ONLYSHAPE OFF */
468 
469 	mywmhints.initial_state = WithdrawnState;
470 	mywmhints.icon_window = iconwin;
471 	mywmhints.icon_x = mysizehints.x;
472 	mywmhints.icon_y = mysizehints.y;
473 	mywmhints.window_group = win;
474 	mywmhints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
475 
476 	XSetWMHints(display, win, &mywmhints);
477 
478 	XSetCommand(display, win, argv, argc);
479 	XMapWindow(display, win);
480 
481 	if (geometry) {
482 		if (sscanf(geometry, "+%d+%d", &wx, &wy) != 2) {
483 			fprintf(stderr, "Bad geometry string.\n");
484 			exit(1);
485 		}
486 		XMoveWindow(display, win, wx, wy);
487 	}
488 }
489