Previousrizzle.cNext
1 /* vim:set nowrap: 2 * 3 * Rizzle - a 'rollup' manager for Motif. 4 * 5 * Copyright 2002-2004, David Wijnants. All rights reserved. 6 * See LICENSE for details. 7 * email: [protected] 8 **/ 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <stdarg.h> 13 #include <string.h> 14 #include <unistd.h> 15 #include <fcntl.h> 16 #include <signal.h> 18 #include <X11/Xlib.h> 19 #include <X11/Xmu/WinUtil.h> 20 #include <X11/Xmu/Error.h>
Version control:
  26 #ifndef VERSION
  27 #error What, no version ?
  28 #endif

  30 const char *rizzle_idents[] = {
  31    "@(#) $Compiled: " __DATE__ " " __TIME__ " $",
  32    "@(#) $Id: rizzle.c,v 1.33.2.11 2004/07/07 13:23:45 dave Exp $",
  33    "@(#) $Name: rel1-2-2 $",
  34 };
Symbolic constants:
  40 #define RESCLASS "Rizzle"
  41 #define RESNAME  "pager"
  42 #define RESTITLE "Pager"

  44 #define SILENT  0
  45 #define QUIET   1
  46 #define VERBOSE 2

  48 #define DEFAULTMARGIN 4
Global variables:
  54 static int  hush = 0;
  55 static int  errors = 0;
  56 static int  noise = SILENT;
  57 static int  nodaemon = 0;
  58 static int  marg = -1;
  59 static int  sqs = -1;
  60 static Atom wm_state;
  61 static Atom wm_delete_window;
  62 static Atom motif_wm_hints;
  63 static Atom rollup_for;
  64 static Atom rolled_up;
  65 static int  bg;

  67 typedef struct wininfo {
  68    Window            full;
  69    Window            small;
  70    char             *name;
  71    struct wininfo   *prev;
  72    struct wininfo   *next;
  73 } WININFO;
  74 static WININFO *rollups;

  76 typedef struct transinfo {
  77    Window            win;
  78    Window            client;
  79    Window            leader;
  80    int               hidden;
  81    struct transinfo *prev;
  82    struct transinfo *next;
  83 } TRANSINFO;
  84 static TRANSINFO *transients;

  86 static struct {
  87    Display *dpy;
  88    int      screen;
  89    Window   root;
  90    Window   win;
  91    Window   pager;
  92    int      x;
  93    int      y;
  94 } current;
Prototypes:
 100 void       ParseParams        (int argc, char **argv);
 101 int        Initialise         (void);
 102 int        AlreadyRunning     (void);
 103 void       InitPager          (void);
 104 void       Daemon             (void);
 105 void       RegisterTransients (void);
 106 Window     UpdateCurrent      (int window);
 107 WININFO   *IsRolledUp         (Window w);
 108 int        IsFullSize         (Window w);
 109 WININFO   *IsOurs             (Window w);
 110 int        IsFragile          (Window w);
 111 WININFO   *RollUpWindow       (Window w);
 112 void       RestoreWindow      (Window w);
 113 WININFO   *AddWindow          (void);
 114 void       RemoveWindow       (WININFO *this);
 115 Window     GetClient          (Window w);
 116 TRANSINFO *AddTransient       (Window w);
 117 void       RemoveTransient    (Window w);
 118 void       HideTransients     (Window cw);
 119 void       UnHideTransients   (Window cw);
 120 Window     TransientFor       (Window cw);
 121 Window     RizzleRollupFor    (Window cw);
 122 Window     IsRizzleRolledUp   (Window cw);
 123 void       RemoveRollupProps  (void);
 124 void       GetWindowState     (Window cw, int *state, Window *icon);
 125 Window     FindTopmost        (void);
 126 int        CheckWindow        (Window w);
 127 void       InitX              (void);
 128 void       ExitX              (void);
 129 int        ErrorHandler       (Display *dpy, XErrorEvent *event);
 130 void       CleanExit          (void);
 131 char      *EventName          (int type);
 132 void       quiet              (char *fmt, ...);
 133 void       verbose            (char *fmt, ...);
 134 void       always             (char *fmt, ...);
Making sure thing are clean on exit (cf. atexit):
 140 void sighand (int signo) {
 141    char buf[80];
 142    sprintf (buf, "\nRizzle killed by signal %d\n", signo);
 143    write (2, buf, strlen(buf));
 144    exit (EXIT_SUCCESS);
 145 }

 147 int IOErrorHandler (Display *dpy) {
 148    char buf[80];
 149    sprintf ( buf,
 150              "\nRizzle killed by X server on %s\n",
 151              DisplayString(dpy) );
 152    write (2, buf, strlen(buf));
 153    exit (EXIT_SUCCESS);
 154    return (0);
 155 }

 157 int stricmp (char *s1, char *s2) {
 158    while ( *s1 != 0 &&
 159            *s2 != 0 &&
 160            *s1 == *s2 ) {
 161       s1++;
 162       s2++;
 163    }
 164    return ( *s1 - *s2 );
 165 }


Previousrizzle.cNext

main(argc,argv)

Main Program.

Parameters

argc(in) int; number of command line parameters.
argv(in) char**; command line parameters.

Returns

