1 /* $Xorg: dsimple.c,v 1.4 2001/02/09 02:05:56 xorgcvs Exp $ */
2 /*
3 
4 Copyright 1993, 1998  The Open Group
5 
6 Permission to use, copy, modify, distribute, and sell this software and its
7 documentation for any purpose is hereby granted without fee, provided that
8 the above copyright notice appear in all copies and that both that
9 copyright notice and this permission notice appear in supporting
10 documentation.
11 
12 The above copyright notice and this permission notice shall be included
13 in all copies or substantial portions of the Software.
14 
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 OTHER DEALINGS IN THE SOFTWARE.
22 
23 Except as contained in this notice, the name of The Open Group shall
24 not be used in advertising or otherwise to promote the sale, use or
25 other dealings in this Software without prior written authorization
26 from The Open Group.
27 
28 */
29 
30 #include <X11/Xos.h>
31 #include <X11/Xlib.h>
32 #include <X11/Xutil.h>
33 #include <X11/cursorfont.h>
34 #include <stdio.h>
35 /*
36  * Other_stuff.h: Definitions of routines in other_stuff.
37  *
38  * Written by Mark Lillibridge.   Last updated 7/1/87
39  */
40 
41 unsigned long Resolve_Color();
42 Pixmap Bitmap_To_Pixmap();
43 Window Select_Window();
44 void out();
45 void blip();
46 Window Window_With_Name();
47 void Fatal_Error();
48 
49 /*
50  * Just_display: A group of routines designed to make the writting of simple
51  *               X11 applications which open a display but do not open
52  *               any windows much faster and easier.  Unless a routine says
53  *               otherwise, it may be assumed to require program_name, dpy,
54  *               and screen already defined on entry.
55  *
56  * Written by Mark Lillibridge.   Last updated 7/1/87
57  */
58 
59 
60 /* This stuff is defined in the calling program by just_display.h */
61 extern char *program_name;
62 extern Display *dpy;
63 extern int screen;
64 
65 
66 /*
67  * Malloc: like malloc but handles out of memory using Fatal_Error.
68  */
Malloc(size)69 char *Malloc(size)
70      unsigned size;
71 {
72 	char *data, *malloc();
73 
74 	if (!(data = malloc(size)))
75 	  Fatal_Error("Out of memory!");
76 
77 	return(data);
78 }
79 
80 
81 /*
82  * Realloc: like Malloc except for realloc, handles NULL using Malloc.
83  */
Realloc(ptr,size)84 char *Realloc(ptr, size)
85         char *ptr;
86         int size;
87 {
88 	char *new_ptr, *realloc();
89 
90 	if (!ptr)
91 	  return(Malloc(size));
92 
93 	if (!(new_ptr = realloc(ptr, size)))
94 	  Fatal_Error("Out of memory!");
95 
96 	return(new_ptr);
97 }
98 
99 
100 /*
101  * Get_Display_Name (argc, argv) Look for -display, -d, or host:dpy (obselete)
102  * If found, remove it from command line.  Don't go past a lone -.
103  */
Get_Display_Name(pargc,argv)104 char *Get_Display_Name(pargc, argv)
105     int *pargc;  /* MODIFIED */
106     char **argv; /* MODIFIED */
107 {
108     int argc = *pargc;
109     char **pargv = argv+1;
110     char *displayname = NULL;
111     int i;
112 
113     for (i = 1; i < argc; i++) {
114 	char *arg = argv[i];
115 
116 	if (!strcmp (arg, "-display") || !strcmp (arg, "-d")) {
117 	    if (++i >= argc) usage ();
118 
119 	    displayname = argv[i];
120 	    *pargc -= 2;
121 	    continue;
122 	}
123 	if (!strcmp(arg,"-")) {
124 		while (i<argc)
125 			*pargv++ = argv[i++];
126 		break;
127 	}
128 	*pargv++ = arg;
129     }
130 
131     *pargv = NULL;
132     return (displayname);
133 }
134 
135 
136 /*
137  * Open_Display: Routine to open a display with correct error handling.
138  *               Does not require dpy or screen defined on entry.
139  */
Open_Display(display_name)140 Display *Open_Display(display_name)
141 char *display_name;
142 {
143 	Display *d;
144 
145 	d = XOpenDisplay(display_name);
146 	if (d == NULL) {
147 	    fprintf (stderr, "%s:  unable to open display '%s'\n",
148 		     program_name, XDisplayName (display_name));
149 	    usage ();
150 	    /* doesn't return */
151 	}
152 
153 	return(d);
154 }
155 
156 
157 /*
158  * Setup_Display_And_Screen: This routine opens up the correct display (i.e.,
159  *                           it calls Get_Display_Name) and then stores a
160  *                           pointer to it in dpy.  The default screen
161  *                           for this display is then stored in screen.
162  *                           Does not require dpy or screen defined.
163  */
Setup_Display_And_Screen(argc,argv)164 void Setup_Display_And_Screen(argc, argv)
165 int *argc;      /* MODIFIED */
166 char **argv;    /* MODIFIED */
167 {
168 	dpy = Open_Display (Get_Display_Name(argc, argv));
169 	screen = DefaultScreen(dpy);
170 }
171 
172 
173 /*
174  * Open_Font: This routine opens a font with error handling.
175  */
Open_Font(name)176 XFontStruct *Open_Font(name)
177 char *name;
178 {
179 	XFontStruct *font;
180 
181 	if (!(font=XLoadQueryFont(dpy, name)))
182 	  Fatal_Error("Unable to open font %s!", name);
183 
184 	return(font);
185 }
186 
187 
188 /*
189  * Beep: Routine to beep the display.
190  */
Beep()191 void Beep()
192 {
193 	XBell(dpy, 50);
194 }
195 
196 
197 /*
198  * ReadBitmapFile: same as XReadBitmapFile except it returns the bitmap
199  *                 directly and handles errors using Fatal_Error.
200  */
_bitmap_error(status,filename)201 static void _bitmap_error(status, filename)
202      int status;
203      char *filename;
204 {
205   if (status == BitmapOpenFailed)
206     Fatal_Error("Can't open file %s!", filename);
207   else if (status == BitmapFileInvalid)
208     Fatal_Error("file %s: Bad bitmap format.", filename);
209   else
210     Fatal_Error("Out of memory!");
211 }
212 
ReadBitmapFile(d,filename,width,height,x_hot,y_hot)213 Pixmap ReadBitmapFile(d, filename, width, height, x_hot, y_hot)
214      Drawable d;
215      char *filename;
216      int *width, *height, *x_hot, *y_hot;
217 {
218   Pixmap bitmap;
219   int status;
220 
221   status = XReadBitmapFile(dpy, RootWindow(dpy, screen), filename,
222 			   (unsigned int *)width, (unsigned int *)height,
223 			   &bitmap, x_hot, y_hot);
224   if (status != BitmapSuccess)
225     _bitmap_error(status, filename);
226 
227   return(bitmap);
228 }
229 
230 
231 /*
232  * WriteBitmapFile: same as XWriteBitmapFile except it handles errors
233  *                  using Fatal_Error.
234  */
WriteBitmapFile(filename,bitmap,width,height,x_hot,y_hot)235 void WriteBitmapFile(filename, bitmap, width, height, x_hot, y_hot)
236      char *filename;
237      Pixmap bitmap;
238      int width, height, x_hot, y_hot;
239 {
240   int status;
241 
242   status= XWriteBitmapFile(dpy, filename, bitmap, width, height, x_hot,
243 			   y_hot);
244   if (status != BitmapSuccess)
245     _bitmap_error(status, filename);
246 }
247 
248 
249 /*
250  * Select_Window_Args: a rountine to provide a common interface for
251  *                     applications that need to allow the user to select one
252  *                     window on the screen for special consideration.
253  *                     This routine implements the following command line
254  *                     arguments:
255  *
256  *                       -root            Selects the root window.
257  *                       -id <id>         Selects window with id <id>. <id> may
258  *                                        be either in decimal or hex.
259  *                       -name <name>     Selects the window with name <name>.
260  *
261  *                     Call as Select_Window_Args(&argc, argv) in main before
262  *                     parsing any of your program's command line arguments.
263  *                     Select_Window_Args will remove its arguments so that
264  *                     your program does not have to worry about them.
265  *                     The window returned is the window selected or 0 if
266  *                     none of the above arguments was present.  If 0 is
267  *                     returned, Select_Window should probably be called after
268  *                     all command line arguments, and other setup is done.
269  *                     For examples of usage, see xwininfo, xwd, or xprop.
270  */
Select_Window_Args(rargc,argv)271 Window Select_Window_Args(rargc, argv)
272      int *rargc;
273      char **argv;
274 #define ARGC (*rargc)
275 {
276 	int nargc=1;
277 	int argc;
278 	char **nargv;
279 	Window w=0;
280 
281 	nargv = argv+1; argc = ARGC;
282 #define OPTION argv[0]
283 #define NXTOPTP ++argv, --argc>0
284 #define NXTOPT if (++argv, --argc==0) usage()
285 #define COPYOPT nargv++[0]=OPTION, nargc++
286 
287 	while (NXTOPTP) {
288 		if (!strcmp(OPTION, "-")) {
289 			COPYOPT;
290 			while (NXTOPTP)
291 			  COPYOPT;
292 			break;
293 		}
294 		if (!strcmp(OPTION, "-root")) {
295 			w=RootWindow(dpy, screen);
296 			continue;
297 		}
298 		if (!strcmp(OPTION, "-name")) {
299 			NXTOPT;
300 			w = Window_With_Name(dpy, RootWindow(dpy, screen),
301 					     OPTION);
302 			if (!w)
303 			  Fatal_Error("No window with name %s exists!",OPTION);
304 			continue;
305 		}
306 		if (!strcmp(OPTION, "-id")) {
307 			NXTOPT;
308 			w=0;
309 			sscanf(OPTION, "0x%lx", &w);
310 			if (!w)
311 			  sscanf(OPTION, "%ld", &w);
312 			if (!w)
313 			  Fatal_Error("Invalid window id format: %s.", OPTION);
314 			continue;
315 		}
316 		COPYOPT;
317 	}
318 	ARGC = nargc;
319 
320 	return(w);
321 }
322 
323 /*
324  * Other_stuff: A group of routines which do common X11 tasks.
325  *
326  * Written by Mark Lillibridge.   Last updated 7/1/87
327  */
328 
329 extern Display *dpy;
330 extern int screen;
331 
332 /*
333  * Resolve_Color: This routine takes a color name and returns the pixel #
334  *                that when used in the window w will be of color name.
335  *                (WARNING:  The colormap of w MAY be modified! )
336  *                If colors are run out of, only the first n colors will be
337  *                as correct as the hardware can make them where n depends
338  *                on the display.  This routine does not require wind to
339  *                be defined.
340  */
Resolve_Color(w,name)341 unsigned long Resolve_Color(w, name)
342      Window w;
343      char *name;
344 {
345 	XColor c;
346 	Colormap colormap;
347 	XWindowAttributes wind_info;
348 
349 	/*
350 	 * The following is a hack to insure machines without a rgb table
351 	 * handle at least white & black right.
352 	 */
353 	if (!strcmp(name, "white"))
354 	  name="#ffffffffffff";
355 	if (!strcmp(name, "black"))
356 	  name="#000000000000";
357 
358 	XGetWindowAttributes(dpy, w, &wind_info);
359 	colormap = wind_info.colormap;
360 
361 	if (!XParseColor(dpy, colormap, name, &c))
362 	  Fatal_Error("Bad color format '%s'.", name);
363 
364 	if (!XAllocColor(dpy, colormap, &c))
365 	  Fatal_Error("XAllocColor failed!");
366 
367 	return(c.pixel);
368 }
369 
370 
371 /*
372  * Bitmap_To_Pixmap: Convert a bitmap to a 2 colored pixmap.  The colors come
373  *                   from the foreground and background colors of the gc.
374  *                   Width and height are required solely for efficiency.
375  *                   If needed, they can be obtained via. XGetGeometry.
376  */
Bitmap_To_Pixmap(dpy,d,gc,bitmap,width,height)377 Pixmap Bitmap_To_Pixmap(dpy, d, gc, bitmap, width, height)
378      Display *dpy;
379      Drawable d;
380      GC gc;
381      Pixmap bitmap;
382      int width, height;
383 {
384   Pixmap pix;
385   int x;
386   unsigned int i, depth;
387   Drawable root;
388 
389   if (!XGetGeometry(dpy, d, &root, &x, &x, &i, &i, &i, &depth))
390     return(0);
391 
392   pix = XCreatePixmap(dpy, d, width, height, (int)depth);
393 
394   XCopyPlane(dpy, bitmap, pix, gc, 0, 0, width, height, 0, 0, 1);
395 
396   return(pix);
397 }
398 
399 
400 /*
401  * blip: a debugging routine.  Prints Blip! on stderr with flushing.
402  */
blip()403 void blip()
404 {
405   outl("blip!");
406 }
407 
408 
409 /* Get the window in which the mouse is */
Get_Mouse_Window(Window w)410 Window Get_Mouse_Window(Window w) {
411   Window new = w,dummy;
412   int i;
413   unsigned int ui;
414   while (new) {
415     w = new;
416     XQueryPointer(dpy,w,&dummy,&new,&i,&i,&i,&i,&ui);
417   }
418   return w;
419 
420 }
421 
422 /*
423  * Routine to let user select a window using the mouse
424  */
425 
Select_Window(dpy)426 Window Select_Window(dpy)
427      Display *dpy;
428 {
429   int status;
430   Cursor cursor;
431   XEvent event;
432   Window target_win = None, root = RootWindow(dpy,screen);
433   int buttons = 0;
434 
435   /* Make the target cursor */
436   cursor = XCreateFontCursor(dpy, XC_crosshair);
437 
438   /* Grab the pointer using target cursor, letting it room all over */
439   status = XGrabPointer(dpy, root, False,
440 			ButtonPressMask|ButtonReleaseMask, GrabModeSync,
441 			GrabModeAsync, root, cursor, CurrentTime);
442   if (status != GrabSuccess) Fatal_Error("Can't grab the mouse.");
443 
444   /* Let the user select a window... */
445   while ((target_win == None) || (buttons != 0)) {
446     /* allow one more event */
447     XAllowEvents(dpy, SyncPointer, CurrentTime);
448     XWindowEvent(dpy, root, ButtonPressMask|ButtonReleaseMask, &event);
449     switch (event.type) {
450     case ButtonPress:
451       if (target_win == None) {
452 	target_win = Get_Mouse_Window(event.xbutton.subwindow); /* window selected */
453 	if (target_win == None) target_win = root;
454       }
455       buttons++;
456       break;
457     case ButtonRelease:
458       if (buttons > 0) /* there may have been some down before we started */
459 	buttons--;
460        break;
461     }
462   }
463 
464   XUngrabPointer(dpy, CurrentTime);      /* Done with pointer */
465 
466   return(target_win);
467 }
468 
469 
470 /*
471  * Window_With_Name: routine to locate a window with a given name on a display.
472  *                   If no window with the given name is found, 0 is returned.
473  *                   If more than one window has the given name, the first
474  *                   one found will be returned.  Only top and its subwindows
475  *                   are looked at.  Normally, top should be the RootWindow.
476  */
Window_With_Name(dpy,top,name)477 Window Window_With_Name(dpy, top, name)
478      Display *dpy;
479      Window top;
480      char *name;
481 {
482 	Window *children, dummy;
483 	unsigned int nchildren;
484 	int i;
485 	Window w=0;
486 	char *window_name;
487 
488 	if (XFetchName(dpy, top, &window_name) && !strcmp(window_name, name))
489 	  return(top);
490 
491 	if (!XQueryTree(dpy, top, &dummy, &dummy, &children, &nchildren))
492 	  return(0);
493 
494 	for (i=0; i<nchildren; i++) {
495 		w = Window_With_Name(dpy, children[i], name);
496 		if (w)
497 		  break;
498 	}
499 	if (children) XFree ((char *)children);
500 	return(w);
501 }
502 
503 /*
504  * outl: a debugging routine.  Flushes stdout then prints a message on stderr
505  *       and flushes stderr.  Used to print messages when past certain points
506  *       in code so we can tell where we are.  Outl may be invoked like
507  *       printf with up to 7 arguments.
508  */
509 /* VARARGS1 */
outl(msg,arg0,arg1,arg2,arg3,arg4,arg5,arg6)510 outl(msg, arg0,arg1,arg2,arg3,arg4,arg5,arg6)
511      char *msg;
512      char *arg0, *arg1, *arg2, *arg3, *arg4, *arg5, *arg6;
513 {
514 	fflush(stdout);
515 	fprintf(stderr, msg, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
516 	fprintf(stderr, "\n");
517 	fflush(stderr);
518 }
519 
520 
521 /*
522  * Standard fatal error routine - call like printf but maximum of 7 arguments.
523  * Does not require dpy or screen defined.
524  */
525 /* VARARGS1 */
Fatal_Error(msg,arg0,arg1,arg2,arg3,arg4,arg5,arg6)526 void Fatal_Error(msg, arg0,arg1,arg2,arg3,arg4,arg5,arg6)
527 char *msg;
528 char *arg0, *arg1, *arg2, *arg3, *arg4, *arg5, *arg6;
529 {
530 	fflush(stdout);
531 	fflush(stderr);
532 	fprintf(stderr, "%s: error: ", program_name);
533 	fprintf(stderr, msg, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
534 	fprintf(stderr, "\n");
535 	exit(1);
536 }
537