home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d3xx / d386 / xlispstat.lha / XLispStat / src3.lzh / UNIX / X11dialogs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-30  |  18.6 KB  |  587 lines

  1. /* X11dialogs - Low level dialog objects for X11                       */
  2. /* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney                  */
  3. /* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz    */
  4. /* You may give out copies of this software; for conditions see the    */
  5. /* file COPYING included with this distribution.                       */
  6.  
  7. /***********************************************************************/
  8. /**                                                                   **/
  9. /**                    General Includes and Definitions               **/
  10. /**                                                                   **/
  11. /***********************************************************************/
  12.  
  13. #include <stdio.h>
  14.  
  15. #include <X11/Xlib.h>
  16. #include <X11/Xutil.h>
  17. #include <X11/Xos.h>
  18. #include <X11/cursorfont.h>
  19.  
  20. #include "dialogs.h"
  21.  
  22. extern Display *StX11Display();
  23.  
  24. typedef struct {
  25.   unsigned long fore, back;
  26. } ColorPair;
  27.  
  28. /***********************************************************************/
  29. /**                                                                   **/
  30. /**                        Global Variables                           **/
  31. /**                                                                   **/
  32. /***********************************************************************/
  33.  
  34. /* configuration parameters - should be set using the defaults database */
  35. static char *DialogFontName = "9x15";
  36. XFontStruct *DialogFont;
  37. unsigned long DialogBorderColor, ButtonBorderColor;
  38. ColorPair DialogC, ButtonC;
  39. unsigned int dialog_border_width, button_border_width, text_border_width,
  40.   list_border_width;
  41. int min_button_height, min_button_width, min_toggle_height, min_choice_height,
  42.   dialog_item_gap;
  43.  
  44. GC DialogGC, DialogRGC;
  45.  
  46. extern XContext EventContext, ObjectContext;
  47.  
  48. #define TOGGLE_MARK_HEIGHT 16
  49. #define CHOICE_MARK_HEIGHT 16
  50.  
  51. /* gray stipple pattern bitmap data for scroll bar thumb items */
  52. #define gray_width 16
  53. #define gray_height 16
  54. static char gray_bits[] = {
  55.    0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
  56.    0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
  57.    0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa};
  58. Pixmap ScrollThumbPM;
  59.  
  60. /* toggle item bitmaps */
  61. #define toggle_off_width TOGGLE_MARK_HEIGHT
  62. #define toggle_off_height TOGGLE_MARK_HEIGHT
  63. static char toggle_off_bits[] = {
  64.    0xff, 0xff, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
  65.    0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
  66.    0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0xff, 0xff};
  67. Pixmap ToggleOffPM;
  68. #define toggle_on_width CHOICE_MARK_HEIGHT
  69. #define toggle_on_height CHOICE_MARK_HEIGHT
  70. static char toggle_on_bits[] = {
  71.    0xff, 0xff, 0x03, 0xc0, 0x05, 0xa0, 0x09, 0x90, 0x11, 0x88, 0x21, 0x84,
  72.    0x41, 0x82, 0x81, 0x81, 0x81, 0x81, 0x41, 0x82, 0x21, 0x84, 0x11, 0x88,
  73.    0x09, 0x90, 0x05, 0xa0, 0x03, 0xc0, 0xff, 0xff};
  74. Pixmap ToggleOnPM;
  75.  
  76. /* choice item bitmaps */
  77. #define choice_off_width 16
  78. #define choice_off_height 16
  79. static char choice_off_bits[] = {
  80.    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x08, 0x10,
  81.    0xe4, 0x27, 0x14, 0x28, 0x14, 0x28, 0x14, 0x28, 0x14, 0x28, 0x14, 0x28,
  82.    0x14, 0x28, 0xe4, 0x27, 0x08, 0x10, 0xf0, 0x0f};
  83. Pixmap ChoiceOffPM;
  84. #define choice_on_width 16
  85. #define choice_on_height 16
  86. static char choice_on_bits[] = {
  87.    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x08, 0x10,
  88.    0xe4, 0x27, 0xf4, 0x2f, 0xf4, 0x2f, 0xf4, 0x2f, 0xf4, 0x2f, 0xf4, 0x2f,
  89.    0xf4, 0x2f, 0xe4, 0x27, 0x08, 0x10, 0xf0, 0x0f};
  90. Pixmap ChoiceOnPM;
  91.  
  92. /* slider button pixmap */
  93. #define left_slider_width 16
  94. #define left_slider_height 16
  95. static char left_slider_bits[] = {
  96.    0x00, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, 0xfc, 0xff,
  97.    0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0xfc, 0xff, 0x08, 0x00, 0x10, 0x00,
  98.    0x20, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00};
  99. Pixmap LeftSliderPM;
  100. #define right_slider_width 16
  101. #define right_slider_height 16
  102. static char right_slider_bits[] = {
  103.    0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0xff, 0x3f,
  104.    0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0xff, 0x3f, 0x00, 0x10, 0x00, 0x08,
  105.    0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00};
  106. Pixmap RightSliderPM;
  107.  
  108. extern Cursor ArrowCursor;
  109. Cursor DoubleArrowCursor, RightArrowCursor, LeftArrowCursor;
  110. Cursor UpDownArrowCursor, UpArrowCursor, DownArrowCursor;
  111.  
  112. /***********************************************************************/
  113. /**                                                                   **/
  114. /**                          Utility Functions                        **/
  115. /**                                                                   **/
  116. /***********************************************************************/
  117.  
  118. Point DialogStringSize(s)
  119.     char *s;
  120. {
  121.   Point pt;
  122.   
  123.   pt.v = DialogFont->max_bounds.ascent + DialogFont->max_bounds.descent;
  124.   pt.h = XTextWidth(DialogFont,s, strlen(s));
  125.  
  126.   return(pt);
  127. }
  128.  
  129. char *checkstring(s)
  130.      LVAL s;
  131. {
  132.   if (! stringp(s)) xlerror("not a string", s);
  133.   return((char *) getstring(s));
  134. }
  135.  
  136. LVAL StX11ItemObject(dpy, win)
  137.      Display *dpy;
  138.      Window win;
  139. {
  140.   LVAL item, win_id;
  141.   LVAL s_window_id = xlenter("WINDOW-ID");
  142.  
  143.   item = NIL;
  144.   win_id = NIL;
  145.   if (XFindContext(dpy, win, ObjectContext, &item) == 0 && objectp(item)) {
  146.     win_id = slot_value(item, s_window_id);
  147.     if (! fixp(win_id)) item = NIL;
  148.   }
  149.   return(item);
  150. }
  151.  
  152. static FindItemType(item)
  153.     LVAL item;
  154. {
  155.   if (consp(item)) return(ITEM_LIST);
  156.   else if (button_item_p(item)) return(BUTTON_ITEM);
  157.   else if (toggle_item_p(item)) return(TOGGLE_ITEM);
  158.   else if (text_item_p(item)) return(TEXT_ITEM);
  159.   else if (choice_item_p(item)) return(CHOICE_ITEM);
  160.   else if (scroll_item_p(item)) return(SCROLL_ITEM);
  161.   else if (list_item_p(item)) return(LIST_ITEM);
  162.   else xlfail("item of unknown type");
  163. }
  164.  
  165. /***********************************************************************/
  166. /**                                                                   **/
  167. /**              Dialog System Initialization and Cleanup             **/
  168. /**                                                                   **/
  169. /***********************************************************************/
  170.  
  171. StX11InitDialogs()
  172. {
  173.   Display *dpy = StX11Display();
  174.   int screen = StX11Screen();
  175.   unsigned long valuemask;
  176.   XGCValues values;
  177.   int font_height, margin;
  178.   char *font;
  179.  
  180.   dialog_border_width = 1;
  181.   button_border_width = 1;
  182.   list_border_width = 1;
  183.   text_border_width = 1;
  184.   min_button_height = 20;
  185.   min_button_width = 100;
  186.   dialog_item_gap = 5;
  187.  
  188.   DialogC.fore = BlackPixel(dpy, screen);
  189.   DialogC.back = WhitePixel(dpy, screen);
  190.   ButtonC.fore = BlackPixel(dpy, screen);
  191.   ButtonC.back = WhitePixel(dpy, screen);
  192.   DialogBorderColor = BlackPixel(dpy, screen);
  193.   ButtonBorderColor = BlackPixel(dpy, screen);
  194.  
  195.   font = (char *) XGetDefault(dpy, "xlisp", "dialog.font");
  196.   if (font == NULL) font = DialogFontName;
  197.   if ((DialogFont = XLoadQueryFont(dpy, font)) == NULL) {
  198.     fprintf(stderr, "xlisp: Can't open %s font\n", font);
  199.     if ((DialogFont = XLoadQueryFont(dpy, DialogFontName)) == NULL) {
  200.       fprintf(stderr, "xlisp: Can't open %s font\n", DialogFontName);
  201.       exit(-1);
  202.     }
  203.   }
  204.  
  205.   min_toggle_height = TOGGLE_MARK_HEIGHT + DialogFont->max_bounds.descent;
  206.   min_choice_height = CHOICE_MARK_HEIGHT + DialogFont->max_bounds.descent;
  207.  
  208.   ScrollThumbPM = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, screen),
  209.                          gray_bits,
  210.                          gray_width, gray_height,
  211.                          BlackPixel(dpy, screen),
  212.                          WhitePixel(dpy, screen),
  213.                          DefaultDepth(dpy, screen));
  214.   ToggleOffPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  215.                       toggle_off_bits, 
  216.                       toggle_off_width, toggle_off_height);
  217.   ToggleOnPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  218.                      toggle_on_bits,
  219.                      toggle_on_width, toggle_on_height);
  220.  
  221.   ChoiceOffPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  222.                       choice_off_bits, 
  223.                       choice_off_width, choice_off_height);
  224.   ChoiceOnPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  225.                      choice_on_bits,
  226.                      choice_on_width, choice_on_height);
  227.  
  228.   LeftSliderPM = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, screen),
  229.                          left_slider_bits,
  230.                          left_slider_width, 
  231.                          left_slider_height,
  232.                          BlackPixel(dpy, screen),
  233.                          WhitePixel(dpy, screen),
  234.                          DefaultDepth(dpy, screen));
  235.   RightSliderPM = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, screen),
  236.                           right_slider_bits,
  237.                           right_slider_width, 
  238.                           right_slider_height,
  239.                           BlackPixel(dpy, screen),
  240.                           WhitePixel(dpy, screen),
  241.                           DefaultDepth(dpy, screen));
  242.  
  243.   valuemask = 0; /* ignore XGCValues and use defaults */
  244.   DialogGC = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
  245.   XSetFont(dpy, DialogGC, DialogFont->fid);
  246.   XSetForeground(dpy, DialogGC, DialogC.fore);
  247.   XSetBackground(dpy, DialogGC, DialogC.back);
  248.  
  249.   valuemask = 0; /* ignore XGCValues and use defaults */
  250.   DialogRGC = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
  251.   XSetFont(dpy, DialogRGC, DialogFont->fid);
  252.   XSetForeground(dpy, DialogRGC, DialogC.back);
  253.   XSetBackground(dpy, DialogRGC, DialogC.fore);
  254.  
  255.   font_height = DialogFont->max_bounds.ascent
  256.               + DialogFont->max_bounds.descent;
  257.   margin = DialogFont->max_bounds.descent / 2;
  258.   if (min_button_height < font_height + 2 * margin)
  259.     min_button_height = font_height + 2 * margin;
  260.   
  261.   DoubleArrowCursor = XCreateFontCursor(dpy, XC_sb_h_double_arrow);
  262.   RightArrowCursor = XCreateFontCursor(dpy, XC_sb_right_arrow);
  263.   LeftArrowCursor = XCreateFontCursor(dpy, XC_sb_left_arrow);
  264.   UpDownArrowCursor = XCreateFontCursor(dpy, XC_sb_v_double_arrow);
  265.   UpArrowCursor = XCreateFontCursor(dpy, XC_sb_up_arrow);
  266.   DownArrowCursor = XCreateFontCursor(dpy, XC_sb_down_arrow);
  267. }
  268.  
  269. StX11FinishDialogs()
  270. {
  271.   Display *dpy = StX11Display();
  272.  
  273.   XUnloadFont(dpy, DialogFont->fid);
  274.   XFreeGC(dpy, DialogGC);
  275.   XFreePixmap(dpy, ScrollThumbPM);
  276.   XFreePixmap(dpy, ToggleOffPM);
  277.   XFreePixmap(dpy, ToggleOnPM);
  278.   XFreePixmap(dpy, ChoiceOffPM);
  279.   XFreePixmap(dpy, ChoiceOnPM);
  280.   XFreePixmap(dpy, LeftSliderPM);
  281.   XFreePixmap(dpy, RightSliderPM);
  282.   XFreeCursor(dpy, DoubleArrowCursor);
  283.   XFreeCursor(dpy, RightArrowCursor);
  284.   XFreeCursor(dpy, LeftArrowCursor);
  285.   XFreeCursor(dpy, UpDownArrowCursor);
  286.   XFreeCursor(dpy, UpArrowCursor);
  287.   XFreeCursor(dpy, DownArrowCursor);
  288. }
  289.  
  290. StX11DialogReset()
  291. {
  292.   Display *dpy = StX11Display();
  293.  
  294.   XUngrabPointer(dpy, CurrentTime);
  295. }
  296.  
  297. /***********************************************************************/
  298. /**                                                                   **/
  299. /**               Constructing and Removing Dialogs                   **/
  300. /**                                                                   **/
  301. /***********************************************************************/
  302.  
  303. static LVAL frame_handler(report, modal)
  304.      XEvent report;
  305.      int modal;
  306. {
  307.   if (modal) return(NIL);
  308.  
  309.   switch(report.type) {
  310.   case ClientMessage:
  311.     StX11HandleClientMessage(report);
  312.     break;
  313.   default:
  314.     break;
  315.   }
  316.   return(NIL);
  317. }
  318.  
  319. DialogAllocate(dialog) 
  320.      LVAL dialog;
  321. {
  322.   char *title;
  323.   Point loc, size;
  324.   int go_away, modeless;
  325.   Window win, panel;
  326.   unsigned int width, height, wheight;
  327.   int left, top;
  328.   XSetWindowAttributes setwinattr;
  329.   unsigned long valuemask;
  330.   Display *dpy = StX11Display();
  331.   int screen = StX11Screen();
  332.  
  333.   if (check_dialog_address(dialog)) DialogRemove(dialog);
  334.     
  335.   if (! stringp(slot_value(dialog, s_title))) 
  336.     xlerror("not a string", slot_value(dialog, s_title));
  337.   title = (char *) getstring(slot_value(dialog, s_title));
  338.  
  339.   loc = ListToPoint(slot_value(dialog, s_location));
  340.   size = ListToPoint(slot_value(dialog, s_size));
  341.   go_away = (slot_value(dialog, s_go_away) != NIL) ? TRUE : FALSE;
  342.   
  343.   modeless = (slot_value(dialog, s_type) == s_modeless) ? TRUE : FALSE;
  344.  
  345.   /* create opaque dialog window */
  346.   left = loc.h; top = loc.v;
  347.   width = size.h; height = size.v;
  348.   wheight = (modeless && go_away) ? height + ClosePanelHeight() : height;
  349.   win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen),
  350.                 left, top, width, wheight, dialog_border_width,
  351.                 DialogBorderColor, DialogC.back);
  352.   if (modeless) StX11SetWindowClass(dpy, win);
  353.   StX11SetNormalHints(dpy, win, left, top, width, wheight);
  354.  
  355.   if (XSaveContext(dpy, win, EventContext, (XContext) frame_handler) != 0)
  356.     xlfail("could not install event handler");
  357.   if (XSaveContext(dpy, win, ObjectContext, (XContext) dialog) != 0)
  358.     xlfail("could not install object in window");
  359.  
  360.   if (! modeless) {
  361.     if (StX11UseICCCM()) StX11SetTransientHint(dpy, win);
  362.     else {
  363.       /* set override_redirect and save_under attributes for a modal dialog */
  364.       valuemask = CWOverrideRedirect | CWSaveUnder;
  365.       setwinattr.override_redirect = TRUE;
  366.       setwinattr.save_under = TRUE;
  367.       XChangeWindowAttributes(dpy, win, valuemask, &setwinattr);
  368.     }
  369.   }
  370.   XStoreName(dpy, win, title);
  371.   set_dialog_address(win, dialog);
  372.   XDefineCursor(dpy, win, ArrowCursor);
  373.   StX11SetStandardHints(dpy, win);
  374.  
  375.   left = 0;
  376.   top = (modeless && go_away) ? ClosePanelHeight() : 0;
  377.   panel = XCreateSimpleWindow(dpy, win,
  378.                   left, top, width, height, dialog_border_width,
  379.                   DialogBorderColor, DialogC.back);
  380.  
  381.   InstallDialogItems(panel, dialog);
  382.   if (modeless && go_away) InstallCloseButton(win, dialog);
  383.  
  384.   /* Display (map) the windows */
  385.   XMapSubwindows(dpy, panel);
  386.   XMapSubwindows(dpy, win);
  387.   XMapWindow(dpy, win);  
  388. }
  389.  
  390. DialogRemove(dialog)
  391.      LVAL dialog;
  392. {
  393.   Window win;
  394.   Display *dpy = StX11Display();
  395.  
  396.   if (check_dialog_address(dialog) 
  397.       && (win = (Window) GETDIALOGADDRESS(dialog)) != nil) {
  398.     if (XDeleteContext(dpy, win, EventContext) != 0)
  399.       xlfail("cound not delete event context");
  400.     if (XDeleteContext(dpy, win, ObjectContext) != 0)
  401.       xlfail("cound not delete object context");
  402.     DeleteDialogItems(dialog);
  403.     DeleteCloseButton(win);
  404.     XDestroyWindow(dpy, win);
  405.     XFlush(dpy);
  406.   }
  407.   if (objectp(dialog)) standard_hardware_clobber(dialog);
  408. }
  409.  
  410. DialogSetDefaultButton(dialog, item) 
  411.      LVAL dialog, item;
  412. {
  413.   if (item == NIL || button_item_p(item))
  414.     set_slot_value(dialog, s_default_button, item);
  415. }
  416.  
  417. static InstallDialogItems(win, dialog)
  418.      Window win;
  419.      LVAL dialog;
  420. {
  421.   LVAL items;
  422.  
  423.   items = slot_value(dialog, s_items);
  424.   InstallItemList(win, items);
  425. }
  426.  
  427. static InstallItemList(win, items)
  428.     Window win;
  429.     LVAL items;
  430. {
  431.   for (; consp(items); items = cdr(items))
  432.     if (consp(car(items))) InstallItemList(win, car(items));
  433.     else InstallItem(win, car(items));
  434. }
  435.   
  436. static InstallItem(win, item)
  437.      Window win;
  438.      LVAL item;
  439. {
  440.   int type;
  441.   
  442.   if (! dialog_item_p(item)) xlerror("not a dialog item", item);
  443.   
  444.   type = FindItemType(item);
  445.   
  446.   switch (type) {
  447.   case BUTTON_ITEM: InstallButtonItem(win, item); break;
  448.   case TOGGLE_ITEM: InstallToggleItem(win, item); break;
  449.   case CHOICE_ITEM: InstallChoiceItem(win, item); break;
  450.   case TEXT_ITEM:   InstallTextItem(win, item); break;
  451.   case SCROLL_ITEM: InstallScrollItem(win, item); break;
  452.   case LIST_ITEM: InstallListItem(win, item); break;
  453.   default: xlfail("unkown item type");
  454.   }
  455. }
  456.  
  457. static DeleteDialogItems(dialog)
  458.      LVAL dialog;
  459. {
  460.   Window win;
  461.   LVAL items;
  462.  
  463.   win = (Window) GETDIALOGADDRESS(dialog);
  464.   if (win != nil) {
  465.     items = slot_value(dialog, s_items);
  466.     DeleteItemList(win, items);
  467.   }
  468. }
  469.  
  470. static DeleteItemList(win, items)
  471.     Window win;
  472.     LVAL items;
  473. {
  474.   for (; consp(items); items = cdr(items))
  475.     if (consp(car(items))) DeleteItemList(win, car(items));
  476.     else DeleteItem(win, car(items));
  477. }
  478.   
  479. static DeleteItem(win, item)
  480.      Window win;
  481.      LVAL item;
  482. {
  483.   int type;
  484.   
  485.   if (! dialog_item_p(item)) xlerror("not a dialog item", item);
  486.   
  487.   type = FindItemType(item);
  488.   
  489.   switch (type) {
  490.   case BUTTON_ITEM: DeleteButtonItem(win, item); break;
  491.   case TOGGLE_ITEM: DeleteToggleItem(win, item); break;
  492.   case CHOICE_ITEM: DeleteChoiceItem(win, item); break;
  493.   case TEXT_ITEM:   DeleteTextItem(win, item); break;
  494.   case SCROLL_ITEM: DeleteScrollItem(win, item); break;
  495.   case LIST_ITEM: DeleteListItem(win, item); break;
  496.   default: xlfail("unkown item type");
  497.   }
  498. }
  499.  
  500. /***********************************************************************/
  501. /**                                                                   **/
  502. /**                       Modal Dialog Loop                           **/
  503. /**                                                                   **/
  504. /***********************************************************************/
  505.  
  506. LVAL DialogGetModalItem(dialog)
  507.      LVAL dialog;
  508. {
  509.   Window win, event_win, old_focus_win;
  510.   Display *dpy = StX11Display();
  511.   XEvent report;
  512.   LVAL result = NIL;
  513.   LVAL (*callback)();
  514.   int old_revert_to, use_icccm;
  515.   LVAL sk_show_window = xlenter(":SHOW-WINDOW");
  516.  
  517.   send_message(dialog, sk_show_window);
  518.   win = GETDIALOGADDRESS(dialog);
  519.   if (win != nil) {
  520.  
  521.     StX11ReleaseButton();
  522.     use_icccm = StX11UseICCCM();
  523.     if (! use_icccm) {
  524.       /* set the input focus and grap the pointer */
  525.       XGetInputFocus(dpy, &old_focus_win, &old_revert_to);
  526.       XSetInputFocus(dpy, win, RevertToPointerRoot, CurrentTime);
  527.       XGrabPointer(dpy, win, TRUE, ButtonReleaseMask,
  528.            GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
  529.     }
  530.  
  531.     /* Loop until button is released, examining each event */
  532.     while (result == NIL) {
  533.       XNextEvent(dpy, &report);
  534.       event_win = report.xany.window;
  535.       if (is_item_window(dpy, event_win, dialog)
  536.       && XFindContext(dpy, event_win, EventContext, &callback) == 0
  537.       && callback != nil)
  538.     result = (*callback)(report, TRUE);
  539.       else if (report.type == Expose)
  540.     StProcessEvent(dpy, report);
  541.       else if (report.type == MappingNotify)
  542.     XRefreshKeyboardMapping(&report);
  543.     }
  544.     if (! use_icccm) {
  545.       XUngrabPointer(dpy, CurrentTime);
  546.       XSetInputFocus(dpy, old_focus_win, old_revert_to, CurrentTime);
  547.     }
  548.     else StX11FlushStdin();
  549.   }
  550.   return(result);
  551. }
  552.  
  553. static is_item_window(dpy, event_win, dialog)
  554.      Display *dpy;
  555.      Window event_win;
  556.      LVAL dialog;
  557. {
  558.   LVAL item;
  559.  
  560.   if (XFindContext(dpy, event_win, ObjectContext, &item) != 0) return(FALSE);
  561.   else if (! objectp(item) || ! dialog_item_p(item)) return(FALSE);
  562.   else if (slot_value(item, s_dialog) != dialog) return(FALSE);
  563.   else return(TRUE);
  564. }
  565.  
  566. install_dialog_item_handler(dpy, win, handler, item)
  567.      Display *dpy;
  568.      Window win;
  569.      LVAL (*handler)(), item;
  570. {
  571.   if (XSaveContext(dpy, win, EventContext, (XContext) handler) != 0)
  572.     xlfail("could not install event handler");
  573. }
  574.   
  575. delete_dialog_item_handler(dpy, win)
  576.      Display *dpy;
  577.      Window win;
  578. {
  579.   if (XDeleteContext(dpy, win, EventContext) != 0)
  580.     xlfail("cound not delete event context");
  581. }
  582.  
  583. #ifdef TODO
  584. register dialog with all subwindows; use in modal loop
  585. make hitting return envoke default button for all dialogs
  586. #endif TODO
  587.