64 #include <X11/cursorfont.h> 68 #include <X11/keysymdef.h> 72 #include "pixmap_helper.h" 74 #include "menu_popup.h" 78 static int MBMenuPopupEvent(Window wID, XEvent *pEvent);
80 #define HEIGHT_SPACING 4 81 #define SEPARATOR_HEIGHT 5 82 #define SEPARATOR_POS 2 84 #define WB_MOUSE_FAR 24 102 pSelf->iSelected = i1;
117 i1 = pSelf->iSelected;
119 if(i1 < 0 || i1 >= pMenu->
nItems)
131 pSelf->iSelected = i1;
146 i1 = pSelf->iSelected;
148 if(i1 < 0 || i1 >= pMenu->
nItems)
153 for(i1--; pMenu->
ppItems && i1 >= 0; i1--)
160 pSelf->iSelected = i1;
182 pSelf->iSelected = i1;
190 if(pSelf->iSelected >= 0 && pSelf->iSelected < pMenu->
nItems)
192 return pMenu->
ppItems[pSelf->iSelected];
200 int iX,
int iY,
int iFlags)
205 unsigned long fg, bg, bd;
206 XSetWindowAttributes xswa;
210 int i1, iHPos, iVPos, iHBorder, iSelected = -1;
233 if(!pDefaultMenuFont && !pFS)
238 else if(pDefaultMenuFont)
240 pFS = pDefaultMenuFont;
249 xsh.flags = (PPosition | PSize);
258 for(i1=0; pMenu && pMenu->
ppItems && i1 < pMenu->
nItems; i1++)
273 iVPos += SEPARATOR_HEIGHT;
277 if(iSelected < 0 || iSelected >= pMenu->
nItems)
285 if(strchr(szText,
'_'))
288 strncpy(tbuf, szText,
sizeof(tbuf)/2);
318 strncpy(tbuf, szText,
sizeof(tbuf)/2);
330 if(iHPos < 2 * iHBorder + pItem->iTextWidth)
335 xsh.height = iVPos + 2;
337 memset(&xswa, 0,
sizeof(xswa));
339 xswa.border_pixel = bd;
340 xswa.background_pixel = bg;
341 xswa.colormap = DefaultColormap(pDisplay, DefaultScreen(pDisplay));
342 xswa.bit_gravity = CenterGravity;
343 xswa.override_redirect = True;
349 WB_ERROR_PRINT(
"%s - not enough memory to allocate structure\n", __FUNCTION__);
353 pRval->ulTag = MENU_POPUP_WINDOW_TAG;
355 pRval->pMenu = pMenu;
359 WB_WARN_PRINT(
"%s - * BUG * pMenu is NULL!\n", __FUNCTION__);
374 pRval->wSelf =
WBCreateWindow(pDisplay, DefaultRootWindow(pDisplay), MBMenuPopupEvent,
"MenuPopup",
375 xsh.x, xsh.y, xsh.width, xsh.height, 0,
377 CWBorderPixel | CWBackPixel | CWColormap | CWBitGravity | CWOverrideRedirect,
379 if(pRval->wSelf == -1)
381 WB_WARN_PRINT(
"%s - WARNING: unable to create window for popup menu\n", __FUNCTION__);
387 pRval->wBar = wIDBar;
388 pRval->wOwner = wIDOwner;
389 pRval->iSelected = iSelected;
390 pRval->iFlags = iFlags;
395 pRval->iWidth = xsh.width - 4;
396 pRval->iHeight = xsh.height - 4;
402 bzero(&xwmh,
sizeof(xwmh));
403 xwmh.flags = InputHint;
414 XSelectInput(pDisplay, pRval->wSelf,
418 a1 = XInternAtom(pDisplay,
"_NET_WM_WINDOW_TYPE", False);
419 ul1 = XInternAtom(pDisplay,
"_NET_WM_WINDOW_TYPE_MENU", False);
420 XChangeProperty(pDisplay, pRval->wSelf, a1, XA_ATOM, 32, PropModeReplace, (
unsigned char *)&ul1, 1);
422 a1 = XInternAtom(pDisplay,
"_NET_WM_STATE", False);
423 ul1 = XInternAtom(pDisplay,
"_NET_WM_STATE_MODAL", False);
424 XChangeProperty(pDisplay, pRval->wSelf, a1, XA_ATOM, 32, PropModeReplace, (
unsigned char *)&ul1, 1);
426 a1 = XInternAtom(pDisplay,
"WM_TRANSIENT_FOR", False);
427 XChangeProperty(pDisplay, pRval->wSelf, a1, XA_WINDOW, 32, PropModeReplace, (
unsigned char *)&wIDOwner, 1);
433 "%s - mapping popup menu window\n", __FUNCTION__);
444 static int __FindMenuPopupWindowCallback(Window wID,
void *pData)
448 if(pMP && (
void *)(pMP->pMenu) == pData)
458 Window wID =
WBLocateWindow(__FindMenuPopupWindowCallback, (
void *)pMenu);
478 if(!pMenuPopupWindow || pMenuPopupWindow->ulTag != MENU_POPUP_WINDOW_TAG)
489 XClientMessageEvent evt;
493 bzero(&evt,
sizeof(evt));
494 evt.type = ClientMessage;
496 evt.display = pDisplay;
497 evt.window = pSelf->wOwner;
504 evt.data.l[0] = pItem->
iAction;
519 WB_DEBUG_PRINT(DebugLevel_Verbose,
"%s - \"%s\" returning %d\n", __FUNCTION__,
536 XClientMessageEvent evt;
540 bzero(&evt,
sizeof(evt));
541 evt.type = ClientMessage;
542 evt.display = pDisplay;
553 int iUIState = MBMenuPopupHandleMenuItemUI(pDisplay, pSelf, pMenu, pItem);
557 XClientMessageEvent evt;
559 bzero(&evt,
sizeof(evt));
560 evt.type = ClientMessage;
562 evt.display = pDisplay;
563 evt.window = pSelf->wOwner;
566 evt.data.l[0] = pItem->
iAction;
573 "%s - Post Event: %08xH %08xH %pH %08xH\n",
579 XBell(pDisplay, -100);
586 static int MenuPopupDoExposeEvent(XExposeEvent *pEvent,
WBMenu *pMenu,
587 Display *pDisplay, Window wID,
590 int i1, iHPos, iVPos, iHeight;
591 XWindowAttributes xwa;
592 WB_FONTC pFont, pTempFont, pDefaultMenuFont;
600 if (XGetWindowAttributes(pDisplay, wID, &xwa) == 0)
602 WB_WARN_PRINT(
"%s - * BUG * unable to get window attributes!\n", __FUNCTION__);
610 if(!pDefaultMenuFont && !pFont)
615 else if(pDefaultMenuFont)
617 pFont = pDefaultMenuFont;
624 WB_WARN_PRINT(
"%s - * BUG * no graphics context!\n", __FUNCTION__);
645 xpt[0].x=xwa.border_width;
646 xpt[0].y=xwa.height-1-2*xwa.border_width - 1;
647 xpt[1].x=xwa.border_width;
648 xpt[1].y=xwa.border_width;
649 xpt[2].x=xwa.width-1-2*xwa.border_width - 1;
650 xpt[2].y=xwa.border_width;
652 WBDrawLines(pDisplay, wID, gc, xpt, 3, CoordModeOrigin);
655 xpt[0].x=xwa.width-1-2*xwa.border_width;
656 xpt[0].y=xwa.border_width + 1;
657 xpt[1].x=xwa.width-1-2*xwa.border_width;
658 xpt[1].y=xwa.height-1-2*xwa.border_width;
659 xpt[2].x=xwa.border_width + 1;
660 xpt[2].y=xwa.height-1-2*xwa.border_width;
662 WBDrawLines(pDisplay, wID, gc, xpt, 3, CoordModeOrigin);
673 for(i1=0; pMenu && pMenu->
ppItems && i1 < pMenu->
nItems; i1++)
693 xpt[0].x=xwa.border_width + 1;
694 xpt[0].y=pItem->
iPosition + SEPARATOR_POS - 1;
695 xpt[1].x=xwa.width-1-2*xwa.border_width;
698 WBDrawLines(pDisplay, wID, gc, xpt, 2, CoordModeOrigin);
701 xpt[1].y=++(xpt[0].y);
702 WBDrawLines(pDisplay, wID, gc, xpt, 2, CoordModeOrigin);
704 iVPos += SEPARATOR_HEIGHT;
717 iUIState = MBMenuPopupHandleMenuItemUI(pDisplay, pSelf, pMenu, pItem);
723 if(i1 == pSelf->iSelected)
731 xwa.border_width + 2, pItem->
iPosition - 1,
732 xwa.width-4-2*xwa.border_width, iItemHeight - 1);
764 strcpy(tbuf, szText);
788 WB_ERROR_PRINT(
"%s - ERROR: cannot locate underscore\n", __FUNCTION__);
811 szText, strlen(szText));
820 int iLen = strlen(p2);
825 xwa.width + xwa.border_width - 2 - iWidth,
833 xpt[0].x=iHPos + iU1 - 1;
835 xpt[1].x=iHPos + iU1 + iU2;
839 "%s - drawing underscore at %d,%d to %d,%d\n",
840 __FUNCTION__, xpt[0].x, xpt[0].y, xpt[1].x, xpt[1].y);
842 WBDrawLines(pDisplay, wID, gc, xpt, 2, CoordModeOrigin);
845 if(i1 == pSelf->iSelected)
851 iVPos += iHeight + HEIGHT_SPACING;
885 if((i1 + 1) < pMenu->
nItems)
891 iMaxY = pSelf->iY + pSelf->iHeight;
894 if(pItem->
iPosition <= iY && iMaxY >= iY)
899 if(pSelf->iSelected == i1)
910 if(pSelf->iSelected >= 0 && pSelf->iSelected < pMenu->
nItems)
912 return pMenu->
ppItems[pSelf->iSelected];
922 if(pSelf->iSelected >= 0 && pSelf->iSelected < pMenu->
nItems)
930 geom.
width = pSelf->iWidth + 1;
937 pSelf->iSelected = i1;
942 geom.
width = pSelf->iWidth + 1;
957 XClientMessageEvent evt;
959 bzero(&evt,
sizeof(evt));
960 evt.type = ClientMessage;
962 evt.window = pSelf->wBar;
966 evt.data.l[1] = iPrevNext;
970 WB_DEBUG_PRINT(DebugLevel_Chatty | DebugSubSystem_Menu | DebugSubSystem_Keyboard,
971 "%s - posting Prev/Next %d to menu bar %d (%08xH)\n",
972 __FUNCTION__, iPrevNext, (
int)pSelf->wBar, (
int)pSelf->wBar);
976 static int MBMenuPopupEvent(Window wID, XEvent *pEvent)
981 WBMenu *pMenu = pSelf ? pSelf->pMenu : NULL;
994 if(pEvent->type == DestroyNotify)
996 if(pEvent->xdestroywindow.window == wID)
999 "%s - DestroyNotify\n", __FUNCTION__);
1011 if(pEvent->type == FocusOut)
1014 "%s - FocusOut\n", __FUNCTION__);
1022 if(pEvent->type == Expose)
1024 return MenuPopupDoExposeEvent((XExposeEvent *)pEvent, pMenu, pDisplay, wID, pSelf);
1029 if((pEvent->type == KeyPress ||
1030 pEvent->type == KeyRelease))
1035 WB_DEBUG_PRINT(DebugLevel_Heavy | DebugSubSystem_Menu | DebugSubSystem_Keyboard | DebugSubSystem_Event,
1036 "%s - key press/release %x (%d) iACS=%x\n", __FUNCTION__, iKey, iKey, iACS);
1038 if(pEvent->type == KeyPress)
1043 && (iKey >= XK_F1 && iKey <= XK_F35))
1049 memcpy(&kevt, &(pEvent->xkey),
sizeof(kevt));
1050 kevt.window = kevt.subwindow = pSelf->wOwner;
1055 XPutBackEvent(pDisplay, (XEvent *)&kevt);
1059 else if(iKey == XK_Left)
1064 __PostActivatePrevNextEvent(pSelf, -1);
1069 else if(iKey == XK_Right)
1074 __PostActivatePrevNextEvent(pSelf, 1);
1079 else if(iKey == XK_Up)
1081 i1 = pSelf->iSelected;
1083 __SetPrevSelection(pSelf, pMenu);
1085 if(i1 != pSelf->iSelected)
1091 else if(iKey == XK_Down)
1093 i1 = pSelf->iSelected;
1095 __SetNextSelection(pSelf, pMenu);
1097 if(i1 != pSelf->iSelected)
1103 else if(iKey == XK_Prior)
1105 i1 = pSelf->iSelected;
1107 __SetFirstSelection(pSelf, pMenu);
1109 if(i1 != pSelf->iSelected)
1115 else if(iKey == XK_Next)
1117 i1 = pSelf->iSelected;
1119 __SetLastSelection(pSelf, pMenu);
1121 if(i1 != pSelf->iSelected)
1128 else if(iKey ==
'\x1b' ||
1134 memcpy(&kevt, &(pEvent->xkey),
sizeof(kevt));
1135 kevt.window = kevt.subwindow = pSelf->wOwner;
1142 XPutBackEvent(pDisplay, (XEvent *)&kevt);
1153 else if(pEvent->type == KeyRelease)
1159 if(!iACS && (iKey ==
'\n' || iKey ==
'\r' || iKey ==
' '))
1161 pItem = __GetCurrentSelection(pSelf, pMenu);
1163 MBMenuPopupHandleMenuItem(pDisplay, wID, pSelf, pMenu, pItem);
1171 if((pEvent->type == ButtonPress ||
1172 pEvent->type == ButtonRelease ||
1173 pEvent->type == MotionNotify))
1179 if(pEvent->type == MotionNotify)
1181 WBXlatCoordPoint(pEvent->xmotion.window, pEvent->xmotion.x, pEvent->xmotion.y,
1183 if(pEvent->xmotion.state & Button1Mask)
1187 else if(!(pEvent->xmotion.state & (Button1Mask | Button2Mask | Button3Mask)))
1198 if(iX < pSelf->iX - WB_MOUSE_FAR || iX > pSelf->iX + pSelf->iWidth + 2 * WB_MOUSE_FAR)
1200 WB_DEBUG_PRINT(DebugLevel_Verbose | DebugSubSystem_Menu | DebugSubSystem_Mouse,
1201 "%s.%d hover outside of popup menu iX=%d menu: left=%d right=%d\n",
1202 __FUNCTION__, __LINE__, iX, pSelf->iX, pSelf->iX + pSelf->iWidth);
1207 #warning need to implement hover select adjacent top level menu 1214 iPrevSel = pSelf->iSelected;
1215 __SelectMenuItemFromMousePos(wID, pSelf, pMenu, iX, iY);
1217 if(iPrevSel != pSelf->iSelected)
1225 else if(pEvent->type == ButtonPress && pMenu)
1227 WBXlatCoordPoint(pEvent->xbutton.window, pEvent->xbutton.x, pEvent->xbutton.y,
1230 if(pEvent->xbutton.state & (Button2Mask | Button3Mask | Button4Mask | Button5Mask
1231 | ShiftMask | LockMask | ControlMask))
1235 else if(iY >= pSelf->iY && iY <= (pSelf->iY + pSelf->iHeight))
1240 if(__SelectMenuItemFromMousePos(wID, pSelf, pMenu, iX, iY))
1245 WB_WARN_PRINT(
"%s - couldn't find the menu - %d, %d\n", __FUNCTION__, iX, iY);
1249 WB_DEBUG_PRINT(DebugLevel_WARN | DebugSubSystem_Menu | DebugSubSystem_Mouse,
1250 "%s.%d - Mouse is out of range - %d, %d, %d, %d, %d, %d\n",
1251 __FUNCTION__, __LINE__, iX, iY, pSelf->iX, pSelf->iY, pSelf->iWidth, pSelf->iHeight);
1256 i1 = pSelf->iSelected;
1257 pSelf->iSelected = -1;
1259 if(i1 < 0 || i1 >= pMenu->
nItems)
1269 geom.
height = pSelf->iHeight;
1278 MBMenuPopupHandleMenuItem(pDisplay, wID, pSelf, pMenu, pItem);
1285 if(pEvent && pEvent->type == ClientMessage)
1290 int iMenuItemIndex = ((XClientMessageEvent *)pEvent)->data.l[1];
1293 if(iMenuItemIndex >= 0 && iMenuItemIndex < pMenu->nItems)
1295 pItem = pMenu->
ppItems[iMenuItemIndex];
1301 MBMenuPopupHandleMenuItem(pDisplay, wID, pSelf, pMenu, pItem);
1307 WB_WARN_PRINT(
"%s - MENU_ACTIVATE event, invalid menu information, %d %d %p %p\n",
1308 __FUNCTION__, iMenuItemIndex, pMenu->
nItems,
1315 int iMenuItem = ((XClientMessageEvent *)pEvent)->data.l[0];
1316 int iPosition = ((XClientMessageEvent *)pEvent)->data.l[1];
1318 for(i1=0; i1 < pMenu->
nPopups; i1++)
1321 "%s - popup menu id = %d\n",
1328 iPosition, pSelf->iY + pSelf->iHeight, 0);
1333 "%s - Displaying popup menu %d\n", __FUNCTION__, iMenuItem);
1338 "%s - done with popup menu %d, return value %d\n", __FUNCTION__, iMenuItem, iRval);
1342 WB_ERROR_PRINT(
"%s - Unable to create popup menu %d\n", __FUNCTION__, iMenuItem);
1351 WB_ERROR_PRINT(
"%s - Unable to locate popup menu %d\n", __FUNCTION__, iMenuItem);
void WBSetWMProperties(Window wID, const char *szTitle, XSizeHints *pNormalHints, XWMHints *pWMHints, XClassHint *pClassHints)
assign standard WM (Window Manager) properties via XSetWMProperties
'window helper' main header file for the X11workbench Toolkit API
void WBClearWindow(Window wID, WBGC gc)
'Paint' helper, erases background by painting the background color within the clipping region
#define WB_DEBUG_PRINT(L,...)
Preferred method of implementing conditional debug output.
int WBFontHeight(WB_FONTC pFont0)
Get the maximum character height from a WB_FONT.
int WBFontAscent(WB_FONTC pFont0)
Get the maximum character ascent from a WB_FONT.
int WBKeyEventProcessKey(const XKeyEvent *pEvent, char *pBuf, int *pcbLen, int *piAltCtrlShift)
Generic keyboard event translation utility.
void WBCreateWindowDefaultGC(Window wID, unsigned long clrFG, unsigned long clrBG)
creates a default WBGC for a window
#define WB_KEYEVENT_ALT
'AltCtrlShift' bit flag for ALT modifier for WBKeyEventProcessKey()
WB_FONT WBCopyFont(Display *pDisplay, WB_FONTC pOldFont)
make a copy of an existing font (best when assigning to a window)
int WBShowModal(Window wID, int bMenuSplashFlag)
Shows a 'modal' window by processing events until the window closes.
Window WBLocateWindow(WBLocateWindowCallback callback, void *pData)
Locate a window by enumerating with a callback function.
int WBWindowDispatch(Window wID, XEvent *pEvent)
Dispatches a window XEvent. May be called directly.
int WBPostPriorityEvent(Window wID, XEvent *pEvent)
Places a copy of the specified event at the end of the priority (internal) event queue.
internal wrapper struct for X11 'geometry' definition
'configuration helper' main header file for the X11 Work Bench Toolkit API
int WBSetFont(WBGC hGC, WB_FONTC pFont)
Assign font to a WBGC, a wrapper for XSetFont()
int WBDrawString(Display *display, Drawable d, WBGC gc, int x, int y, const char *string, int length)
wrapper for XDrawString()
int WBSetForeground(WBGC hGC, unsigned long foreground)
Assign foreground color, a wrapper for XSetForeground()
WB_FONTC WBQueryWindowFont(Window wID)
Returns the WB_FONT assigned to the window (may be NULL), not a copy.
void WBInvalidateGeom(Window wID, const WB_GEOM *pGeom, int bPaintNow)
'Paint' helper, invalidates a geometry for asynchronous Expose event generation
int WBDrawLines(Display *display, Drawable d, WBGC gc, XPoint *points, int npoints, int mode)
Wrapper for XDrawLine()
unsigned long WBGetWindowFGColor(Window wID)
Returns the currently assigned foreground color.
void WBGetWindowGeom2(Window wID, WB_GEOM *pGeom)
Returns the geometry of the window relative to the root window.
void * WBAlloc(int nSize)
High performance memory sub-allocator 'allocate'.
Window WBGetParentWindow(Window wID)
Returns the window's parent (or None if there is no parent)
int WBSetFontNoCopy(WBGC hGC, WB_FONT pFont)
Assign font to a WBGC, a wrapper for XSetFont()
#define WB_ERROR_PRINT(...)
Preferred method of implementing an 'error level' debug message for all subsystems.
void WBFree(void *pBuf)
High performance memory sub-allocator 'free'.
int WBPostEvent(Window wID, XEvent *pEvent)
Places a copy of the specified event at the end of the regular (internal) event queue.
void WBDestroyWindow(Window wID)
Destroy a window.
void WBSetWindowFont(Window wID, WB_FONTC pFont)
assigns the default WB_FONT object for a window
#define WB_MOUSE_INPUT_MASK
'Mouse' input mask, bit flag for window creation
void WBXlatCoordPoint(Window wIDSrc, int iXSrc, int iYSrc, Window wIDDest, int *piXDest, int *piYDest)
Translate X,Y point coordinates relative to a window.
Window WBCreateWindow(Display *pDisplay, Window wIDParent, WBWinEvent pProc, const char *szClass, int iX, int iY, int iWidth, int iHeight, int iBorder, int iIO, WB_UINT64 iFlags, XSetWindowAttributes *pXSWA)
Create a window.
#define WB_STANDARD_INPUT_MASK
'Standard' input mask, bit flag for window creation
WBGC WBBeginPaint(Window wID, XExposeEvent *pEvent, WB_GEOM *pgBounds)
'Paint' helper, creates a WBGC for use in updating the window in an Expose event handler
void WBSetWindowDefaultCursor(Window wID, int idStandardCursor)
Assigns a default cursor (by ID) to a window.
int WBTextWidth(WB_FONTC pFont, const char *szText, int cbText)
Obtain the pixel width of specified text for a specified WB_FONT.
Display * WBGetWindowDisplay(Window wID)
returns the Display associated with a window
void WBSetWindowData(Window wID, int iIndex, void *pData)
assign 'data pointer' for a window and specified index value
void WBSetInputFocus(Window wID)
set input focus to a specific window
int WBFillRectangle(Display *display, Drawable d, WBGC gc, int x, int y, unsigned int width, unsigned int height)
Wrapper for XFillRectangle()
int WBSetBackground(WBGC hGC, unsigned long background)
Assign background color, a wrapper for XSetBackground()
#define WB_KEYEVENT_CTRL
'AltCtrlShift' bit flag for Control modifier for WBKeyEventProcessKey()
An allocated structure containing XFontStruct, XFontInfo, and XftFont [as applicable] for a specified...
void WBEndModal(Window wID, int iRval)
End a modal window with a specific return value.
#define WB_KEYBOARD_INPUT_MASK
'Keyboard' input mask, bit flag for window creation
void WBEndPaint(Window wID, WBGC gc)
'Paint' helper, frees resources and marks the update region 'valid'
internal wrapper struct for GC with local cache
int WBMapWindow(Display *pDisplay, Window wID)
Wrapper for XMapWindow, makes window visible.
Frame Window API functions and definitions.
#define WB_WARN_PRINT(...)
Preferred method of implementing a 'warning level' debug message for all subsystems.
WB_FONTC WBQueryGCFont(WBGC gc)
return the WB_FONTC object that was assigned to a WBGC
#define WB_KEYEVENT_KEYSYM
'AltCtrlShift' bit flag for 'VK_' keys for WBKeyEventProcessKey()