home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / ddd / windows.C < prev    next >
C/C++ Source or Header  |  1998-11-12  |  42KB  |  1,774 lines

  1. // $Id: windows.C,v 1.85 1998/11/12 14:07:43 zeller Exp $ -*- C++ -*-
  2. // DDD window management
  3.  
  4. // Copyright (C) 1996-1998 Technische Universitaet Braunschweig, Germany.
  5. // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
  6. // 
  7. // This file is part of DDD.
  8. // 
  9. // DDD is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public
  11. // License as published by the Free Software Foundation; either
  12. // version 2 of the License, or (at your option) any later version.
  13. // 
  14. // DDD is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. // See the GNU General Public License for more details.
  18. // 
  19. // You should have received a copy of the GNU General Public
  20. // License along with DDD -- see the file COPYING.
  21. // If not, write to the Free Software Foundation, Inc.,
  22. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. // 
  24. // DDD is the data display debugger.
  25. // For details, see the DDD World-Wide-Web page, 
  26. // `http://www.cs.tu-bs.de/softech/ddd/',
  27. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  28.  
  29. char windows_rcsid[] = 
  30.     "$Id: windows.C,v 1.85 1998/11/12 14:07:43 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36. #define LOG_GEOMETRY 0
  37. #define LOG_EVENTS   0
  38.  
  39. #include "windows.h"
  40.  
  41. #include "AppData.h"
  42. #include "BoxRegion.h"
  43. #include "DataDisp.h"
  44. #include "SourceView.h"
  45. #include "TimeOut.h"
  46. #include "assert.h"
  47. #include "cmdtty.h"
  48. #include "ddd.h"
  49. #include "editing.h"
  50. #include "exectty.h"
  51. #include "exit.h"
  52. #include "findParent.h"
  53. #include "frame.h"
  54. #include "wm.h"
  55. #include "MinMaxA.h"
  56. #include "XErrorB.h"
  57.  
  58. #include <Xm/Xm.h>
  59. #include <Xm/DialogS.h>
  60. #include <Xm/PanedW.h>
  61. #include <Xm/MainW.h>
  62. #include <Xm/ScrollBar.h>
  63. #if XmVersion >= 1002
  64. #include <Xm/VendorS.h>        // XmIsMotifWMRunning()
  65. #else
  66. #include <Xm/VendorE.h>        // XmIsMotifWMRunning()
  67. #endif
  68. #include <X11/Xutil.h>
  69.  
  70. #include "Sash.h"        // XmIsSash()
  71. #include <Xm/Separator.h>    // XmIsSeparator()
  72. #include <Xm/SeparatoG.h>    // XmIsSeparatorGadget()
  73.  
  74. // ANSI C++ doesn't like the XtIsRealized() macro
  75. #ifdef XtIsRealized
  76. #undef XtIsRealized
  77. #endif
  78.  
  79. //-----------------------------------------------------------------------------
  80. // Window management
  81. //-----------------------------------------------------------------------------
  82.  
  83. // Shells (only used if separate windows are used)
  84. Widget command_shell;
  85. Widget data_disp_shell;
  86. Widget source_view_shell;
  87.  
  88. // Command tool
  89. Widget tool_shell;
  90. Widget tool_buttons_w;
  91.  
  92. // Shell state stuff
  93. enum WindowState { PoppingUp, PoppedUp, PoppedDown, 
  94.            Iconic, Transient, UnknownShell };
  95.  
  96. #if LOG_EVENTS
  97. static ostream& operator << (ostream& os, WindowState s)
  98. {
  99.     switch (s)
  100.     {
  101.     case PoppingUp:
  102.     return os << "PoppingUp";
  103.     case PoppedUp:
  104.     return os << "PoppedUp";
  105.     case PoppedDown:
  106.     return os << "PoppedDown";
  107.     case Iconic:
  108.     return os << "Iconic";
  109.     case Transient:
  110.     return os << "Transient";
  111.     case UnknownShell:
  112.     return os << "UnknownShell";
  113.     }
  114.  
  115.     return os;
  116. }
  117. #endif
  118.  
  119. static WindowState& state(Widget w)
  120. {
  121.     static WindowState command_shell_state     = PoppedDown;
  122.     static WindowState data_disp_shell_state   = PoppedDown;
  123.     static WindowState source_view_shell_state = PoppedDown;
  124.     static WindowState tool_shell_state        = PoppedDown;
  125.  
  126.     if (w == 0)
  127.     /* do nothing */;
  128.     else if (w == command_shell)
  129.     return command_shell_state;
  130.     else if (w == data_disp_shell)
  131.     return data_disp_shell_state;
  132.     else if (w == source_view_shell)
  133.     return source_view_shell_state;
  134.     else if (w == tool_shell)
  135.     return tool_shell_state;
  136.  
  137.     static WindowState dummy;
  138.     dummy = UnknownShell;
  139.     return dummy;
  140. }
  141.  
  142. static bool popped_down(Widget w)
  143. {
  144.     WindowState st = state(w);
  145.     return st == PoppedDown || st == UnknownShell;
  146. }
  147.  
  148. static void set_state(WindowState& var, WindowState state)
  149. {
  150.     if (state == PoppingUp && var == PoppedUp)
  151.     return;
  152.     var = state;
  153. }
  154.  
  155. static void set_state(Widget w, WindowState s)
  156. {
  157.     WindowState& var = state(w);
  158.     if (var != UnknownShell)
  159.     {
  160.     set_state(var, s);
  161. #if LOG_EVENTS
  162.     clog << XtName(w) << " is " << state(w) << "\n";
  163. #endif
  164.     }
  165. }
  166.  
  167. // Place command tool in upper right edge of REF
  168. static void recenter_tool_shell(Widget ref = 0);
  169.  
  170. // Place command tool in upper right edge of REF, with a distance of
  171. // TOP_OFFSET and RIGHT_OFFSET
  172. static void recenter_tool_shell(Widget ref, int top_offset, int right_offset);
  173.  
  174. // Have command tool follow REF
  175. static void follow_tool_shell(Widget ref = 0);
  176.  
  177. // Get current offset of command tool in TOP_OFFSET and RIGHT_OFFSET;
  178. // return true iff successful.
  179. static bool get_tool_offset(Widget ref, int& top_offset, int& right_offset);
  180.  
  181. // Last offsets as actually used
  182. static int last_top_offset;
  183. static int last_right_offset;
  184. static bool offsets_initialized = false;
  185.  
  186. // Last saved geometry of tool shell
  187. static string last_tool_shell_geometry = "+0+0";
  188.  
  189. static void initialize_offsets()
  190. {
  191.     if (!offsets_initialized)
  192.     {
  193.     last_top_offset   = app_data.tool_top_offset;
  194.     last_right_offset = app_data.tool_right_offset;
  195.     offsets_initialized = true;
  196.     }
  197. }
  198.  
  199. // Return current tool shell position relative to root window
  200. static BoxPoint tool_shell_pos()
  201. {
  202.     int root_x = 0;
  203.     int root_y = 0;
  204.  
  205.     if (tool_shell != 0 && XtIsRealized(tool_shell) && 
  206.     state(tool_shell) == PoppedUp)
  207.     {
  208.     XWindowAttributes attr;
  209.     XGetWindowAttributes(XtDisplay(tool_shell), XtWindow(tool_shell), 
  210.                  &attr);
  211.     Window child;
  212.     XTranslateCoordinates(XtDisplay(tool_shell), XtWindow(tool_shell), 
  213.                   attr.root, 0, 0, &root_x, &root_y, &child);
  214.     }
  215.  
  216.     return BoxPoint(root_x, root_y);
  217. }
  218.  
  219. // Move tool shell to POS
  220. static void move_tool_shell(BoxPoint pos)
  221. {
  222. #if 0
  223.     // Make sure we don't move the tool shell off the screen
  224.     pos[X] = max(pos[X], 0);
  225.     pos[Y] = max(pos[Y], 0);
  226. #endif
  227.  
  228.     if (tool_shell == 0)
  229.     return;
  230.  
  231.     if (pos != tool_shell_pos())
  232.     {
  233.     ostrstream os;
  234.     os << "+" << pos[X] << "+" << pos[Y];
  235.     last_tool_shell_geometry = string(os);
  236.  
  237.     // Move tool shell to POS
  238.     XtVaSetValues(tool_shell,
  239.               XmNgeometry, last_tool_shell_geometry.chars(),
  240.               XmNx, pos[X],
  241.               XmNy, pos[Y],
  242.               NULL);
  243.     }
  244. }
  245.  
  246. static void RecenterToolShellCB(XtPointer = 0, XtIntervalId *id = 0)
  247. {
  248.     if (tool_shell == 0)
  249.     return;
  250.  
  251.     static XtIntervalId recenter_tool_shell_timer = 0;
  252.  
  253.     if (id != 0)
  254.     {
  255.     assert(*id = recenter_tool_shell_timer);
  256.     recenter_tool_shell_timer = 0;
  257.     }
  258.     else if (recenter_tool_shell_timer != 0)
  259.     {
  260.     XtRemoveTimeOut(recenter_tool_shell_timer);
  261.     recenter_tool_shell_timer = 0;
  262.     }
  263.  
  264.     bool have_visible_tool_shell = false;
  265.  
  266.     if (XtIsRealized(tool_buttons_w) && state(tool_shell) == PoppedUp)
  267.     {
  268.     XWindowAttributes attr;
  269.     XGetWindowAttributes(XtDisplay(tool_buttons_w), 
  270.                  XtWindow(tool_buttons_w), &attr);
  271.     have_visible_tool_shell = (attr.map_state == IsViewable);
  272.     }
  273.  
  274.     if (have_visible_tool_shell)
  275.     {
  276.     recenter_tool_shell();
  277.     }
  278.     else
  279.     {
  280.     // Try again in 200 ms
  281.     recenter_tool_shell_timer = 
  282.         XtAppAddTimeOut(XtWidgetToApplicationContext(tool_shell), 
  283.                 200, RecenterToolShellCB, XtPointer(0));
  284.     }
  285. }
  286.  
  287. static void follow_tool_shell(Widget ref)
  288. {
  289.     initialize_offsets();
  290.  
  291.     recenter_tool_shell(ref, last_top_offset, last_right_offset);
  292.     get_tool_offset(ref, last_top_offset, last_right_offset);
  293. }
  294.  
  295. static void FollowToolShellCB(XtPointer = 0, XtIntervalId *id = 0)
  296. {
  297.     if (tool_shell == 0)
  298.     return;
  299.  
  300.     static XtIntervalId follow_tool_shell_timer = 0;
  301.  
  302.     if (id != 0)
  303.     {
  304.     assert(*id = follow_tool_shell_timer);
  305.     follow_tool_shell_timer = 0;
  306.     }
  307.     else if (follow_tool_shell_timer != 0)
  308.     {
  309.     XtRemoveTimeOut(follow_tool_shell_timer);
  310.     follow_tool_shell_timer = 0;
  311.     }
  312.  
  313.     bool have_visible_tool_shell = false;
  314.  
  315.     if (XtIsRealized(tool_buttons_w) && state(tool_shell) == PoppedUp)
  316.     {
  317.     XWindowAttributes attr;
  318.     XGetWindowAttributes(XtDisplay(tool_buttons_w), 
  319.                  XtWindow(tool_buttons_w), &attr);
  320.     have_visible_tool_shell = (attr.map_state == IsViewable);
  321.     }
  322.  
  323.     if (have_visible_tool_shell)
  324.     {
  325.     follow_tool_shell();
  326.     }
  327.     else
  328.     {
  329.     // Try again in 200 ms
  330.     follow_tool_shell_timer = 
  331.         XtAppAddTimeOut(XtWidgetToApplicationContext(tool_shell), 
  332.                 200, FollowToolShellCB, XtPointer(0));
  333.     }
  334. }
  335.  
  336. bool started_iconified(Widget w)
  337. {
  338.     Widget toplevel = w;
  339.     while (XtParent(toplevel))
  340.     toplevel = XtParent(toplevel);
  341.  
  342.     assert(XtIsTopLevelShell(toplevel));
  343.  
  344.     // Well isn't it iconic - don't you think?
  345.     Boolean iconic;
  346.     XtVaGetValues(toplevel, XmNiconic, &iconic, NULL);
  347.     return iconic;
  348. }
  349.  
  350. // Popup initial shell
  351. void initial_popup_shell(Widget w)
  352. {
  353.     if (w == 0)
  354.     return;
  355.  
  356.     Boolean iconic = started_iconified(w);
  357.     XtVaSetValues(w, 
  358.           XmNiconic, iconic,
  359.           XmNinitialState, iconic ? IconicState : NormalState,
  360.           NULL);
  361.     WindowState state = iconic ? Iconic : PoppingUp;
  362.  
  363.     set_state(w, state);
  364.  
  365.     if (iconic || w == tool_shell)
  366.     XtVaSetValues(w, 
  367.               XmNgeometry, "+0+0", 
  368.               XmNx, 0,
  369.               XmNy, 0,
  370.               NULL);
  371.  
  372.     if (w == tool_shell)
  373.     {
  374.     XtManageChild(tool_buttons_w);
  375.     if (!XtIsRealized(tool_shell))
  376.         XtRealizeWidget(tool_shell);
  377.     if (!iconic)
  378.         RecenterToolShellCB();
  379.     }
  380.  
  381.     Widget toplevel = w;
  382.     while (XtParent(toplevel))
  383.     toplevel = XtParent(toplevel);
  384.     assert(XtIsTopLevelShell(toplevel));
  385.  
  386.     if (w != toplevel && XtIsRealized(w))
  387.     XtPopup(w, XtGrabNone);
  388. }
  389.  
  390. void popup_shell(Widget w)
  391. {
  392.     if (w == 0)
  393.     return;
  394.  
  395.     if (w == tool_shell)
  396.     {
  397.     if (!XtIsRealized(tool_shell))
  398.     {
  399.         initial_popup_shell(tool_shell);
  400.         RecenterToolShellCB();
  401.     }
  402.  
  403.     XtManageChild(tool_buttons_w);
  404.     }
  405.  
  406.     if (XtIsRealized(w))
  407.     XtPopup(w, XtGrabNone);
  408.  
  409.     set_state(w, PoppingUp);
  410.  
  411.     // Uniconify window
  412.     if (XtIsRealized(w))
  413.     XMapWindow(XtDisplay(w), XtWindow(w));
  414.     raise_shell(w);
  415. }
  416.  
  417. void popdown_shell(Widget w)
  418. {
  419.     if (w == 0)
  420.     return;
  421.  
  422.     set_state(w, PoppedDown);
  423.  
  424.     if (w == tool_shell)
  425.     XtUnmanageChild(tool_buttons_w);
  426.  
  427.     XtPopdown(w);
  428. }
  429.  
  430. void iconify_shell(Widget w)
  431. {
  432.     if (w == 0 || !XtIsRealized(w))
  433.     return;
  434.  
  435.     set_state(w, Iconic);
  436.  
  437.     XIconifyWindow(XtDisplay(w), XtWindow(w),
  438.            XScreenNumberOfScreen(XtScreen(w)));
  439. }
  440.  
  441. void uniconify_shell(Widget w)
  442. {
  443.     if (w == 0)
  444.     return;
  445.  
  446.     if (state(w) == Iconic)
  447.     {
  448.     popup_shell(w);
  449.     }
  450. }
  451.  
  452. void popup_tty(Widget shell)
  453. {
  454.     if (exec_tty_window())
  455.     {
  456.     XErrorBlocker blocker(XtDisplay(shell));
  457.  
  458.     // Uniconify window
  459.     XMapWindow(XtDisplay(shell), exec_tty_window());
  460.  
  461.     // Place window on top
  462.     XRaiseWindow(XtDisplay(shell), exec_tty_window());
  463.     }
  464. }
  465.  
  466. void iconify_tty(Widget shell)
  467. {
  468.     if (exec_tty_window())
  469.     {
  470.     XIconifyWindow(XtDisplay(shell), exec_tty_window(),
  471.                XScreenNumberOfScreen(XtScreen(shell)));
  472.     }
  473. }
  474.  
  475. // Shell visibility stuff
  476. static int& visibility(Widget w)
  477. {
  478.     static int command_shell_visibility     = VisibilityFullyObscured;
  479.     static int data_disp_shell_visibility   = VisibilityFullyObscured;
  480.     static int source_view_shell_visibility = VisibilityFullyObscured;
  481.     static int tool_shell_visibility        = VisibilityFullyObscured;
  482.  
  483.     if (w == 0)
  484.     /* do nothing */;
  485.     else if (w == command_shell)
  486.     return command_shell_visibility;
  487.     else if (w == data_disp_shell)
  488.     return data_disp_shell_visibility;
  489.     else if (w == source_view_shell)
  490.     return source_view_shell_visibility;
  491.     else if (w == tool_shell)
  492.     return tool_shell_visibility;
  493.  
  494.     static int dummy;
  495.     dummy = VisibilityFullyObscured;
  496.     return dummy;
  497. }
  498.  
  499. static BoxRegion region(Display *display, Window win)
  500. {
  501.     XWindowAttributes attr;
  502.  
  503.     Status ok;
  504.     ok = XGetWindowAttributes(display, win, &attr);
  505.     if (!ok)
  506.     return BoxRegion();
  507.  
  508.     return BoxRegion(BoxPoint(attr.x, attr.y), 
  509.              BoxSize(attr.width, attr.height));
  510. }
  511.  
  512. static bool obscures(Display *display, Window top, Window bottom)
  513. {
  514.     if (top == 0 || bottom == 0)
  515.     return false;
  516.  
  517.     return region(display, bottom) <= region(display, top);
  518. }
  519.  
  520. static bool obscures(Widget top, Widget bottom)
  521. {
  522.     if (top == 0 || bottom == 0 || !XtIsRealized(top) || !XtIsRealized(bottom))
  523.     return false;
  524.  
  525.     if (visibility(bottom) == VisibilityUnobscured)
  526.     return false;
  527.  
  528.     return obscures(XtDisplay(top), XtWindow(top), XtWindow(bottom));
  529. }
  530.  
  531. // Raise WIN above SIBLING
  532. static void raise_above(Display *display, Window win, Window sibling)
  533. {
  534.     if (win == 0 || sibling == 0)
  535.     return;
  536.  
  537.     XErrorBlocker blocker(display);
  538.  
  539.     Window win_frame     = frame(display, win);
  540.     Window sibling_frame = frame(display, sibling);
  541.  
  542.     if (win_frame != 0 && sibling_frame != 0 && win_frame != sibling_frame)
  543.     {
  544.     // Raise WIN just above SIBLING
  545.     XWindowChanges changes;
  546.     changes.stack_mode = Above;
  547.     changes.sibling    = sibling_frame;
  548.  
  549.     XConfigureWindow(display, win_frame,
  550.              CWSibling | CWStackMode, &changes);
  551.     }
  552.     else
  553.     {
  554.     // Raise WIN on top
  555.     XRaiseWindow(display, win);
  556.     }
  557. }
  558.  
  559. inline void raise_tool_above(Window sibling)
  560. {
  561.     if (tool_shell && XtIsRealized(tool_shell) && 
  562.     state(tool_shell) == PoppedUp)
  563.     raise_above(XtDisplay(tool_shell), XtWindow(tool_shell), sibling);
  564. }
  565.  
  566. inline void raise_tool_above(Widget w)
  567. {
  568.     if (w != 0 && XtIsRealized(w))
  569.     raise_tool_above(XtWindow(w));
  570. }
  571.  
  572. void StructureNotifyEH(Widget w, XtPointer, XEvent *event, Boolean *)
  573. {
  574.     bool synthetic = (state(w) == Transient);
  575.  
  576. #if LOG_EVENTS
  577.     if (synthetic)
  578.     clog << "Synthetic event: ";
  579. #endif
  580.  
  581.     switch (event->type)
  582.     {
  583.     case MapNotify:
  584.     if (state(w) == UnknownShell)
  585.         return;
  586.  
  587.     // Reflect state
  588.     set_state(w, PoppedUp);
  589.  
  590. #if 0
  591.     if (!synthetic
  592.         && (w == source_view_shell
  593.         || (source_view_shell == 0 && w == command_shell))
  594.         && !app_data.command_toolbar && app_data.source_window)
  595.     {
  596.         // Popup command tool again
  597.         popup_shell(tool_shell);
  598.         set_state(tool_shell, Transient);
  599.     }
  600. #endif
  601.  
  602.     if (tool_shell != 0)
  603.     {
  604.         // Check position of command tool
  605.         BoxPoint max_pos(WidthOfScreen(XtScreen(tool_shell)) - 1,
  606.                  HeightOfScreen(XtScreen(tool_shell)) - 1);
  607.         if (tool_shell_pos() >= max_pos)
  608.         RecenterToolShellCB();
  609.     }
  610.  
  611.     if (!synthetic && app_data.group_iconify)
  612.     {
  613.         // Some shell was mapped - map all other shells as well
  614.         if (state(command_shell) == Iconic)
  615.         {
  616.         popup_shell(command_shell);
  617.         set_state(command_shell, Transient);
  618.         }
  619.         if (state(data_disp_shell) == Iconic)
  620.         {
  621.         popup_shell(data_disp_shell);
  622.         set_state(data_disp_shell, Transient);
  623.         }
  624.         if (state(source_view_shell) == Iconic)
  625.         {
  626.         popup_shell(source_view_shell);
  627.         set_state(source_view_shell, Transient);
  628.         }
  629.         popup_tty(command_shell);
  630.     }
  631.     break;
  632.  
  633.     case UnmapNotify:
  634.     // Reflect state
  635.     if (state(w) == UnknownShell)
  636.         return;
  637.  
  638.     if (state(w) != Iconic && state(w) != PoppedDown)
  639.         set_state(w, Iconic);
  640.  
  641.     if (!synthetic
  642.         && (w == source_view_shell
  643.         || (source_view_shell == 0 && w == command_shell)))
  644.     {
  645.         // Iconify command tool, too
  646.         iconify_shell(tool_shell);
  647.         set_state(tool_shell, Transient);
  648.     }
  649.  
  650.     if (!synthetic && state(w) != PoppedDown && app_data.group_iconify)
  651.     {
  652.         // Iconify all other windows as well
  653.         if (state(command_shell) == PoppedUp)
  654.         {
  655.         iconify_shell(command_shell);
  656.         set_state(command_shell, Transient);
  657.         }
  658.         if (state(data_disp_shell) == PoppedUp)
  659.         {
  660.         iconify_shell(data_disp_shell);
  661.          set_state(data_disp_shell, Transient);
  662.         }
  663.         if (state(source_view_shell) == PoppedUp)
  664.         {
  665.         iconify_shell(source_view_shell);
  666.         set_state(source_view_shell, Transient);
  667.         }
  668.         iconify_tty(command_shell);
  669.     }
  670.     break;
  671.  
  672.     case VisibilityNotify:
  673.     {
  674.     visibility(w) = event->xvisibility.state;
  675.  
  676.     // Check whether command tool is obscured by some DDD shell
  677.     if (app_data.auto_raise_tool
  678.         && (obscures(command_shell, tool_shell)
  679.         || obscures(data_disp_shell, tool_shell)
  680.         || obscures(source_view_shell, tool_shell)))
  681.     {
  682.         // Command tool is obscured
  683.         if (XmIsMotifWMRunning(tool_shell) && XmIsDialogShell(tool_shell))
  684.         {
  685.         // We have MWM and the command tool is a Dialog Shell.
  686.         // Hence, let MWM keep the command tool on top.
  687.         }
  688.         else
  689.         {
  690.         // Raise command tool
  691.         Widget shell = 
  692.             source_view_shell ? source_view_shell : command_shell;
  693.         raise_tool_above(shell);
  694.         }
  695.     }
  696.  
  697. #if 0                // Doesn't work yet - AZ
  698.     // Check whether command tool is obscured by the exec window
  699.     if (app_data.auto_raise_tool
  700.         && obscures(XtDisplay(tool_shell), exec_tty_window(), 
  701.             XtWindow(tool_shell)))
  702.         raise_tool_above(exec_tty_window());
  703. #endif
  704.  
  705.     break;
  706.     }
  707.  
  708.     case ConfigureNotify:
  709.     {
  710.     if (app_data.sticky_tool
  711.         && have_tool_window()
  712.         && (state(tool_shell) == PoppedUp 
  713.         || state(tool_shell) == Transient))
  714.     {
  715.         // Let `sticky' command tool follow the source window
  716.         initialize_offsets();
  717.  
  718.         if (w == tool_shell)
  719.         {
  720.         // Command tool has been moved
  721. #if LOG_EVENTS
  722.         clog << "Tool has been moved to " << point(event) << "\n";
  723. #endif
  724.  
  725.         // Record offset
  726.         get_tool_offset(0, last_top_offset, last_right_offset);
  727.         }
  728.  
  729.         if (w == source_view_shell || 
  730.         w == command_shell && source_view_shell == 0)
  731.         {
  732.         // Source shell has been moved -- let command tool follow
  733. #if LOG_EVENTS
  734.         clog << "Shell has been moved to " << point(event) << "\n";
  735. #endif
  736.  
  737.         FollowToolShellCB();
  738.         }
  739.     }
  740.     break;
  741.     }
  742.  
  743.     default:
  744.     // Any other event...
  745.     break;
  746.     }
  747. }
  748.  
  749.  
  750. //-----------------------------------------------------------------------------
  751. // Closing shells
  752. //-----------------------------------------------------------------------------
  753.  
  754. // Return number of running input shells
  755. int running_shells()
  756. {
  757.     int shells = 0;
  758.  
  759.     if (!popped_down(command_shell))
  760.     shells++;
  761.     if (!popped_down(source_view_shell))
  762.     shells++;
  763.     if (!popped_down(data_disp_shell))
  764.     shells++;
  765.  
  766.     return shells;
  767. }
  768.  
  769.  
  770. // Generic close callback
  771. void DDDCloseCB(Widget w, XtPointer client_data, XtPointer call_data)
  772. {
  773.     if (running_shells() == 1)
  774.     {
  775.     DDDExitCB(w, XtPointer(EXIT_SUCCESS), 0);
  776.     return;
  777.     }
  778.  
  779.     Widget shell = findTopLevelShellParent(w);
  780.  
  781.     if (shell == command_shell)
  782.     gdbCloseCommandWindowCB(w, client_data, call_data);
  783.     else if (shell == data_disp_shell)
  784.     gdbCloseDataWindowCB(w, client_data, call_data);
  785.     else if (shell == source_view_shell)
  786.     gdbCloseSourceWindowCB(w, client_data, call_data);
  787.     else if (shell == tool_shell)
  788.     gdbCloseToolWindowCB(w, client_data, call_data);
  789.     else
  790.     popdown_shell(shell);
  791. }
  792.  
  793.  
  794.  
  795. // Specific close and open callbacks
  796.  
  797. // Debugger console
  798. void gdbCloseCommandWindowCB(Widget w, XtPointer, XtPointer)
  799. {
  800.     if (!have_data_window() && !have_source_window() && !have_code_window())
  801.     {
  802.     DDDExitCB(w, XtPointer(EXIT_SUCCESS), 0);
  803.     return;
  804.     }
  805.  
  806.     if ((app_data.separate_source_window || !have_source_window())
  807.     && (app_data.separate_data_window || !have_data_window()))
  808.     {
  809.     popdown_shell(command_shell);
  810.     }
  811.  
  812.     unmanage_paned_child(XtParent(gdb_w));
  813.  
  814.     app_data.debugger_console = false;
  815.  
  816.     update_options();
  817. }
  818.  
  819. void gdbOpenCommandWindowCB(Widget, XtPointer, XtPointer)
  820. {
  821.     manage_paned_child(XtParent(gdb_w));
  822.  
  823.     if (app_data.separate_source_window)
  824.     popup_shell(command_shell);
  825.  
  826.     app_data.debugger_console = true;
  827.  
  828.     update_options();
  829. }
  830.  
  831. bool have_command_window()
  832. {
  833.     return XtIsManaged(XtParent(gdb_w));
  834. }
  835.  
  836.  
  837. // Source window
  838. void gdbCloseSourceWindowCB(Widget w, XtPointer client_data, 
  839.                 XtPointer call_data)
  840. {
  841.     if (!have_command_window() && !have_data_window() && !have_code_window())
  842.     {
  843.     DDDExitCB(w, XtPointer(EXIT_SUCCESS), 0);
  844.     return;
  845.     }
  846.  
  847.     // Popdown shell
  848.     popdown_shell(source_view_shell);
  849.  
  850.     // Unmanage source
  851.     unmanage_paned_child(source_view->source_form());
  852.  
  853.     if (source_view_shell != 0)
  854.     unmanage_paned_child(source_view->code_form());
  855.  
  856.     if (!XtIsManaged(source_view->code_form()))
  857.     gdbCloseToolWindowCB(w, client_data, call_data);
  858.  
  859.     app_data.source_window = false;
  860.  
  861.     update_options();
  862. }
  863.  
  864. void gdbCloseCodeWindowCB(Widget w, XtPointer client_data, 
  865.                 XtPointer call_data)
  866. {
  867.     if (!have_command_window() && !have_data_window() && !have_source_window())
  868.     {
  869.     DDDExitCB(w, XtPointer(EXIT_SUCCESS), 0);
  870.     return;
  871.     }
  872.  
  873.     // Unmanage code
  874.     unmanage_paned_child(source_view->code_form());
  875.  
  876.     if (!XtIsManaged(source_view->source_form()))
  877.     gdbCloseToolWindowCB(w, client_data, call_data);
  878.  
  879.     app_data.disassemble = false;
  880.  
  881.     update_options();
  882. }
  883.  
  884. void gdbOpenSourceWindowCB(Widget w, XtPointer client_data,
  885.                XtPointer call_data)
  886. {
  887.     manage_paned_child(source_view->source_form());
  888.     if (source_view_shell != 0 && app_data.disassemble)
  889.     manage_paned_child(source_view->code_form());
  890.     Widget arg_cmd_w = XtParent(source_arg->top());
  891.     manage_paned_child(arg_cmd_w);
  892.  
  893.     popup_shell(source_view_shell);
  894.  
  895.     if (!app_data.command_toolbar)
  896.     gdbOpenToolWindowCB(w, client_data, call_data);
  897.  
  898.     app_data.source_window = true;
  899.  
  900.     update_options();
  901. }
  902.  
  903. void gdbOpenCodeWindowCB(Widget w, XtPointer client_data,
  904.              XtPointer call_data)
  905. {
  906.     manage_paned_child(source_view->code_form());
  907.     Widget arg_cmd_w = XtParent(source_arg->top());
  908.     manage_paned_child(arg_cmd_w);
  909.  
  910.     popup_shell(source_view_shell);
  911.  
  912.     if (!app_data.command_toolbar)
  913.     gdbOpenToolWindowCB(w, client_data, call_data);
  914.  
  915.     app_data.disassemble = true;
  916.  
  917.     update_options();
  918. }
  919.  
  920. bool have_source_window()
  921. {
  922.     return XtIsManaged(source_view->source_form());
  923. }
  924.  
  925. bool have_code_window()
  926. {
  927.     return XtIsManaged(source_view->code_form());
  928. }
  929.  
  930.  
  931. // Data window
  932. void gdbCloseDataWindowCB(Widget w, XtPointer, XtPointer)
  933. {
  934.     if (!have_source_window() && !have_command_window() && !have_code_window())
  935.     {
  936.     DDDExitCB(w, XtPointer(EXIT_SUCCESS), 0);
  937.     return;
  938.     }
  939.  
  940.     popdown_shell(data_disp_shell);
  941.  
  942.     Widget arg_cmd_w = XtParent(source_arg->top());
  943.     if (data_disp->graph_cmd_w == arg_cmd_w)
  944.     {
  945.     // Don't close the common toolbar
  946.     }
  947.     else
  948.     {
  949.     unmanage_paned_child(data_disp->graph_cmd_w);
  950.     }
  951.  
  952.     unmanage_paned_child(data_disp->graph_form());
  953.  
  954.     app_data.data_window = false;
  955.  
  956.     update_options();
  957. }
  958.  
  959. void gdbOpenDataWindowCB(Widget, XtPointer, XtPointer)
  960. {
  961.     manage_paned_child(data_disp->graph_cmd_w);
  962.     manage_paned_child(data_disp->graph_form());
  963.  
  964.     popup_shell(data_disp_shell);
  965.  
  966.     app_data.data_window = true;
  967.  
  968.     update_options();
  969. }
  970.  
  971. bool have_data_window()
  972. {
  973.     return XtIsManaged(data_disp->graph_form());
  974. }
  975.  
  976.  
  977. // Execution window
  978. void gdbCloseExecWindowCB(Widget, XtPointer, XtPointer)
  979. {
  980.     app_data.separate_exec_window = False;
  981.  
  982.     kill_exec_tty();
  983.     update_options();
  984. }
  985.  
  986. void gdbOpenExecWindowCB(Widget, XtPointer, XtPointer)
  987. {
  988.     app_data.separate_exec_window = True;
  989.  
  990.     if (exec_tty_pid() == 0)
  991.     startup_exec_tty();
  992.     popup_tty(command_shell);
  993.     update_options();
  994. }
  995.  
  996. bool have_exec_window()
  997. {
  998.     exec_tty_running();
  999.     return exec_tty_pid() > 0;
  1000. }
  1001.  
  1002.  
  1003. // Tool window
  1004. void gdbCloseToolWindowCB(Widget, XtPointer, XtPointer)
  1005. {
  1006.     popdown_shell(tool_shell);
  1007.     update_options();
  1008. }
  1009.  
  1010. void gdbOpenToolWindowCB(Widget, XtPointer, XtPointer)
  1011. {
  1012.     if (tool_shell == 0)
  1013.     return;
  1014.  
  1015.     XtVaSetValues(tool_shell,
  1016.           XmNgeometry, last_tool_shell_geometry.chars(),
  1017.           NULL);
  1018.  
  1019.     popup_shell(tool_shell);
  1020.  
  1021.     wait_until_mapped(tool_shell);
  1022.     RecenterToolShellCB();
  1023.  
  1024.     update_options();
  1025. }
  1026.  
  1027. bool have_tool_window()
  1028. {
  1029.     return tool_shell != 0;
  1030. }
  1031.  
  1032.  
  1033. //-----------------------------------------------------------------------------
  1034. // Toggling shells
  1035. //-----------------------------------------------------------------------------
  1036.  
  1037. void gdbToggleCommandWindowCB(Widget w, XtPointer client_data,
  1038.                   XtPointer call_data)
  1039. {
  1040.     XmToggleButtonCallbackStruct *info = 
  1041.     (XmToggleButtonCallbackStruct *)call_data;
  1042.  
  1043.     if (info->set)
  1044.     gdbOpenCommandWindowCB(w, client_data, call_data);
  1045.     else
  1046.     gdbCloseCommandWindowCB(w, client_data, call_data);
  1047. }
  1048.  
  1049. void gdbToggleSourceWindowCB(Widget w, XtPointer client_data,
  1050.                   XtPointer call_data)
  1051. {
  1052.     XmToggleButtonCallbackStruct *info = 
  1053.     (XmToggleButtonCallbackStruct *)call_data;
  1054.  
  1055.     if (info->set)
  1056.     gdbOpenSourceWindowCB(w, client_data, call_data);
  1057.     else
  1058.     gdbCloseSourceWindowCB(w, client_data, call_data);
  1059. }
  1060.  
  1061. void gdbToggleCodeWindowCB(Widget w, XtPointer client_data,
  1062.                XtPointer call_data)
  1063. {
  1064.     XmToggleButtonCallbackStruct *info = 
  1065.     (XmToggleButtonCallbackStruct *)call_data;
  1066.  
  1067.     if (info->set)
  1068.     gdbOpenCodeWindowCB(w, client_data, call_data);
  1069.     else
  1070.     gdbCloseCodeWindowCB(w, client_data, call_data);
  1071.  
  1072.     update_options();
  1073. }
  1074.  
  1075. void gdbToggleDataWindowCB(Widget w, XtPointer client_data,
  1076.                   XtPointer call_data)
  1077. {
  1078.     XmToggleButtonCallbackStruct *info = 
  1079.     (XmToggleButtonCallbackStruct *)call_data;
  1080.  
  1081.     if (info->set)
  1082.     gdbOpenDataWindowCB(w, client_data, call_data);
  1083.     else
  1084.     gdbCloseDataWindowCB(w, client_data, call_data);
  1085. }
  1086.  
  1087. void gdbToggleExecWindowCB(Widget w, XtPointer client_data,
  1088.                   XtPointer call_data)
  1089. {
  1090.     XmToggleButtonCallbackStruct *info = 
  1091.     (XmToggleButtonCallbackStruct *)call_data;
  1092.  
  1093.     if (info->set)
  1094.     gdbOpenExecWindowCB(w, client_data, call_data);
  1095.     else
  1096.     gdbCloseExecWindowCB(w, client_data, call_data);
  1097. }
  1098.  
  1099. void gdbToggleToolWindowCB(Widget w, XtPointer client_data,
  1100.                   XtPointer call_data)
  1101. {
  1102.     XmToggleButtonCallbackStruct *info = 
  1103.     (XmToggleButtonCallbackStruct *)call_data;
  1104.  
  1105.     if (info->set)
  1106.     gdbOpenToolWindowCB(w, client_data, call_data);
  1107.     else
  1108.     gdbCloseToolWindowCB(w, client_data, call_data);
  1109. }
  1110.  
  1111.  
  1112. //-----------------------------------------------------------------------------
  1113. // Command tool placement
  1114. //-----------------------------------------------------------------------------
  1115.  
  1116. // Place command tool in upper right edge of REF
  1117. static void recenter_tool_shell(Widget ref)
  1118. {
  1119.     recenter_tool_shell(ref, 
  1120.             app_data.tool_top_offset, app_data.tool_right_offset);
  1121. }
  1122.  
  1123. // Place command tool in upper right edge of REF, with a distance of
  1124. // TOP_OFFSET and RIGHT_OFFSET
  1125. static void recenter_tool_shell(Widget ref, int top_offset, int right_offset)
  1126. {
  1127.     if (ref == 0)
  1128.     ref = source_view->source();
  1129.     if (ref == 0 || !XtIsManaged(ref))
  1130.     ref = source_view->code();
  1131.  
  1132.     if (ref == 0 || tool_shell == 0 || 
  1133.     !XtIsRealized(ref) || !XtIsRealized(tool_shell) ||
  1134.     state(tool_shell) != PoppedUp)
  1135.     return;
  1136.  
  1137.     Window ref_window  = XtWindow(ref);
  1138.     Window tool_window = XtWindow(tool_shell);
  1139.     Window tool_frame  = frame(tool_shell);
  1140.  
  1141.     // Get location of upper right edge of REF
  1142.     XWindowAttributes ref_attributes;
  1143.     XGetWindowAttributes(XtDisplay(ref), ref_window, &ref_attributes);
  1144.  
  1145.     // Get tool shell attributes
  1146.     XWindowAttributes tool_attributes;
  1147.     XGetWindowAttributes(XtDisplay(tool_shell), tool_window, &tool_attributes);
  1148.  
  1149.     // Get tool frame attributes
  1150.     XWindowAttributes frame_attributes;
  1151.     XGetWindowAttributes(XtDisplay(tool_shell), tool_frame, 
  1152.              &frame_attributes);
  1153.  
  1154.     // Determine new position relative to REF
  1155.     int x = ref_attributes.width - tool_attributes.width - right_offset;
  1156.     int y = top_offset;
  1157.  
  1158.     // Correct them relative to frame thickness
  1159.     int frame_x, frame_y;
  1160.     Window frame_child;
  1161.     XTranslateCoordinates(XtDisplay(ref), tool_window,
  1162.               tool_frame,
  1163.               tool_attributes.width, 0, &frame_x, &frame_y,
  1164.               &frame_child);
  1165.  
  1166.     x -= frame_attributes.width - frame_x + frame_attributes.border_width;
  1167.     y += frame_y + frame_attributes.border_width;
  1168.  
  1169.     // Get root coordinates
  1170.     int root_x, root_y;
  1171.     Window ref_child;
  1172.     XTranslateCoordinates(XtDisplay(ref), ref_window, 
  1173.               ref_attributes.root,
  1174.               x, y, &root_x, &root_y,
  1175.               &ref_child);
  1176.  
  1177.     move_tool_shell(BoxPoint(root_x, root_y));
  1178.  
  1179.     last_top_offset     = top_offset;
  1180.     last_right_offset   = right_offset;
  1181.     offsets_initialized = true;
  1182. }
  1183.  
  1184.  
  1185. // Get current offset of command tool in TOP_OFFSET and RIGHT_OFFSET;
  1186. // return true iff successful.
  1187. static bool get_tool_offset(Widget ref, int& top_offset, int& right_offset)
  1188. {
  1189.     if (ref == 0)
  1190.     ref = source_view->source();
  1191.     if (ref == 0 || !XtIsManaged(ref))
  1192.     ref = source_view->code();
  1193.  
  1194.     if (ref == 0 || tool_shell == 0 || 
  1195.     !XtIsRealized(ref) || !XtIsRealized(tool_shell) || 
  1196.     !XtIsManaged(tool_buttons_w) ||
  1197.     state(tool_shell) != PoppedUp)
  1198.     return false;
  1199.  
  1200.     Window ref_window  = XtWindow(ref);
  1201.     Window tool_window = XtWindow(tool_shell);
  1202.     Window tool_frame  = frame(tool_shell);
  1203.  
  1204.     // Get location of upper right edge of REF
  1205.     XWindowAttributes ref_attributes;
  1206.     XGetWindowAttributes(XtDisplay(ref), ref_window, &ref_attributes);
  1207.  
  1208.     // Get tool shell attributes
  1209.     XWindowAttributes tool_attributes;
  1210.     XGetWindowAttributes(XtDisplay(tool_shell), tool_window, &tool_attributes);
  1211.  
  1212.     // Get tool frame attributes
  1213.     XWindowAttributes frame_attributes;
  1214.     XGetWindowAttributes(XtDisplay(tool_shell), tool_frame, 
  1215.              &frame_attributes);
  1216.  
  1217.     // If the tool frame is off the screen, don't store the offset
  1218.     if (frame_attributes.x < 0
  1219.     || frame_attributes.y < 0
  1220.     || frame_attributes.x + frame_attributes.width
  1221.        > WidthOfScreen(XtScreen(tool_shell))
  1222.     || frame_attributes.y + frame_attributes.height
  1223.        > HeightOfScreen(XtScreen(tool_shell)))
  1224.     {
  1225.     return false;
  1226.     }
  1227.  
  1228.     // Fetch root coordinates of upper right edge of command tool
  1229.     int tool_x, tool_y;
  1230.     Window tool_child;
  1231.     XTranslateCoordinates(XtDisplay(tool_shell), tool_window,
  1232.               tool_attributes.root,
  1233.               tool_attributes.width, 0,
  1234.               &tool_x, &tool_y, &tool_child);
  1235.  
  1236.     // Fetch root coordinates of upper right edge of ref
  1237.     int ref_x, ref_y;
  1238.     Window ref_child;
  1239.     XTranslateCoordinates(XtDisplay(ref), ref_window,
  1240.               ref_attributes.root,
  1241.               ref_attributes.width, 0,
  1242.               &ref_x, &ref_y, &ref_child);
  1243.  
  1244.     // Determine offsets
  1245.     int x = ref_x - tool_x;
  1246.     int y = tool_y - ref_y;
  1247.  
  1248.     // Correct them relative to frame thickness
  1249.     int frame_x, frame_y;
  1250.     Window frame_child;
  1251.     XTranslateCoordinates(XtDisplay(ref), tool_window,
  1252.               tool_frame,
  1253.               tool_attributes.width, 0, &frame_x, &frame_y,
  1254.               &frame_child);
  1255.  
  1256.     x -= frame_attributes.width - frame_x + frame_attributes.border_width;
  1257.     y -= frame_y + frame_attributes.border_width;
  1258.  
  1259.     top_offset   = y;
  1260.     right_offset = x;
  1261.     return true;
  1262. }
  1263.  
  1264. // Store current offset of command tool in APP_DATA
  1265. void get_tool_offset()
  1266. {
  1267.     initialize_offsets();
  1268.  
  1269.     if (get_tool_offset(0, last_top_offset, last_right_offset))
  1270.     {
  1271.     app_data.tool_top_offset   = last_top_offset;
  1272.     app_data.tool_right_offset = last_right_offset;
  1273.     }
  1274. }
  1275.  
  1276.  
  1277.  
  1278. // Manage paned child with minimum size
  1279.  
  1280. inline bool is_internal_paned_child(Widget w)
  1281. {
  1282.     return XmIsSash(w) || XmIsSeparator(w) || XmIsSeparatorGadget(w) 
  1283.     || XtIsShell(w);
  1284. }
  1285.  
  1286. static MinMaxAssoc preferred_sizes;
  1287.  
  1288. void save_preferred_paned_sizes(Widget paned)
  1289. {
  1290.     // Fetch children
  1291.     WidgetList children;
  1292.     Cardinal numChildren = 0;
  1293.     XtVaGetValues(paned, XmNchildren, &children, 
  1294.           XmNnumChildren, &numChildren, NULL);
  1295.  
  1296.     // Fetch preferred sizes
  1297.     Cardinal i;
  1298.     for (i = 0; i < numChildren; i++)
  1299.     {
  1300.     Widget child = children[i];
  1301.     if (is_internal_paned_child(child))
  1302.         continue;
  1303.  
  1304.     // Fetch preferred (= initial) height
  1305.     Dimension height = 0;
  1306.     XtVaGetValues(child, XmNheight, &height, NULL);
  1307.     {
  1308.         XtWidgetGeometry size;
  1309.         size.request_mode = CWHeight;
  1310.         XtQueryGeometry(child, NULL, &size);
  1311.         height = max(height, size.height);
  1312.     }
  1313.  
  1314. #if LOG_GEOMETRY
  1315.     clog << XtName(paned) << ": child " << XtName(child) 
  1316.          << " has preferred height " << height << '\n';
  1317. #endif
  1318.  
  1319.     MinMax& preferred_size = preferred_sizes[child];
  1320.     preferred_size.min = preferred_size.max = height;
  1321.     }
  1322. }
  1323.  
  1324. const Dimension MIN_PANED_SIZE = 90;
  1325.  
  1326. static void paned_changed(Widget /* paned */)
  1327. {
  1328.     if (gdb_w != 0)
  1329.     {
  1330.     // Recenter the tool shell
  1331.     RecenterToolShellCB();
  1332.  
  1333.     // Make sure the current command line is visible
  1334.     end_of_lineAct(gdb_w, 0, 0, 0);
  1335.  
  1336.     // Redisplay source and code glyphs
  1337.     source_view->update_glyphs();
  1338.     }
  1339. }
  1340.  
  1341. void manage_paned_child(Widget w)
  1342. {
  1343.     Widget paned = XtParent(w);
  1344.  
  1345.     if (paned == 0 || !XmIsPanedWindow(paned) || XtIsManaged(w))
  1346.     {
  1347.     XtManageChild(w);
  1348.     return;
  1349.     }
  1350.  
  1351. #if LOG_GEOMETRY
  1352.     clog << XtName(paned) << ": managing child " << XtName(w) << "\n";
  1353.     if (preferred_sizes.has(w))
  1354.     {
  1355.     const MinMax& preferred_size = preferred_sizes[w];
  1356.     clog << XtName(paned) << ": child " << XtName(w) 
  1357.          << " has preferred height " << preferred_size.max << '\n';
  1358.     }
  1359. #endif
  1360.  
  1361.     // Fetch children
  1362.     WidgetList children;
  1363.     Cardinal numChildren = 0;
  1364.     XtVaGetValues(paned, XmNchildren, &children, 
  1365.           XmNnumChildren, &numChildren, NULL);
  1366.  
  1367.  
  1368.     // Fetch current constraints
  1369.     MinMaxAssoc sizes;
  1370.     Cardinal i;
  1371.     for (i = 0; i < numChildren; i++)
  1372.     {
  1373.     Widget child = children[i];
  1374.     if (is_internal_paned_child(child))
  1375.         continue;
  1376.  
  1377.     MinMax& size = sizes[child];
  1378.     XtVaGetValues(children[i], 
  1379.               XmNpaneMinimum, &size.min, 
  1380.               XmNpaneMaximum, &size.max,
  1381.               NULL);
  1382.  
  1383. #if LOG_GEOMETRY
  1384.     clog << XtName(paned) << ": child " << XtName(child) 
  1385.          << " is managed (min = " << size.min 
  1386.          << ", max = " << size.max << ")\n";
  1387. #endif
  1388.     }
  1389.  
  1390.     assert(sizes.has(w));
  1391.     const MinMax& wsize = sizes[w];
  1392.     static const MinMax no_constraints;
  1393.  
  1394.     // Ensure that each child keeps at least the minimum size;
  1395.     // don't make it larger than its preferred maximum size.
  1396.     for (i = 0; i < numChildren; i++)
  1397.     {
  1398.     Widget child = children[i];
  1399.     if (!XtIsManaged(child) && child != w)
  1400.         continue;
  1401.     if (!sizes.has(child))
  1402.         continue;
  1403.  
  1404.     Arg args[10];
  1405.     Cardinal arg = 0;
  1406.  
  1407.     MinMax& size = sizes[child];
  1408.     Dimension current_max = size.max;
  1409.  
  1410.     if (child != w
  1411.         && wsize.min <= no_constraints.min 
  1412.         && wsize.max >= no_constraints.max
  1413.         && preferred_sizes.has(child))
  1414.     {
  1415.         // W is resizable: give all other children at most their
  1416.         // preferred (= initial) height
  1417.         MinMax& preferred_size = preferred_sizes[child];
  1418.  
  1419.         if (preferred_size.max < size.max)
  1420.         {
  1421.         XtSetArg(args[arg], XmNpaneMaximum, preferred_size.max); arg++;
  1422.         current_max = preferred_size.max;
  1423.         }
  1424.  
  1425. #if LOG_GEOMETRY
  1426.         clog << XtName(paned) << ": child " << XtName(child) 
  1427.              << " has preferred height " << preferred_size.max << '\n';
  1428. #endif
  1429.     }
  1430.  
  1431.     // Make each child (including W) at least MIN_PANED_SIZE high
  1432.     if (MIN_PANED_SIZE > size.min)
  1433.     {
  1434.         XtSetArg(args[arg], XmNpaneMinimum,
  1435.              min(MIN_PANED_SIZE, current_max)); arg++;
  1436.     }
  1437.  
  1438.     if (arg > 0)
  1439.     {
  1440.         XtSetValues(child, args, arg);
  1441.         size.changed = true;
  1442.     }
  1443.     }
  1444.  
  1445.     // Manage W
  1446.     XtManageChild(w);
  1447.  
  1448.     // Restore old constraints
  1449.     XtVaGetValues(paned, XmNchildren, &children, 
  1450.           XmNnumChildren, &numChildren, NULL);
  1451.  
  1452.     for (i = 0; i < numChildren; i++)
  1453.     {
  1454.     Widget child = children[i];
  1455.     if (!sizes.has(child) || !XtIsManaged(child))
  1456.         continue;
  1457.  
  1458.     MinMax& size = sizes[child];
  1459.  
  1460.     if (size.changed)
  1461.     {
  1462.         XtVaSetValues(child,
  1463.               XmNpaneMinimum, size.min, 
  1464.               XmNpaneMaximum, size.max,
  1465.               NULL);
  1466.     }
  1467.     }
  1468.  
  1469.     paned_changed(w);
  1470. }
  1471.  
  1472. // Return the number of resizable children of PANED
  1473. static int resizable_children(Widget paned)
  1474. {
  1475.     // Fetch children
  1476.     WidgetList children;
  1477.     Cardinal numChildren = 0;
  1478.     XtVaGetValues(paned, XmNchildren, &children, 
  1479.           XmNnumChildren, &numChildren, NULL);
  1480.  
  1481.     // Fetch current constraints
  1482.     MinMaxAssoc sizes;
  1483.     Cardinal i;
  1484.     int n = 0;
  1485.     for (i = 0; i < numChildren; i++)
  1486.     {
  1487.     Widget child = children[i];
  1488.     if (is_internal_paned_child(child) || !XtIsManaged(child))
  1489.         continue;
  1490.  
  1491.     MinMax& size = sizes[child];
  1492.     XtVaGetValues(children[i], 
  1493.               XmNpaneMinimum, &size.min, 
  1494.               XmNpaneMaximum, &size.max,
  1495.               NULL);
  1496.  
  1497.     if (size.min < size.max)
  1498.         n++;
  1499.     }
  1500.  
  1501.     return n;
  1502. }
  1503.  
  1504.  
  1505. // Unmanage W, but be sure the command window doesn't grow.
  1506. void unmanage_paned_child(Widget w)
  1507. {
  1508.     Widget paned = XtParent(w);
  1509.     if (paned == 0 || !XmIsPanedWindow(paned) || !XtIsManaged(w))
  1510.     {
  1511.     XtUnmanageChild(w);
  1512.     return;
  1513.     }
  1514.  
  1515. #if LOG_GEOMETRY
  1516.     clog << XtName(paned) << ": unmanaging child " << XtName(w) << "\n";
  1517. #endif
  1518.  
  1519.     Widget command = XtParent(gdb_w);
  1520.  
  1521.     if (resizable_children(paned) <= 2)
  1522.     {
  1523.     // Only two resizable children left - the remaining one must
  1524.     // be resized to a maximum.  Disable skipAdjust for a moment.
  1525.     Boolean skip_adjust = True;
  1526.     XtVaGetValues(command, XmNskipAdjust, &skip_adjust, NULL);
  1527.     XtVaSetValues(command, XmNskipAdjust, False, NULL);
  1528.  
  1529.     XtUnmanageChild(w);
  1530.  
  1531.     XtVaSetValues(command, XmNskipAdjust, skip_adjust, NULL);
  1532.     }
  1533.     else
  1534.     {
  1535.     // Resize the other child, but keep the command window intact
  1536.     Dimension height = 0;
  1537.     Dimension max = 1000;
  1538.     XtVaGetValues(command, 
  1539.               XmNheight, &height,
  1540.               XmNpaneMaximum, &max,
  1541.               NULL);
  1542.     XtVaSetValues(command, XmNpaneMaximum, height, NULL);
  1543.  
  1544.     XtUnmanageChild(w);
  1545.  
  1546.     XtVaSetValues(command, XmNpaneMaximum, max, NULL);
  1547.     }
  1548.  
  1549.     paned_changed(w);
  1550. }
  1551.  
  1552.  
  1553. // Set the width of PANED to the maximum width of its children
  1554.  
  1555. // Fetch the maximum width.  Do this for each paned window.
  1556. void get_paned_window_width(Widget paned, Dimension& max_width)
  1557. {
  1558.     if (paned == 0 || !XtIsSubclass(paned, xmPanedWindowWidgetClass))
  1559.     return;
  1560.  
  1561.     WidgetList children   = 0;
  1562.     Cardinal num_children = 0;
  1563.  
  1564.     XtVaGetValues(paned,
  1565.           XtNchildren, &children,
  1566.           XtNnumChildren, &num_children,
  1567.           NULL);
  1568.  
  1569.     for (Cardinal i = 0; i < num_children; i++)
  1570.     {
  1571.     Widget child = children[i];
  1572.     if (is_internal_paned_child(child) || !XtIsManaged(child))
  1573.         continue;
  1574.  
  1575.     // Fetch preferred width
  1576.     XtWidgetGeometry size;
  1577.     size.request_mode = CWWidth;
  1578.     XtQueryGeometry(child, NULL, &size);
  1579.  
  1580. #if LOG_GEOMETRY
  1581.     clog << XtName(paned) << ": child " << XtName(child)
  1582.          << " wants width " << size.width << "\n";
  1583. #endif
  1584.  
  1585.     max_width = max(size.width, max_width);
  1586.     }
  1587. }
  1588.  
  1589. // Set the found value.
  1590. void set_paned_window_size(Widget paned, Dimension max_width)
  1591. {
  1592.     if (paned == 0 || !XtIsSubclass(paned, xmPanedWindowWidgetClass))
  1593.     return;
  1594.  
  1595.     XtVaSetValues(paned, XmNwidth, max_width, NULL);
  1596.  
  1597.     WidgetList children     = 0;
  1598.     Cardinal num_children   = 0;
  1599.     Dimension spacing       = 8;
  1600.     Dimension margin_width  = 3;
  1601.     Dimension margin_height = 3;
  1602.  
  1603.     XtVaGetValues(paned,
  1604.           XtNchildren, &children,
  1605.           XtNnumChildren, &num_children,
  1606.           XmNspacing, &spacing,
  1607.           XmNmarginWidth, &margin_width,
  1608.           XmNmarginHeight, &margin_height,
  1609.           NULL);
  1610.  
  1611.     Dimension total_height = 0;
  1612.     int managed_children = 0;
  1613.     for (Cardinal i = 0; i < num_children; i++)
  1614.     {
  1615.     Widget child = children[i];
  1616.     if (is_internal_paned_child(child))
  1617.         continue;
  1618.  
  1619.     // Fetch preferred width
  1620.     Dimension width  = 0;
  1621.     Dimension height = 0;
  1622.     XtVaGetValues(child, XmNwidth, &width, XmNheight, &height, NULL);
  1623.  
  1624.     {
  1625.         XtWidgetGeometry size;
  1626.         size.request_mode = CWWidth | CWHeight;
  1627.         XtQueryGeometry(child, NULL, &size);
  1628.  
  1629.         width  = max(width, size.width);
  1630.         height = max(height, size.height);
  1631.     }
  1632.  
  1633. #if LOG_GEOMETRY
  1634.     clog << XtName(paned) << ": child " << XtName(child) 
  1635.          << " wants height " << height << "\n";
  1636. #endif
  1637.  
  1638.     if (managed_children > 0)
  1639.         total_height += spacing;
  1640.  
  1641.     total_height += height;
  1642.     managed_children++;
  1643.     }
  1644.  
  1645.     XtVaSetValues(paned,
  1646.           XmNwidth, max_width + 2 * margin_width,
  1647.           XmNheight, total_height + 2 * margin_height,
  1648.           NULL);
  1649. }
  1650.  
  1651.  
  1652.  
  1653. //-----------------------------------------------------------------------------
  1654. // Main Window stuff
  1655. //-----------------------------------------------------------------------------
  1656.  
  1657. // Set main window size
  1658. void set_main_window_size(Widget main)
  1659. {
  1660.     if (main == 0 || !XtIsSubclass(main, xmMainWindowWidgetClass))
  1661.     return;
  1662.  
  1663.     WidgetList children   = 0;
  1664.     Cardinal num_children = 0;
  1665.  
  1666.     XtVaGetValues(main,
  1667.           XtNchildren, &children,
  1668.           XtNnumChildren, &num_children,
  1669.           NULL);
  1670.  
  1671.     Dimension max_width    = 0;
  1672.     Dimension total_height = 0;
  1673.     for (Cardinal i = 0; i < num_children; i++)
  1674.     {
  1675.     Widget child = children[i];
  1676.     if (is_internal_paned_child(child))
  1677.         continue;
  1678.     if (XmIsScrollBar(child))
  1679.         continue;
  1680.  
  1681.     // Fetch sizes
  1682.     Dimension width  = 0;
  1683.     Dimension height = 0;
  1684.     XtVaGetValues(child, XmNwidth, &width, XmNheight, &height, NULL);
  1685.  
  1686.     {
  1687.         XtWidgetGeometry size;
  1688.         size.request_mode = CWWidth | CWHeight;
  1689.         XtQueryGeometry(child, NULL, &size);
  1690.  
  1691.         width  = max(width, size.width);
  1692.         height = max(height, size.height);
  1693.     }
  1694.  
  1695. #if LOG_GEOMETRY
  1696.     clog << XtName(main) << ": child " << XtName(child) << " wants " 
  1697.          << BoxSize(width, height) << "\n";
  1698. #endif
  1699.  
  1700.     max_width = max(width, max_width);
  1701.     total_height += height;
  1702.     }
  1703.  
  1704.     XtVaSetValues(main, XmNwidth, max_width, XmNheight, total_height, NULL);
  1705. }
  1706.  
  1707.  
  1708. //-----------------------------------------------------------------------------
  1709. // Scrolled Window stuff
  1710. //-----------------------------------------------------------------------------
  1711.  
  1712. // Promote child size to scrolled window
  1713. void set_scrolled_window_size(Widget child, Widget target)
  1714. {
  1715.     Widget scroll = XtParent(child);
  1716.  
  1717.     assert(XmIsScrolledWindow(scroll));
  1718.  
  1719.     Dimension scrollbar_width = 15;   // Additional space for scrollbar
  1720.  
  1721.     Widget vertical_scroll_bar = 0;
  1722.     Dimension spacing          = 4;
  1723.     Dimension margin_width     = 2;
  1724.     Dimension margin_height    = 2;
  1725.     XtVaGetValues(scroll, 
  1726.           XmNverticalScrollBar, &vertical_scroll_bar,
  1727.           XmNspacing, &spacing,
  1728.           XmNmarginWidth, &margin_width,
  1729.           XmNmarginHeight, &margin_height,
  1730.           NULL);
  1731.  
  1732.     if (vertical_scroll_bar != 0)
  1733.     {
  1734.     XtWidgetGeometry size;
  1735.     size.request_mode = CWWidth;
  1736.     XtQueryGeometry(vertical_scroll_bar, NULL, &size);
  1737.     scrollbar_width = size.width;
  1738.     }
  1739.  
  1740.     // Give the ScrolledWindow the size specified for its child
  1741.     XtWidgetGeometry size;
  1742.     size.request_mode = CWWidth | CWHeight;
  1743.     XtQueryGeometry(child, NULL, &size);
  1744.  
  1745.     if (target == 0)
  1746.     target = scroll;
  1747.  
  1748. #if LOG_GEOMETRY
  1749.     clog << XtName(target) << ": child " << XtName(child) << " wants " 
  1750.      << BoxSize(size.width, size.height) << "\n";
  1751. #endif
  1752.  
  1753.     Dimension border_width     = 1;
  1754.     Dimension shadow_thickness = 2;
  1755.     XtVaGetValues(child,
  1756.           XmNborderWidth, &border_width,
  1757.           XmNshadowThickness, &shadow_thickness,
  1758.           NULL);
  1759.  
  1760.     Dimension width = size.width +
  1761.     border_width * 2 +
  1762.     // shadow_thickness * 2 +
  1763.     spacing +
  1764.     scrollbar_width +
  1765.     margin_width * 2;
  1766.  
  1767.     Dimension height = size.height +
  1768.     border_width * 2 +
  1769.     // shadow_thickness * 2 +
  1770.     margin_height * 2;
  1771.  
  1772.     XtVaSetValues(target, XmNwidth,  width, XmNheight, height, NULL);
  1773. }
  1774.