/* Copyright (C) 1996 Scott W. Sadler All rights reserved. */ /* XsMotifWindow.C History 03-Mar-96 1.0; Scott W. Sadler (ssadler@cisco.com) Created */ // Includes #include #include #include #include #include #include #include #include "XsMotifWindow.h" #include "XsResizeOutline.h" #include "XsMoveOutline.h" #include "xs_motif_icon.xbm" // Constants const int BorderSize_ = 6; const int ButtonSize_ = 23; const int IconSize_ = 70; /* ---------------------------------------------------------------------------- _XsMotifBase */ // Constructor _XsMotifBase::_XsMotifBase (const char *name, XsMotifWindow *win) : XsComponent (name) { assert (win != 0); // Initialize _win = win; _topShadowGC = 0; _bottomShadowGC = 0; } // Destructor _XsMotifBase::~_XsMotifBase ( ) { if (_topShadowGC) XtReleaseGC (_base, _topShadowGC); if (_bottomShadowGC) XtReleaseGC (_base, _bottomShadowGC); } // show void _XsMotifBase::show ( ) { assert (_base != 0); // Install event handler XtAddEventHandler (_base, StructureNotifyMask, False, _mapEventHandler, (XtPointer)this); // Call the base-class XsComponent::show ( ); } // className const char* _XsMotifBase::className ( ) const { return ("_XsMotifBase"); } // _componentDestroyed ( ) void _XsMotifBase::_componentDestroyed ( ) { // Clean up the GCs if (_topShadowGC) XtReleaseGC (_base, _topShadowGC); if (_bottomShadowGC) XtReleaseGC (_base, _bottomShadowGC); _topShadowGC = 0; _bottomShadowGC = 0; // Call the base-class XsComponent::_componentDestroyed ( ); } // _drawShadows void _XsMotifBase::_drawShadows (Position x, Position y, Dimension width, Dimension height, Dimension thick, Boolean reverse) { assert (_base != 0); assert (thick > 0); const int nsegs = 2; XSegment segs[nsegs]; GC topShadowGC; GC bottomShadowGC; // Work out the graphics contexts topShadowGC = (reverse == False) ? _topShadowGC : _bottomShadowGC; bottomShadowGC = (reverse == False) ? _bottomShadowGC : _topShadowGC; for (int loop = 0; loop < thick; loop++) { /* TOP SHADOW DRAWING */ // Across the top segs[0].x1 = x + loop; segs[0].y1 = y + loop; segs[0].x2 = x + width - loop - 2; segs[0].y2 = y + loop; // Down the left side segs[1].x1 = x + loop; segs[1].y1 = y + loop + 1; segs[1].x2 = x + loop; segs[1].y2 = y + height - loop - 2; XDrawSegments (XtDisplay (_base), XtWindow (_base), topShadowGC, segs, nsegs); /* BOTTOM SHADOW DRAWING */ // Across the bottom segs[0].x1 = x + loop; segs[0].y1 = y + height - loop - 1; segs[0].x2 = x + width - loop - 1; segs[0].y2 = y + height - loop - 1; // Down the right side segs[1].x1 = x + width - loop - 1; segs[1].y1 = y + loop; segs[1].x2 = x + width - loop - 1; segs[1].y2 = y + height - loop - 1; XDrawSegments (XtDisplay (_base), XtWindow (_base), bottomShadowGC, segs, nsegs); } } // _drawLine void _XsMotifBase::_drawLine (Position x1, Position y1, Position x2, Position y2, GC &gc) { assert (_base != 0); XDrawLine (XtDisplay (_base), XtWindow (_base), gc, x1, y1, x2, y2); } // _map void _XsMotifBase::_map ( ) { // Create the graphics contexts unsigned long valuemask; XGCValues values; Pixel topShadow; Pixel bottomShadow; XtVaGetValues (_win->base ( ), XmNtopShadowColor, &topShadow, XmNbottomShadowColor, &bottomShadow, NULL); // Create the graphics contexts valuemask = GCForeground | GCLineWidth | GCGraphicsExposures; values.line_width = 0; values.graphics_exposures = False; values.foreground = topShadow; _topShadowGC = XtGetGC (_base, valuemask, &values); values.foreground = bottomShadow; _bottomShadowGC = XtGetGC (_base, valuemask, &values); } // _mapEventHandler void _XsMotifBase::_mapEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*) { if (event->type == MapNotify) { _XsMotifBase *obj = (_XsMotifBase*)clientData; obj->_map ( ); // Remove the event handler XtRemoveEventHandler (obj->_base, StructureNotifyMask, False, obj->_mapEventHandler, clientData); } } /* ---------------------------------------------------------------------------- _XsMotifComponent */ Cursor _XsMotifComponent::_cursors[_XsMotifComponent::NumCursors]; int _XsMotifComponent::_mutex = 0; XtResource _XsMotifComponent::_resourceList[] = { { "borderSize", "BorderSize", XmRDimension, sizeof (Dimension), XtOffset (_XsMotifComponent*, _borderSize), XmRImmediate, (XtPointer)BorderSize_ }, { "buttonSize", "ButtonSize", XmRDimension, sizeof (Dimension), XtOffset (_XsMotifComponent*, _buttonSize), XmRImmediate, (XtPointer)ButtonSize_ } }; // Constructor _XsMotifComponent::_XsMotifComponent (const char *name, XsMotifWindow *win, Widget parent) : _XsMotifBase (name, win) { // Create cursors (if necessary) if (_mutex == 0) { Display *dpy = XtDisplay (win->base ( )); _cursors[TopCursor] = XCreateFontCursor (dpy, XC_top_side); _cursors[BottomCursor] = XCreateFontCursor (dpy, XC_bottom_side); _cursors[LeftCursor] = XCreateFontCursor (dpy, XC_left_side); _cursors[RightCursor] = XCreateFontCursor (dpy, XC_right_side); _cursors[TopLeftCursor] = XCreateFontCursor (dpy, XC_top_left_corner); _cursors[TopRightCursor] = XCreateFontCursor (dpy, XC_top_right_corner); _cursors[BottomLeftCursor] = XCreateFontCursor (dpy, XC_bottom_left_corner); _cursors[BottomRightCursor] = XCreateFontCursor (dpy, XC_bottom_right_corner); _mutex = 1; } // Create the component _base = XtVaCreateWidget (name, widgetClass, (parent != 0) ? parent : _win->base ( ), NULL); // Install destroy handler _installDestroyHandler ( ); // Get resources _getResources (_resourceList, XtNumber (_resourceList)); // Compute the corner size _cornerSize = _buttonSize + _borderSize; // Install event handlers XtAddEventHandler (_base, ExposureMask, False, _exposeEventHandler, (XtPointer)this); XtAddEventHandler (_base, ButtonPressMask | ButtonReleaseMask | Button1MotionMask | Button2MotionMask, False, _inputEventHandler, (XtPointer)this); } // Destructor _XsMotifComponent::~_XsMotifComponent ( ) { // Empty } // className const char* _XsMotifComponent::className ( ) const { return ("_XsMotifComponent"); } // _input void _XsMotifComponent::_input (XEvent*) { // Empty } // _exposeEventHandler void _XsMotifComponent::_exposeEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*) { _XsMotifComponent *obj = (_XsMotifComponent*)clientData; if (event->xexpose.count == 0) obj->_expose (event); } // _inputEventHandler void _XsMotifComponent::_inputEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*) { _XsMotifComponent *obj = (_XsMotifComponent*)clientData; obj->_input (event); } /* ---------------------------------------------------------------------------- _XsMotifCorner */ // Constructor _XsMotifCorner::_XsMotifCorner (const char *name, XsMotifWindow *win, Corner corner) : _XsMotifComponent (name, win) { // Initialize _corner = corner; // Configure component XtVaSetValues (_base, XmNwidth, _cornerSize, XmNheight, _cornerSize, XmNborderWidth, (Dimension)0, NULL); } // Destructor _XsMotifCorner::~_XsMotifCorner ( ) { // Empty } // className const char *_XsMotifCorner::className ( ) const { return ("_XsMotifCorner"); } // _expose void _XsMotifCorner::_expose (XEvent*) { Dimension w, h; if (_topShadowGC == 0) // JACS return; // Get the size of the corner XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL); // Draw the shadow _drawShadows (0, 0, w, h, 1); // Draw the extra lines and relief switch (_corner) { case TopLeft: { _drawLine (1, 1, w - 2, 1, _topShadowGC); _drawLine (1, 1, 1, h - 2, _topShadowGC); // Relief _drawLine (_borderSize - 1, _borderSize - 1, _borderSize + _buttonSize - 2, _borderSize - 1, _bottomShadowGC); _drawLine (_borderSize - 1, _borderSize - 1, _borderSize - 1, _borderSize + _buttonSize - 2, _bottomShadowGC); break; } case TopRight: { _drawLine (1, 1, w - 2, 1, _topShadowGC); _drawLine (w - 2, 1, w - 2, h - 2, _bottomShadowGC); // Relief _drawLine (0, _borderSize - 1, _buttonSize - 1, _borderSize - 1, _bottomShadowGC); _drawLine (w - _borderSize, _borderSize - 1, w - _borderSize, _borderSize + _buttonSize - 2, _topShadowGC); break; } case BottomLeft: { _drawLine (1, 1, 1, h - 2, _topShadowGC); _drawLine (1, h - 2, w - 2, h - 2, _bottomShadowGC); // Relief _drawLine (_borderSize - 1, h - _borderSize, _borderSize + _buttonSize - 2, h - _borderSize, _topShadowGC); _drawLine (_borderSize - 1, 1, _borderSize - 1, _buttonSize - 1, _bottomShadowGC); break; } case BottomRight: { _drawLine (1, h - 2, w - 2, h - 2, _bottomShadowGC); _drawLine (w - 2, 1, w - 2, h - 2, _bottomShadowGC); // Relief _drawLine (1, h - _borderSize, _buttonSize, h - _borderSize, _topShadowGC); _drawLine (w - _borderSize, 1, w - _borderSize, _buttonSize - 1, _topShadowGC); break; } default: assert (0); } } // _input void _XsMotifCorner::_input (XEvent *event) { switch (event->type) { case ButtonPress: { if (event->xbutton.button == 2) { XsMoveOutline move (_win->base ( )); // Start the move if (move.go ( ) != False) { // Relocate the window _win->setPosition (move.x ( ), move.y ( )); } } else if (event->xbutton.button == 3) _win->popupMenu ( ); break; } case ButtonRelease: { switch (event->xbutton.button) { case 1: case 2: { _win->raise ( ); // Raise the window break; } } break; } case MotionNotify: { // Figure kind of resize we are doing int dir; if (_corner == TopLeft) dir = XsResizeOutline::Up | XsResizeOutline::Left; else if (_corner == TopRight) dir = XsResizeOutline::Up | XsResizeOutline::Right; else if (_corner == BottomLeft) dir = XsResizeOutline::Down | XsResizeOutline::Left; else if (_corner == BottomRight) dir = XsResizeOutline::Down | XsResizeOutline::Right; else assert (0); XsResizeOutline resize (_win->base ( ), dir); resize.setMinSize (_win->minWidth ( ), _win->minHeight ( )); // Start the resize if (resize.go ( ) != False) { // Relocate the window _win->setPosition (resize.x ( ), resize.y ( )); _win->setSize (resize.width ( ), resize.height ( )); } break; } } } // _map void _XsMotifCorner::_map ( ) { // Call the base-class _XsMotifComponent::_map ( ); // Install the cursor if (_corner == TopLeft) XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[TopLeftCursor]); else if (_corner == TopRight) XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[TopRightCursor]); else if (_corner == BottomLeft) XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[BottomLeftCursor]); else if (_corner == BottomRight) XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[BottomRightCursor]); else assert (0); } /* ---------------------------------------------------------------------------- _XsMotifSide */ // Constructor _XsMotifSide::_XsMotifSide (const char *name, XsMotifWindow *win, Side side) : _XsMotifComponent (name, win) { // Initialize _side = side; _lastW = _lastH = -1; // Configure component switch (_side) { case Top: case Bottom: { XtVaSetValues (_base, XmNheight, _borderSize, XmNborderWidth, (Dimension)0, NULL); break; } case Left: case Right: { XtVaSetValues (_base, XmNwidth, _borderSize, XmNborderWidth, (Dimension)0, NULL); break; } default: assert (0); } // Install event handler XtAddEventHandler (_base, StructureNotifyMask, False, _configureEventHandler, (XtPointer)this); } // Destructor _XsMotifSide::~_XsMotifSide ( ) { // Empty } // className const char *_XsMotifSide::className ( ) const { return ("_XsMotifSide"); } // _expose void _XsMotifSide::_expose (XEvent *event) { if (_topShadowGC == 0) // JACS return; // Clear out the window first if (event != 0) XClearWindow (XtDisplay (_base), XtWindow (_base)); Dimension w, h; // Get the size of the side XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL); // Draw the shadow _drawShadows (0, 0, w, h, 1); // Draw the extra lines switch (_side) { case Top: { _drawLine (1, 1, w - 2, 1, _topShadowGC); break; } case Bottom: { _drawLine (1, h - 2, w - 2, h - 2, _bottomShadowGC); break; } case Left: { _drawLine (1, 1, 1, h - 2, _topShadowGC); break; } case Right: { _drawLine (w - 2, 1, w - 2, h - 2, _bottomShadowGC); break; } default: assert (0); } } // _input void _XsMotifSide::_input (XEvent *event) { switch (event->type) { case ButtonPress: { if (event->xbutton.button == 2) { XsMoveOutline move (_win->base ( )); // Start the move if (move.go ( ) != False) { // Relocate the window _win->setPosition (move.x ( ), move.y ( )); } } else if (event->xbutton.button == 3) _win->popupMenu ( ); break; } case ButtonRelease: { switch (event->xbutton.button) { case 1: case 2: { _win->raise ( ); // Raise the window break; } } break; } case MotionNotify: { // Figure kind of resize we are doing int dir; if (_side == Top) dir = XsResizeOutline::Up; else if (_side == Bottom) dir = XsResizeOutline::Down; else if (_side == Left) dir = XsResizeOutline::Left; else if (_side == Right) dir = XsResizeOutline::Right; else assert (0); XsResizeOutline resize (_win->base ( ), dir); resize.setMinSize (_win->minWidth ( ), _win->minHeight ( )); // Start the resize if (resize.go ( ) != False) { // Relocate the window _win->setPosition (resize.x ( ), resize.y ( )); _win->setSize (resize.width ( ), resize.height ( )); } break; } } } // _map void _XsMotifSide::_map ( ) { // Call the base-class _XsMotifComponent::_map ( ); // Install the cursor if (_side == Top) XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[TopCursor]); else if (_side == Bottom) XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[BottomCursor]); else if (_side == Left) XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[LeftCursor]); else if (_side == Right) XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[RightCursor]); else assert (0); } // _configure void _XsMotifSide::_configure (XEvent *event) { XConfigureEvent *ce = (XConfigureEvent*)event; /* Check if window has been resized. If so, generate an expose event to redraw its contents. */ if ((_lastW != ce->width) || (_lastH != ce->height)) { if ((_base != 0) && XtIsManaged (_base)) XClearArea (XtDisplay (_base), XtWindow (_base), 0, 0, 0, 0, True); _lastW = ce->width; _lastH = ce->height; } } // _configureEventHandler void _XsMotifSide::_configureEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*) { if (event->type == ConfigureNotify) { _XsMotifSide *obj = (_XsMotifSide*)clientData; obj->_configure (event); } } /* ---------------------------------------------------------------------------- _XsMotifButton */ // Constructor _XsMotifButton::_XsMotifButton (const char *name, XsMotifWindow *win, Button button) : _XsMotifComponent (name, win) { // Initialize _pressed = False; _button = button; // Configure the component XtVaSetValues (_base, XmNheight, _buttonSize, XmNwidth, _buttonSize, XmNborderWidth, (Dimension)0, NULL); } // Destructor _XsMotifButton::~_XsMotifButton ( ) { // Empty } // redraw void _XsMotifButton::redraw ( ) { // Make sure component is viewable if (!XtIsRealized (_base)) return; // Check if window is viewable XWindowAttributes attrs; XGetWindowAttributes (XtDisplay (_base), XtWindow (_base), &attrs); if (attrs.map_state == IsViewable) _expose (0); // Just pretend we got an expose event } // className const char *_XsMotifButton::className ( ) const { return ("_XsMotifButton"); } // _expose void _XsMotifButton::_expose (XEvent *event) { if (_topShadowGC == 0) // JACS return; Dimension w, h; // Get the size of the button XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL); // Draw the shadow _drawShadows (0, 0, w, h, 1, _pressed); // Draw the extra line _drawLine (1, h - 2, w - 2, h - 2, (_pressed) ? _topShadowGC : _bottomShadowGC); // Check if we need to draw the decal if ((_button != Maximize) && (event == 0)) return; // Compute the decal size Dimension dw, dh; Boolean reverse = False; switch (_button) { case Menu: { dw = _buttonSize - 6; dh = 4; break; } case Minimize: { dw = dh = 4; break; } case Maximize: { dw = _buttonSize - 6; dh = dw - 1; if (_win->maximized ( )) reverse = True; break; } default: assert (0); } // Draw the decal _drawShadows ((w / 2) - (dw / 2), (h / 2) - (dh / 2), dw, dh, 1, reverse); } // _input void _XsMotifButton::_input (XEvent *event) { static Time lastTime = (Time)0; switch (event->type) { case ButtonPress: { if (event->xbutton.button == 1) { _pressed = True; if (_button == Menu) { // Get double-click time int multiClick = XtGetMultiClickTime (XtDisplay (_base)); // Check for double-click if ((event->xbutton.time - lastTime) <= multiClick) { _win->close ( ); return; } else lastTime = event->xbutton.time; // Redraw the button (pushed-in) redraw ( ); // Popup the menu _win->popupMenu (False); // The menu will consume the ButtonRelease, so fake one _pressed = False; redraw ( ); } else if ((_button == Minimize) || (_button == Maximize)) { redraw ( ); } } else if (event->xbutton.button == 2) { XsMoveOutline move (_win->base ( )); // Start the move if (move.go ( ) != False) { // Relocate the window _win->setPosition (move.x ( ), move.y ( )); } } else if (event->xbutton.button == 3) _win->popupMenu ( ); break; } case ButtonRelease: { if (event->xbutton.button == 1) { _pressed = False; // Check if pointer is really in the window XButtonEvent *b = &event->xbutton; Dimension width, height; Boolean inWindow = False; XtVaGetValues (_base, XmNwidth, &width, XmNheight, &height, NULL); if ((b->x >= 0) && (b->y >= 0) && (b->x < width) && (b->y < height)) inWindow = True; if (_button == Minimize) { if (inWindow) { if (_win->minimized ( )) _win->restore ( ); else _win->minimize ( ); } else redraw ( ); } else if (_button == Maximize) { if (inWindow) { if (_win->maximized ( )) _win->restore ( ); else _win->maximize ( ); } else redraw ( ); } } break; } } } // _map void _XsMotifButton::_map ( ) { // Call the base-class _XsMotifComponent::_map ( ); // Raise ourself XRaiseWindow (XtDisplay (_base), XtWindow (_base)); } /* ---------------------------------------------------------------------------- _XsMotifTitle */ XtResource _XsMotifTitle::_resourceList[] = { { "title", "Title", XmRString, sizeof (String), XtOffset (_XsMotifTitle*, _titleString), XmRImmediate, NULL }, { "titleFont", "TitleFont", XmRFontStruct, sizeof (XFontStruct*), XtOffset (_XsMotifTitle*, _titleFont), XmRString, "-*-helvetica-bold-o-normal-*-14-*-*-*-*-*-iso8859-1" } }; // Constructor _XsMotifTitle::_XsMotifTitle (const char *name, XsMotifWindow *win) : _XsMotifComponent (name, win) { // Initialize _pressed = False; _titleString = 0; _titleFont = 0; _fontGC = 0; _lastW = _lastH = -1; // Get resources _getResources (_resourceList, XtNumber (_resourceList)); // Copy title string to local memory if (_titleString != 0) { char *tmp = new char[strlen (_titleString) + 1]; strcpy (tmp, _titleString); _titleString = tmp; } // Configure the title XtVaSetValues (_base, XmNheight, _buttonSize, XmNborderWidth, (Dimension)0, NULL); // Install event handler XtAddEventHandler (_base, StructureNotifyMask, False, _configureEventHandler, (XtPointer)this); } // Destructor _XsMotifTitle::~_XsMotifTitle ( ) { if (_fontGC) XtReleaseGC (_base, _fontGC); delete [] _titleString; } // setTitle void _XsMotifTitle::setTitle (const char *title) { assert (title != 0); delete [] _titleString; _titleString = new char[strlen (title) + 1]; strcpy (_titleString, title); } // className const char *_XsMotifTitle::className ( ) const { return ("_XsMotifTitle"); } // _componentDestroyed void _XsMotifTitle::_componentDestroyed ( ) { // Clean up the GCs if (_fontGC) XtReleaseGC (_base, _fontGC); _fontGC = 0; // Call base-class _XsMotifComponent::_componentDestroyed ( ); } // _redraw void _XsMotifTitle::_redraw ( ) { _expose (0); // Just pretend we got an expose event } // _expose void _XsMotifTitle::_expose (XEvent *event) { if (_topShadowGC == 0) // JACS return; // Clear out the window first if (event != 0) XClearWindow (XtDisplay (_base), XtWindow (_base)); Dimension w, h; // Get the size of the button XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL); // Draw the shadow _drawShadows (0, 0, w, h, 1, _pressed); // Draw the extra line _drawLine (1, h - 2, w - 2, h - 2, (_pressed) ? _topShadowGC : _bottomShadowGC); // If this is an artificial event, no need continuing if (event == 0) return; // Draw the text string const int LeftOffset = 5; const int TopOffset = 2; // Figure out the title const char *title = (_titleString != 0) ? _titleString : _win->name ( ); if ((title != 0) && (title[0] != '\0')) { int len = strlen (title); XDrawString (XtDisplay (_base), XtWindow (_base), _fontGC, LeftOffset, TopOffset + _titleFont->ascent, title, len); } } // _input void _XsMotifTitle::_input (XEvent *event) { switch (event->type) { case ButtonPress: { switch (event->xbutton.button) { case 1: { _pressed = True; _redraw ( ); break; } case 2: { XsMoveOutline move (_win->base ( )); // Start the move if (move.go ( ) != False) { // Relocate the window _win->setPosition (move.x ( ), move.y ( )); } break; } case 3: { _win->popupMenu ( ); break; } } break; } case ButtonRelease: { switch (event->xbutton.button) { case 1: case 2: { _pressed = False; _redraw ( ); _win->raise ( ); break; } } break; } case MotionNotify: { XsMoveOutline move (_win->base ( )); // Start the move if (move.go ( ) != False) { // Relocate the window _win->setPosition (move.x ( ), move.y ( )); // Redraw the title bar _pressed = False; _redraw ( ); } break; } } } // _map void _XsMotifTitle::_map ( ) { // Call the base-class _XsMotifComponent::_map ( ); // Raise ourself XRaiseWindow (XtDisplay (_base), XtWindow (_base)); unsigned long valuemask; XGCValues values; Pixel foreground; Pixel background; // Get the pixels XtVaGetValues (_win->base ( ), XmNforeground, &foreground, XmNbackground, &background, NULL); // Create the font graphics context valuemask = GCForeground | GCBackground | GCGraphicsExposures | GCFont; values.foreground = foreground; values.background = background; values.font = _titleFont->fid; values.graphics_exposures = False; _fontGC = XtGetGC (_base, valuemask, &values); } // _configure void _XsMotifTitle::_configure (XEvent *event) { XConfigureEvent *ce = (XConfigureEvent*)event; /* Check if window has been resized. If so, generate an expose event to redraw its contents. */ if ((_lastW != ce->width) || (_lastH != ce->height)) { if ((_base != 0) && XtIsManaged (_base)) XClearArea (XtDisplay (_base), XtWindow (_base), 0, 0, 0, 0, True); _lastW = ce->width; _lastH = ce->height; } } // _configureEventHandler void _XsMotifTitle::_configureEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*) { if (event->type == ConfigureNotify) { _XsMotifTitle *obj = (_XsMotifTitle*)clientData; obj->_configure (event); } } /* ---------------------------------------------------------------------------- _XsMotifIcon */ XtResource _XsMotifIcon::_resourceList[] = { { "iconSize", "IconSize", XmRDimension, sizeof (Dimension), XtOffset (_XsMotifIcon*, _iconSize), XmRImmediate, (XtPointer)IconSize_ }, { "iconName", "IconName", XmRString, sizeof (String), XtOffset (_XsMotifIcon*, _iconName), XmRImmediate, NULL }, { "iconFont", "IconFont", XmRFontStruct, sizeof (XFontStruct*), XtOffset (_XsMotifIcon*, _iconFont), XmRString, "-*-helvetica-bold-r-normal-*-12-*-*-*-*-*-iso8859-1" }, { XmNiconX, XmCIconX, XmRPosition, sizeof (Position), XtOffset (_XsMotifIcon*, _iconX), XmRImmediate, (XtPointer)-1 }, { XmNiconY, XmCIconY, XmRPosition, sizeof (Position), XtOffset (_XsMotifIcon*, _iconY), XmRImmediate, (XtPointer)-1 } }; // Constructor _XsMotifIcon::_XsMotifIcon (const char *name, XsMotifWindow *win, Widget parent) : _XsMotifComponent (name, win, parent) { // Initialize _pixmapGC = 0; _fontGC = 0; _iconName = 0; _pixmap = 0; _freePixmap = False; _width = _height = 0; _placed = 0; // Get resources _getResources (_resourceList, XtNumber (_resourceList)); // Copy icon name to local memory if (_iconName != 0) { char *tmp = new char[strlen (_iconName) + 1]; strcpy (tmp, _iconName); _iconName = tmp; } // Configure the icon XtVaSetValues (_base, XmNwidth, _iconSize, XmNheight, _iconSize, NULL); } // Destructor _XsMotifIcon::~_XsMotifIcon ( ) { if (_fontGC) XtReleaseGC (_base, _fontGC); if (_pixmapGC) XtReleaseGC (_base, _pixmapGC); if (_freePixmap) XFreePixmap (XtDisplay (_base), _pixmap); delete [] _iconName; } // show void _XsMotifIcon::show ( ) { /* Configure the icon position. Either use the position specified in the resource, or place the icon at the top-left corner of the window. */ if (_placed == False) { Position x, y; if (_iconX == -1) { XtVaGetValues (_win->base ( ), XmNx, &x, NULL); if (x < 0) x = 0; _iconX = x; } else x = _iconX; if (_iconY == -1) { XtVaGetValues (_win->base ( ), XmNy, &y, NULL); if (y < 0) y = 0; _iconY = y; } else y = _iconY; XtVaSetValues (_base, XmNx, x, XmNy, y, NULL); _placed = True; } // Call the base class _XsMotifComponent::show ( ); } // setIconName void _XsMotifIcon::setIconName (const char *iconName) { assert (iconName != 0); delete [] _iconName; _iconName = new char[strlen (iconName) + 1]; strcpy (_iconName, iconName); } // setPixmap void _XsMotifIcon::setPixmap (Pixmap pixmap) { assert (pixmap != 0); // Free the existing pixmap (if necessary) if (_freePixmap) { XFreePixmap (XtDisplay (_base), _pixmap); _freePixmap = False; } // Save the new pixmap _pixmap = pixmap; // Get the pixmap width and height Window dummy; int xd, yd; unsigned int uw, uh, ub, ud; XGetGeometry (XtDisplay (_base), _pixmap, &dummy, &xd, &yd, &uw, &uh, &ub, &ud); _width = uw; _height = uh; } // className const char *_XsMotifIcon::className ( ) const { return ("_XsMotifIcon"); } // _componentDestroyed void _XsMotifIcon::_componentDestroyed ( ) { // Clear up the GCs if (_fontGC) XtReleaseGC (_base, _fontGC); if (_pixmapGC) XtReleaseGC (_base, _pixmapGC); if (_freePixmap) XFreePixmap (XtDisplay (_base), _pixmap); _fontGC = 0; _pixmapGC = 0; _freePixmap = 0; // Call the base-class _XsMotifComponent::_componentDestroyed ( ); } // _input void _XsMotifIcon::_input (XEvent *event) { static Time lastTime = (Time)0; switch (event->type) { case ButtonPress: { switch (event->xbutton.button) { case 1: break; case 2: { XsMoveOutline move (_base); // Start the move if (move.go ( ) != False) { // Relocate the window _win->setPosition (move.x ( ), move.y ( )); } break; } case 3: { _win->popupMenu ( ); break; } } break; } case ButtonRelease: { switch (event->xbutton.button) { case 1: { // Get double-click time int multiClick = XtGetMultiClickTime (XtDisplay (_base)); // Check for double-click if ((event->xbutton.time - lastTime) <= multiClick) _win->restore ( ); else { lastTime = event->xbutton.time; _win->raise ( ); } break; } } break; } case MotionNotify: { XsMoveOutline move (_base); // Start the move if (move.go ( ) != False) { // Relocate the icon _win->setPosition (move.x ( ), move.y ( )); } break; } } } // _expose void _XsMotifIcon::_expose (XEvent *) { if (_topShadowGC == 0) // JACS return; Dimension iconHeight; Dimension iconWidth; // Compute icon size XtVaGetValues (_base, XmNwidth, &iconWidth, XmNheight, &iconHeight, NULL); // Draw the shadow _drawShadows (0, 0, iconWidth, iconHeight, 2); // Figure out the icon string const char *iconName = (_iconName != 0) ? _iconName : (_win->title ( ) != 0) ? _win->title ( ) : _win->name ( ); const int fontX = 3; const int fontY = 3; if ((iconName != 0) && (iconName[0] != '\0')) { int textWidth; int len = strlen (iconName); // Compute the text size textWidth = XTextWidth (_iconFont, iconName, len); // Center the text in the bottom of the icon (or left-justify it) int x, y; if (textWidth <= (iconWidth - (fontX * 2))) x = (iconWidth - (int)textWidth) / 2; else x = fontX; y = (int)iconHeight - _iconFont->descent - fontY; // Draw the string XDrawString (XtDisplay (_base), XtWindow (_base), _fontGC, x, y, iconName, len); } // Compute label size int labelHeight = _iconFont->descent + _iconFont->ascent + (fontY * 2); if (labelHeight >= (iconHeight - 6)) return; // Draw the separator int sepY = (iconHeight) - labelHeight; _drawLine (1, sepY, iconWidth - 2, sepY, _bottomShadowGC); _drawLine (1, sepY + 1, iconWidth - 2, sepY + 1, _topShadowGC); // Draw the pixmap frame const int frameX = 4; const int frameY = 4; if ((frameX + 6) >= sepY) return; int frameWidth = iconWidth - (frameX * 2); int frameHeight = sepY - frameY - 2; _drawShadows (frameX, frameY, frameWidth, frameHeight, 1, True); frameWidth -= 2; frameHeight -= 2; _drawShadows (frameX + 1, frameY + 1, frameWidth, frameHeight, 1); frameWidth -= 2; frameHeight -= 2; // Blit the pixmap if (_pixmap != 0) { if ((frameWidth > 0) && (frameHeight > 0)) { int origX, origY; int drawW, drawH; // Center the pixmap or top-left orient it if (frameWidth > _width) { origX = (frameWidth - _width) / 2; origX += frameX + 2; drawW = _width; } else { origX = frameX + 2; drawW = frameWidth; } if (frameHeight > _height) { origY = (frameHeight - _height) / 2; origY += frameY + 2; drawH = _height; } else { origY = frameY + 2; drawH = frameHeight; } XCopyArea (XtDisplay (_base), _pixmap, XtWindow (_base), _pixmapGC, 0, 0, drawW, drawH, origX, origY); } } } // _map void _XsMotifIcon::_map ( ) { unsigned long valuemask; XGCValues values; Pixel fg; Pixel bg; int depth; // Call the base-class _XsMotifComponent::_map ( ); // Get the icon pixels XtVaGetValues (_win->base ( ), XmNdepth, &depth, XmNbackground, &bg, XmNforeground, &fg, NULL); // Create the default icon pixmap if (_pixmap == 0) { _pixmap = XCreatePixmapFromBitmapData (XtDisplay (_base), XtWindow (_base), xs_motif_icon_bits, xs_motif_icon_width, xs_motif_icon_height, fg, bg, depth); // Set this pixmap setPixmap (_pixmap); _freePixmap = True; // Create the icon pixmap graphics context valuemask = GCGraphicsExposures | GCForeground | GCBackground; values.graphics_exposures = False; values.foreground = fg; values.background = bg; _pixmapGC = XtGetGC (_base, valuemask, &values); } // Create the font graphics context valuemask = GCForeground | GCBackground | GCGraphicsExposures | GCFont; values.foreground = fg; values.background = bg; values.font = _iconFont->fid; values.graphics_exposures = False; _fontGC = XtGetGC (_base, valuemask, &values); } /* ---------------------------------------------------------------------------- _XsMotifMenu */ // Static definitions int _XsMotifMenu::_count = 0; Cursor _XsMotifMenu::_cursor = None; Pixmap _XsMotifMenu::_stipple = None; Display *_XsMotifMenu::_dpy = 0; // Resources XtResource _XsMotifMenu::_resourceList[] = { { "saveUnder", "SaveUnder", XmRBoolean, sizeof (Boolean), XtOffset (_XsMotifMenu*, _saveUnder), XmRImmediate, (XtPointer)True }, { "restoreString", "RestoreString", XmRString, sizeof (String), XtOffset (_XsMotifMenu*, _strings[Restore]), XmRString, "Restore" }, { "moveString", "MoveString", XmRString, sizeof (String), XtOffset (_XsMotifMenu*, _strings[Move]), XmRString, "Move" }, { "sizeString", "SizeString", XmRString, sizeof (String), XtOffset (_XsMotifMenu*, _strings[Size]), XmRString, "Size" }, { "minimizeString", "MinimizeString", XmRString, sizeof (String), XtOffset (_XsMotifMenu*, _strings[Minimize]), XmRString, "Minimize" }, { "maximizeString", "MaximizeString", XmRString, sizeof (String), XtOffset (_XsMotifMenu*, _strings[Maximize]), XmRString, "Maximize" }, { "raiseString", "RaiseString", XmRString, sizeof (String), XtOffset (_XsMotifMenu*, _strings[Raise]), XmRString, "Raise" }, { "lowerString", "LowerString", XmRString, sizeof (String), XtOffset (_XsMotifMenu*, _strings[Lower]), XmRString, "Lower" }, { "closeString", "CloseString", XmRString, sizeof (String), XtOffset (_XsMotifMenu*, _strings[Close]), XmRString, "Close" }, { "menuFont", "menuFont", XmRFontStruct, sizeof (XFontStruct*), XtOffset (_XsMotifMenu*, _menuFont), XmRString, "-*-helvetica-bold-o-normal-*-14-*-*-*-*-*-iso8859-1" } }; // Constructor _XsMotifMenu::_XsMotifMenu (const char *name, XsMotifWindow *win) : _XsMotifBase (name, win) { // Create the cursor (if necessary) if (_count++ == 0) { // Create the menu cursor _cursor = XCreateFontCursor (XtDisplay (win->base ( )), XC_arrow); // Create a stippled pixmap Widget parent = _win->base ( ); Pixel foreground; Pixel background; int depth; XtVaGetValues (parent, XmNforeground, &foreground, XmNbackground, &background, XmNdepth, &depth, NULL); const int pixmapWidth = 2; const int pixmapHeight = 2; static unsigned char pixmapBits[] = { 0x02, 0x01 }; _dpy = XtDisplay (parent); _stipple = XCreatePixmapFromBitmapData (_dpy, DefaultRootWindow (_dpy), (char*)pixmapBits, pixmapWidth, pixmapHeight, foreground, background, depth); } // Initialize _fontGC = 0; _grayGC = 0; _backgroundGC = 0; // Create the component (why doesn't overrideShell work?) _base = XtVaCreatePopupShell (_name, topLevelShellWidgetClass, XtParent (_win->base ( )), XmNoverrideRedirect, True, XmNborderWidth, 1, NULL); // Install destroy handler _installDestroyHandler ( ); // Install event handler ('cause we never call _XsMotifBase::show) XtAddEventHandler (_base, StructureNotifyMask, False, _mapEventHandler, (XtPointer)this); // Get resources _getResources (_resourceList, XtNumber (_resourceList)); // Get the background color Pixel bg; XtVaGetValues (_win->base ( ), XmNbackground, &bg, NULL); // Compute the size of the (largest) menu item int textHeight = _menuFont->ascent + _menuFont->descent; int textWidth = 0; int tmp; for (int loop = 0; loop < Num; loop++) { tmp = XTextWidth (_menuFont, _strings[loop], strlen (_strings[loop])); if (tmp > textWidth) textWidth = tmp; } // Put a border around the buttons textWidth += (2 * HorizTextOffset); textHeight += (2 * VertTextOffset); /* The menu height is the menu-shadow (1 pixel on top and bottom) + the items themselves. */ int menuHeight = (2 * ShadowThickness) + // Top and bottom shadow (textHeight * Num); // The menu items /* The menu width is the menu-shadow (1 pixel on the left and right) + the largest menu text (calculated above) */ int menuWidth = (2 * ShadowThickness) + // Left and right shadow textWidth; // Largest text item // Configure the popup XtVaSetValues (_base, XmNsaveUnder, _saveUnder, XmNwidth, menuWidth, XmNheight, menuHeight, NULL); } // Destructor _XsMotifMenu::~_XsMotifMenu ( ) { if (_fontGC) XtReleaseGC (_base, _fontGC); if (_grayGC) XtReleaseGC (_base, _grayGC); if (_backgroundGC) XtReleaseGC (_base, _backgroundGC); // Free the pixmap (if necessary) if (--_count == 0) XFreePixmap (_dpy, _stipple); } // popup void _XsMotifMenu::popup (Boolean atPointer) { assert (_base != 0); Position x, y; // Compute the location of the menu. if (atPointer) { unsigned int mask; Window win; int winX, winY; int rootX, rootY; // Menu at pointer location XQueryPointer (XtDisplay (_base), XtWindow (XtParent (_base)), &win, &win, &rootX, &rootY, &winX, &winY, &mask); x = (Position)rootX; y = (Position)rootY; } else { // Menu at top-left corner of client area XtTranslateCoords (_win->clientArea ( ), 0, 0, &x, &y); } // Move the menu XtVaSetValues (_base, XmNx, x, XmNy, y, NULL); // Initialize the item _curItem = NoItem; // Pop it up XtPopup (_base, XtGrabNone); // Grab the pointer if (_grabPointer ( ) == FALSE) return; // Update the menu _processEvents ( ); // Pop the menu down XtPopdown (_base); // Ungrab the pointer _ungrabPointer ( ); if (_curItem != NoItem) { /* Post a work-proc to process this item. This will allow everything to get caught up before we process the menu item */ XtAppContext appContext = XtWidgetToApplicationContext (_base); XtAppAddWorkProc (appContext, _workProc, (XtPointer)this); } } // className const char *_XsMotifMenu::className ( ) const { return ("_XsMotifMenu"); } // _componentDestroyed void _XsMotifMenu::_componentDestroyed ( ) { // Clean up the GCs if (_fontGC) XtReleaseGC (_base, _fontGC); if (_grayGC) XtReleaseGC (_base, _grayGC); if (_backgroundGC) XtReleaseGC (_base, _backgroundGC); _fontGC = 0; _grayGC = 0; _backgroundGC = 0; // Call the base-class _XsMotifBase::_componentDestroyed ( ); } // _processEvents void _XsMotifMenu::_processEvents ( ) { assert (_base != 0); XtAppContext appContext = XtWidgetToApplicationContext (_base); XEvent event; Display *dpy = XtDisplay (_base); int done = 0; while (!done) { XtAppNextEvent (appContext, &event); // Process this event switch (event.type) { case ButtonRelease: { done = 1; break; } case Expose: { _redrawMenu ( ); break; } case MotionNotify: { XEvent next; // Process only the last motion event while (XPending (dpy) > 0) { XPeekEvent (dpy, &next); if (next.type != MotionNotify) break; XtAppNextEvent (appContext, &event); } // Track the mouse and toggle the menu items Item item = _trackPointer ((XMotionEvent*)&event); // Unselect the current item (if the item is different) if (item != _curItem) { _toggleItem (_curItem, False); // Select the new item _toggleItem ((_curItem = item), True); } break; } default: { XtDispatchEvent (&event); break; } } } } // _processItem void _XsMotifMenu::_processItem (Item item) { if (item == NoItem) return; switch (item) { case Restore: { _win->restore ( ); break; } case Move: { Widget base = (_win->minimized ( )) ? _win->icon ( ) : _win->base ( ); // Warp the pointer to the center of the window Dimension width, height; XtVaGetValues (base, XmNwidth, &width, XmNheight, &height, NULL); XWarpPointer (XtDisplay (_base), None, XtWindow (base), 0, 0, 0, 0, (width / 2), (height / 2)); // Move the window XsMoveOutline move (base); // Start the move if (move.go (True) != False) { // Relocate the window _win->setPosition (move.x ( ), move.y ( )); } break; } case Size: { Widget base = (_win->minimized ( )) ? _win->icon ( ) : _win->base ( ); // Warp the pointer to the center of the window Dimension width, height; XtVaGetValues (base, XmNwidth, &width, XmNheight, &height, NULL); XWarpPointer (XtDisplay (_base), None, XtWindow (base), 0, 0, 0, 0, (width / 2), (height / 2)); // Resize the window XsResizeOutline resize (_win->base ( ), XsResizeOutline::Undetermined); resize.setMinSize (_win->minWidth ( ), _win->minHeight ( )); // Start the resize if (resize.go (True) != False) { // Relocate the window _win->setPosition (resize.x ( ), resize.y ( )); _win->setSize (resize.width ( ), resize.height ( )); } break; } case Minimize: { _win->minimize ( ); break; } case Maximize: { _win->maximize ( ); break; } case Raise: { _win->raise ( ); break; } case Lower: { _win->lower ( ); break; } case Close: { _win->close ( ); break; } default: assert (0); } } // _redrawMenu void _XsMotifMenu::_redrawMenu ( ) { Dimension w, h; // Get the size of the menu XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL); // Draw a shadow around the menu _drawShadows (0, 0, w, h, ShadowThickness); // Cycle and draw all of the elements for (int loop = 0; loop < Num; loop++) _redrawItem ((Item)loop); } // _redrawItem void _XsMotifMenu::_redrawItem (Item item) { if (item == NoItem) return; int x = ShadowThickness + HorizTextOffset; int y; /* Compute the y-position of the element. This will be the size of the top-shadow + the items before it + the offset of the item itself */ y = ShadowThickness + // Top shadow (item * ((VertTextOffset * 2) + (_menuFont->descent + _menuFont->ascent))) + (VertTextOffset + _menuFont->ascent); // The item iteself // Figure out the graphics-context GC gc; if (_win->minimized ( )) gc = ((item == Size) || (item == Minimize)) ? _grayGC : _fontGC; else if (_win->maximized ( )) gc = (item == Maximize) ? _grayGC : _fontGC; else gc = (item == Restore) ? _grayGC : _fontGC; // Draw the string XDrawString (XtDisplay (_base), XtWindow (_base), gc, x, y, _strings[item], strlen (_strings[item])); } // _toggleItem void _XsMotifMenu::_toggleItem (Item item, Boolean active) { if (item == NoItem) return; /* Either draw the background of the specified item in the active color or the standard background color */ GC gc = (active) ? _topShadowGC : _backgroundGC; // Get the width of the menu Dimension menuWidth; XtVaGetValues (_base, XmNwidth, &menuWidth, NULL); // Compute the location and size of the rectangle int x, y; unsigned int width, height; x = ShadowThickness; height = ((VertTextOffset * 2) + (_menuFont->descent + _menuFont->ascent)); y = ShadowThickness + (item * height); width = menuWidth - (2 * ShadowThickness); // Draw the filled rectangle XFillRectangle (XtDisplay (_base), XtWindow (_base), gc, x, y, width, height); // Redraw the text _redrawItem (item); } // _trackPointer _XsMotifMenu::Item _XsMotifMenu::_trackPointer (XMotionEvent *event) { assert (_base != 0); Dimension menuWidth; Dimension menuHeight; Position x, y; // Get the menu size and position XtVaGetValues (_base, XmNwidth, &menuWidth, XmNheight, &menuHeight, XmNx, &x, XmNy, &y, NULL); // Make sure the pointer is in the menu if ((event->x_root < x) || (event->x_root > (x + menuWidth))) return (NoItem); if ((event->y_root < y) || (event->y_root > (y + menuHeight))) return (NoItem); // Make sure the pointer is on the confines of the shadow if ((event->x < ShadowThickness) || (event->x > (menuWidth - (2 * ShadowThickness)))) return (NoItem); if ((event->y < ShadowThickness) || (event->y > (menuHeight - (2 * ShadowThickness)))) return (NoItem); /* Now we are just concerned with the y-position. Subtract off the shadow thickness to normalize the location */ int yPos = event->y - ShadowThickness; // Compute which item the mouse is in int itemHeight = (VertTextOffset * 2) + (_menuFont->descent + _menuFont->ascent); Item item = (Item)(yPos / itemHeight); // Validate that the item is not grayed-out if (_win->minimized ( )) { if ((item == Size) || (item == Minimize)) item = NoItem; } else if (_win->maximized ( )) { if (item == Maximize) item = NoItem; } else if (item == Restore) item = NoItem; return (item); } // _grabPointer Boolean _XsMotifMenu::_grabPointer ( ) { // Sync everything up before being grabby XSync (XtDisplay (_base), False); // Grab the pointer if (XGrabPointer (XtDisplay (_base), XtWindow (_base), False, (unsigned int)(ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask), GrabModeAsync, GrabModeAsync, None, _cursor, CurrentTime) != GrabSuccess) { XBell (XtDisplay (_base), 100); return (False); } return (True); } // _ungrabPointer void _XsMotifMenu::_ungrabPointer ( ) { // Ungrab the pointer XUngrabPointer (XtDisplay (_base), CurrentTime); // Sync everything back up XSync (XtDisplay (_base), False); } // _map void _XsMotifMenu::_map ( ) { // Call the base-class _XsMotifBase::_map ( ); unsigned long valuemask; XGCValues values; Pixel foreground; Pixel background; // Get the pixels XtVaGetValues (XtParent (_base), XmNforeground, &foreground, NULL); XtVaGetValues (_base, XmNbackground, &background, NULL); // Create the font graphics context valuemask = GCForeground | GCBackground | GCGraphicsExposures | GCFont; values.foreground = foreground; values.background = background; values.font = _menuFont->fid; values.graphics_exposures = False; _fontGC = XtGetGC (_base, valuemask, &values); // Create the insensitive font graphics context valuemask |= (GCFillStyle | GCTile); values.fill_style = FillTiled; values.tile = _stipple; _grayGC = XtGetGC (_base, valuemask, &values); // Create the background contexts valuemask = GCForeground | GCLineWidth | GCGraphicsExposures; values.line_width = 0; values.graphics_exposures = False; values.foreground = background; _backgroundGC = XtGetGC (_base, valuemask, &values); } // _workProc Boolean _XsMotifMenu::_workProc (XtPointer clientData) { _XsMotifMenu *obj = (_XsMotifMenu*)clientData; if (obj->_curItem != NoItem) obj->_processItem (obj->_curItem); return (True); } /* ---------------------------------------------------------------------------- XsMotifWindow */ // Static definitions XtResource XsMotifWindow::_resourceList[] = { { "showBorder", "ShowBorder", XmRBoolean, sizeof (Boolean), XtOffset (XsMotifWindow*, _showBorder), XmRImmediate, (XtPointer)True }, { "showResize", "ShowResize", XmRBoolean, sizeof (Boolean), XtOffset (XsMotifWindow*, _showResize), XmRImmediate, (XtPointer)True }, { "showTitle", "ShowTitle", XmRBoolean, sizeof (Boolean), XtOffset (XsMotifWindow*, _showTitle), XmRImmediate, (XtPointer)True }, { "showMenu", "ShowMenu", XmRBoolean, sizeof (Boolean), XtOffset (XsMotifWindow*, _showMenu), XmRImmediate, (XtPointer)True }, { "showMinimize", "ShowMinimize", XmRBoolean, sizeof (Boolean), XtOffset (XsMotifWindow*, _showMinimize), XmRImmediate, (XtPointer)True }, { "showMaximize", "ShowMaximize", XmRBoolean, sizeof (Boolean), XtOffset (XsMotifWindow*, _showMaximize), XmRImmediate, (XtPointer)True }, { "lowerOnIconify", "LowerOnIconify", XmRBoolean, sizeof (Boolean), XtOffset (XsMotifWindow*, _lowerOnIconify), XmRImmediate, (XtPointer)False }, { XmNminWidth, XmCMinWidth, XmRDimension, sizeof (Dimension), XtOffset (XsMotifWindow*, _minW), XmRImmediate, (XtPointer)((BorderSize_ + ButtonSize_) * 3) }, { XmNmaxWidth, XmCMaxWidth, XmRDimension, sizeof (Dimension), XtOffset (XsMotifWindow*, _maxW), XmRImmediate, (XtPointer)-1 }, { XmNminHeight, XmCMinHeight, XmRDimension, sizeof (Dimension), XtOffset (XsMotifWindow*, _minH), XmRImmediate, (XtPointer)((BorderSize_ + ButtonSize_) * 3) }, { XmNmaxHeight, XmCMaxHeight, XmRDimension, sizeof (Dimension), XtOffset (XsMotifWindow*, _maxH), XmRImmediate, (XtPointer)-1 } }; // Constructor XsMotifWindow::XsMotifWindow (const char *name) : XsMDIWindow (name) { int loop; // Initialize for (loop = 0; loop < _XsMotifSide::Max; loop++) { _corners[loop] = 0; _sides[loop] = 0; } for (loop = 0; loop < _XsMotifButton::Max; loop++) _buttons[loop] = 0; _title = 0; _icon = 0; _menu = 0; _maximized = False; _minimized = False; } // Destructor XsMotifWindow::~XsMotifWindow ( ) { int loop; for (loop = 0; loop < _XsMotifSide::Max; loop++) { delete _corners[loop]; delete _sides[loop]; } for (loop = 0; loop < _XsMotifButton::Max; loop++) delete _buttons[loop]; delete _title; delete _icon; delete _menu; } // raise void XsMotifWindow::raise ( ) { Widget w = (_minimized == True) ? _icon->base ( ) : _base; assert (w != 0); XRaiseWindow (XtDisplay (w), XtWindow (w)); } // lower void XsMotifWindow::lower ( ) { Widget w = (_minimized == True) ? _icon->base ( ) : _base; assert (w != 0); XLowerWindow (XtDisplay (w), XtWindow (w)); } // minimize void XsMotifWindow::minimize ( ) { assert (_base != 0); // Check if we are already minimized if (_minimized == True) return; // Minimize the window hide ( ); _minimized = True; // Lower (if necessary) if (_lowerOnIconify) lower ( ); _icon->show ( ); } // maximize void XsMotifWindow::maximize ( ) { assert (_base != 0); // Check if we are already in this state if (_maximized == True) return; // Restore (if necessary) if (_minimized) restore ( ); // Save current dimensions XtVaGetValues (_base, XmNx, &_savedX, XmNy, &_savedY, XmNwidth, &_savedWidth, XmNheight, &_savedHeight, NULL); /* Constrain the new window size. The size of the maximized window is equal to the size of the current clip-window of the canvas. */ const Dimension offset = 5; // Border around max'd window Widget clipWindow = XtParent (XtParent (_base)); assert (clipWindow != 0); Dimension clipW, clipH; Window child; int newX, newY; XtVaGetValues (clipWindow, XmNheight, &clipH, XmNwidth, &clipW, NULL); // Add in offset if (clipW > (offset * 2)) clipW -= (offset * 2); if (clipH > (offset * 2)) clipH -= (offset * 2); // Compute the new window position (map clip-window to work-area) XTranslateCoordinates (XtDisplay (_base), XtWindow (clipWindow), XtWindow (XtParent (_base)), (int)offset, (int)offset, &newX, &newY, &child); // Set new maximum dimensions setPosition ((Position)newX, (Position)newY); setSize (clipW, clipH); _maximized = True; // Redraw the maximize button _buttons[_XsMotifButton::Maximize]->redraw ( ); } // restore void XsMotifWindow::restore ( ) { assert (_base != 0); // Check if we are already restored if ((_maximized == False) && (_minimized == False)) return; // Either un-minimize or un-maximize if (_minimized) { // Restore the window _icon->hide ( ); _minimized = False; // If maximized, restore again if (_maximized) restore ( ); // Show the window show ( ); } else { // Restore saved dimensions setPosition (_savedX, _savedY); setSize (_savedWidth, _savedHeight); } } // close void XsMotifWindow::close ( ) { /* Don't delete the window (because its not ours to delete). Just hide it. */ if (_minimized) _icon->hide ( ); else hide ( ); } // setTitle void XsMotifWindow::setTitle (const char *title) { if (_title != 0) _title->setTitle (title); } // setIconName void XsMotifWindow::setIconName (const char *iconName) { if (_icon != 0) _icon->setIconName (iconName); } // setPixmap void XsMotifWindow::setPixmap (Pixmap pixmap) { if (_icon != 0) _icon->setPixmap (pixmap); } // popupMenu void XsMotifWindow::popupMenu (Boolean b) { if (_menu != 0) _menu->popup (b); } // setPosition void XsMotifWindow::setPosition (Position x, Position y) { if (_base != 0) { Widget w = (_minimized == True) ? _icon->base ( ) : _base; assert (w != 0); XtVaSetValues (w, XmNx, x, XmNy, y, NULL); } else XsMDIWindow::setPosition (x, y); // Cache the points } // setSize void XsMotifWindow::setSize (Dimension w, Dimension h) { // Set the window size if (_base != 0) { if (w < _minW) w = _minW; else if ((_maxW != (Dimension)-1) && (w > _maxW)) w = _maxW; if (h < _minH) h = _minH; else if ((_maxH != (Dimension)-1) && (h > _maxH)) h = _maxH; if (_minimized == False) XtVaSetValues (_base, XmNwidth, w, XmNheight, h, NULL); // If window was maximized, change the window state back to normal if (_maximized == True) { _maximized = False; // Redraw the maximize button _buttons[_XsMotifButton::Maximize]->redraw ( ); } } else XsMDIWindow::setSize (w, h); // Cache the points } // className const char* XsMotifWindow::className ( ) const { return ("XsMotifWindow"); } // _createWindow void XsMotifWindow::_createWindow (Widget parent) { assert (parent != 0); // Create the window frame _base = XtVaCreateWidget (_name, xmFormWidgetClass, parent, XmNborderWidth, (Dimension)1, NULL); // Install destroy handler _installDestroyHandler ( ); // Get resources _getResources (_resourceList, XtNumber (_resourceList)); /* Fix configuration inter-dependencies. Here are the rules: 1) If there is no border, then there are no resize handles 2) If there is no title, then there are no buttons (would look stupid) */ if (_showBorder == False) _showResize = False; if (_showTitle == False) { _showMenu = False; _showMinimize = False; _showMaximize = False; } /* Corners */ if (_showResize) { // Top-Left _corners[_XsMotifCorner::TopLeft] = new _XsMotifCorner ("topLeft", this, _XsMotifCorner::TopLeft); XtVaSetValues (_corners[_XsMotifCorner::TopLeft]->base ( ), XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, NULL); // Top-Right _corners[_XsMotifCorner::TopRight] = new _XsMotifCorner ("topRight", this, _XsMotifCorner::TopRight); XtVaSetValues (_corners[_XsMotifCorner::TopRight]->base ( ), XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, NULL); // Bottom-Left _corners[_XsMotifCorner::BottomLeft] = new _XsMotifCorner ("bottomLeft", this, _XsMotifCorner::BottomLeft); XtVaSetValues (_corners[_XsMotifCorner::BottomLeft]->base ( ), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, NULL); // Bottom-Right _corners[_XsMotifCorner::BottomRight] = new _XsMotifCorner ("bottomRight", this, _XsMotifCorner::BottomRight); XtVaSetValues (_corners[_XsMotifCorner::BottomRight]->base ( ), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, NULL); } /* Sides */ if (_showBorder) { // Top _sides[_XsMotifSide::Top] = new _XsMotifSide ("top", this, _XsMotifSide::Top); XtVaSetValues (_sides[_XsMotifSide::Top]->base ( ), XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, NULL); if (_showResize) { XtVaSetValues (_sides[_XsMotifSide::Top]->base ( ), XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, _corners[_XsMotifCorner::TopLeft]->base ( ), XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, _corners[_XsMotifCorner::TopRight]->base ( ), NULL); } else { XtVaSetValues (_sides[_XsMotifSide::Top]->base ( ), XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); } // Bottom _sides[_XsMotifSide::Bottom] = new _XsMotifSide ("bottom", this, _XsMotifSide::Bottom); XtVaSetValues (_sides[_XsMotifSide::Bottom]->base ( ), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, NULL); if (_showResize) { XtVaSetValues (_sides[_XsMotifSide::Bottom]->base ( ), XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, _corners[_XsMotifCorner::BottomLeft]->base ( ), XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, _corners[_XsMotifCorner::BottomRight]->base ( ), NULL); } else { XtVaSetValues (_sides[_XsMotifSide::Bottom]->base ( ), XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); } // Left side _sides[_XsMotifSide::Left] = new _XsMotifSide ("left", this, _XsMotifSide::Left); XtVaSetValues (_sides[_XsMotifSide::Left]->base ( ), XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, NULL); if (_showResize) { XtVaSetValues (_sides[_XsMotifSide::Left]->base ( ), XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, _corners[_XsMotifCorner::TopLeft]->base ( ), XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, _corners[_XsMotifCorner::BottomLeft]->base ( ), NULL); } else { XtVaSetValues (_sides[_XsMotifSide::Left]->base ( ), XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); } // Right side _sides[_XsMotifSide::Right] = new _XsMotifSide ("right", this, _XsMotifSide::Right); XtVaSetValues (_sides[_XsMotifSide::Right]->base ( ), XmNleftAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, NULL); if (_showResize) { XtVaSetValues (_sides[_XsMotifSide::Right]->base ( ), XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, _corners[_XsMotifCorner::TopRight]->base ( ), XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, _corners[_XsMotifCorner::BottomRight]->base ( ), NULL); } else { XtVaSetValues (_sides[_XsMotifSide::Right]->base ( ), XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); } } // Menu button if (_showMenu) { _buttons[_XsMotifButton::Menu] = new _XsMotifButton ("menu", this, _XsMotifButton::Menu); XtVaSetValues (_buttons[_XsMotifButton::Menu]->base ( ), XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, NULL); if (_showBorder) { XtVaSetValues (_buttons[_XsMotifButton::Menu]->base ( ), XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, _sides[_XsMotifSide::Left]->base ( ), XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, _sides[_XsMotifSide::Top]->base ( ), NULL); } else { XtVaSetValues (_buttons[_XsMotifButton::Menu]->base ( ), XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); } } // Maximize button if (_showMaximize) { _buttons[_XsMotifButton::Maximize] = new _XsMotifButton ("maximize", this, _XsMotifButton::Maximize); XtVaSetValues (_buttons[_XsMotifButton::Maximize]->base ( ), XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_NONE, NULL); if (_showBorder) { XtVaSetValues (_buttons[_XsMotifButton::Maximize]->base ( ), XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, _sides[_XsMotifSide::Top]->base ( ), XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, _sides[_XsMotifSide::Right]->base ( ), NULL); } else { XtVaSetValues (_buttons[_XsMotifButton::Maximize]->base ( ), XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); } } // Minimize button if (_showMinimize) { _buttons[_XsMotifButton::Minimize] = new _XsMotifButton ("minimize", this, _XsMotifButton::Minimize); XtVaSetValues (_buttons[_XsMotifButton::Minimize]->base ( ), XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_NONE, NULL); if (_showBorder) { XtVaSetValues (_buttons[_XsMotifButton::Minimize]->base ( ), XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, _sides[_XsMotifSide::Top]->base ( ), XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, _sides[_XsMotifSide::Right]->base ( ), NULL); } else { XtVaSetValues (_buttons[_XsMotifButton::Minimize]->base ( ), XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); } if (_showMaximize) { XtVaSetValues (_buttons[_XsMotifButton::Minimize]->base ( ), XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, _buttons[_XsMotifButton::Maximize]->base ( ), NULL); } } /* Titlebar */ if (_showTitle) { _title = new _XsMotifTitle ("title", this); XtVaSetValues (_title->base ( ), XmNbottomAttachment, XmATTACH_NONE, NULL); if (_showBorder) { XtVaSetValues (_title->base ( ), XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, _sides[_XsMotifSide::Top]->base ( ), XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, _sides[_XsMotifSide::Left]->base ( ), XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, _sides[_XsMotifSide::Right]->base ( ), NULL); } else { XtVaSetValues (_title->base ( ), XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); } if (_showMenu) { XtVaSetValues (_title->base ( ), XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, _buttons[_XsMotifButton::Menu]->base ( ), NULL); } Widget ba = (_buttons[_XsMotifButton::Minimize] != 0) ? _buttons[_XsMotifButton::Minimize]->base ( ) : (_buttons[_XsMotifButton::Maximize] != 0) ? _buttons[_XsMotifButton::Maximize]->base ( ) : 0; if (ba) { XtVaSetValues (_title->base ( ), XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, ba, NULL); } } /* Icon */ _icon = new _XsMotifIcon ("icon", this, parent); /* Menu */ _menu = new _XsMotifMenu ("menu", this); /* Client Area */ _clientArea = XtVaCreateWidget ("clientArea", xmFormWidgetClass, _base, NULL); if (_showBorder) { XtVaSetValues (_clientArea, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, _sides[_XsMotifSide::Left]->base ( ), XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, _sides[_XsMotifSide::Right]->base ( ), XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, _sides[_XsMotifSide::Bottom]->base ( ), NULL); } else { XtVaSetValues (_clientArea, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); } Widget topW = (_showTitle) ? _title->base ( ) : (_showBorder) ? _sides[_XsMotifSide::Top]->base ( ) : 0; if (topW) { XtVaSetValues (_clientArea, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, topW, NULL); } else XtVaSetValues (_clientArea, XmNtopAttachment, XmATTACH_FORM, NULL); // Call the class function to create the contents of the window _buildClientArea (_clientArea); // Add an event handler to be called when this window is mapped XtAddEventHandler (_base, StructureNotifyMask, False, _mapEventHandler, (XtPointer)this); // Show everything int loop; for (loop = 0; loop < _XsMotifSide::Max; loop++) { if (_corners[loop] != 0) _corners[loop]->show ( ); if (_sides[loop] != 0) _sides[loop]->show ( ); } for (loop = 0; loop < _XsMotifButton::Max; loop++) { if (_buttons[loop] != 0) _buttons[loop]->show ( ); } if (_title != 0) _title->show ( ); } // _mapEvent void XsMotifWindow::_mapEvent ( ) { // Raise the client-area XRaiseWindow (XtDisplay (_clientArea), XtWindow (_clientArea)); } // _mapEventHandler void XsMotifWindow::_mapEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*) { if (event->type == MapNotify) { XsMotifWindow *obj = (XsMotifWindow*)clientData; obj->_mapEvent ( ); XtRemoveEventHandler (obj->_base, StructureNotifyMask, False, obj->_mapEventHandler, clientData); } }