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

  1. /* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT
  2.  * Copyright 1989 Massachusetts Institute of Technology
  3.  */
  4. /*****************************************************\
  5. *                               *
  6. *     BULL WINDOW MANAGER for X11 .              *
  7. *                               *
  8. *         MODULE defining the Menu Wob Class    *
  9. *                               *
  10. \*****************************************************/
  11.  
  12. /*  include  */
  13.  
  14. #include    "EXTERN.h"
  15. #include "wool.h"
  16. #include "wl_atom.h"
  17. #include "wl_number.h"
  18. #include "wl_string.h"
  19. #include "wl_list.h"
  20. #include "gwm.h"
  21. #include "wl_fsm.h"
  22. #include "wl_pixmap.h"
  23. #include "wl_cursor.h"
  24. #include "wl_bar.h"
  25. #include "wl_menu.h"
  26.  
  27. /*  local constants  */
  28.  
  29. /*  external  */
  30.  
  31. extern Wob      NewWob();
  32.  
  33. extern Menu MenuOpen();
  34. extern MenuClose(), MenuEventHandler(), ReconfigureMenu();
  35.  
  36. #ifdef SHAPE            /* compile with -I/usr/include/X11 AND
  37.                    -I/usr/include/X11/extensions to work on
  38.                    machines having shapes.h in either place */
  39. #include    <shape.h>
  40. extern MenuIsShaped(), UpdateMenuShape();
  41. #endif /* SHAPE */
  42.  
  43. WOB_METHOD       MenuClass[] = {
  44.                    0,    /* METHODS_ARRAY */
  45.                    WobEval,
  46.                    WobPrint,
  47.                    WobRelease,
  48.                    WobExecute,
  49.                    WobSet,
  50.                    WobGetCValue,
  51.                    (WOB_METHOD) MenuOpen,
  52.                    MenuClose,
  53.                    MenuEventHandler,
  54.                                (WOB_METHOD) wool_undefined_method_1,
  55.                    WobGetDimensions,
  56.                                (WOB_METHOD) wool_undefined_method_2,
  57.                                (WOB_METHOD) wool_undefined_method_2,
  58.                                ReconfigureMenu,
  59.             (WOB_METHOD) wool_undefined_method_2,
  60.             (WOB_METHOD) wool_undefined_method_1,
  61.             (WOB_METHOD) wool_undefined_method_1,
  62.             (WOB_METHOD) wool_undefined_method_1,
  63.             (WOB_METHOD) wool_undefined_method_1,
  64.             (WOB_METHOD) wool_undefined_method_1
  65. };
  66.  
  67. unsigned int    MenuMask = 0;
  68.  
  69. /*  routines  */
  70.  
  71. Menu    NewMenu(), MenuOpen();
  72.  
  73. /*
  74.  * Set up a menu
  75.  */
  76.  
  77. Menu
  78. SetUpMenu(wl_menu)
  79. WOOL_Menu    wl_menu;
  80. {
  81.     Menu menu = NewMenu(Context->rootWob, wl_menu);
  82.  
  83.     UpdateMenuGeometry(menu);
  84.     MenuOpen(menu);
  85.     return menu;
  86. }
  87.  
  88. Menu
  89. MenuOpen(menu)
  90. Menu             menu;
  91. {
  92.     int             i;
  93.  
  94.     check_window_size(menu);
  95.     menu -> hook =
  96.     XCreateSimpleWindow(dpy, Context->root,
  97.                 menu -> box.x, menu -> box.y,
  98.                 menu -> box.width, menu -> box.height,
  99.                 menu -> box.borderwidth,
  100.                 menu -> box.borderpixel, menu -> box.background);
  101.     menu -> status = MenuStatus | TopLevelXWindowStatus;
  102.     WobRecordHook(menu);
  103.     for (i = 0; i < menu -> nbars; i++)
  104.     WOOL_send(WOOL_open, menu -> bars[i], (menu -> bars[i]));
  105.     menu -> curstate = (int) WOOL_send(WOOL_open, menu -> fsm, (menu -> fsm));
  106.     menu -> input_mask = MenuMask | ((WOOL_Fsm) menu -> fsm) -> mask;
  107.     XSelectInput(dpy, menu -> hook, menu -> input_mask); 
  108.     if (menu -> cursor != NIL)
  109.     XDefineCursor(dpy, menu -> hook,
  110.               ((WOOL_Cursor) menu -> cursor) -> cursor);
  111.     if (menu -> bordertile != NIL)
  112.     XSetWindowBorderPixmap(dpy, menu -> hook,
  113.                    ((WOOL_Pixmap) menu -> bordertile) -> pixmap);
  114.     {
  115.     XSetWindowAttributes wa;    /* menus are OverrideRedirect */
  116.  
  117.     wa.override_redirect = 1;
  118.     XChangeWindowAttributes(dpy, menu -> hook, CWOverrideRedirect, &wa);
  119.     }
  120. #ifdef SHAPE
  121.     if (MenuIsShaped(menu)) {
  122.       UpdateMenuShape(menu);
  123.     }
  124. #endif /* SHAPE */
  125.     XMapSubwindows(dpy, menu -> hook);
  126.     return menu;
  127. }
  128.  
  129. Menu 
  130. NewMenu(parent, wl_menu)
  131. Wob             parent;
  132. WOOL_Menu    wl_menu;
  133. {
  134.     int             i;
  135.     Menu            menu;
  136.     int             dir =
  137.     (wl_menu -> direction == HORIZONTAL ? VERTICAL : HORIZONTAL);
  138.     WOOL_OBJECT     object;
  139.  
  140.     menu = (Menu) NewWob(sizeof(struct _Menu)
  141.              + sizeof(Bar) * Max(0, (wl_menu -> bars_size - 1)));
  142.     wl_menu = (WOOL_Menu) wool_type_or_evaluate(wl_menu, WLMenu);
  143.     menu -> type = MenuClass;
  144.     menu -> parent = parent;
  145.     menu -> screen = ((ClientWindow) parent) -> screen;
  146.     menu -> box.borderwidth = wl_menu -> borderwidth;
  147.     menu -> box.borderpixel = wl_menu -> borderpixel;
  148.     menu -> box.background = wl_menu -> background;
  149.     menu -> direction = wl_menu -> direction;
  150.     menu -> bar_separator = wl_menu -> bar_separator;
  151.     menu -> min_width = DefaultMenuMinWidth;
  152.     menu -> max_width = DefaultMenuMaxWidth;
  153.     increase_reference(menu  -> menu = 
  154.                        wool_type_or_evaluate(wl_menu -> menu, WLMenu));
  155.     increase_reference(menu -> property = (WOOL_OBJECT) wl_menu -> property);
  156.     increase_reference(menu -> bordertile =
  157.             wool_type_or_evaluate(wl_menu -> bordertile, WLPixmap));
  158.     increase_reference(menu -> fsm =
  159.                wool_type_or_evaluate(wl_menu -> fsm, WLFsm));
  160.     increase_reference(menu -> cursor =
  161.                wool_type_or_evaluate(wl_menu -> cursor, WLCursor));
  162.     menu -> nbars = wl_menu -> bars_size;
  163.     for (i = 0; i < wl_menu -> bars_size; i++) {
  164.     object = wool_type_or_evaluate(wl_menu -> bars[i], WLBar);
  165.     UpdateClientWindowBar(menu, &(menu -> bars[i]), object, dir);
  166.     }
  167.     return menu;
  168. }
  169.  
  170. MenuClose(menu)
  171. Menu             menu;
  172. {
  173.     int i;
  174.  
  175.     for (i = 0; i < menu -> nbars; i++) {
  176.     BarClose(menu -> bars[i]);
  177.     }
  178.     WobRelease(menu);
  179. }
  180.  
  181. /*
  182.  * Set here the dimensions of a menu
  183.  */
  184.  
  185. UpdateMenuGeometry(menu)
  186. Menu    menu;
  187. {
  188.     int             i, width = 0, length = 0;
  189.     int             dir = menu -> direction;
  190.  
  191.     for (i = 0; i < menu -> nbars; i++) {
  192.     if (dir == HORIZONTAL) {
  193.         menu -> bars[i] -> box.x = length;
  194.         menu -> bars[i] -> box.y = 0;
  195.     } else {
  196.         menu -> bars[i] -> box.x = 0;
  197.         menu -> bars[i] -> box.y = length;
  198.     }
  199.     length += UpdateBarWidth(menu -> bars[i]) +
  200.         menu -> bar_separator;
  201.     width = Max(NaturalBarLength(menu -> bars[i]), width);
  202.     }
  203.     width = Min(Max(width, menu -> min_width), menu -> max_width);
  204.     length = Max(length - menu -> bar_separator, 1);
  205.     if (dir == HORIZONTAL) {
  206.     menu -> box.width = length;
  207.     menu -> box.height = width;
  208.     } else {
  209.     menu -> box.width = width;
  210.     menu -> box.height = length;
  211.     }
  212.     for (i = 0; i < menu -> nbars; i++) {
  213.     if (dir == HORIZONTAL)
  214.         menu -> bars[i] -> box.height = width
  215.         - 2 * menu -> bars[i] -> box.borderwidth;
  216.     else
  217.         menu -> bars[i] -> box.width = width
  218.         - 2 * menu -> bars[i] -> box.borderwidth;
  219.     UpdateBarLength(menu -> bars[i]);
  220.     }
  221.  
  222. }
  223.  
  224. /*
  225.  * Since a menu will receive events for its sons, we must transmit them!
  226.  */
  227.  
  228. MenuEventHandler(menu, evt)
  229. Menu    menu;
  230. XEvent    *evt;
  231. {
  232.     int             i;
  233.  
  234.     switch (evt -> type) {
  235.     case GWMUserEvent:
  236.     WLFsm_action(menu -> fsm, menu, evt);
  237.     if (GWM_Propagate_user_events)
  238.         for (i = 0; i < menu -> nbars; i++)
  239.         if (menu -> bars[i])
  240.             WOOL_send(WOOL_process_event, menu -> bars[i],
  241.                   (menu -> bars[i], evt));
  242.     break;
  243.     case ClientMessage:
  244.     if (evt -> xclient.message_type == XA_WM_PROTOCOLS
  245.         && evt -> xclient.data.l[0] == (long) XA_WM_DELETE_WINDOW) {
  246.                 /* to not be sent messages later */
  247.         if (((ClientWindow) menu -> parent) -> client_wob == (Wob) menu)
  248.         ((ClientWindow) menu -> parent) -> client_wob = 0;
  249.         MenuClose(menu);
  250.     } else {
  251.         WLFsm_action(menu -> fsm, menu, evt);
  252.     }
  253.     break;
  254.     case PropertyNotify:    /* HACK for placed menus */
  255.     WOOL_send(WOOL_process_event, menu -> parent, (menu -> parent, evt));
  256.     break;
  257.     default:
  258.     WLFsm_action(menu -> fsm, menu, evt);
  259.     }
  260. }
  261.     
  262. ReconfigureMenu(menu, culprit)
  263. Menu     menu;
  264. Bar      culprit;        /* only bar */
  265. {
  266.     int             i, width = menu -> box.width, height = menu ->box.height;
  267.     int shaped = 0;
  268.  
  269.     UpdateMenuGeometry(menu);
  270.     for (i = 0; i < menu -> nbars; i++)
  271.     if (menu -> bars[i])
  272.         WOOL_send(WOOL_reconfigure, menu -> bars[i],
  273.               (menu -> bars[i], menu));
  274. #ifdef SHAPE
  275.     if ((shaped = MenuIsShaped(menu))) {
  276.       UpdateMenuShape(menu);
  277.     }
  278. #endif /* SHAPE */
  279.     if ((width != menu -> box.width) || (height != menu -> box.height) || shaped) {
  280.     XResizeWindow(dpy, menu -> hook,
  281.               menu -> box.width, menu -> box.height);
  282.     if (menu -> parent && menu -> parent -> type == ClientWindowClass &&
  283.         ((ClientWindow) menu -> parent) -> client_wob == (Wob) menu) {
  284.         WOOL_send(WOOL_reconfigure, menu -> parent,
  285.               (menu -> parent, menu));
  286.         UpdateMenuNormalHints(menu, 0, 0, 0,
  287.                   menu -> box.width, menu -> box.height);
  288.     }
  289.     }
  290. }
  291.  
  292. /*
  293.  * Place a fixed menu on the screen
  294.  * usage (place-menu "name-of-this-menu" menu [x y])
  295.  */
  296.  
  297. WOOL_OBJECT
  298. PlaceFixedMenu(argc, argv)
  299. int argc;
  300. WOOL_String    *argv;
  301. {
  302.     int             x = 0, y = 0;
  303.     WOOL_Menu       wl_menu;
  304.     Window          w;
  305.     XClassHint      classhints;
  306.     XWMHints        wm_hints;
  307.     ClientWindow    wob;
  308.     XSetWindowAttributes wa;
  309.     WOOL_String     icon_name;
  310.     WOOL_OBJECT     starts_iconic;
  311.     WOOL_String     wl_string;
  312.  
  313.     if (argc < 2 || argc == 3 || argc > 4)
  314.     return wool_error(BAD_NUMBER_OF_ARGS, argc);
  315.     must_be_string(argv[0], 0);
  316.     if (argc == 4) {
  317.     must_be_number(argv[2], 2);
  318.     must_be_number(argv[3], 3);
  319.     x = ((WOOL_Number) argv[2]) -> number;
  320.     y = ((WOOL_Number) argv[3]) -> number;
  321.     }
  322.     wl_menu = (WOOL_Menu) wool_type_or_evaluate(argv[1], WLMenu);
  323.     w = wl_menu -> wob_menu -> hook;
  324.  
  325.     /* Now, set the names */
  326.     XStoreName(dpy, w, argv[0] -> string);
  327.     get_val_from_context(icon_name, WA_icon_name);
  328.     get_val_from_context(starts_iconic, WA_starts_iconic);
  329.     if(icon_name != (WOOL_String) NIL)
  330.     XSetIconName(dpy, w, icon_name -> string);
  331.     else
  332.     XSetIconName(dpy, w, argv[0] -> string);
  333.     wl_string = (WOOL_String) WOOL_send(WOOL_eval, WA_class_name,
  334.                     (WA_class_name));
  335.     if (wl_string->type == WLString)
  336.     classhints.res_class = wl_string->string;
  337.     else
  338.     classhints.res_class = "Gwm";
  339.     wl_string = (WOOL_String) WOOL_send(WOOL_eval, WA_client_name,
  340.                     (WA_client_name));
  341.     if (wl_string->type == WLString)
  342.     classhints.res_name = wl_string->string;
  343.     else
  344.     classhints.res_name = "menu";
  345.     XSetClassHint(dpy, w, &classhints);
  346.     /* machine_name */
  347.     XChangeProperty(dpy, w, XA_WM_CLIENT_MACHINE, XA_STRING, 8, PropModeReplace,
  348.             ((WOOL_String) wool_host_name)->string,
  349.             strlen(((WOOL_String) wool_host_name)->string));
  350.  
  351.     /* normal_hints */
  352.     UpdateMenuNormalHints(wl_menu -> wob_menu, (argc == 4 ? 1 : 0), x, y,
  353.               wl_menu -> wob_menu -> box.width,
  354.               wl_menu -> wob_menu -> box.height);
  355.  
  356.     /* WM_hints */
  357.     if (starts_iconic == NIL) {
  358.     wm_hints.flags = 0;
  359.     } else {
  360.     wm_hints.flags = StateHint;
  361.     wm_hints.initial_state = WM_STATE_Iconified;
  362.     }
  363.     XSetWMHints(dpy, w, &wm_hints);
  364.  
  365.     /* participate in the delete_window protocol */
  366.     {
  367. #define GWM_menus_number_of_protocols 1
  368.     Window          protocols[GWM_menus_number_of_protocols];
  369.  
  370.     protocols[0] = XA_WM_DELETE_WINDOW;
  371.  
  372.     XChangeProperty(dpy, w, XA_WM_PROTOCOLS, XA_ATOM, 32, PropModeReplace,
  373.             (unsigned char *)protocols, GWM_menus_number_of_protocols);
  374.     }
  375.  
  376.     /* a placed menu is no more OverrideRedirect */
  377.     wa.override_redirect = 0;
  378.     XChangeWindowAttributes(dpy, w, CWOverrideRedirect, &wa);
  379.  
  380.     /* now decorate it and map it */
  381.     wob = (ClientWindow) DecorateWindow(w, Context -> rootWob, 0, 1);
  382.  
  383.     ClientWindowInitialMap(wob);
  384.  
  385.     return (WOOL_OBJECT) WLNumber_make(wob);
  386. }
  387.  
  388. UpdateMenuNormalHints(menu, pos, x, y, width, height)
  389. Menu menu;
  390. int pos, x, y, width, height;
  391. {
  392.     XSizeHints      normal_hints;
  393.  
  394.     normal_hints.min_width = normal_hints.max_width = width;
  395.     normal_hints.min_height = normal_hints.max_height = height;
  396.     if (pos) {
  397.     normal_hints.x = x;
  398.     normal_hints.y = y;
  399.     XMoveWindow(dpy, menu -> hook, x, y);
  400.     }
  401. #ifdef NOBASEDIMS
  402.     normal_hints.flags = (pos ? USPosition : 0) | PMinSize | PMaxSize; 
  403.     XSetNormalHints(dpy, menu -> hook, &normal_hints);
  404. #else /* NOBASEDIMS */
  405.     normal_hints.win_gravity = StaticGravity;
  406.     normal_hints.flags = (pos ? USPosition : 0) | PMinSize | PMaxSize | PWinGravity; 
  407.     XSetWMNormalHints(dpy, menu -> hook, &normal_hints);
  408. #endif /* NOBASEDIMS */
  409. }
  410.  
  411. #ifdef SHAPE
  412. /* non-rectangular extension */
  413.  
  414. int
  415. MenuIsShaped(menu)
  416. Menu    menu;
  417. {
  418.   int i;
  419.   for (i = 0; i < menu -> nbars; i++)
  420.     if (menu -> bars[i] && ((Bar) menu -> bars[i]) -> shaped)
  421.       return 1;
  422.   return 0;
  423. }
  424.  
  425. UpdateMenuShape(menu)
  426. Menu    menu;
  427. {
  428.   XRectangle rect, rect2;
  429.   int i;
  430.  
  431.   rect.x = - menu -> box.borderwidth;
  432.   rect.y = - menu -> box.borderwidth;
  433.   rect.width = menu -> box.width + 2 * menu -> box.borderwidth;
  434.   rect.height = menu -> box.height + 2 * menu -> box.borderwidth;
  435.   XShapeCombineRectangles(dpy, menu -> hook, ShapeBounding,
  436.                           0, 0,
  437.                           &rect, 1, ShapeSet, 0);
  438.   for (i = 0; i < menu -> nbars; i++)
  439.     if (menu -> bars[i]) {
  440.       rect2.x = menu -> bars[i] -> box.x + menu -> bars[i] -> box.borderwidth;
  441.       rect2.y = menu -> bars[i] -> box.y + menu -> bars[i] -> box.borderwidth;
  442.       rect2.width = menu -> bars[i] -> box.width;
  443.       rect2.height = menu -> bars[i] -> box.height;
  444.       XShapeCombineRectangles(dpy, menu -> hook, ShapeBounding,
  445.                               0, 0,
  446.                               &rect2, 1, ShapeSubtract, 0);
  447.       XShapeCombineShape(dpy, menu -> hook, ShapeBounding,
  448.                          rect2.x, 
  449.                          rect2.y, 
  450.                          menu -> bars[i] -> hook, ShapeBounding,
  451.                          ShapeUnion);
  452.     }
  453. }
  454.  
  455.  
  456. #endif /* SHAPE */
  457.  
  458.