Logo Search packages:      
Sourcecode: ddd version File versions  Download package

windows.C

// $Id$ -*- C++ -*-
// DDD window management

// Copyright (C) 1996-1998 Technische Universitaet Braunschweig, Germany.
// Written by Andreas Zeller <zeller@gnu.org>.
// 
// This file is part of DDD.
// 
// DDD is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
// 
// DDD is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public
// License along with DDD -- see the file COPYING.
// If not, write to the Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// 
// DDD is the data display debugger.
// For details, see the DDD World-Wide-Web page, 
// `http://www.gnu.org/software/ddd/',
// or send a mail to the DDD developers <ddd@gnu.org>.

char windows_rcsid[] = 
    "$Id$";

#define LOG_GEOMETRY 0
#define LOG_EVENTS   0
#define LOG_MOVES    0

#include "windows.h"

#include "AppData.h"
#include "BoxRegion.h"
#include "DataDisp.h"
#include "SourceView.h"
#include "TimeOut.h"
#include "assert.h"
#include "cmdtty.h"
#include "ddd.h"
#include "editing.h"
#include "exectty.h"
#include "exit.h"
#include "findParent.h"
#include "frame.h"
#include "wm.h"
#include "MinMaxA.h"
#include "Tool.h"
#include "XErrorB.h"

#include <Xm/Xm.h>
#include <Xm/DialogS.h>
#include <Xm/PanedW.h>
#include <Xm/MainW.h>
#include <Xm/ScrollBar.h>
#if XmVersion >= 1002
#include <Xm/VendorS.h>       // XmIsMotifWMRunning()
#else
#include <Xm/VendorE.h>       // XmIsMotifWMRunning()
#endif
#include <X11/Xutil.h>

#include "Sash.h"       // XmIsSash()
#include <Xm/Separator.h>     // XmIsSeparator()
#include <Xm/SeparatoG.h>     // XmIsSeparatorGadget()

// ANSI C++ doesn't like the XtIsRealized() macro
#ifdef XtIsRealized
#undef XtIsRealized
#endif

//-----------------------------------------------------------------------------
// Window management
//-----------------------------------------------------------------------------

// Shells (only used if separate windows are used)
Widget command_shell;
Widget data_disp_shell;
Widget source_view_shell;

// Command tool
Widget tool_shell;
Widget tool_buttons_w;

// Shell state stuff
enum WindowState { PoppingUp, PoppedUp, PoppedDown, 
               Iconic, Transient, UnknownShell };

#if LOG_EVENTS
static ostream& operator << (ostream& os, WindowState s)
{
    switch (s)
    {
    case PoppingUp:
      return os << "PoppingUp";
    case PoppedUp:
      return os << "PoppedUp";
    case PoppedDown:
      return os << "PoppedDown";
    case Iconic:
      return os << "Iconic";
    case Transient:
      return os << "Transient";
    case UnknownShell:
      return os << "UnknownShell";
    }

    return os;
}
#endif

static WindowState& state(Widget w)
{
    static WindowState command_shell_state     = PoppedDown;
    static WindowState data_disp_shell_state   = PoppedDown;
    static WindowState source_view_shell_state = PoppedDown;
    static WindowState tool_shell_state        = PoppedDown;

    if (w == 0)
      /* do nothing */;
    else if (w == command_shell)
      return command_shell_state;
    else if (w == data_disp_shell)
      return data_disp_shell_state;
    else if (w == source_view_shell)
      return source_view_shell_state;
    else if (w == tool_shell)
      return tool_shell_state;

    static WindowState dummy;
    dummy = UnknownShell;
    return dummy;
}

static bool popped_down(Widget w)
{
    WindowState st = state(w);
    return st == PoppedDown || st == UnknownShell;
}

static void set_state(WindowState& var, WindowState state)
{
    if (state == PoppingUp && var == PoppedUp)
      return;
    var = state;
}

static void set_state(Widget w, WindowState s)
{
    WindowState& var = state(w);
    if (var != UnknownShell)
    {
      set_state(var, s);
#if LOG_EVENTS
      std::clog << XtName(w) << " is " << state(w) << "\n";
#endif
    }
}

// Place command tool in upper right edge of REF
static void recenter_tool_shell(Widget ref = 0);

// Place command tool in upper right edge of REF, with a distance of
// TOP_OFFSET and RIGHT_OFFSET
static void recenter_tool_shell(Widget ref, int top_offset, int right_offset);

// Have command tool follow REF
static void follow_tool_shell(Widget ref = 0);

// Get current offset of command tool in TOP_OFFSET and RIGHT_OFFSET;
// return true iff successful.
static bool get_tool_offset(Widget ref, int& top_offset, int& right_offset);

// Last offsets as actually used
static int last_top_offset;
static int last_right_offset;
static bool offsets_initialized = false;

// Last saved geometry of tool shell
static string last_tool_shell_geometry = "+0+0";

static void initialize_offsets()
{
    if (!offsets_initialized)
    {
      last_top_offset   = app_data.tool_top_offset;
      last_right_offset = app_data.tool_right_offset;
      offsets_initialized = true;
    }
}

// Return current tool shell position relative to root window
static BoxPoint tool_shell_pos()
{
    int root_x = 0;
    int root_y = 0;

    if (tool_shell != 0 && XtIsRealized(tool_shell) && 
      state(tool_shell) == PoppedUp)
    {
      XWindowAttributes attr;
      XGetWindowAttributes(XtDisplay(tool_shell), XtWindow(tool_shell), 
                       &attr);
      Window child;
      XTranslateCoordinates(XtDisplay(tool_shell), XtWindow(tool_shell), 
                        attr.root, 0, 0, &root_x, &root_y, &child);
    }

    return BoxPoint(root_x, root_y);
}

static XtIntervalId move_tool_shell_timer = 0;

static BoxPoint last_tool_shell_position;
static BoxPoint tool_shell_move_offset(0, 0);

static void move_tool_shell(const BoxPoint& pos, bool verify = true);

// Verify shell position after movement
static void VerifyToolShellPositionCB(XtPointer = 0, XtIntervalId *id = 0)
{
    (void) id;                // Use it
    assert (*id == move_tool_shell_timer);
    move_tool_shell_timer = 0;

#if LOG_MOVES
    std::clog << "Tool position found:    " << tool_shell_pos() << "\n";
    std::clog << "Tool position expected: " << last_tool_shell_position << "\n";
#endif

    BoxPoint diff = tool_shell_pos() - last_tool_shell_position;
    if (diff != BoxPoint(0, 0))
    {
      tool_shell_move_offset = -diff;
      move_tool_shell(last_tool_shell_position, false);
    }
}

