📄 xsmotifwindow.c
字号:
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -