1/*
2
3Copyright 1993, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29#include <X11/Xos.h>
30#include <X11/Xlib.h>
31#include <X11/Xutil.h>
32#include <X11/cursorfont.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <stdarg.h>
36
37/*
38 * Other_stuff.h: Definitions of routines in other_stuff.
39 *
40 * Written by Mark Lillibridge.   Last updated 7/1/87
41 */
42
43#include "clientwin.h"
44#include "dsimple.h"
45
46/*
47 * Just_display: A group of routines designed to make the writing of simple
48 *               X11 applications which open a display but do not open
49 *               any windows much faster and easier.  Unless a routine says
50 *               otherwise, it may be assumed to require program_name, dpy,
51 *               and screen already defined on entry.
52 *
53 * Written by Mark Lillibridge.   Last updated 7/1/87
54 */
55
56
57/* This stuff is defined in the calling program by just_display.h */
58const char *program_name = "unknown_program";
59Display *dpy = NULL;
60int      screen = 0;
61
62
63/*
64 * Get_Display_Name (argc, argv) Look for -display, -d, or host:dpy (obsolete)
65 * If found, remove it from command line.  Don't go past a lone -.
66 */
67char *
68Get_Display_Name(int *pargc,    /* MODIFIED */
69                 char **argv)   /* MODIFIED */
70{
71    int argc = *pargc;
72    char **pargv = argv + 1;
73    char *displayname = NULL;
74
75    for (int i = 1; i < argc; i++) {
76        char *arg = argv[i];
77
78        if (!strcmp(arg, "-display") || !strcmp(arg, "-d")) {
79            if (++i >= argc)
80                usage("-display requires an argument", EXIT_FAILURE);
81
82            displayname = argv[i];
83            *pargc -= 2;
84            continue;
85        }
86        if (!strcmp(arg, "-")) {
87            while (i < argc)
88                *pargv++ = argv[i++];
89            break;
90        }
91        *pargv++ = arg;
92    }
93
94    *pargv = NULL;
95    return (displayname);
96}
97
98
99/*
100 * Open_Display: Routine to open a display with correct error handling.
101 *               Does not require dpy or screen defined on entry.
102 */
103Display *
104Open_Display(const char *display_name)
105{
106    Display *d;
107
108    d = XOpenDisplay(display_name);
109    if (d == NULL) {
110        fprintf(stderr, "%s:  unable to open display '%s'\n",
111                program_name, XDisplayName(display_name));
112        exit(1);
113    }
114
115    return (d);
116}
117
118
119/*
120 * Setup_Display_And_Screen: This routine opens up the correct display (i.e.,
121 *                           it calls Get_Display_Name) and then stores a
122 *                           pointer to it in dpy.  The default screen
123 *                           for this display is then stored in screen.
124 *                           Does not require dpy or screen defined.
125 */
126void
127Setup_Display_And_Screen(int *argc,     /* MODIFIED */
128                         char **argv)   /* MODIFIED */
129{
130    char *displayname = NULL;
131
132    displayname = Get_Display_Name(argc, argv);
133    dpy = Open_Display(displayname);
134    screen = XDefaultScreen(dpy);
135}
136
137/*
138 * Close_Display: Close display
139 */
140void
141Close_Display(void)
142{
143    if (dpy == NULL)
144        return;
145
146    XCloseDisplay(dpy);
147    dpy = NULL;
148}
149
150
151/*
152 * Select_Window_Args: a routine to provide a common interface for
153 *                     applications that need to allow the user to select one
154 *                     window on the screen for special consideration.
155 *                     This routine implements the following command line
156 *                     arguments:
157 *
158 *                       -root            Selects the root window.
159 *                       -id <id>         Selects window with id <id>. <id> may
160 *                                        be either in decimal or hex.
161 *                       -name <name>     Selects the window with name <name>.
162 *
163 *                     Call as Select_Window_Args(&argc, argv) in main before
164 *                     parsing any of your program's command line arguments.
165 *                     Select_Window_Args will remove its arguments so that
166 *                     your program does not have to worry about them.
167 *                     The window returned is the window selected or 0 if
168 *                     none of the above arguments was present.  If 0 is
169 *                     returned, Select_Window should probably be called after
170 *                     all command line arguments, and other setup is done.
171 *                     For examples of usage, see xwininfo, xwd, or xprop.
172 */
173Window
174Select_Window_Args(int *rargc, char **argv)
175#define ARGC (*rargc)
176{
177    int nargc = 1;
178    int argc;
179    char **nargv;
180    Window w = 0;
181
182    nargv = argv + 1;
183    argc = ARGC;
184
185#define OPTION argv[0]
186#define NXTOPTP ++argv, --argc>0
187#define NXTOPT(arg) if (++argv, --argc==0) \
188        usage(arg " requires an argument", EXIT_FAILURE)
189#define COPYOPT nargv++[0]=OPTION, nargc++
190
191    while (NXTOPTP) {
192        if (!strcmp(OPTION, "-")) {
193            COPYOPT;
194            while (NXTOPTP)
195                COPYOPT;
196            break;
197        }
198        if (!strcmp(OPTION, "-root")) {
199            w = RootWindow(dpy, screen);
200            continue;
201        }
202        if (!strcmp(OPTION, "-name")) {
203            NXTOPT("-name");
204            w = Window_With_Name(dpy, RootWindow(dpy, screen), OPTION);
205            if (!w)
206                Fatal_Error("No window with name %s exists!", OPTION);
207            continue;
208        }
209        if (!strcmp(OPTION, "-id")) {
210            NXTOPT("-id");
211            w = 0;
212            sscanf(OPTION, "0x%lx", &w);
213            if (!w)
214                sscanf(OPTION, "%lu", &w);
215            if (!w)
216                Fatal_Error("Invalid window id format: %s.", OPTION);
217            continue;
218        }
219        COPYOPT;
220    }
221    ARGC = nargc;
222
223    return (w);
224}
225
226/*
227 * Other_stuff: A group of routines which do common X11 tasks.
228 *
229 * Written by Mark Lillibridge.   Last updated 7/1/87
230 */
231
232
233/*
234 * Routine to let user select a window using the mouse
235 */
236
237Window
238Select_Window(Display *disp, int descend)
239{
240    int status;
241    Cursor cursor;
242    XEvent event;
243    Window target_win = None, root = RootWindow(disp, screen);
244    int buttons = 0;
245
246    /* Make the target cursor */
247    cursor = XCreateFontCursor(disp, XC_crosshair);
248
249    /* Grab the pointer using target cursor, letting it room all over */
250    status = XGrabPointer(disp, root, False,
251                          ButtonPressMask | ButtonReleaseMask, GrabModeSync,
252                          GrabModeAsync, root, cursor, CurrentTime);
253    if (status != GrabSuccess)
254        Fatal_Error("Can't grab the mouse.");
255
256    /* Let the user select a window... */
257    while ((target_win == None) || (buttons != 0)) {
258        /* allow one more event */
259        XAllowEvents(disp, SyncPointer, CurrentTime);
260        XWindowEvent(disp, root, ButtonPressMask | ButtonReleaseMask, &event);
261        switch (event.type) {
262        case ButtonPress:
263            if (target_win == None) {
264                target_win = event.xbutton.subwindow;   /* window selected */
265                if (target_win == None)
266                    target_win = root;
267            }
268            buttons++;
269            break;
270        case ButtonRelease:
271            if (buttons > 0) /* there may have been some down before we started */
272                buttons--;
273            break;
274        }
275    }
276
277    XUngrabPointer(disp, CurrentTime);  /* Done with pointer */
278
279    if (!descend || (target_win == root))
280        return (target_win);
281
282    target_win = Find_Client(disp, root, target_win);
283
284    return (target_win);
285}
286
287
288/*
289 * Window_With_Name: routine to locate a window with a given name on a display.
290 *                   If no window with the given name is found, 0 is returned.
291 *                   If more than one window has the given name, the first
292 *                   one found will be returned.  Only top and its subwindows
293 *                   are looked at.  Normally, top should be the RootWindow.
294 */
295Window
296Window_With_Name(Display *disp, Window top, const char *name)
297{
298    Window *children, dummy;
299    unsigned int nchildren;
300    unsigned int i;
301    Window w = 0;
302    char *window_name;
303
304    if (XFetchName(disp, top, &window_name) && !strcmp(window_name, name))
305        return (top);
306
307    if (!XQueryTree(disp, top, &dummy, &dummy, &children, &nchildren))
308        return (0);
309
310    for (i = 0; i < nchildren; i++) {
311        w = Window_With_Name(disp, children[i], name);
312        if (w)
313            break;
314    }
315
316    if (children)
317        XFree((char *) children);
318
319    return (w);
320}
321
322/*
323 * outl: a debugging routine.  Flushes stdout then prints a message on stderr
324 *       and flushes stderr.  Used to print messages when past certain points
325 *       in code so we can tell where we are.  Outl may be invoked like printf.
326 */
327void
328outl(const char *msg, ...)
329{
330    va_list args;
331
332    fflush(stdout);
333    va_start(args, msg);
334    vfprintf(stderr, msg, args);
335    va_end(args);
336    fprintf(stderr, "\n");
337    fflush(stderr);
338}
339
340/*
341 * Standard fatal error routine - call like printf.
342 * Does not require dpy or screen defined.
343 */
344void
345Fatal_Error(const char *msg, ...)
346{
347    va_list args;
348
349    fflush(stdout);
350    fflush(stderr);
351    fprintf(stderr, "%s: error: ", program_name);
352    va_start(args, msg);
353    vfprintf(stderr, msg, args);
354    va_end(args);
355    fprintf(stderr, "\n");
356    Close_Display();
357    exit(EXIT_FAILURE);
358}
359