// Move tool shell to POS.  If VERIFY is set, verify and correct 
// any displacement induced by the window manager.
static void move_tool_shell(const BoxPoint& pos, bool verify)
{
#if 0
    // Make sure we don't move the tool shell off the screen
    pos[X] = max(pos[X], 0);
    pos[Y] = max(pos[Y], 0);
#endif

    if (tool_shell == 0)
      return;

    if (pos != tool_shell_pos())
    {
#if LOG_MOVES
      std::clog << "Moving tool to: " << pos[X] << ", " << pos[Y] << "\n";
#endif

      BoxPoint given_pos = pos + tool_shell_move_offset;

      std::ostringstream os;
      os << "+" << given_pos[X] << "+" << given_pos[Y];
      last_tool_shell_geometry = string(os);
      last_tool_shell_position = pos;

      // Move tool shell to POS
      XtVaSetValues(tool_shell,
                  XmNgeometry, last_tool_shell_geometry.chars(),
                  XmNx, given_pos[X],
                  XmNy, given_pos[Y],
                  XtPointer(0));

      // Verify tool shell position
      if (move_tool_shell_timer != 0)
      {
          XtRemoveTimeOut(move_tool_shell_timer);
          move_tool_shell_timer = 0;
      }

      if (verify)
      {
          move_tool_shell_timer = 
            XtAppAddTimeOut(XtWidgetToApplicationContext(tool_shell),
                        100, VerifyToolShellPositionCB, XtPointer(0));
      }
    }
}

static void RecenterToolShellCB(XtPointer = 0, XtIntervalId *id = 0)
{
    if (tool_shell == 0)
      return;

    static XtIntervalId recenter_tool_shell_timer = 0;

    if (id != 0)
    {
      assert(*id = recenter_tool_shell_timer);
      recenter_tool_shell_timer = 0;
    }
    else if (recenter_tool_shell_timer != 0)
    {
      XtRemoveTimeOut(recenter_tool_shell_timer);
      recenter_tool_shell_timer = 0;
    }

    bool have_visible_tool_shell = false;

    if (XtIsRealized(tool_buttons_w) && state(tool_shell) == PoppedUp)
    {
      XWindowAttributes attr;
      XGetWindowAttributes(XtDisplay(tool_buttons_w), 
                       XtWindow(tool_buttons_w), &attr);
      have_visible_tool_shell = (attr.map_state == IsViewable);
    }

    if (have_visible_tool_shell)
    {
      recenter_tool_shell();
    }
    else
    {
      // Try again in 200 ms
      recenter_tool_shell_timer = 
          XtAppAddTimeOut(XtWidgetToApplicationContext(tool_shell), 
                      200, RecenterToolShellCB, XtPointer(0));
    }
}

static void follow_tool_shell(Widget ref)
{
    initialize_offsets();
    recenter_tool_shell(ref, last_top_offset, last_right_offset);
}

static void FollowToolShellCB(XtPointer = 0, XtIntervalId *id = 0)
{
    if (tool_shell == 0)
      return;

    static XtIntervalId follow_tool_shell_timer = 0;

    if (id != 0)
    {
      assert(*id = follow_tool_shell_timer);
      follow_tool_shell_timer = 0;
    }
    else if (follow_tool_shell_timer != 0)
    {
      XtRemoveTimeOut(follow_tool_shell_timer);
      follow_tool_shell_timer = 0;
    }

    bool have_visible_tool_shell = false;

    if (XtIsRealized(tool_buttons_w) && state(tool_shell) == PoppedUp)
    {
      XWindowAttributes attr;
      XGetWindowAttributes(XtDisplay(tool_buttons_w), 
                       XtWindow(tool_buttons_w), &attr);
      have_visible_tool_shell = (attr.map_state == IsViewable);
    }

    if (have_visible_tool_shell)
    {
      follow_tool_shell();
    }
    else
    {
      // Try again in 200 ms
      follow_tool_shell_timer = 
          XtAppAddTimeOut(XtWidgetToApplicationContext(tool_shell), 
                      200, FollowToolShellCB, XtPointer(0));
    }
}

bool started_iconified(Widget w)
{
    Widget toplevel = w;
    while (XtParent(toplevel))
      toplevel = XtParent(toplevel);

    assert(XtIsTopLevelShell(toplevel));

    // Well isn't it iconic - don't you think?
    Boolean iconic;
    XtVaGetValues(toplevel, XmNiconic, &iconic, XtPointer(0));
    return iconic;
}

// Popup initial shell
void initial_popup_shell(Widget w)
{
    if (w == 0)
      return;

    Boolean iconic = started_iconified(w);
    XtVaSetValues(w, 
              XmNiconic, iconic,
              XmNinitialState, iconic ? IconicState : NormalState,
              XtPointer(0));
    WindowState state = iconic ? Iconic : PoppingUp;

    set_state(w, state);

    if (iconic || w == tool_shell)
      XtVaSetValues(w, 
                  XmNgeometry, "+0+0", 
                  XmNx, 0,
                  XmNy, 0,
                  XtPointer(0));

    if (w == tool_shell)
    {
      XtManageChild(tool_buttons_w);
      if (!XtIsRealized(tool_shell))
          XtRealizeWidget(tool_shell);
      if (!iconic)
          RecenterToolShellCB();
    }

    Widget toplevel = w;
    while (XtParent(toplevel))
      toplevel = XtParent(toplevel);
    assert(XtIsTopLevelShell(toplevel));

    if (w != toplevel && XtIsRealized(w))
      XtPopup(w, XtGrabNone);
}

void popup_shell(Widget w)
{
    if (w == 0)
      return;

    if (w == tool_shell)
    {
      if (!XtIsRealized(tool_shell))
      {
          initial_popup_shell(tool_shell);
          RecenterToolShellCB();
      }

      XtManageChild(tool_buttons_w);
    }

    if (XtIsRealized(w))
      XtPopup(w, XtGrabNone);

    set_state(w, PoppingUp);

    // Uniconify window
    if (XtIsRealized(w))
      XMapWindow(XtDisplay(w), XtWindow(w));
    raise_shell(w);
}

void popdown_shell(Widget w)
{
    if (w == 0)
      return;

    set_state(w, PoppedDown);

    if (w == tool_shell)
      XtUnmanageChild(tool_buttons_w);

    XtPopdown(w);
}

void iconify_shell(Widget w)
{
    if (w == 0 || !XtIsRealized(w))
      return;

    set_state(w, Iconic);

    XIconifyWindow(XtDisplay(w), XtWindow(w),
               XScreenNumberOfScreen(XtScreen(w)));
}

void uniconify_shell(Widget w)
{
    if (w == 0)
      return;

    if (state(w) == Iconic)
    {
      popup_shell(w);
    }
}

static void popup_tty(Widget shell)
{
    if (exec_tty_window())
    {
      XErrorBlocker blocker(XtDisplay(shell));

      // Uniconify window
      XMapWindow(XtDisplay(shell), exec_tty_window());

      // Place window on top
      XRaiseWindow(XtDisplay(shell), exec_tty_window());
    }
}

static void iconify_tty(Widget shell)
{
    if (exec_tty_window())
    {
      XIconifyWindow(XtDisplay(shell), exec_tty_window(),
                   XScreenNumberOfScreen(XtScreen(shell)));
    }
}

// Shell visibility stuff
static int& visibility(Widget w)
{
    static int command_shell_visibility     = VisibilityFullyObscured;
    static int data_disp_shell_visibility   = VisibilityFullyObscured;
    static int source_view_shell_visibility = VisibilityFullyObscured;
    static int tool_shell_visibility        = VisibilityFullyObscured;

    if (w == 0)
      /* do nothing */;
    else if (w == command_shell)
      return command_shell_visibility;
    else if (w == data_disp_shell)
      return data_disp_shell_visibility;
    else if (w == source_view_shell)
      return source_view_shell_visibility;
    else if (w == tool_shell)
      return tool_shell_visibility;

    static int dummy;
    dummy = VisibilityFullyObscured;
    return dummy;
}

static BoxRegion region(Display *display, Window win)
{
    XWindowAttributes attr;

    Status ok;
    ok = XGetWindowAttributes(display, win, &attr);
    if (!ok)
      return BoxRegion();

    return BoxRegion(BoxPoint(attr.x, attr.y), 
                 BoxSize(attr.width, attr.height));
}

static bool obscures(Display *display, Window top, Window bottom)
{
    if (top == 0 || bottom == 0)
      return false;

    return region(display, bottom) <= region(display, top);
}

static bool obscures(Widget top, Widget bottom)
{
    if (top == 0 || bottom == 0 || !XtIsRealized(top) || !XtIsRealized(bottom))
      return false;

    if (visibility(bottom) == VisibilityUnobscured)
      return false;

    return obscures(XtDisplay(top), XtWindow(top), XtWindow(bottom));
}

// Raise WIN above SIBLING
static void raise_above(Display *display, Window win, Window sibling)
{
    if (win == 0 || sibling == 0)
      return;

    XErrorBlocker blocker(display);

    Window win_frame     = frame(display, win);
    Window sibling_frame = frame(display, sibling);

    if (win_frame != 0 && sibling_frame != 0 && win_frame != sibling_frame)
    {
      // Raise WIN just above SIBLING
      XWindowChanges changes;
      changes.stack_mode = Above;
      changes.sibling    = sibling_frame;

      XConfigureWindow(display, win_frame,
                   CWSibling | CWStackMode, &changes);
    }
    else
    {
      // Raise WIN on top
      XRaiseWindow(display, win);
    }
}

inline void raise_tool_above(Window sibling)
{
    if (tool_shell && XtIsRealized(tool_shell) && 
      state(tool_shell) == PoppedUp)
      raise_above(XtDisplay(tool_shell), XtWindow(tool_shell), sibling);
}

inline void raise_tool_above(Widget w)
{
    if (w != 0 && XtIsRealized(w))
      raise_tool_above(XtWindow(w));
}

static XtIntervalId recentering_tool_shell_timer = 0;

void StructureNotifyEH(Widget w, XtPointer, XEvent *event, Boolean *)
{
    bool synthetic = (state(w) == Transient);

#if LOG_EVENTS
    if (synthetic)
      std::clog << "Synthetic event: ";
#endif

    switch (event->type)
    {
    case MapNotify:
      if (state(w) == UnknownShell)
          return;

      // Reflect state
      set_state(w, PoppedUp);

#if 0
      if (!synthetic
          && (w == source_view_shell
            || (source_view_shell == 0 && w == command_shell))
          && !app_data.command_toolbar && app_data.source_window)
      {
          // Popup command tool again
          popup_shell(tool_shell);
          set_state(tool_shell, Transient);
      }
#endif

      if (tool_shell != 0)
      {
          // Check position of command tool
          BoxPoint max_pos(WidthOfScreen(XtScreen(tool_shell)) - 1,
                       HeightOfScreen(XtScreen(tool_shell)) - 1);
          if (tool_shell_pos() >= max_pos)
            RecenterToolShellCB();
      }

      if (!synthetic && app_data.group_iconify)
      {
          // Some shell was mapped - map all other shells as well
          if (state(command_shell) == Iconic)
          {
            popup_shell(command_shell);
            set_state(command_shell, Transient);
          }
          if (state(data_disp_shell) == Iconic)
          {
            popup_shell(data_disp_shell);
            set_state(data_disp_shell, Transient);
          }
          if (state(source_view_shell) == Iconic)
          {
            popup_shell(source_view_shell);
            set_state(source_view_shell, Transient);
          }
          popup_tty(command_shell);
      }
      break;

    case UnmapNotify:
      // Reflect state
      if (state(w) == UnknownShell)
          return;

      if (state(w) != Iconic && state(w) != PoppedDown)
          set_state(w, Iconic);

      if (!synthetic
          && (w == source_view_shell
            || (source_view_shell == 0 && w == command_shell)))
      {
          // Iconify command tool, too
          iconify_shell(tool_shell);
          set_state(tool_shell, Transient);
      }

      if (!synthetic && state(w) != PoppedDown && app_data.group_iconify)
      {
          // Iconify all other windows as well
          if (state(command_shell) == PoppedUp)
          {
            iconify_shell(command_shell);
            set_state(command_shell, Transient);
          }
          if (state(data_disp_shell) == PoppedUp)
          {
            iconify_shell(data_disp_shell);
            set_state(data_disp_shell, Transient);
          }
          if (state(source_view_shell) == PoppedUp)
          {
            iconify_shell(source_view_shell);
            set_state(source_view_shell, Transient);
          }
          iconify_tty(command_shell);
      }
      break;

    case VisibilityNotify:
    {
      visibility(w) = event->xvisibility.state;

      // Check whether command tool is obscured by some DDD shell
      if (app_data.auto_raise_tool
          && (obscures(command_shell, tool_shell)
            || obscures(data_disp_shell, tool_shell)
            || obscures(source_view_shell, tool_shell)))
      {
          // Command tool is obscured
          if (XmIsMotifWMRunning(tool_shell) && XmIsDialogShell(tool_shell))
          {
            // We have MWM and the command tool is a Dialog Shell.
            // Hence, let MWM keep the command tool on top.
          }
          else
          {
            // Raise command tool
            Widget shell = 
                source_view_shell ? source_view_shell : command_shell;
            raise_tool_above(shell);
          }
      }

#if 0                   // Doesn't work yet - AZ
      // Check whether command tool is obscured by the exec window
      if (app_data.auto_raise_tool
          && obscures(XtDisplay(tool_shell), exec_tty_window(), 
                  XtWindow(tool_shell)))
          raise_tool_above(exec_tty_window());
#endif

      break;
    }

    case ConfigureNotify:
    {
      if (app_data.sticky_tool
          && have_tool_window()
          && (state(tool_shell) == PoppedUp 
            || state(tool_shell) == Transient))
      {
          // Let `sticky' command tool follow the source window
          initialize_offsets();

          if (w == tool_shell)
          {
            // Command tool has been moved
#if LOG_EVENTS || LOG_MOVES
            std::clog << "Tool has been moved to " << point(event) << "\n";
#endif

            if (recentering_tool_shell_timer == 0)
            {
                // Record offset
                get_tool_offset(0, last_top_offset, last_right_offset);
            }
          }

          if (w == source_view_shell || 
            w == command_shell && source_view_shell == 0)
          {
            // Source shell has been moved -- let command tool follow
#if LOG_EVENTS || LOG_MOVES
            std::clog << "Shell has been moved to " << point(event) << "\n";
#endif

            FollowToolShellCB();
          }
      }
      break;
    }

    default:
      // Any other event...
      break;
    }
}


