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