int; EXIT_SUCCESS or EXIT_FAILURE.

 181 int main (int argc, char **argv)
 182 {
 183    int    dx = -1, dy = -1;           /* button-down coordinates */

 185    Window mw = None;                  /* temp variable - plain window */

 187    XEvent event;                      /* message from event queue */
Initialisation.
 193    ParseParams (argc, argv);
 194    if ( !Initialise() ) return (EXIT_FAILURE);
 195    if ( !nodaemon ) Daemon ();
 196    RegisterTransients ();
 197    UpdateCurrent (1);
 198    atexit (CleanExit);
 199    RemoveRollupProps ();
Make clear from the start what we're going to do.
 205    printf ("rizzle: rollup windows enabled\n");
 206    if ( marg != DEFAULTMARGIN ) printf ("rizzle: wiggle margin %d\n", marg);
 207    printf ("\n");
If running as a daemon, stop all further stdio.
 213    if ( !nodaemon ) {
 214       fflush (stdout);
 215       close (STDIN_FILENO); open ("/dev/null", O_RDONLY);
 216       close (STDOUT_FILENO); open ("/dev/null", O_WRONLY);
 217    }
The event loop:
 223    for (;;) {

 225       XNextEvent (current.dpy, &event);
 226       if ( event.type != UnmapNotify ) mw = None;

 228       switch ( event.type ) {
We track motion events because we need to know which window the mouse cursor is on before the popup menu appears. If we didn't, we'd get the window id of the popup menu every time.
 237          case MotionNotify:

 239             current.x   = event.xmotion.x;
 240             current.y   = event.xmotion.y;
 241             current.win = event.xmotion.window;
 242             dx = dy = -1;
 243             break;
If a window suddenly appears, remember its id and the current mouse position, and also check that the cursor has not been moved by more than a few pixels. The problem is, though, that our own windows will also generate MapNotify events, so we have to check these first.
 253          case MapNotify:

 255             verbose ("MapNotify event\n");
 256             if ( IsOurs(GetClient(event.xmap.window)) ) break;
 257             dx = current.x;
 258             dy = current.y;
 259             UpdateCurrent (0);
 260             if ( abs(current.x-dx) <= marg &&
 261                  abs(current.y-dy) <= marg ) {
 262                mw = event.xmap.window;
 263                dx = current.x;
 264                dy = current.y;
 265             }
 266             break;
When a window disappears from view, do the clever stuff.

Check that the disappearing window is the same as the one that appeared just a moment ago (i.e. it came and went), which suggests it may have been a popup window. Even so, it might still be one of ours (it might be the full-size window we've just hidden away). Second, check that the cursor has not moved (by more than a few pixels); and that the window has not gone altogether (i.e. been destroyed). If it looks like it was the elusive popup window, do some more checks to decide whether to roll up or restore the window, or to ignore it anyway (e.g. it must be in the title bar of a window).

 284          case UnmapNotify:

 286             verbose ("UnmapNotify event\n");
 287             if ( event.xunmap.window == mw &&
 288                  IsOurs(event.xunmap.window) == 0 ) {
 289                UpdateCurrent (1);
 290                if ( abs(current.x-dx) <= marg &&
 291                     abs(current.y-dy) <= marg &&
 292                     current.win != None &&
 293                     CheckWindow(current.win) != 0 &&
 294                     IsFragile(GetClient(current.win)) == 0 ) {
 295                   mw = current.win;
 296                   if ( IsRolledUp(mw) ) RestoreWindow (mw);
 297                   else if ( IsFullSize(mw) ) RollUpWindow (mw);
 298                }
 299             }
 300             dx = dy = -1;
 301             mw = None;
 302             break;
We also need to track the creation of transient windows, because they need to be manually remapped when a rolled-up window is restored.
 310          case CreateNotify:
 311             verbose ("CreateNotify event\n");
 312             AddTransient (event.xcreatewindow.window);
 313             break;
 314          case DestroyNotify:
 315             verbose ("DestroyNotify event\n");
 316             RemoveTransient (event.xdestroywindow.window);
 317             break;
Anything else ? Just ignore it for now. Expect to see client messages when a rolled-up window is closed by double-clicking the top-left-hand corner (the window will have been restored as a side-effect).
 326          case ClientMessage:
 327          default:

 329             verbose ("%s event\n", EventName(event.type));
 330             break;
 331       }
 332    }
Event loop over. This code is never actually reached, as there is no stop condition in the event loop (we just keep running until we're killed or the X server terminates).
 340    XCloseDisplay (current.dpy);
 341    return (EXIT_SUCCESS);
 342 }


Previousrizzle.cNext

ParseParams(argc,argv)

Interpret command line parameters.

Parameters

argc(in) int; number of command line parameters.
argv(in) char**; command line parameters.

Returns

None.

 358 void ParseParams (int argc, char **argv)
 359 {
 360    char  *p;                          /* sliding pointer */

 362    int    t,                          /* loop counter */
 363           i,                          /* just another int */
 364           usage = 0;                  /* nonzero to display usage */

 366    for (t=1; t<argc; t++) {
 367       if ( *argv[t] == '-' ) {
 368          for (p=argv[t]+1; *p; p++) {
 369             switch ( *p ) {
 370                case 's': noise = SILENT;  break;
 371                case 'q': noise = QUIET;   break;
 372                case 'v': noise = VERBOSE; break;
 373                case 'd': nodaemon = 1;    break;
 374                default:  usage = 1;       break;
 375             }
 376          }
 377       } else if ( sscanf(argv[t],"sqs=%d",&i) ) {
 378          sqs = i;
 379          verbose ("Assuming %d-pixel title bar\n", sqs);
 380       } else {
 381          usage = 1;
 382          break;
 383       }
 384    }

 386    if ( usage ) {
 387       fprintf (stderr, "\n");
 388       fprintf (stderr, "Usage:    $ rizzle [-dsqv]\n");
 389       fprintf (stderr, "\n");
 390       fprintf (stderr, "Options:  d  do not become a daemon\n");
 391       fprintf (stderr, "          s  silent, no diagnostics\n");
 392       fprintf (stderr, "          q  quiet, minimum diagnostics\n");
 393       fprintf (stderr, "          v  verbose, lots of diagnostics\n");
 394       fprintf (stderr, "\n");
 395       exit (EXIT_FAILURE);
 396    }
 397 }


Previousrizzle.cNext

Initialise()

Initialise X and prepare for pointer and map/unmap events on the root window; and allocate memory for the window and transients lists.

Parameters

None.

Returns

int; nonzero ok, zero on failure.

 414 int Initialise (void)
 415 {
 416    int yesno = 0;                     /* nonzero for success */

 418    char *res;                         /* resource string */

 420    long mask = PointerMotionMask      /* Motion */
 421              | SubstructureNotifyMask /* Map, Unmap, Create, Destroy */
 422              ;

 424    XColor col;                        /* colour */

 426    if ( (rollups=(WININFO*)calloc(1,sizeof(WININFO))) &&
 427         (transients=(TRANSINFO*)calloc(1,sizeof(TRANSINFO))) ) {
 428       InitX ();
 429       if ( !AlreadyRunning() ) {
 430          InitPager ();
 431          /* some more X initialisation */
 432          XSelectInput (current.dpy, current.root, mask);
 433          /* get default background colour */
 434          if (( res=XGetDefault(current.dpy,"Rizzle",XNBackground) )) {
 435             Colormap cmap = DefaultColormap (current.dpy, current.screen);
 436             if ( XParseColor(current.dpy,cmap,res,&col) ) {
 437                XAllocColor (current.dpy, cmap, &col);
 438                bg = col.pixel;
 439             } else {
 440                quiet ("Invalid background colour '%s', defaulting to black\n", res);
 441             }
 442          } else {
 443             quiet ("No *background resource, defaulting to black\n");
 444          }
 445          /* wiggle margin */
 446          if ( marg <= 0 ) {
 447             res = XGetDefault (current.dpy, "Rizzle", "moveThreshold");
 448             if ( !res ) res = XGetDefault (current.dpy, "Mwm", "moveThreshold");
 449             if ( !res ) res = "(undefined)";
 450             marg = atoi (res);
 451             if ( marg <= 0 ) marg = DEFAULTMARGIN;
 452          }
 453          /* install error handlers */
 454          XSetErrorHandler (ErrorHandler);
 455          XSetIOErrorHandler (IOErrorHandler);
 456          signal (SIGINT, sighand);
 457          signal (SIGTERM, sighand);
 458          yesno = 1;
 459       } else {
 460          fprintf ( stderr,
 461                    "Already running on display %s\n",
 462                    DisplayString(current.dpy) );
 463       }
 464    } else {
 465       fprintf (stderr, "Out of memory\n");
 466    }

 468    if ( yesno ) {
 469       printf ( "\n"
 470                "Rizzle %s - a 'rollup' manager for Motif.\n"
 471                "\n"
 472                "Copyright (c) 2002-2004 David Wijnants\n"
 473                "\n"
 474                "No money back, no guarantees, no nothing; just the software and the full source\n"
 475                "code, for you to do with whatever you like. See the file LICENSE for details.\n"
 476                "\n"
 477                "email: [protected]\n"
 478                "\n",
 479                VERSION );
 480    }

 482    return (yesno);
 483 }


Previousrizzle.cNext

AlreadyRunning()

Check that there isn't already a rizzle running, as multiple instances will only interfere with each other.

Parameters

None.

Returns

int; nonzero there is already a rizzle, zero if not.

 499 int AlreadyRunning (void)
 500 {
 501    unsigned int  ncld,                /* number of child windows */
 502                  c;                   /* (child) loop counter */

 504    Window        wdummy,              /* dummy parameter */
 505                 *cld=NULL,            /* child window array */
 506                  cw,                  /* client window id */
 507                  running=None;        /* running rizzle's window id */

 509    XClassHint    ch;                  /* class hints */

 511    if ( XQueryTree ( current.dpy,
 512                      current.root,
 513                      &wdummy,
 514                      &wdummy,
 515                      &cld,
 516                      &ncld ) && ncld ) {
 517       for (c=0; c<ncld; c++) {
 518          cw = XmuClientWindow (current.dpy, cld[c]);
 519          if ( XGetClassHint(current.dpy,cw,&ch) ) {
 520             if ( ch.res_class && !strcmp(ch.res_class,RESCLASS) &&
 521                  ch.res_name && !strcmp(ch.res_name,RESNAME) ) {
 522                running = cw;
 523             }
 524             XFree (ch.res_class);
 525             XFree (ch.res_name);
 526             if ( running ) break;
 527          }
 528       }
 529       XFree (cld);
 530    }

 532    return (running);
 533 }


Previousrizzle.cNext

InitPager()

Create the pager window.

This doesn't do anything yet, but the fact that the window exists, gives an indication that there's already a rizzle running. The window is also guaranteed to go away if we are killed uncleanly, whereas a lockfile tends to stay around rather annoyingly.

Parameters

None.

Returns

None.

 554 void InitPager (void)
 555 {
 556    XClassHint chint;                  /* class hints */

 558    current.pager = XCreateSimpleWindow ( current.dpy,
 559                                          current.root,
 560                                          10, 10,
 561                                          10, 10,
 562                                          1, 1,
 563                                          0 );
 564    XStoreName (current.dpy, current.pager, RESTITLE);
 565    chint.res_class = RESCLASS;
 566    chint.res_name  = RESNAME;
 567    XSetWMProperties ( current.dpy,
 568                       current.pager,
 569                       NULL,
 570                       NULL,
 571                       NULL, 0,
 572                       NULL, /* size hints */
 573                       NULL,
 574                       &chint );
 575 }


Previousrizzle.cNext

Daemon()

Become a daemon process; this ensures we don't end up a zombie when we're killed.

Parameters

None.

Returns

None.

 591 void Daemon (void)
 592 {
 593    fflush (stdout);
 594    if ( fork() ) exit (EXIT_SUCCESS);
 595    setsid ();
 596    if ( fork() ) exit (EXIT_SUCCESS);
 597 }


Previousrizzle.cNext

RegisterTransients()

Check already existing toplevel windows, keeping track of the ones that are transient.

Parameters

None.

Returns

None.

 613 void RegisterTransients (void)
 614 {
 615    unsigned int  ncld,                /* number of child windows */
 616                  c;                   /* (child) loop counter */

 618    Window        wdummy,              /* dummy parameter */
 619                 *cld=NULL;            /* child window array */

 621    if ( !XQueryTree ( current.dpy,
 622                       RootWindow(current.dpy,current.screen),
 623                       &wdummy,
 624                       &wdummy,
 625                       &cld,
 626                       &ncld ) ) {
 627       always ("XQueryTree() failed\n");
 628       return;
 629    }

 631    if ( cld ) {
 632       for (c=0; c<ncld; c++) AddTransient (cld[c]);
 633       XFree (cld);
 634    }
 635 }


Previousrizzle.cNext

UpdateCurrent(window)

Register the current pointer location and, optionally, which window it's on. Keep the bits in the global structure current.

Parameters

window(in) int; nonzero to include window in update.

Returns

Window; current window.

 652 Window UpdateCurrent (int window)
 653 {
 654    int          idummy;               /* dummy integer */
 655    unsigned int udummy;               /* dummy unsigned */
 656    Window       wdummy;               /* dummy window */

 658    Window       cwin;                 /* current window */

 660    XQueryPointer ( current.dpy,            /* display */
 661                    current.root,           /* window */
 662                    &wdummy,                /* root return */
 663                    &cwin,                  /* child return */
 664                    &current.x, &current.y, /* root x,y return */
 665                    &idummy, &idummy,       /* child x,y return */
 666                    &udummy );              /* mask return */

 668    if ( window ) current.win = cwin;

 670    return (cwin);
 671 }


Previousrizzle.cNext

IsRolledUp(w)

Check if the specified window is one of our rolled-up title bars; just a matter of scanning our linked list.

Parameters

w(in) Window; (plain) window id.

Returns

WININFO*; the window list element if the window is currently rolled up, NULL if not.

 688 WININFO *IsRolledUp (Window w)
 689 {
 690    WININFO *this;                     /* sliding pointer */

 692    if ( !CheckWindow(w) ) return (NULL);
 693    w = GetClient (w);

 695    for ( this = rollups;
 696          this->next != NULL && this->small != w;
 697          this = this->next ) ;

 699    if ( this != NULL && this->small == w ) {
 700       verbose ("Window 0x%lx is a rollup\n", w);
 701       return (this);
 702    }

 704    verbose ("Window 0x%lx is not a rollup\n", w);
 705    return (NULL);
 706 }


Previousrizzle.cNext

IsFullSize(w)

Check that we've clicked on the title bar of a full size window. This is the complicated bit that probably depends most on mwm, as other window managers are likely to give different XQueryTree() results.

Parameters

w(in) Window; (plain) window id.

Returns

int; nonzero if on title bar, zero if not.

 724 int IsFullSize (Window w)
 725 {
 726    unsigned int       ncld;           /* number of children */

 728    Window            *cld = NULL,     /* child window array */
 729                       tcw,            /* 'topmost child window' */
 730                       wdummy;         /* dummy window variable */

 732    XWindowAttributes  attr;           /* window attributes */

 734    int wx, wy; unsigned int ww, wh, wb, wd; /* window geometry */
Note: we do not convert to client window ids here, as the X routines [ the XQueryTree() hierarchy in particular ] require the plain window id from the X event. We do make a quick check to see if the window still exists (I know, this is an impossible thing to do...).
 744    if ( !CheckWindow(w) ) return (0);
First of all, check that it's not an override redirect window, i.e. one we have to ignore.
 751    verbose ("Attributes: ");
 752    if ( !XGetWindowAttributes(current.dpy,w,&attr) ) {
 753       always ("XGetWindowAttributes() failed !\n");
 754       return (0);
 755    }
 756    if ( attr.override_redirect ) {
 757       verbose ("override redirect !\n");
 758       return (0);
 759    }
 760    verbose ("ok.\n");
Check if the window has children, so we don't blitz mwm icons (because they are not override redirect). While we've got the list of children, remember the id of the topmost in the stacking order [ which is the last one in the list returned by QueryTree() ] in case we need to figure out the size of the title bar.
 771    verbose ("Children: ");
 772    if ( !XQueryTree ( current.dpy,
 773                       w,
 774                       &wdummy,
 775                       &wdummy,
 776                       &cld,
 777                       &ncld ) || !cld ) {
 778       verbose ("none !\n");
 779       return (0);
 780    }
 781    verbose ("%d, ok\n", ncld);
 782    tcw = cld[ncld-1];
 783    XFree (cld);
If we don't already know the size of the title bar, now's the time to work it out from the x,y coordinates of the topmost child window.
 791    if ( sqs == -1 ) {
 792       XGetGeometry ( current.dpy,
 793                      tcw,
 794                      &wdummy,
 795                      &wx, &wy,
 796                      &ww, &wh,
 797                      &wb, &wd );
 798       if ( !wy ) {
 799          verbose ("Still no title bar size\n");
 800          return (0);
 801       }
 802       sqs = wy;
 803       verbose ("Title bar is %d pixels\n", sqs);
 804    }
Check that the current pointer location is in the top band of the window (title bar), but not on the system menu button.
 811    verbose ("Pointer location: ");
 812    XGetGeometry ( current.dpy,
 813                   w,
 814                   &wdummy,
 815                   &wx, &wy,
 816                   &ww, &wh,
 817                   &wb, &wd );
 818    if ( (current.y-wy) > sqs || (current.x-wx) < sqs ) {
 819       verbose ("not in top %d pixels !\n", sqs);
 820       return (0);
 821    }
 822    verbose ("in top %d pixels, ok.\n", sqs);
All the boxes have been ticked, we're in business !
 828    verbose ("We're on a title bar.\n");
 829    return (1);
 830 }


Previousrizzle.cNext

IsOurs(w)

Check if the specified window is one of ours (full-size or rolled-up), so we can ignore the map/unmap events for these. Just a matter of scanning our linked list.

Parameters

w(in) Window; window id.

Returns

WININFO*; the window list element if the window is one of ours, NULL if not.

 848 WININFO *IsOurs (Window w)
 849 {
 850    WININFO *this;                     /* sliding pointer */

 852    for ( this = rollups;
 853          this->next != NULL && w != this->small && w != this->full;
 854          this = this->next ) ;

 856    if ( this != NULL && this->small == w ) {
 857       return (this);
 858    }

 860    return (NULL);
 861 }


Previousrizzle.cNext

IsFragile(w)

Check if the specified window is one we should definitely not roll up because something horrible might happen (like mwm dying).

If the window has a resource called isFragile that is set to 'true', treat the application as fragile. If the resource is set to 'false', treat the application as safe, regardless of 'known dodgyness'.

One or two particularly important and commonly-used 'dodgy' applications (such as mwm) are hard-coded for convenience, because you wouldn't want rizzle to break a typical system by default if you happen to forget to define the necessary resources.

Parameters

w(in) Window; (client) window id.

Returns

int; zero if it's safe to rollup this window, nonzero if it isn't.

 890 int IsFragile (Window cw)
 891 {
 892    char       *res;                /* resource value */

 894    int         unsafe = 0;         /* nonzero means do not roll up */

 896    XClassHint  ch;                 /* class hints: name and resource */

 898    if ( XGetClassHint(current.dpy,cw,&ch) ) {
 899       if ( ch.res_class ) {
 900          if ( !strcmp(ch.res_class,"Mwm") ) {
 901             unsafe = 1;
 902             res = XGetDefault (current.dpy, ch.res_class, "isFragile");
 903             if ( res ) {
 904                if ( !stricmp(res,"f") ||
 905                     !stricmp(res,"false") ) {
 906                   verbose ( "Your %s is not fragile? "
 907                             "Ok, on your head be it, then.\n",
 908                             ch.res_class );
 909                   unsafe = 0;
 910                }
 911             }
 912          } else {
 913             res = XGetDefault (current.dpy, ch.res_class, "isFragile");
 914             if ( res ) {
 915                if ( !stricmp(res,"t") ||
 916                     !stricmp(res,"true") ) {
 917                   unsafe = 1;
 918                }
 919             }
 920          }
 921       }
 922       XFree (ch.res_name);
 923       XFree (ch.res_class);
 924    }

 926    return (unsafe);
 927 }


Previousrizzle.cNext

RollUpWindow(w)

Remove the specified window from view, and replace it with a rolled-up title bar. The replacement title bar gets the same position, width and properties as the original window.

Parameters

w(in) Window; (plain) window id of full-size window.

Returns

WININFO*; new window list element if the window has been rolled up, NULL if not.

 946 WININFO *RollUpWindow (Window w)
 947 {
 948    int            wx, wy,             /* window location */
 949                   idummy,             /* dummy int variable */
 950                   format;             /* format of property data */

 952    unsigned int   ww, wb,             /* window dimensions */
 953                   udummy;             /* dummy unsigned int variable */

 955    unsigned long  nitems,             /* number of items in props */
 956                   bytesafter;         /* number of bytes not read */

 958    unsigned char *props = NULL;       /* mwm properties */

 960    Window         wdummy,             /* dummy window variable */
 961                   cw;                 /* client window */

 963    XSizeHints     hints;              /* minimum window size */

 965    WININFO       *new;                /* new window list element */

 967    Atom           type;               /* type of property data */
Add the window to the linked list.
 973    new = AddWindow ();
 974    if ( !new ) return (NULL);
 975    cw = GetClient (w);
XGetGeometry() and XResizeWindow() are a bit weird; to get the rolled-up title bar in the same position as the original window, we must use the client window width (i.e. without a border), and the toplevel position (because the client window always has 0,0 coordinates) - hence the two function calls.
 985    XGetGeometry ( current.dpy,
 986                   cw,
 987                   &wdummy,
 988                   &idummy, &idummy,
 989                   &ww, &udummy,
 990                   &udummy, &udummy );
 991    XGetGeometry ( current.dpy,
 992                   w,
 993                   &wdummy,
 994                   &wx, &wy,
 995                   &udummy, &udummy,
 996                   &wb, &udummy );
Create a new rolled-up window, and store its client window id. Also make sure we trap the WM_DELETE_WINDOW protocol events, otherwise we'll get deaded (you rotten swine, Eccles!) whenever a rolled-up window gets double-clicked in its top-left-hand corner.
1006    new->small = XCreateSimpleWindow ( current.dpy,  /* display */
1007                                       current.root, /* parent */
1008                                       1, 1,         /* x,y */
1009                                       1, 1,         /* width,height */
1010                                       wb,           /* border width */
1011                                       0,            /* border pixel */
1012                                       bg );         /* background */
1013    XSetWMProtocols (current.dpy, new->small, &wm_delete_window, 1);
Copy the original window's properties to the rollup (including such things as the absence of resize handles on dialog boxes).
1020    if ( !XGetWindowProperty ( current.dpy,    /* display */
1021                               cw,             /* window */
1022                               motif_wm_hints, /* property */
1023                               0L,             /* long offset */
1024                               20L,            /* long length */
1025                               False,          /* don't delete */
1026                               motif_wm_hints, /* required type */
1027                               &type,          /* actual type return */
1028                               &format,        /* format return */
1029                               &nitems,        /* number of items */
1030                               &bytesafter,    /* bytes after return */
1031                               &props )        /* mwm hints */
1032                         && props ) {
1033       XChangeProperty ( current.dpy,
1034                         new->small,
1035                         motif_wm_hints,
1036                         type,
1037                         format,
1038                         PropModeReplace,
1039                         props,
1040                         nitems );
1041       XFree (props);
1042    }
If the original window is transient, make the rolled-up one transient for the same leader.
1049    new->small = GetClient (new->small);
1050    if (( wdummy=TransientFor(cw) )) {
1051       XSetTransientForHint (current.dpy, new->small, wdummy);
1052    }
The rolled-up window wants to be resizeable horizontally, but not vertically.
1059    hints.max_height = 0;
1060    hints.max_width = DisplayWidth (current.dpy, current.screen);
1061    hints.flags = PMaxSize;
1062    XSetWMProperties ( current.dpy, /* display */
1063                       new->small,  /* window */
1064                       NULL,        /* window name */
1065                       NULL,        /* icon name */
1066                       NULL,        /* argv */
1067                       0,           /* argc */
1068                       &hints,      /* normal_hints */
1069                       NULL,        /* wm_hints */
1070                       NULL );      /* class_hint */
Make the rolled-up window easier to recognise and pair up with its original, by setting their _RIZZLE_ROLLUP_FOR and _RIZZLE_ROLLED_UP properties.
1078    XChangeProperty ( current.dpy,
1079                      new->small,
1080                      rollup_for,
1081                      rollup_for,
1082                      32,
1083                      PropModeReplace,
1084                      (unsigned char*)&cw,
1085                      1 );
1086    XChangeProperty ( current.dpy,
1087                      cw,
1088                      rolled_up,
1089                      rolled_up,
1090                      32,
1091                      PropModeReplace,
1092                      (unsigned char*)&new->small,
1093                      1 );
If a window has mapped transients, we will get DestroyNotify events when those windows are automatically popped down by the window manager. When this happens, we must not remove those windows from the list of transients, as we will need to remap them ourselves when the rolled-up window is restored.
1103    HideTransients (cw);
Popup the rolled-up window, and remove the original from view.
1109    new->full = cw;
1110    if ( XFetchName(current.dpy,new->full,&new->name) && new->name ) {
1111       XStoreName (current.dpy, new->small, new->name);
1112    }
1113    XMapWindow (current.dpy, new->small);
1114    XMoveResizeWindow (current.dpy, new->small, wx, wy, ww, 1);
1115    quiet ("Rolling up 0x%lx (%s)\n", new->full, new->name?new->name:"");
1116    XWithdrawWindow (current.dpy, new->full, current.screen);
1117    return (new);
1118 }


Previousrizzle.cNext

RestoreWindow(w)

Replace the specified rolled-up window with its full-size equivalent. The full-size window has its original height, but the position and width are taken from the rollup, which may have been moved or resized by the user.

Parameters

w(in) Window; window id of rolled-up window.

Returns

None.

1137 void RestoreWindow (Window w)
1138 {
1139    int          wx, wy,               /* window location */
1140                 idummy;               /* dummy int variable */

1142    unsigned int ww, wh,               /* window dimensions */
1143                 udummy;               /* dummy unsigned int variable */

1145    Window       wdummy,               /* dummy window variable */
1146                 cw;                   /* client window */

1148    XWMHints    *hints;                /* did window start iconic ? */

1150    WININFO     *this;                 /* sliding pointer */
Lookup the rollup window in the linked list, using its client window id.
1157    cw = GetClient (w);
1158    for ( this = rollups;
1159          this->next != NULL && this->small != cw;
1160          this = this->next ) ;
1161    if ( !this ) {
1162       always ("'ere, this isn't a rollup...\n");
1163       return;
1164    }
If the application was started as an icon, make sure it stays up, and doesn't go back to its iconic state.
1171    if (( hints=XGetWMHints(current.dpy,this->full) )) {
1172       if ( hints->initial_state == IconicState ) {
1173          hints->initial_state = NormalState;
1174          XSetWMHints (current.dpy, this->full, hints);
1175       }
1176       XFree (hints);
1177    }
We have the same problem restoring the window as when we shrank it, namely that we have to ask for a client-size window (without a border), and get a slightly larger window, but the position is given with the border included. In this case we have three function calls, because we also need the original height (even though we're not going to be changing it).
1189    XGetGeometry ( current.dpy,
1190                   this->full,
1191                   &wdummy,
1192                   &idummy, &idummy,
1193                   &udummy, &wh,
1194                   &udummy, &udummy );
1195    XGetGeometry ( current.dpy,
1196                   w,
1197                   &wdummy,
1198                   &wx, &wy,
1199                   &udummy, &udummy,
1200                   &udummy, &udummy );
1201    XGetGeometry ( current.dpy,
1202                   this->small,
1203                   &wdummy,
1204                   &idummy, &idummy,
1205                   &ww, &udummy,
1206                   &udummy, &udummy );
Remove the window's _RIZZLE_ROLLED_UP property.
1212    XDeleteProperty (current.dpy, this->full, rolled_up);
Popup the full-size window, and remove the rollup from view. Make sure the restored window is the same width as the rolled-up title bar, and get rid of the rollup. Before removing the window from the list, we will need to manually remap (unhide) its transients.
1221    quiet ("Unrolling 0x%lx (%s)\n", this->full, this->name?this->name:"");
1222    XMapWindow (current.dpy, this->full);
1223    XMoveResizeWindow ( current.dpy,
1224                        this->full,
1225                        wx, wy,
1226                        ww, wh );
1227    XDestroyWindow (current.dpy, this->small);
1228    if ( this->name ) XFree (this->name);
1229    UnHideTransients (this->full);
1230    RemoveWindow (this);
1231 }


Previousrizzle.cNext

AddWindow()

Create a new entry in the linked list of currently rolled-up windows. The new entry will be inserted at head of the linked list, as the entries are not in any particular order.

Parameters

None.

Returns

WININFO*; newly created window list item.

1249 WININFO *AddWindow (void)
1250 {
1251    WININFO *head = rollups,           /* start of window list */
1252            *new;                      /* new item to insert at head */

1254    if (( new=(WININFO*)malloc(sizeof(WININFO)) )) {
1255       memset (new, 0, sizeof(WININFO));
1256       new->prev = head;
1257       new->next = head->next;
1258       if ( new->next ) new->next->prev = new;
1259       head->next = new;
1260    } else {
1261       quiet ("Not enough memory\n");
1262    }

1264    return (new);
1265 }


Previousrizzle.cNext

RemoveWindow(this)

Remove an entry from the linked list of currently rolled-up windows. Any dynamic data in the entry (e.g. malloc'ed memory, windows we've created) must have been freed beforehand.

Parameters

this(inout) WININFO*; entry to remove, will be zeroed and freed.

Returns

None.

1284 void RemoveWindow (WININFO *this)
1285 {
1286    this->prev->next = this->next;
1287    if ( this->next ) this->next->prev = this->prev;
1288    memset (this, 0, sizeof(WININFO));
1289    free (this);
1290 }


Previousrizzle.cNext

GetClient(w)

Convenience routine to get the client window id for a given window.

Parameters

w(in) Window; window to get client window id for.

Returns

Window; client window of w.

1306 Window GetClient (Window w)
1307 {
1308    return ( XmuClientWindow(current.dpy,w) );
1309 }


Previousrizzle.cNext

AddTransient(w)

Add a window to the linked list of transients if the window is transient.

Parameters

w(in) Window; (plain) window id for entry.

Returns

TRANSINFO*; newly created linked list item if the window is transient, NULL if not.

1326 TRANSINFO *AddTransient (Window w)
1327 {
1328    TRANSINFO *head = transients,      /* head of list */
1329              *new,                    /* new item to insert at head */
1330              *this;                   /* sliding pointer */

1332    Window     tfor,                   /* window we're transient for */
1333               cw = GetClient(w);      /* client window */
Check that the window is transient in the first place. If the window is the same as its client window, ignore it, as it is about to be reparented.
1341    if ( cw == w ) return (NULL);
1342    tfor = TransientFor (cw);
1343    if ( !tfor ) return (NULL);
Lookup the window in the linked list of transients. If the window is already in the list, update the details, as they are likely to have changed (transient windows have an unfortunate tendency to be destroyed for no apparent reason, that's their very nature).
1352    for ( this = transients;
1353          this->next != NULL && this->client != cw;
1354          this = this->next ) ;
1355    if ( this != NULL && this->client == cw ) {
1356       this->win = w;
1357       this->leader = tfor;
1358       return (this);
1359    }
Create a new linked list entry, and insert it at the start of the list.
1366    if (( new=(TRANSINFO*)malloc(sizeof(TRANSINFO)) )) {
1367       memset (new, 0, sizeof(TRANSINFO));
1368       new->win = w;
1369       new->client = cw;
1370       new->leader = tfor;
1371       new->hidden = 0;
1372       new->prev = head;
1373       new->next = head->next;
1374       if ( new->next ) new->next->prev = new;
1375       head->next = new;
1376    } else {
1377       quiet ("Not enough memory\n");
1378    }
Return the new item, or NULL if malloc failed.
1384    return (new);
1385 }


Previousrizzle.cNext

RemoveTransient(w)

Remove an entry from the linked list of transients.

Parameters

w(in) Window; (plain) window id of entry to remove.

Returns

None.

1400 void RemoveTransient (Window w)
1401 {
1402    TRANSINFO *this;                   /* sliding pointer */

1404    for ( this = transients;
1405          this->next != NULL && this->win != w;
1406          this = this->next ) ;

1408    if ( this != NULL && this->win == w && this->hidden == 0 ) {
1409       this->prev->next = this->next;
1410       if ( this->next ) this->next->prev = this->prev;
1411       memset (this, 0, sizeof(TRANSINFO));
1412       free (this);
1413    }
1414 }


Previousrizzle.cNext

HideTransients(cw)

When a window is rolled up, its transients will automatically be unmapped by the window manager.

When this happens, we will receive DestroyNotify events, so we must remember not to remove them, as we'll need to know which transients to remap when the rolled-up window is restored.

Parameters

cw client window id.

Returns

None.

1435  static void HideTransientsR (Window cw)
1436  {
1437     TRANSINFO *this;
1438     for (this=transients; this; this=this->next) {
1439        if ( this->leader == cw ) {
1440           this->hidden++;
1441           HideTransientsR (this->client);
1442        }
1443     }
1444  }

1446 void HideTransients (Window cw)
1447 {
1448    TRANSINFO *this;
1449    for (this=transients; this; this=this->next) {
1450       if ( this->client == cw ) {
1451          this->hidden++;
1452          break;
1453       }
1454    }
1455    HideTransientsR (cw);
1456 }


Previousrizzle.cNext

UnHideTransients(cw)

When a rolled-up window is restored, we will need to remap its associated transients ourselves, as mwm will not do it for us. When we do, we will also need to re-associate the windows with the window they were transient for.

Parameters

cw client window id.

Returns

None.

1475  static void UnHideTransientsR (Window cw)
1476  {
1477     TRANSINFO *this;
1478     for (this=transients; this; this=this->next) {
1479        if ( this->leader == cw ) {
1480           if ( this->hidden ) this->hidden--;
1481           if ( !this->hidden ) XMapWindow (current.dpy, this->client);
1482           UnHideTransientsR (this->client);
1483        }
1484     }
1485  }

1487 void UnHideTransients (Window cw)
1488 {
1489    TRANSINFO *this;
1490    for (this=transients; this; this=this->next) {
1491       if ( this->client == cw ) {
1492          if ( this->hidden ) this->hidden--;
1493          break;
1494       }
1495    }
1496    UnHideTransientsR (cw);
1497 }


Previousrizzle.cNext

TransientFor(cw)

Convenience routine to return the transient for hint of a window, if it has one.

Parameters

cw(in) Window; client window to get hint for.

Returns

Window; window id of the leader the window is transient for, or None if the window is not transient.

1514 Window TransientFor (Window cw)
1515 {
1516    Window tfor;                       /* window we're transient for */

1518    if ( XGetTransientForHint(current.dpy,cw,&tfor) && tfor )
1519       return (tfor);
1520    else
1521       return (None);
1522 }


Previousrizzle.cNext

RizzleRollupFor(cw)

Return the specified window's _RIZZLE_ROLLUP_FOR property - if it has one.

If the window has the said property, its value is the window id of the hidden full-size window. If the window hasn't got the property, None is returned, since the window is not a rollup.

Parameters

cw(in) Window; (client) window id.

Returns

None.

1543 Window RizzleRollupFor (Window cw)
1544 {
1545    int            format;      /* property format - ignored */

1547    unsigned char *prop;        /* property value - window id */

1549    unsigned long  nitems,      /* number of properties - ignored */
1550                   bytesafter;  /* number of unread bytes - ignored */

1552    Window         ret=None;    /* window id to return */

1554    Atom           type;        /* property type - ignored */

1556    if ( !XGetWindowProperty ( current.dpy,
1557                               cw,
1558                               rollup_for,
1559                               0L,
1560                               20L,
1561                               False,
1562                               AnyPropertyType,
1563                               &type,
1564                               &format,
1565                               &nitems,
1566                               &bytesafter,
1567                               &prop ) && prop ) {
1568       ret = *(Window*)prop;
1569       XFree (prop);
1570    }
1571    return (ret);
1572 }


Previousrizzle.cNext

IsRizzleRolledUp(cw)

Check if the specified window is invisible because it is rolled up (by looking at its _RIZZLE_ROLLED_UP property).

If if is rolled up, then the returned (property) value is the window id of its rollup. If it the window isn't rolled up, None is returned.

Parameters

cw(in) Window; (client) window id.

Returns

None.

1593 Window IsRizzleRolledUp (Window cw)
1594 {
1595    int            format;      /* property format - ignored */

1597    unsigned char *prop;        /* property value - window id */

1599    unsigned long  nitems,      /* number of properties - ignored */
1600                   bytesafter;  /* number of unread bytes - ignored */

1602    Window         ret=None;    /* window id to return */

1604    Atom           type;        /* property type - ignored */

1606    if ( !XGetWindowProperty ( current.dpy,
1607                               cw,
1608                               rolled_up,
1609                               0L,
1610                               20L,
1611                               False,
1612                               AnyPropertyType,
1613                               &type,
1614                               &format,
1615                               &nitems,
1616                               &bytesafter,
1617                               &prop ) && prop ) {
1618       ret = *(Window*)prop;
1619       XFree (prop);
1620    }
1621    return (ret);
1622 }


Previousrizzle.cNext

RemoveRollupProps()

Remove the _RIZZLE_ROLLED_UP properties from all toplevel windows (the _RIZZLE_ROLLUP_FORs are cleaned up automatically as the rollups are destroyed whenever rizzle exits or dies).

Parameters

None.

Returns

None.

1640 void RemoveRollupProps (void)
1641 {
1642    unsigned int ncld,             /* number of child windows */
1643                 c;                /* (child) loop counter */

1645    Window       wdummy,           /* dummy Window parameter */
1646                *cld=NULL,         /* child window array */
1647                 cw;               /* client window id */

1649    if ( XQueryTree ( current.dpy,
1650                      current.root,
1651                      &wdummy,
1652                      &wdummy,
1653                      &cld,
1654                      &ncld ) && ncld ) {
1655       for (c=0; c<ncld; c++) {
1656          cw = GetClient (cld[c]);
1657          XDeleteProperty (current.dpy, cw, rolled_up);
1658       }
1659    }
1660 }


Previousrizzle.cNext

GetWindowState(cw,state,icon)

Get the specified window's WM_STATE property, which returns the window's state (IconicState, NormalState or WithdrawnState) and its icon window.

Parameters

cw(in) Window; (client) window id.
state(out) int; IconicState, WithdrawnState or NormalState.
icon(out) Window*; the window's icon.

Returns

None.

1680 void GetWindowState (Window cw, int *state, Window *icon)
1681 {
1682    int            format,      /* property format - ignored */
1683                  *prop;        /* property value - window id */

1685    unsigned long  nitems,      /* number of properties - ignored */
1686                   bytesafter;  /* number of unread bytes - ignored */

1688    Atom           type;        /* property type - ignored */

1690    if ( !XGetWindowProperty ( current.dpy,
1691                               cw,
1692                               wm_state,
1693                               0L,
1694                               8L,
1695                               False,
1696                               wm_state,
1697                               &type,
1698                               &format,
1699                               &nitems,
1700                               &bytesafter,
1701                               (unsigned char**)&prop ) && prop ) {
1702       *state = prop[0];
1703       *icon  = prop[1];
1704       XFree (prop);
1705    } else {
1706       *state = WithdrawnState;
1707       *icon = None;
1708    }
1709 }


Previousrizzle.cNext

CheckWindow(w)

Check a window id for validity (this is impossible !). Since X is asynchronous, errors happen after the event, and there is no way of predicting when the error will surface.

We cover up most of the errors here, by getting our custom error handler to suppress BadWindow diagnostics while the hush flag is set. Some errors will still creep through. Note I could have avoided this problem if I'd kept a list of all windows in the first place, but then I'd have ended up writing a window manager...

Parameters

w(in) Window; window id to be checked.

Returns

int; nonzero if ok, zero on error.

1735 int CheckWindow (Window w)
1736 {
1737    int ret;                           /* return value */

1739    XWindowAttributes attr;            /* (dummy) window attributes */

1741    errors = 0;

1743    hush = 1;
1744    XGetWindowAttributes (current.dpy, w, &attr);
1745    XSync (current.dpy, False);
1746    hush = 0;

1748    ret = ( errors == 0 );
1749    errors = 0;
1750    if ( !ret ) quiet ("Window 0x%lx is faulty\n", w);

1752    return (ret);
1753 }


Previousrizzle.cNext

InitX()

Initialise standard X things.

Parameters

None.

Returns

None.

1768 void InitX (void)
1769 {
1770    current.dpy = XOpenDisplay (NULL);
1771    if ( !current.dpy ) {
1772       fprintf (stderr, "Cannot open display\n");
1773       exit (EXIT_FAILURE);
1774    }
1775    current.screen = DefaultScreen (current.dpy);
1776    current.root = RootWindow (current.dpy, current.screen);
1777    wm_state = XInternAtom (current.dpy, "WM_STATE", False);
1778    wm_delete_window = XInternAtom (current.dpy, "WM_DELETE_WINDOW", False);
1779    motif_wm_hints = XInternAtom (current.dpy, "_MOTIF_WM_HINTS", False);
1780    rollup_for = XInternAtom (current.dpy, "_RIZZLE_ROLLUP_FOR", False);
1781    rolled_up = XInternAtom (current.dpy, "_RIZZLE_ROLLED_UP", False);
1782 }

1784 void ExitX (void)
1785 {
1786    XFlush (current.dpy);
1787    exit (EXIT_SUCCESS);
1788 }


Previousrizzle.cNext

ErrorHandler(dpy,event)

Catch X diagnostics happening asynchronously after some error.

Expect (!) some BadWindow diagnostics as a result of trying to find out the client window id for a window that is dead...

Parameters

dpy(in) Display*; where it happened.
event(in) XErrorEvent*; what happened.

Returns

int; always zero.

1809 int ErrorHandler (Display *dpy, XErrorEvent *event)
1810 {
1811    errors++;

1813    if ( !hush ) {
1814       if ( event->error_code != BadWindow ||
1815            noise >= QUIET ) {
1816          fprintf (stderr, "\n");
1817          fprintf (stderr, "\n");
1818          fprintf (stderr, "***************************************************************************\n");
1819          XmuPrintDefaultErrorMessage (dpy, event, stderr);
1820          fprintf (stderr, "***************************************************************************\n");
1821          fprintf (stderr, "\n");
1822          fprintf (stderr, "\n");
1823       }

1825       if ( event->error_code == BadWindow ||
1826            event->error_code == BadDrawable ) return (0);
1827       else exit (EXIT_FAILURE);
1828    }

1830    return (0);
1831 }


Previousrizzle.cNext

CleanExit()

Before exiting the program, make sure everything is ok; in particular that any rolled-up windows are remapped.

Parameters

None.

Returns

None.

1847 void CleanExit (void)
1848 {
1849    char     str[80];                  /* string buffer */

1851    WININFO *this = rollups;           /* sliding pointer */
Bring back the rolled-up windows. FIXME this would be done much nicer by RestoreWindow(), but that won't work for some reason; perhaps this is just not a terribly good time to be doing things with Xlib...
1860    while (( this=this->next )) {
1861       sprintf (str, "Restoring 0x%lx ", this->full);
1862       write (2, str, strlen(str));
1863       if ( this->name ) write (2, this->name, strlen(this->name));
1864       write (2, "\n", 1);
1865       XMapWindow (current.dpy, this->full);
1866    }
1867    RemoveRollupProps ();
1868    XSync (current.dpy, False);
1869 }


Previousrizzle.cNext

EventName(type)

Return the event name for a given event type.

Parameters

type(in) int; event type.

Returns

char*; event name.

1884 char *EventName (int type)
1885 {
1886    switch ( type ) {
1887       case KeyPress:         return ("KeyPress");
1888       case KeyRelease:       return ("KeyRelease");
1889       case ButtonPress:      return ("ButtonPress");
1890       case ButtonRelease:    return ("ButtonRelease");
1891       case MotionNotify:     return ("MotionNotify");
1892       case EnterNotify:      return ("EnterNotify");
1893       case LeaveNotify:      return ("LeaveNotify");
1894       case FocusIn:          return ("FocusIn");
1895       case FocusOut:         return ("FocusOut");
1896       case KeymapNotify:     return ("KeymapNotify");
1897       case Expose:           return ("Expose");
1898       case GraphicsExpose:   return ("GraphicsExpose");
1899       case NoExpose:         return ("NoExpose");
1900       case VisibilityNotify: return ("VisibilityNotify");
1901       case CreateNotify:     return ("CreateNotify");
1902       case DestroyNotify:    return ("DestroyNotify");
1903       case UnmapNotify:      return ("UnmapNotify");
1904       case MapNotify:        return ("MapNotify");
1905       case MapRequest:       return ("MapRequest");
1906       case ReparentNotify:   return ("ReparentNotify");
1907       case ConfigureNotify:  return ("ConfigureNotify");
1908       case ConfigureRequest: return ("ConfigureRequest");
1909       case GravityNotify:    return ("GravityNotify");
1910       case ResizeRequest:    return ("ResizeRequest");
1911       case CirculateNotify:  return ("CirculateNotify");
1912       case CirculateRequest: return ("CirculateRequest");
1913       case PropertyNotify:   return ("PropertyNotify");
1914       case SelectionClear:   return ("SelectionClear");
1915       case SelectionRequest: return ("SelectionRequest");
1916       case SelectionNotify:  return ("SelectionNotify");
1917       case ColormapNotify:   return ("ColormapNotify");
1918       case ClientMessage:    return ("ClientMessage");
1919       case MappingNotify:    return ("MappingNotify");
1920       default:               return ("???");
1921    }
1922    return ("???");
1923 }


Previousrizzle.cNext

quiet|verbose|always(fmt,...)

printf-type convenience routines to output debugging info depending on the requested noise level.

quiet() speaks when necessary, or when saying something useful, except if the noise level is set to silent. verbose() is used to give lots of information, not all of it useful, and can be told to shut up by setting the noise level to quiet or silent. always() displays the information, regardless of the noise level, even when set to silent [use this only for essential diagnostics].

Parameters

fmt(in) char*; printf format specifier.
...(in) additional parameters depending on format.

Returns

None.

1949 void quiet (char *fmt, ...)
1950 {
1951    if ( noise >= QUIET ) {
1952       va_list list;
1953       va_start (list, fmt);
1954       vfprintf (stderr, fmt, list);
1955       va_end (list);
1956    }
1957 }

1959 void verbose (char *fmt, ...)
1960 {
1961    if ( noise >= VERBOSE ) {
1962       va_list list;
1963       va_start (list, fmt);
1964       vfprintf (stderr, fmt, list);
1965       va_end (list);
1966    }
1967 }

1969 void always (char *fmt, ...)
1970 {
1971    va_list list;
1972    va_start (list, fmt);
1973    vfprintf (stderr, fmt, list);
1974    va_end (list);
1975 }