//-----------------------------------------------------------------------------
// Closing shells
//-----------------------------------------------------------------------------

// Return number of running input shells
int running_shells()
{
    int shells = 0;

    if (!popped_down(command_shell))
      shells++;
    if (!popped_down(source_view_shell))
      shells++;
    if (!popped_down(data_disp_shell))
      shells++;
    if (app_data.tty_mode)
      shells++;

    return shells;
}


// Generic close callback
void DDDCloseCB(Widget w, XtPointer client_data, XtPointer call_data)
{
    if (running_shells() == 1)
    {
      DDDExitCB(w, XtPointer(EXIT_SUCCESS), 0);
      return;
    }

    Widget shell = findTopLevelShellParent(w);

    if (shell == command_shell)
    {
      if (data_disp_shell == 0)
      {
          gdbCloseDataWindowCB(w, client_data, call_data);
      }

      if (source_view_shell == 0)
      {
          gdbCloseCodeWindowCB(w, client_data, call_data);
          gdbCloseSourceWindowCB(w, client_data, call_data);
      }

      gdbCloseCommandWindowCB(w, client_data, call_data);
    }
    else if (shell == data_disp_shell)
      gdbCloseDataWindowCB(w, client_data, call_data);
    else if (shell == source_view_shell)
      gdbCloseSourceWindowCB(w, client_data, call_data);
    else if (shell == tool_shell)
      gdbCloseToolWindowCB(w, client_data, call_data);
    else
      popdown_shell(shell);
}



// Specific close and open callbacks

// Debugger console
void gdbCloseCommandWindowCB(Widget w, XtPointer, XtPointer)
{
    if (!app_data.tty_mode && 
      !have_data_window() && !have_source_window() && !have_code_window())
    {
      DDDExitCB(w, XtPointer(EXIT_SUCCESS), 0);
      return;
    }

    if ((app_data.separate_source_window || !have_source_window())
      && (app_data.separate_data_window || !have_data_window()))
    {
      popdown_shell(command_shell);
    }

    unmanage_paned_child(XtParent(gdb_w));

    app_data.debugger_console = false;

    update_options();
}

void gdbOpenCommandWindowCB(Widget, XtPointer, XtPointer)
{
    manage_paned_child(XtParent(gdb_w));

    if (app_data.separate_source_window)
      popup_shell(command_shell);

    app_data.debugger_console = true;

    update_options();
}

bool have_command_window()
{
    return XtIsManaged(XtParent(gdb_w));
}


// Source window
void gdbCloseSourceWindowCB(Widget w, XtPointer client_data, 
                      XtPointer call_data)
{
    if (!app_data.tty_mode && 
      !have_command_window() && !have_data_window() && !have_code_window())
    {
      DDDExitCB(w, XtPointer(EXIT_SUCCESS), 0);
      return;
    }

    // Popdown shell
    if (source_view_shell)
    {
      popdown_shell(source_view_shell);
    }
    else if (!have_command_window() && 
           !have_data_window() && 
           !have_code_window())
    {
      popdown_shell(command_shell);
    }

    // Unmanage source
    unmanage_paned_child(source_view->source_form());

    if (source_view_shell != 0)
      unmanage_paned_child(source_view->code_form());

    if (!XtIsManaged(source_view->code_form()))
      gdbCloseToolWindowCB(w, client_data, call_data);

    app_data.source_window = false;

    update_options();
}

void gdbCloseCodeWindowCB(Widget w, XtPointer client_data, 
                      XtPointer call_data)
{
    if (!app_data.tty_mode && 
      !have_command_window() && !have_data_window() && !have_source_window())
    {
      DDDExitCB(w, XtPointer(EXIT_SUCCESS), 0);
      return;
    }

    // Unmanage code
    unmanage_paned_child(source_view->code_form());

    if (!XtIsManaged(source_view->source_form()))
      gdbCloseToolWindowCB(w, client_data, call_data);

    app_data.disassemble = false;

    update_options();
}

void gdbOpenSourceWindowCB(Widget w, XtPointer client_data,
                     XtPointer call_data)
{
    manage_paned_child(source_view->source_form());
    if (source_view_shell != 0 && app_data.disassemble)
      manage_paned_child(source_view->code_form());
    Widget arg_cmd_w = XtParent(source_arg->top());
    manage_paned_child(arg_cmd_w);

    if (source_view_shell)
      popup_shell(source_view_shell);
    else
      popup_shell(command_shell);

    if (!app_data.command_toolbar)
      gdbOpenToolWindowCB(w, client_data, call_data);

    app_data.source_window = true;

    update_options();
}

