home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / gwm18a.zip / contrib / gwmsh / gwmsh.c < prev    next >
C/C++ Source or Header  |  1995-07-03  |  22KB  |  881 lines

  1. /* gwmsh.c - Simple minded gwm interface
  2.  *
  3.  * Copyright (C) 1994 Valeriy E. Ushakov
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2, or (at your option)
  8.  * any later version.
  9.  * 
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  * 
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, you can either send email to this
  17.  * program's author (see below) or write to:
  18.  * 
  19.  *              The Free Software Foundation, Inc.
  20.  *              675 Mass Ave.
  21.  *              Cambridge, MA 02139, USA. 
  22.  * 
  23.  * Please send bug reports, etc. to uwe@niif.spb.su
  24.  * 
  25.  * Description:
  26.  * 
  27.  *   This programm is intended to be a simple line oriented interface
  28.  * to GWM. Besides all, it was written for learning purposes (being my
  29.  * first X hack). Canonical GNU Emacs have no interface to x11 so this
  30.  * might be a kind of quick and dirty solution for this, thou this
  31.  * part is yet to be written.
  32.  * 
  33.  * $Id: gwm.shar,v 1.107 1995/07/03 09:24:22 colas Exp $
  34.  *
  35.  * $Log: gwm.shar,v $
  36.  * Revision 1.107  1995/07/03  09:24:22  colas
  37.  * *** Version 1.8a ***
  38.  *
  39.  * logging by sending an udppacket is now disablable at run
  40.  * time by setting the environment variables NO_GWM_LOG or NO_KOALA_SPY
  41.  *
  42.  * Revision 1.100  1995/05/29  15:56:57  colas
  43.  * simple-win.gwm: new parameters:
  44.  *     label like simple-icon
  45.  *     legend to place the label on sides of window
  46.  *     lpad and rpad: number of () to pad the label with stretchable space
  47.  * bar-max-wdths set by default to 1000
  48.  *
  49.  * John Carr <jfc@MIT.EDU>: patches to supress warnings on AIX/RS_6000/xlc
  50.  * rxterm install fixed once more
  51.  *
  52.  * Revision 1.97  1995/05/16  16:16:36  colas
  53.  * contrib/scripts/find-bar-nils
  54.  *
  55. # Revision 1.5  1995/05/15  22:29:34  colas
  56. # bar can have abitrary shaped backgrounds (shaped tiles)
  57. #
  58.  * Revision 1.95  1995/05/11  17:06:56  colas
  59.  * better spy
  60.  *
  61.  * Revision 1.93  1995/04/26  16:34:51  colas
  62.  * Makefile added in distrib
  63.  *
  64.  * simple-icon.gwm:
  65.  *
  66.  *     - customize item "legend" can now be instead of () or t the strings:
  67.  *       "top" "base" "right" "left" for the positions where you want the string
  68.  *       to appear
  69.  *       e.g: (customize simple-icon any XTerm "left")
  70.  *
  71.  *     - new customization item "label" to provide either a fixed string or a
  72.  *       lambda which will be used to filter the label
  73.  *       must return a non-empty string otherwise the unfiltered label is used
  74.  *       e.g: to supress the Netscape: in netscape icon titles
  75.  *       (customize simple-icon any Netscape
  76.  *           label (lambdaq (s) (match "Netscape: \\(.*\\)$" s 1))
  77.  *       )
  78.  *
  79.  * iconify a window doesnt not loose the window anymore in case of error in wool
  80.  * code
  81.  *
  82.  * Revision 1.92  1995/04/25  14:31:09  colas
  83.  * *** Version 1.7p_beta_2 ***
  84.  *
  85.  * Revision 1.3  1994/09/30  17:36:38  uwe
  86.  * (get_window_propety_string): Is smarter now. It reads some portion of property and make
  87.  * second query only if property value was not read completely at first try.
  88.  * (xmalloc): New function. In case there's no -liberty.
  89.  *
  90.  * Revision 1.2  1994/09/21  20:50:49  uwe
  91.  * Fixed typo in declaration of get_window_property_string argument dpy.
  92.  * It's a Display* -- silly typo.
  93.  *
  94.  * Revision 1.1  1994/09/21  20:35:42  uwe
  95.  * Initial revision
  96.  *
  97.  */
  98.  
  99. #ifdef sun4                     /* XXX: This belongs elsewhere */
  100. #  define HAVE_ALLOCA_H
  101. #endif
  102.  
  103. #ifdef HAVE_ALLOCA_H
  104. #  include <alloca.h>
  105. #endif
  106. #include <signal.h>
  107. #include <setjmp.h>
  108.  
  109. #include <ctype.h>
  110. #if defined(USG) || defined(_POSIX_VERSION)
  111. #  include <string.h>
  112. #else
  113. #  include <strings.h>
  114. #endif
  115. #include <stdio.h>
  116. #include <getopt.h>
  117. #include <varargs.h>
  118.  
  119. #include <X11/Xlib.h>
  120. #include <X11/Xatom.h>
  121.  
  122. #ifdef USE_READLINE
  123. #include <readline/readline.h>
  124. #include <readline/history.h>
  125. #else
  126. char *readline ();
  127. #endif
  128.  
  129. #ifndef __STDC__
  130. #  ifdef __GNUC__
  131. #    define const    __const__
  132. #    define volatile __volatile__
  133. #  else /* !__STDC__ && !__GNUC__ */
  134. #    define const
  135. #    define volatile
  136. #  endif
  137. #endif /* !__STDC__ */
  138.  
  139. #ifdef __GNUC__
  140. #  define NORETURN __attribute__ ((noreturn))
  141. #else
  142. #  define NORETURN
  143. #endif
  144.  
  145. /* Application name */
  146. char *progname;
  147.  
  148. /* Command line options */
  149. int under_emacs_p;
  150. int query_only_p;
  151. int use_WINDOWID_p;
  152. char *gwm_single_command = NULL;
  153.  
  154. /* Type of windows to apply batch commands to */
  155. int all_p;
  156. int icon_p;
  157. int main_p;
  158. int mapped_p;
  159. int stacking_p;
  160. /* any of icon main mapped stacking*/
  161. int all_specific_p;
  162.  
  163. /* X realted globals */
  164. char *display_name = NULL;      /* Use $DISPLAY by default */
  165.  
  166. Display *dpy;                   /* Display */
  167. Screen screen_num;              /* Screen number */
  168. Window working_window;          /* Window to communicate with GWM */
  169.  
  170. Atom XA_GWM_RUNNING;            /* Whether gwm is running */
  171. Atom XA_GWM_EXECUTE;            /* Text for gwm to execute */
  172. Atom XA_GWM_RESULT;             /* To get eval result from gwm */
  173.  
  174. /* Shell functions */
  175. char *get_gwm_form ();
  176. void gwm_shell () NORETURN;     /* Shell motor function */
  177. void gwmsh_eval_print ();
  178. void gwmsh_eval_print_for_all ();
  179.  
  180. /* Communication */
  181. Bool gwm_running_p ();
  182. void gwm_execute ();
  183. unsigned char *gwm_get_result ();
  184.  
  185. /* Window functions */
  186. Bool window_valid_p ();
  187. Bool find_window_in_hierarchy ();
  188. unsigned char *get_window_property_string ();
  189.  
  190. /* Jump buffer to handle intrs while reading */
  191. jmp_buf intr_while_reading;
  192. void abort_result_waiting_loop ();
  193.  
  194. /* Auxilary staff */
  195. char *save_optarg ();
  196. volatile void barf () NORETURN;
  197. volatile void die () NORETURN;
  198.  
  199. char *xmalloc ();
  200. void free ();
  201.  
  202. /*
  203.  * Function: usage
  204.  *
  205.  *   Prints out on stderr usage summary
  206.  *
  207.  * Returns:     Nothing
  208.  * Parameters:  None
  209.  */
  210. void
  211. usage ()
  212. {
  213.     fputs ("--all      -A   For all windows\n\
  214. --command  -c   Execute the command.\n\
  215. --emacs    -e   Run gwmsh from under emacs. Not intended for ordinary use.\n\
  216. --help     -h   Print this usage and exit successfully.\n\
  217. --icons    -I   For all icons\n\
  218. --main     -W   For all main windows\n\
  219. --mapped   -M   For all mapped\n\
  220. --query    -q   Query if GWM is running\n\
  221. --stacking -S   For all in stacking order\n\
  222. --window   -w   Use $WINDOWID window to communicate with GWM.\n",
  223.            stderr);
  224. }
  225.  
  226. /*
  227.  * Function: main
  228.  *
  229.  *   I'm not *THAT* bore.
  230.  */
  231. void
  232. main (ac, av)
  233.   int ac;
  234.   char **av;
  235. {
  236.     char *s;
  237.  
  238.     progname = av[0];
  239.     if (s = rindex (progname, '/'))
  240.         progname = s+1;
  241.  
  242.     for (;;) {
  243.  
  244.         static const struct option long_option[] = {
  245.           { "all",     no_argument,       0,               'A'},
  246.           { "command", required_argument, 0,               'c'},
  247.           { "display", required_argument, 0,               'd'},
  248.           { "emacs",   no_argument,       &under_emacs_p,   1 },
  249.           { "help",    no_argument,       0,               'h'},
  250.           { "icon",    no_argument,       0,               'I'},
  251.           { "main",    no_argument,       0,               'W'},
  252.           { "mapped",  no_argument,       0,               'M'},
  253.           { "query",   no_argument,       &query_only_p,    1 },
  254.           { "stacking",no_argument,       0,               'S'},
  255.           { "window",  no_argument,       &use_WINDOWID_p,  1 },
  256.           { NULL, 0, 0, 0}
  257.         };
  258.  
  259.         int option_index = 0;
  260.         int c = getopt_long_only (ac, av, "c:ehqwAIMSW", long_option, &option_index);
  261.  
  262.         if (c == EOF)
  263.             break;
  264.  
  265.     option_switch:
  266.         switch (c) {
  267.  
  268.         case 0: /* Non-flag long option. */
  269.             /*Pass it along to the code that handles short one */
  270.             c = long_option[option_index].val;
  271.             goto option_switch;
  272.         case 1:
  273.             break;
  274.         case 'c':
  275.             save_optarg (&gwm_single_command);
  276.             break;
  277.         case 'd': /* !!! This is NOT in short options !!! */
  278.             save_optarg (&display_name);
  279.             break;
  280.         case 'e':
  281.             under_emacs_p = 1;
  282.             break;
  283.         case 'h':
  284.             usage ();
  285.             die (0);
  286.             break;
  287.         case 'q':
  288.             query_only_p = 1;
  289.             break;
  290.         case 'w':
  291.             use_WINDOWID_p = 1;
  292.             break;
  293.         case 'A':
  294.             all_p = 1;
  295.             break;
  296.         case 'I':
  297.             icon_p = 1;
  298.             break;
  299.         case 'M':
  300.             mapped_p = 1;
  301.             break;
  302.         case 'S':
  303.             stacking_p = 1;
  304.             break;
  305.         case 'W':
  306.             main_p = 1;
  307.             break;
  308.         case '?':
  309.             usage ();
  310.             die (1);
  311.             break;
  312.         default:
  313.             barf ("panic, getopt returned 0%o\n", c);
  314.         }
  315.     }
  316.  
  317.     if (main_p && icon_p)
  318.         barf ("-I and -W are mutually exclusive");
  319.  
  320.     all_specific_p = icon_p || main_p || mapped_p || stacking_p;
  321.     if (all_p && all_specific_p)
  322.         barf ("-A should be the only option");
  323.  
  324.     dpy = XOpenDisplay (display_name);
  325.     if (dpy == NULL)
  326.         barf ("Cannot open display %s", XDisplayName (display_name));
  327.  
  328.     /* Check for GWM running */
  329.     if (!gwm_running_p ())
  330.         barf ("GWM is not running on %s", XDisplayName(display_name));
  331.     else if (query_only_p)
  332.         die (0);
  333.  
  334.     /* Get window we will use to communicate to GWM */
  335.     if (use_WINDOWID_p) {
  336.         extern char *getenv ();
  337.         char *wid = getenv ("WINDOWID");
  338.         if (!wid)
  339.             barf ("No WINDOWID environment variable");
  340.         if (!sscanf (wid, "%ld", &working_window))
  341.             barf ("corrupted $WINDOWID = %ld", wid);
  342.         if (!window_valid_p (working_window))
  343.             barf ( "Invalid window %ld", working_window);
  344.     }
  345.     else {
  346.         working_window = DefaultRootWindow (dpy);
  347.     }
  348.  
  349.     /* Create atoms to comunicate with GWM */
  350.     XA_GWM_EXECUTE = XInternAtom (dpy, "GWM_EXECUTE", True);
  351.     if (XA_GWM_EXECUTE == None)
  352.         barf ("Can't intern GWM_EXECUTE");
  353.     XA_GWM_RESULT = XInternAtom (dpy, "GWM_RESULT", False);
  354.     if (XA_GWM_RESULT == None)
  355.         barf ("Can't intern GWM_RESULT");
  356.  
  357.     XSelectInput (dpy, working_window, PropertyChangeMask);
  358.  
  359.     signal (SIGINT, SIG_IGN);
  360.  
  361.     /* Ok, we are ready to pass commands to GWM */
  362.     if (all_p || all_specific_p) {
  363.         /* XXX: More consistent batch commands parsing*/
  364.         char *spec = alloca (100); /* XXX: Magic number here */
  365.         spec [0] = '\0';
  366.         if (icon_p)
  367.             strcat (spec, " 'icon");
  368.         else if (main_p)
  369.             strcat (spec, " 'window");
  370.         if (mapped_p)
  371.             strcat (spec, " 'mapped");
  372.         if (stacking_p)
  373.             strcat (spec, " 'stacking-order");
  374.  
  375.         if (gwm_single_command)
  376.             gwmsh_eval_print_for_all (spec, gwm_single_command);
  377.         else 
  378.             /* XXX: Would wrapping them all together be more logical? */
  379.             while (optind < ac)
  380.                 gwmsh_eval_print_for_all (spec, av[optind++]);
  381.     }
  382.     else if (gwm_single_command)
  383.         gwmsh_eval_print (gwm_single_command);
  384.     else
  385.         gwm_shell ();
  386.  
  387.     die (0);
  388. }
  389.  
  390. /*
  391.  * Function: gwm_running_p
  392.  *
  393.  *   Check if gwm is running on the display
  394.  *
  395.  * Returns:     Bool
  396.  - 
  397.  * Parameters:  None
  398.  */
  399. Bool
  400. gwm_running_p ()
  401. {
  402.     /* Hidden window GWM creates */
  403.     Window gwm_window;
  404.  
  405.  
  406.     Status result;
  407.     Atom actual_type;
  408.     int actual_format;
  409.     unsigned long nitems;
  410.     unsigned long bytes_after;
  411.     Window *gwm_window_id_ptr;
  412.  
  413.     /* Check for GWM_RUNNING presence */
  414.     XA_GWM_RUNNING = XInternAtom (dpy, "GWM_RUNNING", True);
  415.     if (XA_GWM_RUNNING == None)
  416.         return (False);
  417.  
  418.     /* Make shure that GWM_RUNNING is valid */
  419.     result = XGetWindowProperty (dpy, DefaultRootWindow (dpy), XA_GWM_RUNNING,
  420.                                  0l, 1l, False, XA_GWM_RUNNING,
  421.                                  &actual_type, &actual_format,
  422.                                  &nitems, &bytes_after,
  423.                                  (unsigned char **) &gwm_window_id_ptr);
  424.     if (!((result == Success)
  425.           && (actual_type == XA_GWM_RUNNING)
  426.           && (actual_format == 32)
  427.           && (nitems == 1)
  428.           && (bytes_after == 0)))
  429.         barf ("XGetWindowProperty failed to read GWM_RUNNING");
  430.  
  431.     gwm_window = *gwm_window_id_ptr;
  432.     XFree ((void *) gwm_window_id_ptr);
  433.  
  434.     /* Well, make shure gwm_window exists */
  435.     return (window_valid_p (gwm_window));
  436. }
  437.  
  438. /*
  439.  * Function: gwm_shell
  440.  *
  441.  *   Shell read - pass to gwm - read from gwm - print loop
  442.  *
  443.  * Returns:     Never
  444.  * Parameters:  None
  445.  */
  446. void
  447. gwm_shell ()
  448. {
  449.     char *form;
  450.  
  451.     for (;;) {
  452.         form = get_gwm_form ("gwm> ");
  453.         if (!form) {
  454.             putchar ('\n');
  455.             die (0);
  456.         }
  457.         gwmsh_eval_print (form);
  458.     }
  459. }
  460.  
  461. /*
  462.  * Function: gwmsh_eval_print
  463.  *
  464.  *   Prints out result of text evaluation.
  465.  *
  466.  * Returns:     Nothing
  467.  * Parameters:  text - gwm form to pass to gwm_execute after wrapping
  468.  * it so that result would come to us via GWM_RESULT property.
  469.  */
  470. void
  471. gwmsh_eval_print (text)
  472.   char *text;
  473. {
  474.     char *gwm_command;
  475.     char *gwm_result;
  476.  
  477.     gwm_command = alloca (strlen (text) + 200); /* XXX: Magic numer here */
  478.     sprintf (gwm_command,
  479. "(set-x-property \"GWM_RESULT\"\
  480.  (with-output-to-string\
  481.  (if (error-occurred (? %s))\
  482.  (? \"Wool Error\"))))", text); 
  483.     gwm_execute (gwm_command, False);
  484.     gwm_result = gwm_get_result ();
  485.     if (gwm_result) {
  486.         fputs (gwm_result, stdout);
  487.         fputc ('\n', stdout);
  488.         free (gwm_result);
  489.     }
  490. }
  491.  
  492. /*
  493.  * Function: gwmsh_eval_print_for_all
  494.  *
  495.  *   Wrap up text in the loop thru all windows and pass it to
  496.  * gwmsh_eval_print.
  497.  *
  498.  * Returns:     Nothing
  499.  * Parameters:  spec - Loop thru this kind of windows only.
  500.  *              text - Command to be executes for these windows.
  501.  */
  502. void
  503. gwmsh_eval_print_for_all (spec, text)
  504.   char *spec;
  505.   char *text;
  506. {
  507.     char *gwm_command;
  508.  
  509.     gwm_command = alloca (strlen (text) + 50); /* XXX: magic number here */
  510.     sprintf (gwm_command, "(for window (list-of-windows %s) %s)", spec, text);
  511.     gwmsh_eval_print (gwm_command);
  512. }
  513.  
  514. /*
  515.  * Function: gwm_execute
  516.  *
  517.  *   Pass text to gwm via GWM_EXECUTE property. Sync with server
  518.  * according to sync_p flag.
  519.  *
  520.  * Returns:     Nothing
  521.  * Parameters:  text   - Pointer to gwm form to be passed to gwm
  522.  *              sync_p - Should we sync with server
  523.  */
  524. void
  525. gwm_execute (text, sync_p)
  526.   char *text;
  527.   Bool sync_p;
  528. {
  529.     XChangeProperty (dpy, working_window, XA_GWM_EXECUTE,
  530.                      XA_STRING, 8, PropModeReplace,
  531.                      text, strlen (text) + 1);
  532.     if (sync_p)
  533.         XSync (dpy, False);
  534. }
  535.  
  536. /*
  537.  * Function: abort_result_waiting_loop (signal hanldler).
  538.  *
  539.  *   Aborts the gwm_get_result event waiting loop upon SIGINT.
  540.  *
  541.  * Returns:     Nothing
  542.  * Parameters:  None
  543.  */
  544. void
  545. abort_result_waiting_loop ()
  546. {
  547.     longjmp (intr_while_reading, 1);
  548. }
  549.  
  550. /*
  551.  * Function: gwm_get_result
  552.  *
  553.  *   Looks for the result returned by gwm in GWM_RESULT property.
  554.  *
  555.  * Returns:     char *
  556.  -
  557.  * Parameters:  None
  558.  */
  559. unsigned char *
  560. gwm_get_result ()
  561. {
  562.     XEvent ev;
  563.     unsigned char *gwm_result = NULL;
  564.  
  565.     if (setjmp (intr_while_reading)) {
  566.         signal (SIGINT, SIG_IGN);
  567.         gwm_result = "Inerrupted";
  568.         goto deliver_result;
  569.     }
  570.  
  571.     signal (SIGINT, abort_result_waiting_loop);
  572.  
  573.     /* Get evaluation result from GWM_RESULT property */
  574.     for (;;) {
  575.         XNextEvent (dpy, &ev);
  576.         switch (ev.type) {
  577.  
  578.         case PropertyNotify:
  579.  
  580.             if ((ev.xproperty.atom  == XA_GWM_RESULT)
  581.                 && (ev.xproperty.state == PropertyNewValue)) {
  582.  
  583.                 gwm_result = get_window_property_string (dpy, working_window,
  584.                                                          XA_GWM_RESULT, True);
  585.                 if (!gwm_result)
  586.                     fputs ("Error reading GWM_RESULT.\n", stderr);
  587.                 goto deliver_result;
  588.             }
  589.             break; /* to next event */
  590.  
  591.         default:
  592.             fprintf (stderr, "Unexpected event %d ignored\n", ev.type);
  593.         }
  594.     }
  595.  deliver_result:
  596.     signal (SIGINT, SIG_IGN);
  597.     return gwm_result;
  598. }
  599.  
  600. /* --------------------------------------
  601.  * Utility functions to deal with windows
  602.  */
  603.  
  604. /*
  605.  * Function: get_window_property_string
  606.  *
  607.  *   Looks for the given property of type XA_STRING and arbitrary
  608.  * length. If anyone know better way of doing this, please fix.
  609.  *
  610.  * Returns:     char *
  611.  - 
  612.  * Parameters:  dpy      -  Display
  613.  *              w        -  Window
  614.  *              prop     -  Property to be read
  615.  *              delete_p -  Delete it?
  616.  */
  617. #define INITIAL_QUERY_LEN 20l
  618.  
  619. unsigned char *
  620. get_window_property_string (dpy, w, prop, delete_p)
  621.   Display *dpy;                 /* XXX: shadows global dpy */
  622.   Window w;
  623.   Atom prop;
  624.   Bool delete_p;
  625. {
  626.     Status retcode;
  627.     Atom actual_type;
  628.     int actual_format;
  629.     unsigned long nitems;
  630.     unsigned long bytes_after;
  631.     unsigned char *buf = NULL;
  632.  
  633.     unsigned long len;
  634.     unsigned long already_read;
  635.     unsigned long real_size_in_bytes;
  636.  
  637.     unsigned char *prop_val;
  638.  
  639.     retcode = XGetWindowProperty (dpy, w, prop,
  640.                                   0l, INITIAL_QUERY_LEN, False, XA_STRING,
  641.                                   &actual_type, &actual_format,
  642.                                   &nitems, &bytes_after,
  643.                                   &buf);
  644.     if ((actual_type != XA_STRING)
  645.         || (actual_format != 8)) {
  646.         XFree (buf);
  647.         return NULL;
  648.     }
  649.  
  650.     real_size_in_bytes = nitems + bytes_after;
  651.     already_read = nitems;
  652.     prop_val = (unsigned char *) xmalloc (real_size_in_bytes + 1);
  653.     memcpy (prop_val, buf, nitems + 1); /* Including trailing null! */
  654.     XFree (buf);
  655.  
  656.     if (!bytes_after)
  657.         return prop_val;
  658.  
  659.     len = (bytes_after + 3) / 4;
  660.     retcode = XGetWindowProperty (dpy, w, prop,
  661.                                   INITIAL_QUERY_LEN, len, delete_p, XA_STRING,
  662.                                   &actual_type, &actual_format,
  663.                                   &nitems, &bytes_after,
  664.                                   &buf);
  665.     if ((retcode != Success)
  666.         || (actual_type != XA_STRING)
  667.         || (actual_format != 8)) {
  668.         XFree (buf);
  669.         free (prop_val);
  670.         return NULL;
  671.     }
  672.  
  673.     memcpy (prop_val + already_read, buf, nitems + 1);
  674.     XFree (buf);
  675.     return prop_val;
  676. }
  677.  
  678. /*
  679.  * Function: window_valid_p
  680.  *
  681.  *   Whether gived window id is valid
  682.  *
  683.  * Returns:     Bool
  684.  - 
  685.  * Parameters:  w - Window to validate
  686.  */
  687. Bool
  688. window_valid_p (w)
  689.   Window w;
  690. {
  691.     /* XXX: Any simpler way to walidate window ??? */
  692.     return find_window_in_hierarchy (DefaultRootWindow (dpy), w);
  693. }
  694.  
  695. /*
  696.  * Function: find_window_in_hierarchy
  697.  *
  698.  *   Status of search for the given window in the hierarchy
  699.  *
  700.  * Returns:     Bool
  701.  - 
  702.  * Parameters:  hier_root  - Window hierarchy root
  703.  *              sought_win - Window sought
  704.  */
  705. Bool
  706. find_window_in_hierarchy (hier_root, sought_win)
  707.   Window hier_root;
  708.   Window sought_win;
  709. {
  710.     int found = False;
  711.     int child_no;
  712.  
  713.     Window root_ignored;
  714.     Window parent_ignored;
  715.     Window *child;
  716.     int n_children;
  717.  
  718.     XQueryTree (dpy, hier_root, &root_ignored, &parent_ignored, 
  719.                 &child, &n_children);
  720.  
  721.     /* Search it breadth first, for sought_win is most likely the top one */
  722.     for (child_no = 0; child_no < n_children; ++child_no)
  723.         if (child[child_no] == sought_win) {
  724.             found = True;
  725.             goto done;
  726.         }
  727.  
  728.     /* Hmm. It's not here try to recurse */
  729.     for (child_no = 0; child_no < n_children; ++child_no)
  730.         if (find_window_in_hierarchy (child[child_no], sought_win)) {
  731.             found = True;
  732.             goto done;
  733.         }
  734.  done:
  735.     XFree ((void *) child);
  736.     return (found);
  737. }
  738.  
  739. /* --------------------------------
  740.  * Misc functions to make life easy
  741.  */
  742.  
  743. /*
  744.  * Function: get_gwm_form
  745.  *
  746.  *   Generic wrapper for read. One day it might look after parens and
  747.  * allow multiple line commands.
  748.  *
  749.  * Returns:     char *
  750.  - 
  751.  * Parameters:  prompt
  752.  */
  753. char *
  754. get_gwm_form (prompt)
  755.   char *prompt;
  756. {
  757.     static char *line_read = NULL;
  758.     register char *s;
  759.  
  760.     if (line_read) {
  761.         free (line_read);
  762.         line_read = NULL;
  763.     }
  764.     s = line_read = readline (prompt);
  765.     if (s) {
  766.         while (isspace (*s))
  767.             ++s;
  768.         if (*s)
  769.             add_history (s);
  770.     }
  771.     return s;
  772. }
  773.  
  774. #ifndef USE_READLINE
  775.  
  776. #define BUFSIZE 1000
  777.  
  778. /*
  779.  * Function: readline
  780.  *
  781.  *   Cheap plastic imitation of GNU readline.
  782.  *
  783.  * Returns:     char *
  784.  - 
  785.  * Parameters:  prompt 
  786.  */
  787. char *
  788. readline (prompt)
  789.   char *prompt;
  790. {
  791.     char buf[BUFSIZE+2];
  792.     if (prompt)
  793.         fputs (prompt, stdout);
  794.     return fgets (buf, BUFSIZE, stdin);
  795. }
  796.  
  797. #endif /* !USE_READLINE */
  798.  
  799. /*
  800.  * Function: save_optarg
  801.  *
  802.  *   Rather silly function that just copies global optarg where told.
  803.  *
  804.  * Returns:     char *
  805.  - 
  806.  * Parameters:  to - place to copy to
  807.  */
  808. char *
  809. save_optarg (to)
  810.   char **to;
  811. {
  812.     *to = xmalloc (strlen (optarg) + 1);
  813.     return strcpy (*to, optarg);
  814. }
  815.  
  816. /*
  817.  * Function: barf
  818.  *
  819.  *   Barf and die.
  820.  *
  821.  * Returns:     Never
  822.  * Parameters:  Those of printf
  823.  */
  824. volatile void
  825. barf (va_alist)
  826.   va_dcl
  827. {
  828.     va_list ap;
  829.     register char *format;
  830.  
  831.     fprintf (stderr, "%s: ", progname);
  832.  
  833.     va_start (ap);
  834.  
  835.     format = va_arg (ap, char *);
  836.     vfprintf (stderr, format, ap);
  837.     va_end (ap);
  838.     fputc ('\n', stderr);
  839.  
  840.     die (1);
  841. }
  842.  
  843. /*
  844.  * Function: die
  845.  *
  846.  *   Nothing is permanent.
  847.  *
  848.  * Returns:     Never
  849.  * Parameters:  code - to return upon exit
  850.  */
  851. volatile void
  852. die (code)
  853.   int code;
  854. {
  855.     if (dpy != NULL)
  856.         XCloseDisplay (dpy);
  857.     exit (code);
  858. }
  859. #ifdef NO_LIBERTY
  860.  
  861. /*
  862.  * Function: xmalloc
  863.  *
  864.  *   Malloc wrapper. Exits on malloc failure.
  865.  *
  866.  * Returns:     char *
  867.  - 
  868.  * Parameters:  size -  size
  869.  */
  870. char *
  871. xmalloc (size)
  872.   unsigned size;
  873. {
  874.     char *malloc ();
  875.     char *s = malloc (size);
  876.     if (!s)
  877.         barf ("Out of core");
  878.     return s;
  879. }
  880. #endif
  881.