MenuButton.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $TOG: MenuButton.c /main/9 1998/04/09 17:51:40 mgreess $
  24. *
  25. * (c) Copyright 1996 Digital Equipment Corporation.
  26. * (c) Copyright 1996 Hewlett-Packard Company.
  27. * (c) Copyright 1996 International Business Machines Corp.
  28. * (c) Copyright 1986, 1991, 1996 Sun Microsystems, Inc.
  29. * (c) Copyright 1996 Novell, Inc.
  30. * (c) Copyright 1996 FUJITSU LIMITED.
  31. * (c) Copyright 1996 Hitachi.
  32. */
  33. /*
  34. * Copyright (C) 1986,1991 Sun Microsystems, Inc
  35. * All rights reserved.
  36. * Notice of copyright on this source code
  37. * product does not indicate publication.
  38. *
  39. * RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by
  40. * the U.S. Government is subject to restrictions as set forth
  41. * in subparagraph (c)(1)(ii) of the Rights in Technical Data
  42. * and Computer Software Clause at DFARS 252.227-7013 (Oct. 1988)
  43. * and FAR 52.227-19 (c) (June 1987).
  44. *
  45. * Sun Microsystems, Inc., 2550 Garcia Avenue,
  46. * Mountain View, California 94043.
  47. *
  48. */
  49. /*
  50. * The DtMenuButton widget is rigged with the Motif widget binary compatibilit
  51. * mechanism. All Motif-specific changes for this mechanism are preceded
  52. * by a comment including the string "MotifBc".
  53. *
  54. * For a description of the Motif widget binary compatibility mechanism
  55. * see the reference manual entry on XmResolveAllPartOffsets().
  56. *
  57. */
  58. #include <Dt/DtMsgsP.h>
  59. #include "MenuButtonP.h"
  60. #include <Xm/LabelP.h>
  61. #include <Xm/MenuUtilP.h>
  62. #include <Xm/DrawP.h>
  63. #include <Xm/XmP.h>
  64. #include <Xm/XmPrivate.h> /* _XmRecordEvent, _XmSetInDragMode, ... */
  65. #include <X11/keysymdef.h>
  66. #include "DtWidgetI.h"
  67. /*
  68. * MotifBc
  69. */
  70. #define DtMenuButtonIndex (XmLabelIndex + 1)
  71. static XmOffsetPtr ipot; /* Instance part offset table */
  72. static XmOffsetPtr cpot; /* Constraint part offset table */
  73. #ifndef Max
  74. #define Max(x, y) (((x) > (y)) ? (x) : (y))
  75. #endif
  76. #define GLYPH_PIX_SPACE 4 /* pixels between label and bit map */
  77. /*
  78. * MotifBc
  79. */
  80. #define CascadingCallback(w) XmField(w,ipot,DtMenuButton,cascading_callback,XtCallbackList)
  81. #define MenuRect(w) XmField(w,ipot,DtMenuButton,menu_rect,XRectangle)
  82. #define LNormalGC(w) XmField(w,ipot,XmLabel,normal_GC,GC)
  83. #define LAlignment(w) XmField(w,ipot,XmLabel,alignment,unsigned char)
  84. #define LRecomputeSize(w) XmField(w,ipot,XmLabel,recompute_size,Boolean)
  85. #define LLabelType(w) XmField(w,ipot,XmLabel,label_type,unsigned char)
  86. /* Access macro definitions */
  87. #define MB_PVT_SMENU(mb) XmField(mb,ipot,DtMenuButton,private_submenu,Boolean)
  88. #define MB_LAST_TIMESTAMP(mb) XmField(mb,ipot,DtMenuButton,last_timestamp,Time)
  89. #define MB_SMENU(mb) XmField(mb,ipot,DtMenuButton,submenu,Widget)
  90. #define MB_PIXMAP(mb) XmField(mb,ipot,DtMenuButton,menu_pixmap,Pixmap)
  91. #define MB_GLYPH_X(mb) (XmField(mb,ipot,DtMenuButton,menu_rect,XRectangle)).x
  92. #define MB_GLYPH_Y(mb) (XmField(mb,ipot,DtMenuButton,menu_rect,XRectangle)).y
  93. #define MB_GLYPH_WIDTH(mb) (XmField(mb,ipot,DtMenuButton,menu_rect,XRectangle)).width
  94. #define MB_GLYPH_HEIGHT(mb) (XmField(mb,ipot,DtMenuButton,menu_rect,XRectangle)).height
  95. #define MB_ARMED(mb) XmField(mb,ipot,DtMenuButton,armed,Boolean)
  96. #define MB_POPPED_UP(mb) XmField(mb,ipot,DtMenuButton,popped_up,Boolean)
  97. #define MB_GC(mb) XmField(mb,ipot,DtMenuButton,gc,GC)
  98. /******** Static Function Declarations ********/
  99. static void ClassInitialize (void);
  100. static void AdjustMenuButtonSize(
  101. DtMenuButtonWidget menubtn,
  102. Boolean adjustWidth,
  103. Boolean adjustHeight) ;
  104. static void Arm(
  105. DtMenuButtonWidget mb) ;
  106. static void ArmAndActivate(
  107. Widget wid,
  108. XEvent *event,
  109. String *params,
  110. Cardinal *num_params) ;
  111. static void CalculateMenuGlyphSize(
  112. DtMenuButtonWidget menubtn) ;
  113. static void CallCascadingCallbacks(
  114. Widget w,
  115. XEvent *event) ;
  116. static void Destroy(
  117. Widget wid) ;
  118. static void Disarm(
  119. DtMenuButtonWidget mb,
  120. Boolean pop_down) ;
  121. static void DrawArrow(
  122. Widget wid);
  123. static void Draw3DShadows(
  124. DtMenuButtonWidget mb) ;
  125. static void DrawMenuGlyph(
  126. DtMenuButtonWidget mb) ;
  127. static void GetGC(
  128. DtMenuButtonWidget mb);
  129. static void Initialize(
  130. Widget w_req,
  131. Widget w_new,
  132. ArgList args,
  133. Cardinal *num_args) ;
  134. static void LocateMenuGlyph(
  135. DtMenuButtonWidget menubtn) ;
  136. static void MenuButtonHandler(
  137. Widget wid,
  138. XtPointer cd,
  139. XEvent *event,
  140. Boolean *cont_to_dispatch) ;
  141. static void Popup(
  142. DtMenuButtonWidget mb,
  143. XEvent *event,
  144. Boolean call_cbacks );
  145. static void Redisplay(
  146. Widget mb,
  147. XEvent *event,
  148. Region region) ;
  149. static void Resize(
  150. Widget mb) ;
  151. static void Select(
  152. Widget wid,
  153. XEvent *event,
  154. String *param,
  155. Cardinal *num_param) ;
  156. static Boolean SetValues(
  157. Widget cw,
  158. Widget rw,
  159. Widget nw,
  160. ArgList args,
  161. Cardinal *num_args) ;
  162. static void GetTopManager(
  163. Widget w,
  164. Widget *topManager) ;
  165. /******** End Static Function Declarations ********/
  166. /*
  167. * event translation tables for menubutton.
  168. */
  169. static char menuButton_translations[] = "\
  170. <Key>space:Select()\n\
  171. <Key>osfSelect:Select()";
  172. static XtActionsRec menuButton_actions [] = {
  173. {"Select", Select}
  174. };
  175. /* MotifBc */
  176. #define DtOffset(field) XmPartOffset(DtMenuButton,field)
  177. #define XmPrimOffset(field) XmPartOffset(XmPrimitive,field)
  178. #define XmLabelOffset(field) XmPartOffset(XmLabel,field)
  179. static XmPartResource resources[] = {
  180. {
  181. DtNcascadingCallback,
  182. DtCCallback,
  183. XmRCallback,
  184. sizeof (XtCallbackList),
  185. DtOffset(cascading_callback),
  186. XmRCallback,
  187. NULL
  188. },
  189. {
  190. DtNsubMenuId,
  191. DtCMenuWidget, /* submenu */
  192. XmRMenuWidget,
  193. sizeof (Widget),
  194. DtOffset(submenu),
  195. XmRMenuWidget,
  196. (XtPointer) NULL
  197. },
  198. {
  199. DtNcascadePixmap,
  200. DtCPixmap,
  201. XmRPrimForegroundPixmap,
  202. sizeof(Pixmap),
  203. DtOffset(menu_pixmap),
  204. XmRImmediate,
  205. (XtPointer) XmUNSPECIFIED_PIXMAP
  206. },
  207. {
  208. XmNshadowThickness,
  209. XmCShadowThickness,
  210. XmRHorizontalDimension,
  211. sizeof (Dimension),
  212. XmPrimOffset(shadow_thickness),
  213. XmRImmediate,
  214. (XtPointer) 2
  215. },
  216. {
  217. XmNtraversalOn,
  218. XmCTraversalOn,
  219. XmRBoolean,
  220. sizeof(Boolean),
  221. XmPrimOffset(traversal_on),
  222. XmRImmediate,
  223. (XtPointer) TRUE
  224. },
  225. {
  226. XmNhighlightThickness,
  227. XmCHighlightThickness,
  228. XmRHorizontalDimension,
  229. sizeof (Dimension),
  230. XmPrimOffset(highlight_thickness),
  231. XmRImmediate,
  232. (XtPointer) 2
  233. },
  234. {
  235. XmNmarginWidth,
  236. XmCMarginWidth,
  237. XmRHorizontalDimension,
  238. sizeof (Dimension),
  239. XmLabelOffset(margin_width),
  240. XmRImmediate,
  241. (XtPointer)6
  242. },
  243. };
  244. externaldef(xmmenubuttonclassrec)
  245. DtMenuButtonClassRec dtMenuButtonClassRec = {
  246. { /* core class record */
  247. (WidgetClass) &xmLabelClassRec, /* superclass ptr */
  248. "DtMenuButton", /* class_name */
  249. sizeof(DtMenuButtonPart), /* size of Pulldown widget */
  250. (XtProc)ClassInitialize, /* class init proc */
  251. NULL, /* chained class init */
  252. FALSE, /* class is not init'ed */
  253. Initialize, /* widget init proc */
  254. NULL, /* init_hook proc */
  255. XtInheritRealize, /* widget realize proc */
  256. menuButton_actions, /* class action table */
  257. XtNumber (menuButton_actions), /* num of actions */
  258. (XtResourceList)resources, /* this class's resource list*/
  259. XtNumber (resources), /* resource_count */
  260. NULLQUARK, /* xrm_class */
  261. TRUE, /* compress motion */
  262. XtExposeCompressMaximal, /* compress exposure */
  263. TRUE, /* compress enter-leave */
  264. FALSE, /* no VisibilityNotify */
  265. Destroy, /* class destroy proc */
  266. Resize, /* class resize proc */
  267. Redisplay, /* expose proc */
  268. SetValues, /* set_value proc */
  269. NULL, /* set_value_hook proc */
  270. XtInheritSetValuesAlmost, /* set_value_almost proc */
  271. NULL, /* get_values_hook */
  272. NULL, /* class accept focus proc */
  273. XtVersionDontCheck, /* current version */
  274. NULL, /* callback offset list */
  275. menuButton_translations, /* default translation table */
  276. XtInheritQueryGeometry, /* query geo proc */
  277. NULL, /* display accelerator*/
  278. (XtPointer)NULL, /* extension */
  279. },
  280. {
  281. /* Primitive Class record */
  282. XmInheritWidgetProc, /* border_highlight */
  283. XmInheritWidgetProc, /* border_uhighlight */
  284. XtInheritTranslations, /* translations */
  285. ArmAndActivate, /* arm & activate */
  286. NULL, /* get resources */
  287. 0, /* num get_resources */
  288. (XtPointer)NULL, /* extension */
  289. },
  290. { /* Label Class record */
  291. XmInheritWidgetProc, /* set override callback */
  292. XmInheritMenuProc, /* menu procedures */
  293. XtInheritTranslations, /* menu traversal xlation */
  294. NULL, /* extension */
  295. },
  296. { /* menu_button class record */
  297. NULL, /* extension */
  298. }
  299. };
  300. /*
  301. * Now make a public symbol that points to this class record.
  302. */
  303. externaldef(dtmenubuttonwidgetclass)
  304. WidgetClass dtMenuButtonWidgetClass =
  305. (WidgetClass) &dtMenuButtonClassRec;
  306. /*
  307. * MotifBc, to calculate offset var. ipot
  308. */
  309. static void
  310. ClassInitialize(void)
  311. {
  312. XmResolveAllPartOffsets(dtMenuButtonWidgetClass, &ipot, &cpot);
  313. }
  314. static void
  315. Draw3DShadows(
  316. DtMenuButtonWidget mb )
  317. {
  318. if (XtIsRealized((Widget)mb))
  319. XmeDrawShadows (XtDisplay (mb), XtWindow (mb),
  320. mb->primitive.top_shadow_GC,
  321. mb->primitive.bottom_shadow_GC,
  322. mb->primitive.highlight_thickness,
  323. mb->primitive.highlight_thickness,
  324. mb->core.width - 2 *
  325. mb->primitive.highlight_thickness,
  326. mb->core.height - 2 *
  327. mb->primitive.highlight_thickness,
  328. mb->primitive.shadow_thickness,
  329. (MB_ARMED(mb) == TRUE) ? XmSHADOW_IN: XmSHADOW_OUT);
  330. }
  331. static void
  332. DrawMenuGlyph(
  333. DtMenuButtonWidget mb )
  334. {
  335. if ((MB_GLYPH_WIDTH(mb) != 0)){
  336. if(MB_PIXMAP(mb) != XmUNSPECIFIED_PIXMAP)
  337. XCopyArea (XtDisplay(mb),
  338. MB_PIXMAP(mb),
  339. XtWindow(mb),
  340. LNormalGC(mb), 0, 0,
  341. MB_GLYPH_WIDTH(mb), MB_GLYPH_HEIGHT(mb),
  342. MB_GLYPH_X(mb), MB_GLYPH_Y(mb));
  343. else
  344. DrawArrow((Widget)mb);
  345. }
  346. }
  347. /*
  348. * Redisplay the widget.
  349. */
  350. static void
  351. Redisplay(
  352. Widget mb,
  353. XEvent *event,
  354. Region region )
  355. {
  356. if (XtIsRealized (mb)) {
  357. /* Label expose method does the initial work */
  358. XtExposeProc expose;
  359. _DtProcessLock();
  360. expose = xmLabelClassRec.core_class.expose;
  361. _DtProcessUnlock();
  362. (* expose)(mb, event, region) ;
  363. DrawMenuGlyph((DtMenuButtonWidget) mb);
  364. Draw3DShadows ((DtMenuButtonWidget) mb);
  365. }
  366. }
  367. static void
  368. Arm(
  369. DtMenuButtonWidget mb )
  370. {
  371. XmProcessTraversal( (Widget) mb, XmTRAVERSE_CURRENT);
  372. if (MB_ARMED(mb) == FALSE) {
  373. MB_ARMED(mb) = TRUE;
  374. DrawMenuGlyph(mb);
  375. Draw3DShadows (mb);
  376. }
  377. }
  378. static void
  379. ArmAndActivate(
  380. Widget wid,
  381. XEvent *event,
  382. String *params,
  383. Cardinal *num_params )
  384. {
  385. DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ;
  386. if(MB_SMENU(mb) == (Widget)NULL ||
  387. event == (XEvent*) NULL)
  388. return;
  389. if (!_XmIsEventUnique(event))
  390. return;
  391. Popup(mb, event, TRUE);
  392. _XmSetInDragMode((Widget)mb,FALSE);
  393. if (!XmProcessTraversal(MB_SMENU(mb), XmTRAVERSE_CURRENT))
  394. XtSetKeyboardFocus(XtParent(MB_SMENU(mb)), MB_SMENU(mb));
  395. _XmRecordEvent(event);
  396. }
  397. static void
  398. Disarm(
  399. DtMenuButtonWidget mb,
  400. Boolean pop_down )
  401. {
  402. if (MB_ARMED(mb) == TRUE) {
  403. MB_ARMED(mb) = FALSE;
  404. if (pop_down == TRUE &&
  405. MB_SMENU(mb) != (Widget)NULL)
  406. XtUnmanageChild(MB_SMENU(mb));
  407. Draw3DShadows(mb);
  408. DrawMenuGlyph(mb);
  409. }
  410. }
  411. /*ARGSUSED*/
  412. static void
  413. Select(
  414. Widget wid,
  415. XEvent *event,
  416. String *param,
  417. Cardinal *num_param )
  418. {
  419. DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ;
  420. XtActionProc arm_and_activate;
  421. if(MB_POPPED_UP(mb) == TRUE) {
  422. Disarm(mb,TRUE);
  423. return;
  424. }
  425. _DtProcessLock();
  426. arm_and_activate = ((DtMenuButtonClassRec *)(mb->core.widget_class))->
  427. primitive_class.arm_and_activate;
  428. _DtProcessUnlock();
  429. (* arm_and_activate) ((Widget) mb, event, NULL, NULL);
  430. }
  431. static void
  432. PreMenuButtonHandler(
  433. Widget wid,
  434. XtPointer cd,
  435. XEvent *event,
  436. Boolean *cont_to_dispatch)
  437. {
  438. DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ;
  439. if(MB_SMENU(mb) == (Widget)NULL ||
  440. event->xany.type != ButtonPress ||
  441. event->xbutton.time <= MB_LAST_TIMESTAMP(mb))
  442. return;
  443. if(event->xbutton.button==Button1||event->xbutton.button==Button3)
  444. {
  445. String btnstr=NULL;
  446. XtVaGetValues(MB_SMENU(mb), XmNmenuPost, &btnstr, NULL);
  447. if (btnstr==NULL || !strcmp(btnstr,"") ||
  448. !strcmp(btnstr, "<Btn3Down>"))
  449. event->xbutton.button=Button3;
  450. else if (!strcmp(btnstr, "<Btn1Down>"))
  451. event->xbutton.button=Button1;
  452. else
  453. XtWarning(MB_POST);
  454. }
  455. }
  456. static void
  457. MenuButtonHandler(
  458. Widget wid,
  459. XtPointer cd,
  460. XEvent *event,
  461. Boolean *cont_to_dispatch)
  462. {
  463. DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ;
  464. if(MB_SMENU(mb) == (Widget)NULL ||
  465. event->xany.type != ButtonPress ||
  466. event->xbutton.time <= MB_LAST_TIMESTAMP(mb))
  467. return;
  468. else
  469. MB_LAST_TIMESTAMP(mb) = event->xbutton.time;
  470. Popup (mb, event, TRUE);
  471. }
  472. static void
  473. CallCascadingCallbacks(
  474. Widget w,
  475. XEvent *event )
  476. {
  477. DtMenuButtonWidget mb = (DtMenuButtonWidget)w;
  478. XmAnyCallbackStruct cback;
  479. if(MB_POPPED_UP(mb) == TRUE)
  480. return;
  481. cback.reason = DtCR_CASCADING;
  482. cback.event = event;
  483. XtCallCallbackList ((Widget) mb,
  484. CascadingCallback(mb), &cback);
  485. }
  486. static void
  487. PopdownCallback(Widget w, XtPointer client_data, XtPointer call_data)
  488. {
  489. DtMenuButtonWidget mb = (DtMenuButtonWidget)client_data;
  490. Disarm(mb,FALSE);
  491. MB_POPPED_UP(mb) = FALSE;
  492. MB_LAST_TIMESTAMP(mb) = XtLastTimestampProcessed(XtDisplay(mb));
  493. }
  494. static void
  495. PopupCallback(Widget w, XtPointer client_data, XtPointer call_data)
  496. {
  497. DtMenuButtonWidget mb = (DtMenuButtonWidget)client_data;
  498. Arm(mb);
  499. MB_POPPED_UP(mb) = TRUE;
  500. }
  501. /*
  502. * Call the cascading callbacks and popup any submenu.
  503. */
  504. static void
  505. Popup(
  506. DtMenuButtonWidget mb,
  507. XEvent *event,
  508. Boolean call_cbacks )
  509. {
  510. Position x=0, y=0;
  511. Position root_x=0, root_y=0;
  512. Position save_x = 0, save_y = 0;
  513. Dimension sw=0, sh=0;
  514. int dx = 0, dy = 0;
  515. Screen *screen;
  516. if((MB_SMENU(mb) == (Widget)NULL) ||
  517. (MB_POPPED_UP(mb) == TRUE))
  518. return;
  519. if (call_cbacks)
  520. CallCascadingCallbacks((Widget)mb, event);
  521. x = (Position)((int)XtWidth((Widget)mb) - (int)XtWidth(MB_SMENU(mb)))/2;
  522. y = XtHeight((Widget)mb) - mb->primitive.highlight_thickness + 1;
  523. XtTranslateCoords((Widget)mb, x,y, &root_x, &root_y);
  524. /* Check if not completely on the screen */
  525. screen = XtScreen(mb);
  526. sw = WidthOfScreen(screen);
  527. sh = HeightOfScreen(screen);
  528. if((dx = root_x - sw + XtWidth(MB_SMENU(mb))) > 0)
  529. root_x -= dx;
  530. if((dy = root_y - sh + XtHeight(MB_SMENU(mb))) > 0) {
  531. root_y -= (2 - (mb->primitive.highlight_thickness<<1));
  532. root_y -= (XtHeight(mb) + XtHeight(MB_SMENU(mb)));
  533. }
  534. save_x = event->xbutton.x_root;
  535. save_y = event->xbutton.y_root;
  536. event->xbutton.x_root = root_x;
  537. event->xbutton.y_root = root_y;
  538. /* Position the menu */
  539. XmMenuPosition(MB_SMENU(mb),(XButtonPressedEvent*)event);
  540. event->xbutton.x_root = save_x;
  541. event->xbutton.y_root = save_y;
  542. XtManageChild(MB_SMENU(mb));
  543. }
  544. /*
  545. * Get the menu glyph size set up.
  546. */
  547. static void
  548. CalculateMenuGlyphSize(
  549. DtMenuButtonWidget menubtn )
  550. {
  551. Window rootwin;
  552. int x,y; /* must be int */
  553. unsigned int width, height, border, depth; /* must be int */
  554. if (MB_PIXMAP(menubtn) != XmUNSPECIFIED_PIXMAP) {
  555. XGetGeometry(XtDisplay(menubtn), MB_PIXMAP(menubtn),
  556. &rootwin, &x, &y, &width, &height,
  557. &border, &depth);
  558. MB_GLYPH_WIDTH(menubtn) = (Dimension) width;
  559. MB_GLYPH_HEIGHT(menubtn) = (Dimension) height;
  560. } else {
  561. int ht, st;
  562. Dimension side;
  563. unsigned int text_height;
  564. ht = menubtn->primitive.highlight_thickness;
  565. st = menubtn->primitive.shadow_thickness;
  566. text_height = Lab_TextRect_height(menubtn);
  567. side = Max( (text_height * 2 / 3) + 2 * (ht + st),
  568. (2*(ht + (st-1) +1)) +1 );
  569. MB_GLYPH_WIDTH(menubtn) =
  570. MB_GLYPH_HEIGHT(menubtn) = side;
  571. }
  572. }
  573. /*
  574. * Set up the menu glyph location.
  575. */
  576. static void
  577. LocateMenuGlyph(
  578. DtMenuButtonWidget menubtn )
  579. {
  580. Dimension buffer;
  581. MB_GLYPH_X(menubtn) =
  582. XtWidth (menubtn) -
  583. menubtn->primitive.highlight_thickness -
  584. menubtn->primitive.shadow_thickness -
  585. Lab_MarginWidth(menubtn) -
  586. MB_GLYPH_WIDTH(menubtn);
  587. buffer = menubtn->primitive.highlight_thickness +
  588. menubtn->primitive.shadow_thickness +
  589. Lab_MarginHeight(menubtn);
  590. MB_GLYPH_Y(menubtn) = (Position)((int)buffer +
  591. (((int)XtHeight(menubtn) - 2*(int)buffer) -
  592. (int)MB_GLYPH_HEIGHT(menubtn)) / 2);
  593. }
  594. /*
  595. * Make room for menu glyph in menu button.
  596. */
  597. static void
  598. AdjustMenuButtonSize(
  599. DtMenuButtonWidget menubtn,
  600. Boolean adjustWidth,
  601. Boolean adjustHeight )
  602. {
  603. Dimension delta;
  604. /*
  605. * Modify the size of the menubutton to acommadate the menu.
  606. * The menu should fit inside MarginRight.
  607. */
  608. if ((int)(MB_GLYPH_WIDTH(menubtn) + GLYPH_PIX_SPACE) >
  609. (int)Lab_MarginRight(menubtn)) {
  610. delta = MB_GLYPH_WIDTH(menubtn) + GLYPH_PIX_SPACE -
  611. Lab_MarginRight(menubtn);
  612. Lab_MarginRight(menubtn) += delta;
  613. if (adjustWidth)
  614. XtWidth(menubtn) += delta;
  615. else {
  616. if (LAlignment(menubtn) == XmALIGNMENT_END)
  617. Lab_TextRect_x(menubtn) -= delta;
  618. else
  619. if (LAlignment(menubtn) == XmALIGNMENT_CENTER)
  620. Lab_TextRect_x(menubtn) -= delta/2;
  621. }
  622. }
  623. /*
  624. * the menu height should fit inside of
  625. * TextRect + marginTop + marginBottom
  626. */
  627. delta = MB_GLYPH_HEIGHT(menubtn) +
  628. 2 * (Lab_MarginHeight(menubtn) +
  629. menubtn->primitive.shadow_thickness +
  630. menubtn->primitive.highlight_thickness);
  631. if (delta > XtHeight(menubtn)) {
  632. delta -= XtHeight(menubtn);
  633. Lab_MarginTop(menubtn) += delta/2;
  634. Lab_TextRect_y(menubtn) += delta/2;
  635. Lab_MarginBottom(menubtn) += delta - (delta/2);
  636. if (adjustHeight)
  637. XtHeight(menubtn) += delta;
  638. }
  639. LocateMenuGlyph(menubtn);
  640. }
  641. /*
  642. * Destroy the widget
  643. */
  644. static void
  645. Destroy(
  646. Widget wid )
  647. {
  648. DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ;
  649. XmRowColumnWidget submenu = (XmRowColumnWidget) MB_SMENU(mb);
  650. Widget shell;
  651. XtRemoveAllCallbacks ((Widget) mb, DtNcascadingCallback);
  652. if(submenu != (XmRowColumnWidget)NULL) {
  653. shell = XtParent((Widget)submenu);
  654. XtRemoveCallback(shell, XtNpopupCallback,PopupCallback, (XtPointer)mb);
  655. XtRemoveCallback(shell, XtNpopdownCallback, PopdownCallback,(XtPointer)mb);
  656. }
  657. if(MB_PVT_SMENU(mb) == TRUE) {
  658. XtDestroyWidget((Widget)submenu);
  659. MB_SMENU(mb) = NULL;
  660. MB_PVT_SMENU(mb) = FALSE;
  661. }
  662. }
  663. /*
  664. * Resize Method.
  665. */
  666. static void
  667. Resize(
  668. Widget mb )
  669. {
  670. if (mb != (Widget)NULL) {
  671. /* Label resize method lays out the label string */
  672. XtWidgetProc resize;
  673. _DtProcessLock();
  674. resize = xmLabelClassRec.core_class.resize;
  675. _DtProcessUnlock();
  676. (* resize) (mb);
  677. LocateMenuGlyph ((DtMenuButtonWidget) mb);
  678. }
  679. }
  680. /*
  681. * Set Values Method.
  682. */
  683. static Boolean
  684. SetValues(
  685. Widget cw,
  686. Widget rw,
  687. Widget nw,
  688. ArgList args,
  689. Cardinal *num_args )
  690. {
  691. DtMenuButtonWidget old = (DtMenuButtonWidget) cw ;
  692. DtMenuButtonWidget requested = (DtMenuButtonWidget) rw ;
  693. DtMenuButtonWidget new_w = (DtMenuButtonWidget) nw ;
  694. Boolean flag = FALSE;
  695. Boolean adjustWidth = FALSE;
  696. Boolean adjustHeight = FALSE;
  697. unsigned char rowcol_type = 0;
  698. Boolean menu_glyph_changed = FALSE;
  699. if (MB_SMENU(new_w) != (Widget)NULL) {
  700. XtVaGetValues(MB_SMENU(new_w), XmNrowColumnType,
  701. &rowcol_type, NULL);
  702. if(rowcol_type != XmMENU_POPUP) {
  703. MB_SMENU(new_w) = NULL;
  704. XtError(MB_SUBMENU);
  705. }
  706. }
  707. /* Never let traversal become FALSE */
  708. new_w->primitive.traversal_on = TRUE;
  709. if ((LRecomputeSize(new_w)) ||
  710. (requested->core.width <= 0))
  711. adjustWidth = TRUE;
  712. if ((LRecomputeSize(new_w)) ||
  713. (requested->core.height <= 0))
  714. adjustHeight = TRUE;
  715. /* get new pixmap size */
  716. if ((MB_PIXMAP(old) != MB_PIXMAP (new_w)) ||
  717. (Lab_TextRect_height(old) != Lab_TextRect_height(new_w))) {
  718. CalculateMenuGlyphSize (new_w);
  719. menu_glyph_changed = TRUE;
  720. }
  721. if ((old->primitive.foreground !=
  722. new_w->primitive.foreground) ||
  723. (old->core.background_pixel !=
  724. new_w->core.background_pixel)) {
  725. menu_glyph_changed = TRUE;
  726. GetGC(new_w);
  727. }
  728. /*
  729. * Resize widget if submenu appeared or disappeared, or if the
  730. * menu glyph changed.
  731. */
  732. if ( menu_glyph_changed == TRUE ||
  733. (LLabelType(old) != LLabelType(new_w)) ||
  734. (MB_SMENU(old) != MB_SMENU(new_w))) {
  735. AdjustMenuButtonSize (new_w, adjustWidth, adjustHeight);
  736. flag = TRUE;
  737. if ((MB_SMENU(old) != MB_SMENU(new_w))) {
  738. if(MB_SMENU(new_w)) {
  739. XtRemoveEventHandler((Widget)new_w,
  740. ButtonPressMask, False,
  741. PreMenuButtonHandler, MB_SMENU(old));
  742. XtInsertEventHandler((Widget)new_w,
  743. ButtonPressMask, False,
  744. PreMenuButtonHandler, MB_SMENU(new_w),
  745. XtListHead);
  746. XtAddCallback(XtParent(
  747. MB_SMENU(new_w)),
  748. XtNpopdownCallback,
  749. PopdownCallback, (XtPointer)new_w);
  750. XtAddCallback(XtParent(
  751. MB_SMENU(new_w)),
  752. XtNpopupCallback,
  753. PopupCallback, (XtPointer)new_w);
  754. }
  755. if(MB_PVT_SMENU(old) == TRUE) {
  756. XtDestroyWidget(MB_SMENU(old));
  757. MB_PVT_SMENU(new_w) = FALSE;
  758. }
  759. }
  760. } else if ((new_w->primitive.highlight_thickness !=
  761. old->primitive.highlight_thickness) ||
  762. (new_w->primitive.shadow_thickness !=
  763. old->primitive.shadow_thickness) ||
  764. (Lab_MarginRight (new_w) != Lab_MarginRight (old)) ||
  765. (Lab_MarginHeight (new_w) != Lab_MarginHeight (old)) ||
  766. (Lab_MarginTop (new_w) != Lab_MarginTop (old)) ||
  767. (Lab_MarginBottom (new_w) != Lab_MarginBottom (old))) {
  768. CalculateMenuGlyphSize (new_w);
  769. AdjustMenuButtonSize (new_w,adjustWidth, adjustHeight);
  770. flag = TRUE;
  771. } else if ((Lab_MarginWidth(new_w) != Lab_MarginWidth(old)) ||
  772. (new_w->core.width != old->core.width) ||
  773. (new_w->core.height != old->core.height)) {
  774. LocateMenuGlyph (new_w);
  775. flag = TRUE;
  776. }
  777. return (flag);
  778. }
  779. /*
  780. * Initialize
  781. */
  782. static void
  783. Initialize(
  784. Widget w_req,
  785. Widget w_new,
  786. ArgList args,
  787. Cardinal *num_args )
  788. {
  789. DtMenuButtonWidget req = (DtMenuButtonWidget) w_req ;
  790. DtMenuButtonWidget new_w = (DtMenuButtonWidget) w_new ;
  791. Widget topManager;
  792. Boolean adjustWidth = FALSE;
  793. Boolean adjustHeight = FALSE;
  794. Widget parent = XtParent(new_w);
  795. unsigned char rowcol_type = 0;
  796. char *name = NULL;
  797. if ((XmIsRowColumn (parent))) {
  798. XtVaGetValues(parent, XmNrowColumnType,
  799. &rowcol_type, NULL);
  800. if(rowcol_type != XmWORK_AREA)
  801. XtError(MB_PARENT);
  802. }
  803. name = XtMalloc(10 + strlen(new_w->core.name));
  804. sprintf(name,"submenu_%s",new_w->core.name);
  805. GetTopManager(w_new,&topManager);
  806. MB_SMENU(new_w) = XmCreatePopupMenu(topManager, name, NULL, 0);
  807. /* Remove our passive grab */
  808. XtUngrabButton(topManager, RC_PostButton(MB_SMENU(new_w)), AnyModifier);
  809. MB_PVT_SMENU(new_w) = TRUE;
  810. MB_ARMED(new_w) = FALSE;
  811. MB_POPPED_UP(new_w) = FALSE;
  812. MB_LAST_TIMESTAMP(new_w) = 0;
  813. MB_GC(new_w) = (GC)NULL;
  814. if (req->core.width <= 0)
  815. adjustWidth = TRUE;
  816. if (req->core.height <= 0)
  817. adjustHeight = TRUE;
  818. CalculateMenuGlyphSize (new_w);
  819. AdjustMenuButtonSize (new_w, adjustWidth, adjustHeight);
  820. GetGC(new_w);
  821. new_w->primitive.traversal_on = TRUE;
  822. if(MB_SMENU(new_w) != (Widget)NULL) {
  823. XtInsertEventHandler((Widget)new_w, ButtonPressMask,
  824. False, PreMenuButtonHandler, MB_SMENU(new_w), XtListHead);
  825. XtAddEventHandler((Widget)new_w, ButtonPressMask,
  826. FALSE, MenuButtonHandler, MB_SMENU(new_w));
  827. XtAddCallback(XtParent(MB_SMENU(new_w)), XtNpopdownCallback,
  828. PopdownCallback, (XtPointer)new_w);
  829. XtAddCallback(XtParent(MB_SMENU(new_w)), XtNpopupCallback,
  830. PopupCallback, (XtPointer)new_w);
  831. }
  832. XtFree(name);
  833. }
  834. static void
  835. DrawArrow(
  836. Widget wid )
  837. {
  838. GC gc, tsGC, bsGC;
  839. Pixel tsc, bsc;
  840. int ht,st;
  841. unsigned int text_height;
  842. DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ;
  843. Window win = XtWindow(wid);
  844. Display *dpy = XtDisplay(wid);
  845. ht = mb->primitive.highlight_thickness;
  846. st = mb->primitive.shadow_thickness;
  847. text_height = Lab_TextRect_height(mb);
  848. tsc = mb->primitive.top_shadow_color;
  849. bsc = mb->primitive.bottom_shadow_color;
  850. tsGC = mb->primitive.top_shadow_GC;
  851. bsGC = mb->primitive.bottom_shadow_GC;
  852. gc = MB_GC(mb);
  853. /* armed arrow */
  854. if(MB_ARMED(mb) == TRUE) {
  855. XFillRectangle(dpy, win, gc,
  856. MB_GLYPH_X(mb), MB_GLYPH_Y(mb),
  857. MB_GLYPH_WIDTH(mb), MB_GLYPH_HEIGHT(mb));
  858. XmeDrawArrow(dpy, win,
  859. bsGC, tsGC, gc,
  860. MB_GLYPH_X(mb) + ht + st - 1,
  861. MB_GLYPH_Y(mb) + ht + st - 1,
  862. MB_GLYPH_WIDTH(mb) - 2*(ht + st - 1),
  863. MB_GLYPH_HEIGHT(mb) - 2*(ht + st - 1),
  864. st, XmARROW_DOWN);
  865. } else {
  866. /* standard (unarmed) arrow */
  867. XFillRectangle(dpy, win, gc,
  868. MB_GLYPH_X(mb), MB_GLYPH_Y(mb),
  869. MB_GLYPH_WIDTH(mb), MB_GLYPH_HEIGHT(mb));
  870. XmeDrawArrow(dpy, win,
  871. tsGC, bsGC, gc,
  872. MB_GLYPH_X(mb) + ht + st - 1,
  873. MB_GLYPH_Y(mb) + ht + st - 1,
  874. MB_GLYPH_WIDTH(mb) - 2*(ht + st - 1),
  875. MB_GLYPH_HEIGHT(mb) - 2*(ht + st - 1),
  876. st, XmARROW_DOWN);
  877. }
  878. }
  879. static void
  880. GetGC(
  881. DtMenuButtonWidget mb)
  882. {
  883. XGCValues values;
  884. Pixel bg;
  885. if(MB_GC(mb) != (GC)NULL) {
  886. XtReleaseGC((Widget)mb, MB_GC(mb));
  887. MB_GC(mb) = (GC)NULL;
  888. }
  889. bg = mb->core.background_pixel;
  890. values.foreground = values.background = bg;
  891. values.graphics_exposures = FALSE;
  892. MB_GC(mb) = XtGetGC ((Widget) mb,
  893. GCForeground | GCBackground | GCGraphicsExposures, &values);
  894. }
  895. /*
  896. *************************************************************************
  897. *
  898. * Public Routines
  899. *
  900. *************************************************************************
  901. */
  902. Widget
  903. DtCreateMenuButton(
  904. Widget parent,
  905. char *name,
  906. ArgList al,
  907. Cardinal ac )
  908. {
  909. return XtCreateWidget(name,dtMenuButtonWidgetClass,parent, al, ac);
  910. }
  911. static void
  912. GetTopManager(
  913. Widget w,
  914. Widget *topManager )
  915. {
  916. while (XmIsManager(XtParent(w)))
  917. w = XtParent(w);
  918. * topManager = w;
  919. }