void gdbOpenCodeWindowCB(Widget w, XtPointer client_data,
                   XtPointer call_data)
{
    manage_paned_child(source_view->code_form());
    Widget arg_cmd_w = XtParent(source_arg->top());
    manage_paned_child(arg_cmd_w);

    if (source_view_shell)
      popup_shell(source_view_shell);
    else
      popup_shell(command_shell);

    if (!app_data.command_toolbar)
      gdbOpenToolWindowCB(w, client_data, call_data);

    app_data.disassemble = true;

    update_options();
}

bool have_source_window()
{
    return XtIsManaged(source_view->source_form());
}

bool have_code_window()
{
    return XtIsManaged(source_view->code_form());
}


// Data window
void gdbCloseDataWindowCB(Widget w, XtPointer, XtPointer)
{
    if (!app_data.tty_mode && 
      !have_source_window() && !have_command_window() && !have_code_window())
    {
      DDDExitCB(w, XtPointer(EXIT_SUCCESS), 0);
      return;
    }

    if (data_disp_shell)
    {
      popdown_shell(data_disp_shell);
    }
    else if (!have_source_window() && 
           !have_command_window() && 
           !have_code_window())
    {
      popdown_shell(command_shell);
    }

    Widget arg_cmd_w = XtParent(source_arg->top());
    if (data_disp->graph_cmd_w == arg_cmd_w)
    {
      // Don't close the common toolbar
    }
    else
    {
      unmanage_paned_child(data_disp->graph_cmd_w);
    }

    unmanage_paned_child(data_disp->graph_form());

    app_data.data_window = false;

    update_options();
}

void gdbOpenDataWindowCB(Widget, XtPointer, XtPointer)
{
    manage_paned_child(data_disp->graph_cmd_w);
    manage_paned_child(data_disp->graph_form());

    if (data_disp_shell)
      popup_shell(data_disp_shell);
    else
      popup_shell(command_shell);

    app_data.data_window = true;

    update_options();
}

bool have_data_window()
{
    return XtIsManaged(data_disp->graph_form());
}


// Execution window
void gdbCloseExecWindowCB(Widget, XtPointer, XtPointer)
{
    app_data.separate_exec_window = False;

    kill_exec_tty();
    update_options();
}

void gdbOpenExecWindowCB(Widget, XtPointer, XtPointer)
{
    app_data.separate_exec_window = True;

    if (exec_tty_pid() == 0)
      startup_exec_tty();
    popup_tty(command_shell);
    update_options();
}

bool have_exec_window()
{
    exec_tty_running();
    return exec_tty_pid() > 0;
}


// Tool window
void gdbCloseToolWindowCB(Widget, XtPointer, XtPointer)
{
    if (tool_shell == 0 || !XtIsRealized(tool_shell))
      return;

    popdown_shell(tool_shell);
    update_options();
}

void gdbOpenToolWindowCB(Widget, XtPointer, XtPointer)
{
    if (tool_shell == 0)
      create_command_tool();

    if (tool_shell == 0 || !XtIsRealized(tool_shell))
      return;

    XtVaSetValues(tool_shell,
              XmNgeometry, last_tool_shell_geometry.chars(),
              XtPointer(0));

    popup_shell(tool_shell);

    wait_until_mapped(tool_shell);
    RecenterToolShellCB();

    update_options();
}

bool have_tool_window()
{
    return tool_shell != 0;
}


//-----------------------------------------------------------------------------
// Toggling shells
//-----------------------------------------------------------------------------

void gdbToggleCommandWindowCB(Widget w, XtPointer client_data,
                        XtPointer call_data)
{
    XmToggleButtonCallbackStruct *info = 
      (XmToggleButtonCallbackStruct *)call_data;

    if (info->set)
      gdbOpenCommandWindowCB(w, client_data, call_data);
    else
      gdbCloseCommandWindowCB(w, client_data, call_data);
}

void gdbToggleSourceWindowCB(Widget w, XtPointer client_data,
                        XtPointer call_data)
{
    XmToggleButtonCallbackStruct *info = 
      (XmToggleButtonCallbackStruct *)call_data;

    if (info->set)
      gdbOpenSourceWindowCB(w, client_data, call_data);
    else
      gdbCloseSourceWindowCB(w, client_data, call_data);
}

void gdbToggleCodeWindowCB(Widget w, XtPointer client_data,
                     XtPointer call_data)
{
    XmToggleButtonCallbackStruct *info = 
      (XmToggleButtonCallbackStruct *)call_data;

    if (info->set)
      gdbOpenCodeWindowCB(w, client_data, call_data);
    else
      gdbCloseCodeWindowCB(w, client_data, call_data);

    update_options();
}

void gdbToggleDataWindowCB(Widget w, XtPointer client_data,
                        XtPointer call_data)
{
    XmToggleButtonCallbackStruct *info = 
      (XmToggleButtonCallbackStruct *)call_data;

    if (info->set)
      gdbOpenDataWindowCB(w, client_data, call_data);
    else
      gdbCloseDataWindowCB(w, client_data, call_data);
}

void gdbToggleExecWindowCB(Widget w, XtPointer client_data,
                        XtPointer call_data)
{
    XmToggleButtonCallbackStruct *info = 
      (XmToggleButtonCallbackStruct *)call_data;

    if (info->set)
      gdbOpenExecWindowCB(w, client_data, call_data);
    else
      gdbCloseExecWindowCB(w, client_data, call_data);
}

void gdbToggleToolWindowCB(Widget w, XtPointer client_data,
                        XtPointer call_data)
{
    XmToggleButtonCallbackStruct *info = 
      (XmToggleButtonCallbackStruct *)call_data;

    if (info->set)
      gdbOpenToolWindowCB(w, client_data, call_data);
    else
      gdbCloseToolWindowCB(w, client_data, call_data);
}


//-----------------------------------------------------------------------------
// Command tool placement
//-----------------------------------------------------------------------------

static void RecenteredToolShellCB(XtPointer, XtIntervalId *id)
{
    (void) id;                // Use it
    assert (*id == recentering_tool_shell_timer);
    recentering_tool_shell_timer = 0;
}

// Place command tool in upper right edge of REF
static void recenter_tool_shell(Widget ref)
{
    recenter_tool_shell(ref, 
                  app_data.tool_top_offset, app_data.tool_right_offset);
}

