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

  1. /* X11buttons - buttons for X11 dialogs and windows                    */
  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 <X11/Xlib.h>
  14. #include <X11/Xutil.h>
  15. #include <X11/Xos.h>
  16.  
  17. #include "dialogs.h"
  18.  
  19. extern Display *StX11Display();
  20. extern Point DialogStringSize();
  21. extern LVAL StX11ItemObject();
  22. extern char *checkstring();
  23.  
  24. typedef struct {
  25.   unsigned long fore, back;
  26. } ColorPair;
  27.  
  28. /* layout defines */
  29. # define BUTTON_PAD 15
  30. # define BUTTON_LEAD 5
  31.  
  32. # define CloseButton 1
  33. # define MenuButton 2
  34.  
  35. # define CLOSE_TEXT "Close"
  36. # define MENU_TEXT "Menu"
  37.  
  38. /***********************************************************************/
  39. /**                                                                   **/
  40. /**                        Global Variables                           **/
  41. /**                                                                   **/
  42. /***********************************************************************/
  43.  
  44. /* configuration parameters - should be set using the defaults database */
  45. extern XFontStruct *DialogFont;
  46. extern unsigned long DialogBorderColor, ButtonBorderColor;
  47. extern ColorPair DialogC, ButtonC;
  48. extern unsigned int dialog_border_width, button_border_width;
  49. extern int min_button_height, min_button_width, dialog_item_gap;
  50.  
  51. extern GC DialogGC, DialogRGC;
  52.  
  53. extern XContext EventContext, ObjectContext, CloseContext, MenuContext;
  54.  
  55. extern LVAL s_menu, sk_select;
  56.  
  57. /***********************************************************************/
  58. /**                                                                   **/
  59. /**                         Button Items                              **/
  60. /**                                                                   **/
  61. /***********************************************************************/
  62.  
  63. static LVAL track_button(dpy, win, item, modal)
  64.      Display *dpy;
  65.      Window win;
  66.      LVAL item;
  67.      int modal;
  68. {
  69.   int done = FALSE;
  70.   LVAL result = NIL;
  71.   XEvent report;
  72.  
  73.   draw_button(dpy, win, item, TRUE);
  74.  
  75.   while (! done) {
  76.     XNextEvent(dpy, &report);
  77.     switch (report.type) {
  78.     case ButtonRelease:
  79.       done = TRUE;
  80.       result = item;
  81.       break;
  82.     case LeaveNotify:
  83.       done = TRUE;
  84.       if (report.xcrossing.window == win)
  85.     XSetWindowBorderWidth(dpy, win, button_border_width);
  86.       break;
  87.     default:
  88.       break;
  89.     }
  90.   }
  91.   draw_button(dpy, win, item, FALSE);
  92.       
  93.   if (! modal && result != NIL) send_message(item, sk_do_action);
  94.  
  95.   return(result);
  96. }
  97.  
  98. static draw_button(dpy, win, item, reversed)
  99.      Display *dpy;
  100.      Window win;
  101.      LVAL item;
  102.      int reversed;
  103. {
  104.   Point ssz, bsz;
  105.   char *text;
  106.   int x, y, len;
  107.   GC gc;
  108.   unsigned long color;
  109.  
  110.   gc = (reversed) ? DialogRGC : DialogGC;
  111.   color = (reversed) ? DialogC.fore : DialogC.back;
  112.  
  113.   XSetWindowBackground(dpy, win, color);
  114.   XClearWindow(dpy, win);
  115.   text = checkstring(slot_value(item, s_text));
  116.   ssz = DialogStringSize(text);
  117.   bsz = ListToPoint(slot_value(item, s_size));
  118.   x = (bsz.h - ssz.h) / 2;
  119.   y = (bsz.v - ssz.v) / 2 + DialogFont->max_bounds.ascent;
  120.   len = strlen(text);
  121.   XDrawString(dpy, win, gc, x, y, text, len);
  122.   XSetWindowBackground(dpy, win, DialogC.back);
  123. }
  124.   
  125. static LVAL button_handler(report, modal)
  126.      XEvent report;
  127.      int modal;
  128. {
  129.   Display *dpy = StX11Display();
  130.   Window win;
  131.   LVAL item;
  132.   LVAL result = NIL;
  133.  
  134.   win = report.xany.window;
  135.   item = StX11ItemObject(dpy, win);
  136.   if (item != NIL) {
  137.     switch (report.type) {
  138.     case Expose:
  139.       draw_button(dpy, win, item, FALSE);
  140.       break;
  141.     case ButtonPress:
  142.       result = track_button(dpy, win, item, modal);
  143.       break;
  144.     case ButtonRelease:
  145.       break;
  146.     case EnterNotify:
  147.       XSetWindowBorderWidth(dpy,report.xcrossing.window, 
  148.                 button_border_width + 1);
  149.       break;
  150.     case LeaveNotify:
  151.       XSetWindowBorderWidth(dpy, report.xcrossing.window, button_border_width);
  152.       break;
  153.     default: 
  154.       break;
  155.     }
  156.   }
  157.   return(result);
  158. }
  159.  
  160. InstallButtonItem(win, item)
  161.      Window win;
  162.      LVAL item;
  163. {
  164.   Display *dpy = StX11Display();
  165.   Point loc, size;
  166.   Window button;
  167.   LVAL s_window_id = xlenter("WINDOW-ID");
  168.  
  169.   loc = ListToPoint(slot_value(item, s_location));
  170.   size = ListToPoint(slot_value(item, s_size));
  171.   button = XCreateSimpleWindow(dpy, win, loc.h, loc.v, size.h, size.v,
  172.                    button_border_width,
  173.                                ButtonBorderColor, ButtonC.back);
  174.   XSelectInput(dpy, button, 
  175.            StructureNotifyMask | ExposureMask | EnterWindowMask |
  176.                LeaveWindowMask | ButtonPressMask | ButtonReleaseMask);
  177.  
  178.   set_slot_value(item, s_window_id, cvfixnum((FIXTYPE) button));
  179.  
  180.   install_dialog_item_handler(dpy, button, button_handler, item);
  181.   if (XSaveContext(dpy, button, ObjectContext, (XContext) item) != 0)
  182.     xlfail("could not install object in window");
  183. }
  184.  
  185. DeleteButtonItem(win, item)
  186.      Window win;
  187.      LVAL item;
  188. {
  189.   Display *dpy = StX11Display();
  190.   Window button;
  191.   LVAL s_window_id = xlenter("WINDOW-ID");
  192.  
  193.   button = (Window) getfixnum(slot_value(item, s_window_id));
  194.  
  195.   delete_dialog_item_handler(dpy, button);
  196.   if (XDeleteContext(dpy, button, ObjectContext) != 0)
  197.     xlfail("cound not delete object context");
  198.   set_slot_value(item, s_window_id, NIL);
  199. }
  200.  
  201. DialogButtonGetDefaultSize(item, width, height)
  202.      LVAL item;
  203.      int *width, *height;
  204. {
  205.   Point sz;
  206.  
  207.   sz = DialogStringSize(checkstring(slot_value(item, s_text)));
  208.   if (width != nil) *width = max(sz.h + BUTTON_PAD, min_button_width);
  209.   if (height != nil) *height = max(sz.v + BUTTON_LEAD, min_button_height);
  210. }
  211.  
  212. /***********************************************************************/
  213. /**                                                                   **/
  214. /**                          Close Buttons                            **/
  215. /**                                                                   **/
  216. /***********************************************************************/
  217.  
  218. ClosePanelHeight()
  219. {
  220.   Point sz;
  221.  
  222.   sz = DialogStringSize(CLOSE_TEXT);
  223.   return (sz.v + 4 * BUTTON_LEAD);
  224. }
  225.  
  226. static LVAL special_button_object(dpy, button)
  227.      Display *dpy;
  228.      Window button;
  229. {
  230.   LVAL object;
  231.  
  232.   if (XFindContext(dpy, button, ObjectContext, &object) == 0 
  233.       && objectp(object))
  234.     return(object);
  235.   else return(NIL);
  236. }
  237.  
  238. static Point special_button_size(type)
  239.      int type;
  240. {
  241.   char *text;
  242.   Point bsz, ssz;
  243.  
  244.   switch (type) {
  245.   case CloseButton: text = CLOSE_TEXT; break;
  246.   case MenuButton:  text = MENU_TEXT;  break;
  247.   default: break;
  248.   }
  249.  
  250.   ssz = DialogStringSize(text);
  251.   bsz.h = max(ssz.h + BUTTON_PAD, min_button_width);
  252.   bsz.v = max(ssz.v + BUTTON_LEAD, min_button_height);
  253.   return(bsz);
  254. }
  255.  
  256. static track_special_button(dpy, win, type, modal)
  257.      Display *dpy;
  258.      Window win;
  259.      int type, modal;
  260. {
  261.   int done = FALSE, result = FALSE;
  262.   XEvent report;
  263.   LVAL object;
  264.  
  265.   draw_special_button(dpy, win, type, TRUE);
  266.  
  267.   while (! done) {
  268.     XNextEvent(dpy, &report);
  269.     switch (report.type) {
  270.     case ButtonRelease:
  271.       done = TRUE;
  272.       result = TRUE;
  273.       break;
  274.     case LeaveNotify:
  275.       done = TRUE;
  276.       if (report.xcrossing.window == win)
  277.     XSetWindowBorderWidth(dpy, win, button_border_width);
  278.       break;
  279.     default:
  280.       break;
  281.     }
  282.   }
  283.   draw_special_button(dpy, win, type, FALSE);
  284.  
  285.   if (! modal && result == TRUE) {
  286.     switch (type) {
  287.     case CloseButton: 
  288.       object = special_button_object(dpy, win);
  289.       if (object != NIL) send_message(object, sk_close);
  290.       break;
  291.     default:
  292.       break;
  293.     }
  294.   }
  295. }
  296.  
  297. static draw_special_button(dpy, win, type, reversed)
  298.      Display *dpy;
  299.      Window win;
  300.      int type, reversed;
  301. {
  302.   Point ssz, bsz;
  303.   char *text;
  304.   int x, y, len;
  305.   GC gc;
  306.   unsigned long color;
  307.  
  308.   switch (type) {
  309.   case CloseButton: text = CLOSE_TEXT; break;
  310.   case MenuButton:  text = MENU_TEXT; break;
  311.   default: break;
  312.   }
  313.  
  314.   gc = (reversed) ? DialogRGC : DialogGC;
  315.   color = (reversed) ? DialogC.fore : DialogC.back;
  316.  
  317.   XSetWindowBackground(dpy, win, color);
  318.   XClearWindow(dpy, win);
  319.   ssz = DialogStringSize(text);
  320.   bsz = special_button_size(type);
  321.   x = (bsz.h - ssz.h) / 2;
  322.   y = (bsz.v - ssz.v) / 2 + DialogFont->max_bounds.ascent;
  323.   len = strlen(text);
  324.   XDrawString(dpy, win, gc, x, y, text, len);
  325.   XSetWindowBackground(dpy, win, DialogC.back);
  326. }
  327.   
  328. static LVAL basic_special_button_handler(report, modal, type)
  329.      XEvent report;
  330.      int modal, type;
  331. {
  332.   Display *dpy = StX11Display();
  333.   int screen = StX11Screen();
  334.   Window win, child;
  335.   int x, y, item;
  336.   LVAL object, menu;
  337.  
  338.   if (modal) return(NIL);
  339.  
  340.   win = report.xany.window;
  341.   object = special_button_object(dpy, win);
  342.   if (objectp(object) && GETWINDOWADDRESS(object) != nil) {
  343.     switch (report.type) {
  344.     case Expose:
  345.       draw_special_button(dpy, win, type, FALSE);
  346.       break;
  347.     case ButtonPress:
  348.       switch(type) {
  349.       case MenuButton:
  350.     XTranslateCoordinates(dpy, win, RootWindow(dpy, screen),
  351.                   report.xbutton.x, report.xbutton.y, &x, &y,
  352.                   &child);
  353.     menu = slot_value(object, s_menu);
  354.     if (menu_p(menu)) {
  355.       draw_special_button(dpy, win, type, TRUE);
  356.       XSetWindowBorderWidth(dpy, report.xcrossing.window, 
  357.                 button_border_width);
  358.       item = StMObPopup(menu, x, y, NIL);
  359.       draw_special_button(dpy, win, type, FALSE);
  360.       if (item > 0) send_message1(menu, sk_select, item);
  361.     }
  362.     else 
  363.       XSetWindowBorderWidth(dpy, report.xcrossing.window, 
  364.                 button_border_width);
  365.     break;
  366.       default:
  367.     track_special_button(dpy, win, type, modal);
  368.     break;
  369.       }
  370.       break;
  371.     case ButtonRelease:
  372.       break;
  373.     case EnterNotify:
  374.       XSetWindowBorderWidth(dpy,report.xcrossing.window, 
  375.                 button_border_width + 1);
  376.       break;
  377.     case LeaveNotify:
  378.       XSetWindowBorderWidth(dpy, report.xcrossing.window, button_border_width);
  379.       break;
  380.     default: 
  381.       break;
  382.     }
  383.   }
  384.   return(NIL);
  385. }
  386.  
  387. static LVAL close_button_handler(report, modal)
  388.      XEvent report;
  389.      int modal;
  390. {
  391.   return(basic_special_button_handler(report, modal, CloseButton));
  392. }
  393.  
  394. static LVAL menu_button_handler(report, modal)
  395.      XEvent report;
  396.      int modal;
  397. {
  398.   return(basic_special_button_handler(report, modal, MenuButton));
  399. }
  400.  
  401. static install_special_button(win, object, type)
  402.      Window win;
  403.      LVAL object;
  404.      int type;
  405. {
  406.   Display *dpy = StX11Display();
  407.   Point loc, size;
  408.   Window button;
  409.   LVAL (*handler)();
  410.   int width, height, gravity;
  411.   XSetWindowAttributes winattr;
  412.  
  413.   switch (type) {
  414.   case CloseButton:
  415.     loc.h = BUTTON_LEAD;
  416.     loc.v = BUTTON_LEAD;
  417.     size = special_button_size(type);
  418.     handler = close_button_handler;
  419.     gravity = NorthWestGravity;
  420.     break;
  421.   case MenuButton:
  422.     size = special_button_size(type);
  423.     loc.v = BUTTON_LEAD;
  424.     StWGetSize(win, &width, &height, TRUE);
  425.     loc.h = width - size.h - BUTTON_LEAD;
  426.     handler = menu_button_handler;
  427.     gravity = NorthEastGravity;
  428.   default:
  429.     break;
  430.   }
  431.  
  432.   button = XCreateSimpleWindow(dpy, win, loc.h, loc.v, size.h, size.v,
  433.                    button_border_width,
  434.                                ButtonBorderColor, ButtonC.back);
  435.   XSelectInput(dpy, button, 
  436.            StructureNotifyMask | ExposureMask | EnterWindowMask |
  437.                LeaveWindowMask | ButtonPressMask | ButtonReleaseMask);
  438.  
  439.   winattr.win_gravity = gravity;
  440.   XChangeWindowAttributes(dpy, button, CWWinGravity, &winattr);
  441.  
  442.   switch (type) {
  443.   case CloseButton:
  444.     if (XSaveContext(dpy, win, CloseContext, (XContext) button) != 0)
  445.       xlfail("could not install close button context");
  446.     break;
  447.   case MenuButton:
  448.     if (XSaveContext(dpy, win, MenuContext, (XContext) button) != 0)
  449.       xlfail("could not install menu button context");
  450.     break;
  451.   default:
  452.     break;
  453.   }
  454.   if (XSaveContext(dpy, button, EventContext, (XContext) handler) != 0)
  455.     xlfail("could not install event handler");
  456.   if (XSaveContext(dpy, button, ObjectContext, (XContext) object) != 0)
  457.     xlfail("could not install object in window");
  458. }
  459.  
  460. static delete_special_button(win, type)
  461.      Window win;
  462. {
  463.   Display *dpy = StX11Display();
  464.   Window button;
  465.   XContext context;
  466.  
  467.   switch (type) {
  468.   case CloseButton: context = CloseContext; break;
  469.   case MenuButton:  context = MenuContext;  break;
  470.   default: break;
  471.   }
  472.  
  473.   if (XFindContext(dpy, win, context, &button) == 0) {
  474.     if (XDeleteContext(dpy, win, context) != 0)
  475.       xlfail("could not delete buttont context");
  476.     if (XDeleteContext(dpy, button, EventContext) != 0)
  477.       xlfail("could not delete event context");
  478.     if (XDeleteContext(dpy, button, ObjectContext) != 0)
  479.       xlfail("could not delete object context");
  480.   }
  481. }
  482.  
  483. InstallCloseButton(win, object)
  484.      Window win;
  485.      LVAL object;
  486. {
  487.   install_special_button(win, object, CloseButton);
  488. }
  489.  
  490. DeleteCloseButton(win)
  491.      Window win;
  492. {
  493.   delete_special_button(win, CloseButton);
  494. }
  495.  
  496. InstallMenuButton(win, object)
  497.      Window win;
  498.      LVAL object;
  499. {
  500.   install_special_button(win, object, MenuButton);
  501. }
  502.  
  503. DeleteMenuButton(win)
  504.      Window win;
  505. {
  506.   delete_special_button(win, MenuButton);
  507. }
  508.