// Place command tool in upper right edge of REF, with a distance of
// TOP_OFFSET and RIGHT_OFFSET
static void recenter_tool_shell(Widget ref, int top_offset, int right_offset)
{
    if (ref == 0)
      ref = source_view->source();
    if (ref == 0 || !XtIsManaged(ref))
      ref = source_view->code();

    if (ref == 0 || tool_shell == 0 || 
      !XtIsRealized(ref) || !XtIsRealized(tool_shell) ||
      state(tool_shell) != PoppedUp)
      return;

#if LOG_MOVES
    std::clog << "Recentering tool to offset: " << right_offset 
            << ", " << top_offset << "\n";
#endif

    Window ref_window  = XtWindow(ref);
    Window tool_window = XtWindow(tool_shell);
    Window tool_frame  = frame(tool_shell);

    // Get location of upper right edge of REF
    XWindowAttributes ref_attributes;
    XGetWindowAttributes(XtDisplay(ref), ref_window, &ref_attributes);

    // Get tool shell attributes
    XWindowAttributes tool_attributes;
    XGetWindowAttributes(XtDisplay(tool_shell), tool_window, &tool_attributes);

    // Get tool frame attributes
    XWindowAttributes frame_attributes;
    XGetWindowAttributes(XtDisplay(tool_shell), tool_frame, 
                   &frame_attributes);

    // Determine new position relative to REF
    int x = ref_attributes.width - tool_attributes.width - right_offset;
    int y = top_offset;

    // Correct them relative to frame thickness
    int frame_x, frame_y;
    Window frame_child;
    XTranslateCoordinates(XtDisplay(ref), tool_window,
                    tool_frame,
                    tool_attributes.width, 0, &frame_x, &frame_y,
                    &frame_child);

    x -= frame_attributes.width - frame_x + frame_attributes.border_width;
    y += frame_y + frame_attributes.border_width;

    // Get root coordinates
    int root_x, root_y;
    Window ref_child;
    XTranslateCoordinates(XtDisplay(ref), ref_window, 
                    ref_attributes.root,
                    x, y, &root_x, &root_y,
                    &ref_child);

    move_tool_shell(BoxPoint(root_x, root_y));

    last_top_offset     = top_offset;
    last_right_offset   = right_offset;
    offsets_initialized = true;

    if (recentering_tool_shell_timer)
      XtRemoveTimeOut(recentering_tool_shell_timer);

    recentering_tool_shell_timer = 
      XtAppAddTimeOut(XtWidgetToApplicationContext(tool_shell), 
                  500, RecenteredToolShellCB, XtPointer(0));
}


// Get current offset of command tool in TOP_OFFSET and RIGHT_OFFSET;
// return true iff successful.
static bool get_tool_offset(Widget ref, int& top_offset, int& right_offset)
{
    if (ref == 0)
      ref = source_view->source();
    if (ref == 0 || !XtIsManaged(ref))
      ref = source_view->code();

    if (ref == 0 || tool_shell == 0 || 
      !XtIsRealized(ref) || !XtIsRealized(tool_shell) || 
      !XtIsManaged(tool_buttons_w) ||
      state(tool_shell) != PoppedUp)
      return false;

    Window ref_window  = XtWindow(ref);
    Window tool_window = XtWindow(tool_shell);
    Window tool_frame  = frame(tool_shell);

    // Get location of upper right edge of REF
    XWindowAttributes ref_attributes;
    XGetWindowAttributes(XtDisplay(ref), ref_window, &ref_attributes);

    // Get tool shell attributes
    XWindowAttributes tool_attributes;
    XGetWindowAttributes(XtDisplay(tool_shell), tool_window, &tool_attributes);

    // Get tool frame attributes
    XWindowAttributes frame_attributes;
    XGetWindowAttributes(XtDisplay(tool_shell), tool_frame, 
                   &frame_attributes);

    // If the tool frame is off the screen, don't store the offset
    if (frame_attributes.x < 0
      || frame_attributes.y < 0
      || frame_attributes.x + frame_attributes.width
         > WidthOfScreen(XtScreen(tool_shell))
      || frame_attributes.y + frame_attributes.height
         > HeightOfScreen(XtScreen(tool_shell)))
    {
      return false;
    }

    // Fetch root coordinates of upper right edge of command tool
    int tool_x, tool_y;
    Window tool_child;
    XTranslateCoordinates(XtDisplay(tool_shell), tool_window,
                    tool_attributes.root,
                    tool_attributes.width, 0,
                    &tool_x, &tool_y, &tool_child);

    // Fetch root coordinates of upper right edge of ref
    int ref_x, ref_y;
    Window ref_child;
    XTranslateCoordinates(XtDisplay(ref), ref_window,
                    ref_attributes.root,
                    ref_attributes.width, 0,
                    &ref_x, &ref_y, &ref_child);

    // Determine offsets
    int x = ref_x - tool_x;
    int y = tool_y - ref_y;

    // Correct them relative to frame thickness
    int frame_x, frame_y;
    Window frame_child;
    XTranslateCoordinates(XtDisplay(ref), tool_window,
                    tool_frame,
                    tool_attributes.width, 0, &frame_x, &frame_y,
                    &frame_child);

    x -= frame_attributes.width - frame_x + frame_attributes.border_width;
    y -= frame_y + frame_attributes.border_width;

#if LOG_MOVES
    std::clog << "Current offset: " << x << ", " << y << "\n";
#endif

    top_offset   = y;
    right_offset = x;
    return true;
}

// Store current offset of command tool in APP_DATA
void get_tool_offset()
{
    initialize_offsets();

    if (get_tool_offset(0, last_top_offset, last_right_offset))
    {
      app_data.tool_top_offset   = last_top_offset;
      app_data.tool_right_offset = last_right_offset;
    }
}



// Manage paned child with minimum size

inline bool is_internal_paned_child(Widget w)
{
    return XmIsSash(w) || XmIsSeparator(w) || XmIsSeparatorGadget(w) 
      || XtIsShell(w);
}

static MinMaxAssoc preferred_sizes;

void save_preferred_paned_sizes(Widget paned)
{
    // Fetch children
    WidgetList children;
    Cardinal numChildren = 0;
    XtVaGetValues(paned, XmNchildren, &children, 
              XmNnumChildren, &numChildren, XtPointer(0));

    // Fetch preferred sizes
    Cardinal i;
    for (i = 0; i < numChildren; i++)
    {
      Widget child = children[i];
      if (is_internal_paned_child(child))
          continue;

      // Fetch preferred (= initial) height
      Dimension height = 0;
      XtVaGetValues(child, XmNheight, &height, XtPointer(0));
      {
          XtWidgetGeometry size;
          size.request_mode = CWHeight;
          XtQueryGeometry(child, (XtWidgetGeometry *)0, &size);
          height = max(height, size.height);
      }

#if LOG_GEOMETRY
      std::clog << XtName(paned) << ": child " << XtName(child) 
              << " has preferred height " << height << '\n';
#endif

      MinMax& preferred_size = preferred_sizes[child];
      preferred_size.min = preferred_size.max = height;
    }
}

const Dimension MIN_PANED_SIZE = 90;

static void paned_changed(Widget /* paned */)
{
    if (gdb_w != 0)
    {
      // Recenter the tool shell
      RecenterToolShellCB();

      // Make sure the current command line is visible
      end_of_lineAct(gdb_w, 0, 0, 0);

      // Redisplay source and code glyphs
      source_view->update_glyphs();
    }
}

void manage_paned_child(Widget w)
{
    Widget paned = XtParent(w);

    if (paned == 0 || !XmIsPanedWindow(paned) || XtIsManaged(w))
    {
      XtManageChild(w);
      return;
    }

#if LOG_GEOMETRY
    std::clog << XtName(paned) << ": managing child " << XtName(w) << "\n";
    if (preferred_sizes.has(w))
    {
      const MinMax& preferred_size = preferred_sizes[w];
      std::clog << XtName(paned) << ": child " << XtName(w) 
              << " has preferred height " << preferred_size.max << '\n';
    }
#endif

    // Fetch children
    WidgetList children;
    Cardinal numChildren = 0;
    XtVaGetValues(paned, XmNchildren, &children, 
              XmNnumChildren, &numChildren, XtPointer(0));


    // Fetch current constraints
    MinMaxAssoc sizes;
    Cardinal i;
    for (i = 0; i < numChildren; i++)
    {
      Widget child = children[i];
      if (is_internal_paned_child(child))
          continue;

      MinMax& size = sizes[child];
      XtVaGetValues(children[i], 
                  XmNpaneMinimum, &size.min, 
                  XmNpaneMaximum, &size.max,
                  XtPointer(0));

#if LOG_GEOMETRY
      std::clog << XtName(paned) << ": child " << XtName(child) 
              << " is managed (min = " << size.min 
              << ", max = " << size.max << ")\n";
#endif
    }

    assert(sizes.has(w));
    const MinMax& wsize = sizes[w];
    static const MinMax no_constraints;

    // Ensure that each child keeps at least the minimum size;
    // don't make it larger than its preferred maximum size.
    for (i = 0; i < numChildren; i++)
    {
      Widget child = children[i];
      if (!XtIsManaged(child) && child != w)
          continue;
      if (!sizes.has(child))
          continue;

      Arg args[10];
      Cardinal arg = 0;

      MinMax& size = sizes[child];
      Dimension current_max = size.max;

      if (child != w
          && wsize.min <= no_constraints.min 
          && wsize.max >= no_constraints.max
          && preferred_sizes.has(child))
      {
          // W is resizable: give all other children at most their
          // preferred (= initial) height
          MinMax& preferred_size = preferred_sizes[child];

          if (preferred_size.max < size.max)
          {
            XtSetArg(args[arg], XmNpaneMaximum, preferred_size.max); arg++;
            current_max = preferred_size.max;
          }

#if LOG_GEOMETRY
          std::clog << XtName(paned) << ": child " << XtName(child) 
                  << " has preferred height " << preferred_size.max << '\n';
#endif
      }

      // Make each child (including W) at least MIN_PANED_SIZE high
      if (MIN_PANED_SIZE > size.min)
      {
          XtSetArg(args[arg], XmNpaneMinimum,
                 min(MIN_PANED_SIZE, current_max)); arg++;
      }

      if (arg > 0)
      {
          XtSetValues(child, args, arg);
          size.changed = true;
      }
    }

    // Manage W
    XtManageChild(w);

    // Restore old constraints
    XtVaGetValues(paned, XmNchildren, &children, 
              XmNnumChildren, &numChildren, XtPointer(0));

    for (i = 0; i < numChildren; i++)
    {
      Widget child = children[i];
      if (!sizes.has(child) || !XtIsManaged(child))
          continue;

      MinMax& size = sizes[child];

      if (size.changed)
      {
          XtVaSetValues(child,
                    XmNpaneMinimum, size.min, 
                    XmNpaneMaximum, size.max,
                    XtPointer(0));
      }
    }

    paned_changed(w);
}

// Return the number of resizable children of PANED
static int resizable_children(Widget paned)
{
    // Fetch children
    WidgetList children;
    Cardinal numChildren = 0;
    XtVaGetValues(paned, XmNchildren, &children, 
              XmNnumChildren, &numChildren, XtPointer(0));

    // Fetch current constraints
    MinMaxAssoc sizes;
    Cardinal i;
    int n = 0;
    for (i = 0; i < numChildren; i++)
    {
      Widget child = children[i];
      if (is_internal_paned_child(child) || !XtIsManaged(child))
          continue;

      MinMax& size = sizes[child];
      XtVaGetValues(children[i], 
                  XmNpaneMinimum, &size.min, 
                  XmNpaneMaximum, &size.max,
                  XtPointer(0));

      if (size.min < size.max)
          n++;
    }

    return n;
}


// Unmanage W, but be sure the command window doesn't grow.
void unmanage_paned_child(Widget w)
{
    Widget paned = XtParent(w);
    if (paned == 0 || !XmIsPanedWindow(paned) || !XtIsManaged(w))
    {
      XtUnmanageChild(w);
      return;
    }

#if LOG_GEOMETRY
    std::clog << XtName(paned) << ": unmanaging child " << XtName(w) << "\n";
#endif

    Widget command = XtParent(gdb_w);

    if (resizable_children(paned) <= 2)
    {
      // Only two resizable children left - the remaining one must
      // be resized to a maximum.  Disable skipAdjust for a moment.
      Boolean skip_adjust = True;
      XtVaGetValues(command, XmNskipAdjust, &skip_adjust, XtPointer(0));
      XtVaSetValues(command, XmNskipAdjust, False, XtPointer(0));

      XtUnmanageChild(w);

      XtVaSetValues(command, XmNskipAdjust, skip_adjust, XtPointer(0));
    }
    else
    {
      // Resize the other child, but keep the command window intact
      Dimension height = 0;
      Dimension max = 1000;
      XtVaGetValues(command, 
                  XmNheight, &height,
                  XmNpaneMaximum, &max,
                  XtPointer(0));
      XtVaSetValues(command, XmNpaneMaximum, height, XtPointer(0));

      XtUnmanageChild(w);

      XtVaSetValues(command, XmNpaneMaximum, max, XtPointer(0));
    }

    paned_changed(w);
}


// Set the width of PANED to the maximum width of its children

// Fetch the maximum width.  Do this for each paned window.
void get_paned_window_width(Widget paned, Dimension& max_width)
{
    if (paned == 0 || !XtIsSubclass(paned, xmPanedWindowWidgetClass))
      return;

    WidgetList children   = 0;
    Cardinal num_children = 0;

    XtVaGetValues(paned,
              XtNchildren, &children,
              XtNnumChildren, &num_children,
              XtPointer(0));

    for (Cardinal i = 0; i < num_children; i++)
    {
      Widget child = children[i];
      if (is_internal_paned_child(child) || !XtIsManaged(child))
          continue;

      // Fetch preferred width
      XtWidgetGeometry size;
      size.request_mode = CWWidth;
      XtQueryGeometry(child, (XtWidgetGeometry *)0, &size);

#if LOG_GEOMETRY
      std::clog << XtName(paned) << ": child " << XtName(child)
              << " wants width " << size.width << "\n";
#endif

      max_width = max(size.width, max_width);
    }
}

// Set the found value.
void set_paned_window_size(Widget paned, Dimension max_width)
{
    if (paned == 0 || !XtIsSubclass(paned, xmPanedWindowWidgetClass))
      return;

    XtVaSetValues(paned, XmNwidth, max_width, XtPointer(0));

    WidgetList children     = 0;
    Cardinal num_children   = 0;
    Dimension spacing       = 8;
    Dimension margin_width  = 3;
    Dimension margin_height = 3;

    XtVaGetValues(paned,
              XtNchildren, &children,
              XtNnumChildren, &num_children,
              XmNspacing, &spacing,
              XmNmarginWidth, &margin_width,
              XmNmarginHeight, &margin_height,
              XtPointer(0));

    Dimension total_height = 0;
    int managed_children = 0;
    for (Cardinal i = 0; i < num_children; i++)
    {
      Widget child = children[i];
      if (is_internal_paned_child(child))
          continue;

      // Fetch preferred width
      Dimension width  = 0;
      Dimension height = 0;
      XtVaGetValues(child, 
                  XmNwidth, &width, 
                  XmNheight, &height, 
                  XtPointer(0));

      {
          XtWidgetGeometry size;
          size.request_mode = CWWidth | CWHeight;
          XtQueryGeometry(child, (XtWidgetGeometry *)0, &size);

          width  = max(width, size.width);
          height = max(height, size.height);
      }

#if LOG_GEOMETRY
      std::clog << XtName(paned) << ": child " << XtName(child) 
              << " wants height " << height << "\n";
#endif

      if (managed_children > 0)
          total_height += spacing;

      total_height += height;
      managed_children++;
    }

    XtVaSetValues(paned,
              XmNwidth, max_width + 2 * margin_width,
              XmNheight, total_height + 2 * margin_height,
              XtPointer(0));
}



//-----------------------------------------------------------------------------
// Main Window stuff
//-----------------------------------------------------------------------------

// Set main window size
void set_main_window_size(Widget main)
{
    if (main == 0 || !XtIsSubclass(main, xmMainWindowWidgetClass))
      return;

    WidgetList children   = 0;
    Cardinal num_children = 0;

    XtVaGetValues(main,
              XtNchildren, &children,
              XtNnumChildren, &num_children,
              XtPointer(0));

    Dimension max_width    = 0;
    Dimension total_height = 0;
    for (Cardinal i = 0; i < num_children; i++)
    {
      Widget child = children[i];
      if (is_internal_paned_child(child))
          continue;
      if (XmIsScrollBar(child))
          continue;

      // Fetch sizes
      Dimension width  = 0;
      Dimension height = 0;
      XtVaGetValues(child, 
                  XmNwidth, &width, 
                  XmNheight, &height, 
                  XtPointer(0));

      {
          XtWidgetGeometry size;
          size.request_mode = CWWidth | CWHeight;
          XtQueryGeometry(child, (XtWidgetGeometry *)0, &size);

          width  = max(width, size.width);
          height = max(height, size.height);
      }

#if LOG_GEOMETRY
      std::clog << XtName(main) << ": child " << XtName(child) << " wants " 
              << BoxSize(width, height) << "\n";
#endif

      max_width = max(width, max_width);
      total_height += height;
    }

    XtVaSetValues(main, 
              XmNwidth, max_width, 
              XmNheight, total_height, 
              XtPointer(0));
}


//-----------------------------------------------------------------------------
// Scrolled Window stuff
//-----------------------------------------------------------------------------

// Promote child size to scrolled window
void set_scrolled_window_size(Widget child, Widget target)
{
    Widget scroll = XtParent(child);

    assert(XmIsScrolledWindow(scroll));

    Dimension scrollbar_width = 15;   // Additional space for scrollbar

    Widget vertical_scroll_bar = 0;
    Dimension spacing          = 4;
    Dimension margin_width     = 2;
    Dimension margin_height    = 2;
    XtVaGetValues(scroll, 
              XmNverticalScrollBar, &vertical_scroll_bar,
              XmNspacing, &spacing,
              XmNmarginWidth, &margin_width,
              XmNmarginHeight, &margin_height,
              XtPointer(0));

    if (vertical_scroll_bar != 0)
    {
      XtWidgetGeometry size;
      size.request_mode = CWWidth;
      XtQueryGeometry(vertical_scroll_bar, (XtWidgetGeometry *)0, &size);
      scrollbar_width = size.width;
    }

    // Give the ScrolledWindow the size specified for its child
    XtWidgetGeometry size;
    size.request_mode = CWWidth | CWHeight;
    XtQueryGeometry(child, (XtWidgetGeometry *)0, &size);

    if (target == 0)
      target = scroll;

#if LOG_GEOMETRY
    std::clog << XtName(target) << ": child " << XtName(child) << " wants " 
            << BoxSize(size.width, size.height) << "\n";
#endif

    Dimension border_width     = 1;
    Dimension shadow_thickness = 2;
    XtVaGetValues(child,
              XmNborderWidth, &border_width,
              XmNshadowThickness, &shadow_thickness,
              XtPointer(0));

    Dimension width = size.width +
      border_width * 2 +
      // shadow_thickness * 2 +
      spacing +
      scrollbar_width +
      margin_width * 2;

    Dimension height = size.height +
      border_width * 2 +
      // shadow_thickness * 2 +
      margin_height * 2;

    XtVaSetValues(target, XmNwidth,  width, XmNheight, height, XtPointer(0));
}

Generated by  Doxygen 1.6.0   Back to index