PageRenderTime 485ms CodeModel.GetById 53ms RepoModel.GetById 0ms app.codeStats 1ms

/ExtLibs/wxWidgets/src/motif/mdi/lib/XsMotifWindow.C

https://bitbucket.org/lennonchan/cafu
C | 2415 lines | 1465 code | 624 blank | 326 comment | 272 complexity | e84605fa5b510461a0ec1e84cef7bbf3 MD5 | raw file
  1. /*
  2. Copyright (C) 1996 Scott W. Sadler
  3. All rights reserved.
  4. */
  5. /*
  6. XsMotifWindow.C
  7. History
  8. 03-Mar-96 1.0; Scott W. Sadler (ssadler@cisco.com)
  9. Created
  10. */
  11. // Includes
  12. #include <assert.h>
  13. #include <Xm/Form.h>
  14. #include <Xm/RowColumn.h>
  15. #include <Xm/SeparatoG.h>
  16. #include <Xm/PushBG.h>
  17. #include <X11/Shell.h>
  18. #include <X11/cursorfont.h>
  19. #include "XsMotifWindow.h"
  20. #include "XsResizeOutline.h"
  21. #include "XsMoveOutline.h"
  22. #include "xs_motif_icon.xbm"
  23. // Constants
  24. const int BorderSize_ = 6;
  25. const int ButtonSize_ = 23;
  26. const int IconSize_ = 70;
  27. /*
  28. ----------------------------------------------------------------------------
  29. _XsMotifBase
  30. */
  31. // Constructor
  32. _XsMotifBase::_XsMotifBase (const char *name, XsMotifWindow *win) :
  33. XsComponent (name)
  34. {
  35. assert (win != 0);
  36. // Initialize
  37. _win = win;
  38. _topShadowGC = 0;
  39. _bottomShadowGC = 0;
  40. }
  41. // Destructor
  42. _XsMotifBase::~_XsMotifBase ( )
  43. {
  44. if (_topShadowGC)
  45. XtReleaseGC (_base, _topShadowGC);
  46. if (_bottomShadowGC)
  47. XtReleaseGC (_base, _bottomShadowGC);
  48. }
  49. // show
  50. void _XsMotifBase::show ( )
  51. {
  52. assert (_base != 0);
  53. // Install event handler
  54. XtAddEventHandler (_base, StructureNotifyMask, False, _mapEventHandler, (XtPointer)this);
  55. // Call the base-class
  56. XsComponent::show ( );
  57. }
  58. // className
  59. const char* _XsMotifBase::className ( ) const
  60. {
  61. return ("_XsMotifBase");
  62. }
  63. // _componentDestroyed ( )
  64. void _XsMotifBase::_componentDestroyed ( )
  65. {
  66. // Clean up the GCs
  67. if (_topShadowGC)
  68. XtReleaseGC (_base, _topShadowGC);
  69. if (_bottomShadowGC)
  70. XtReleaseGC (_base, _bottomShadowGC);
  71. _topShadowGC = 0;
  72. _bottomShadowGC = 0;
  73. // Call the base-class
  74. XsComponent::_componentDestroyed ( );
  75. }
  76. // _drawShadows
  77. void _XsMotifBase::_drawShadows (Position x, Position y, Dimension width,
  78. Dimension height, Dimension thick, Boolean reverse)
  79. {
  80. assert (_base != 0);
  81. assert (thick > 0);
  82. const int nsegs = 2;
  83. XSegment segs[nsegs];
  84. GC topShadowGC;
  85. GC bottomShadowGC;
  86. // Work out the graphics contexts
  87. topShadowGC = (reverse == False) ? _topShadowGC : _bottomShadowGC;
  88. bottomShadowGC = (reverse == False) ? _bottomShadowGC : _topShadowGC;
  89. for (int loop = 0; loop < thick; loop++)
  90. {
  91. /*
  92. TOP SHADOW DRAWING
  93. */
  94. // Across the top
  95. segs[0].x1 = x + loop;
  96. segs[0].y1 = y + loop;
  97. segs[0].x2 = x + width - loop - 2;
  98. segs[0].y2 = y + loop;
  99. // Down the left side
  100. segs[1].x1 = x + loop;
  101. segs[1].y1 = y + loop + 1;
  102. segs[1].x2 = x + loop;
  103. segs[1].y2 = y + height - loop - 2;
  104. XDrawSegments (XtDisplay (_base), XtWindow (_base), topShadowGC, segs, nsegs);
  105. /*
  106. BOTTOM SHADOW DRAWING
  107. */
  108. // Across the bottom
  109. segs[0].x1 = x + loop;
  110. segs[0].y1 = y + height - loop - 1;
  111. segs[0].x2 = x + width - loop - 1;
  112. segs[0].y2 = y + height - loop - 1;
  113. // Down the right side
  114. segs[1].x1 = x + width - loop - 1;
  115. segs[1].y1 = y + loop;
  116. segs[1].x2 = x + width - loop - 1;
  117. segs[1].y2 = y + height - loop - 1;
  118. XDrawSegments (XtDisplay (_base), XtWindow (_base), bottomShadowGC, segs, nsegs);
  119. }
  120. }
  121. // _drawLine
  122. void _XsMotifBase::_drawLine (Position x1, Position y1, Position x2, Position y2, GC &gc)
  123. {
  124. assert (_base != 0);
  125. XDrawLine (XtDisplay (_base), XtWindow (_base), gc, x1, y1, x2, y2);
  126. }
  127. // _map
  128. void _XsMotifBase::_map ( )
  129. {
  130. // Create the graphics contexts
  131. unsigned long valuemask;
  132. XGCValues values;
  133. Pixel topShadow;
  134. Pixel bottomShadow;
  135. XtVaGetValues (_win->base ( ), XmNtopShadowColor, &topShadow, XmNbottomShadowColor,
  136. &bottomShadow, NULL);
  137. // Create the graphics contexts
  138. valuemask = GCForeground | GCLineWidth | GCGraphicsExposures;
  139. values.line_width = 0;
  140. values.graphics_exposures = False;
  141. values.foreground = topShadow;
  142. _topShadowGC = XtGetGC (_base, valuemask, &values);
  143. values.foreground = bottomShadow;
  144. _bottomShadowGC = XtGetGC (_base, valuemask, &values);
  145. }
  146. // _mapEventHandler
  147. void _XsMotifBase::_mapEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*)
  148. {
  149. if (event->type == MapNotify)
  150. {
  151. _XsMotifBase *obj = (_XsMotifBase*)clientData;
  152. obj->_map ( );
  153. // Remove the event handler
  154. XtRemoveEventHandler (obj->_base, StructureNotifyMask, False, obj->_mapEventHandler, clientData);
  155. }
  156. }
  157. /*
  158. ----------------------------------------------------------------------------
  159. _XsMotifComponent
  160. */
  161. Cursor _XsMotifComponent::_cursors[_XsMotifComponent::NumCursors];
  162. int _XsMotifComponent::_mutex = 0;
  163. XtResource _XsMotifComponent::_resourceList[] = {
  164. {
  165. "borderSize",
  166. "BorderSize",
  167. XmRDimension,
  168. sizeof (Dimension),
  169. XtOffset (_XsMotifComponent*, _borderSize),
  170. XmRImmediate,
  171. (XtPointer)BorderSize_
  172. },
  173. {
  174. "buttonSize",
  175. "ButtonSize",
  176. XmRDimension,
  177. sizeof (Dimension),
  178. XtOffset (_XsMotifComponent*, _buttonSize),
  179. XmRImmediate,
  180. (XtPointer)ButtonSize_
  181. }
  182. };
  183. // Constructor
  184. _XsMotifComponent::_XsMotifComponent (const char *name, XsMotifWindow *win,
  185. Widget parent) : _XsMotifBase (name, win)
  186. {
  187. // Create cursors (if necessary)
  188. if (_mutex == 0)
  189. {
  190. Display *dpy = XtDisplay (win->base ( ));
  191. _cursors[TopCursor] = XCreateFontCursor (dpy, XC_top_side);
  192. _cursors[BottomCursor] = XCreateFontCursor (dpy, XC_bottom_side);
  193. _cursors[LeftCursor] = XCreateFontCursor (dpy, XC_left_side);
  194. _cursors[RightCursor] = XCreateFontCursor (dpy, XC_right_side);
  195. _cursors[TopLeftCursor] = XCreateFontCursor (dpy, XC_top_left_corner);
  196. _cursors[TopRightCursor] = XCreateFontCursor (dpy, XC_top_right_corner);
  197. _cursors[BottomLeftCursor] = XCreateFontCursor (dpy, XC_bottom_left_corner);
  198. _cursors[BottomRightCursor] = XCreateFontCursor (dpy, XC_bottom_right_corner);
  199. _mutex = 1;
  200. }
  201. // Create the component
  202. _base = XtVaCreateWidget (name, widgetClass, (parent != 0) ? parent : _win->base ( ), NULL);
  203. // Install destroy handler
  204. _installDestroyHandler ( );
  205. // Get resources
  206. _getResources (_resourceList, XtNumber (_resourceList));
  207. // Compute the corner size
  208. _cornerSize = _buttonSize + _borderSize;
  209. // Install event handlers
  210. XtAddEventHandler (_base, ExposureMask, False, _exposeEventHandler, (XtPointer)this);
  211. XtAddEventHandler (_base, ButtonPressMask | ButtonReleaseMask | Button1MotionMask | Button2MotionMask, False, _inputEventHandler, (XtPointer)this);
  212. }
  213. // Destructor
  214. _XsMotifComponent::~_XsMotifComponent ( )
  215. {
  216. // Empty
  217. }
  218. // className
  219. const char* _XsMotifComponent::className ( ) const
  220. {
  221. return ("_XsMotifComponent");
  222. }
  223. // _input
  224. void _XsMotifComponent::_input (XEvent*)
  225. {
  226. // Empty
  227. }
  228. // _exposeEventHandler
  229. void _XsMotifComponent::_exposeEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*)
  230. {
  231. _XsMotifComponent *obj = (_XsMotifComponent*)clientData;
  232. if (event->xexpose.count == 0)
  233. obj->_expose (event);
  234. }
  235. // _inputEventHandler
  236. void _XsMotifComponent::_inputEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*)
  237. {
  238. _XsMotifComponent *obj = (_XsMotifComponent*)clientData;
  239. obj->_input (event);
  240. }
  241. /*
  242. ----------------------------------------------------------------------------
  243. _XsMotifCorner
  244. */
  245. // Constructor
  246. _XsMotifCorner::_XsMotifCorner (const char *name, XsMotifWindow *win, Corner corner)
  247. : _XsMotifComponent (name, win)
  248. {
  249. // Initialize
  250. _corner = corner;
  251. // Configure component
  252. XtVaSetValues (_base, XmNwidth, _cornerSize, XmNheight, _cornerSize,
  253. XmNborderWidth, (Dimension)0, NULL);
  254. }
  255. // Destructor
  256. _XsMotifCorner::~_XsMotifCorner ( )
  257. {
  258. // Empty
  259. }
  260. // className
  261. const char *_XsMotifCorner::className ( ) const
  262. {
  263. return ("_XsMotifCorner");
  264. }
  265. // _expose
  266. void _XsMotifCorner::_expose (XEvent*)
  267. {
  268. Dimension w, h;
  269. if (_topShadowGC == 0) // JACS
  270. return;
  271. // Get the size of the corner
  272. XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL);
  273. // Draw the shadow
  274. _drawShadows (0, 0, w, h, 1);
  275. // Draw the extra lines and relief
  276. switch (_corner)
  277. {
  278. case TopLeft:
  279. {
  280. _drawLine (1, 1, w - 2, 1, _topShadowGC);
  281. _drawLine (1, 1, 1, h - 2, _topShadowGC);
  282. // Relief
  283. _drawLine (_borderSize - 1, _borderSize - 1, _borderSize +
  284. _buttonSize - 2, _borderSize - 1, _bottomShadowGC);
  285. _drawLine (_borderSize - 1, _borderSize - 1, _borderSize - 1,
  286. _borderSize + _buttonSize - 2, _bottomShadowGC);
  287. break;
  288. }
  289. case TopRight:
  290. {
  291. _drawLine (1, 1, w - 2, 1, _topShadowGC);
  292. _drawLine (w - 2, 1, w - 2, h - 2, _bottomShadowGC);
  293. // Relief
  294. _drawLine (0, _borderSize - 1, _buttonSize - 1, _borderSize - 1,
  295. _bottomShadowGC);
  296. _drawLine (w - _borderSize, _borderSize - 1, w - _borderSize,
  297. _borderSize + _buttonSize - 2, _topShadowGC);
  298. break;
  299. }
  300. case BottomLeft:
  301. {
  302. _drawLine (1, 1, 1, h - 2, _topShadowGC);
  303. _drawLine (1, h - 2, w - 2, h - 2, _bottomShadowGC);
  304. // Relief
  305. _drawLine (_borderSize - 1, h - _borderSize, _borderSize +
  306. _buttonSize - 2, h - _borderSize, _topShadowGC);
  307. _drawLine (_borderSize - 1, 1, _borderSize - 1,
  308. _buttonSize - 1, _bottomShadowGC);
  309. break;
  310. }
  311. case BottomRight:
  312. {
  313. _drawLine (1, h - 2, w - 2, h - 2, _bottomShadowGC);
  314. _drawLine (w - 2, 1, w - 2, h - 2, _bottomShadowGC);
  315. // Relief
  316. _drawLine (1, h - _borderSize, _buttonSize, h - _borderSize,
  317. _topShadowGC);
  318. _drawLine (w - _borderSize, 1, w - _borderSize,
  319. _buttonSize - 1, _topShadowGC);
  320. break;
  321. }
  322. default:
  323. assert (0);
  324. }
  325. }
  326. // _input
  327. void _XsMotifCorner::_input (XEvent *event)
  328. {
  329. switch (event->type)
  330. {
  331. case ButtonPress:
  332. {
  333. if (event->xbutton.button == 2)
  334. {
  335. XsMoveOutline move (_win->base ( ));
  336. // Start the move
  337. if (move.go ( ) != False)
  338. {
  339. // Relocate the window
  340. _win->setPosition (move.x ( ), move.y ( ));
  341. }
  342. }
  343. else if (event->xbutton.button == 3)
  344. _win->popupMenu ( );
  345. break;
  346. }
  347. case ButtonRelease:
  348. {
  349. switch (event->xbutton.button)
  350. {
  351. case 1:
  352. case 2:
  353. {
  354. _win->raise ( ); // Raise the window
  355. break;
  356. }
  357. }
  358. break;
  359. }
  360. case MotionNotify:
  361. {
  362. // Figure kind of resize we are doing
  363. int dir;
  364. if (_corner == TopLeft)
  365. dir = XsResizeOutline::Up | XsResizeOutline::Left;
  366. else if (_corner == TopRight)
  367. dir = XsResizeOutline::Up | XsResizeOutline::Right;
  368. else if (_corner == BottomLeft)
  369. dir = XsResizeOutline::Down | XsResizeOutline::Left;
  370. else if (_corner == BottomRight)
  371. dir = XsResizeOutline::Down | XsResizeOutline::Right;
  372. else
  373. assert (0);
  374. XsResizeOutline resize (_win->base ( ), dir);
  375. resize.setMinSize (_win->minWidth ( ), _win->minHeight ( ));
  376. // Start the resize
  377. if (resize.go ( ) != False)
  378. {
  379. // Relocate the window
  380. _win->setPosition (resize.x ( ), resize.y ( ));
  381. _win->setSize (resize.width ( ), resize.height ( ));
  382. }
  383. break;
  384. }
  385. }
  386. }
  387. // _map
  388. void _XsMotifCorner::_map ( )
  389. {
  390. // Call the base-class
  391. _XsMotifComponent::_map ( );
  392. // Install the cursor
  393. if (_corner == TopLeft)
  394. XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[TopLeftCursor]);
  395. else if (_corner == TopRight)
  396. XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[TopRightCursor]);
  397. else if (_corner == BottomLeft)
  398. XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[BottomLeftCursor]);
  399. else if (_corner == BottomRight)
  400. XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[BottomRightCursor]);
  401. else
  402. assert (0);
  403. }
  404. /*
  405. ----------------------------------------------------------------------------
  406. _XsMotifSide
  407. */
  408. // Constructor
  409. _XsMotifSide::_XsMotifSide (const char *name, XsMotifWindow *win, Side side) :
  410. _XsMotifComponent (name, win)
  411. {
  412. // Initialize
  413. _side = side;
  414. _lastW = _lastH = -1;
  415. // Configure component
  416. switch (_side)
  417. {
  418. case Top:
  419. case Bottom:
  420. {
  421. XtVaSetValues (_base, XmNheight, _borderSize, XmNborderWidth,
  422. (Dimension)0, NULL);
  423. break;
  424. }
  425. case Left:
  426. case Right:
  427. {
  428. XtVaSetValues (_base, XmNwidth, _borderSize, XmNborderWidth,
  429. (Dimension)0, NULL);
  430. break;
  431. }
  432. default:
  433. assert (0);
  434. }
  435. // Install event handler
  436. XtAddEventHandler (_base, StructureNotifyMask, False, _configureEventHandler, (XtPointer)this);
  437. }
  438. // Destructor
  439. _XsMotifSide::~_XsMotifSide ( )
  440. {
  441. // Empty
  442. }
  443. // className
  444. const char *_XsMotifSide::className ( ) const
  445. {
  446. return ("_XsMotifSide");
  447. }
  448. // _expose
  449. void _XsMotifSide::_expose (XEvent *event)
  450. {
  451. if (_topShadowGC == 0) // JACS
  452. return;
  453. // Clear out the window first
  454. if (event != 0)
  455. XClearWindow (XtDisplay (_base), XtWindow (_base));
  456. Dimension w, h;
  457. // Get the size of the side
  458. XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL);
  459. // Draw the shadow
  460. _drawShadows (0, 0, w, h, 1);
  461. // Draw the extra lines
  462. switch (_side)
  463. {
  464. case Top:
  465. {
  466. _drawLine (1, 1, w - 2, 1, _topShadowGC);
  467. break;
  468. }
  469. case Bottom:
  470. {
  471. _drawLine (1, h - 2, w - 2, h - 2, _bottomShadowGC);
  472. break;
  473. }
  474. case Left:
  475. {
  476. _drawLine (1, 1, 1, h - 2, _topShadowGC);
  477. break;
  478. }
  479. case Right:
  480. {
  481. _drawLine (w - 2, 1, w - 2, h - 2, _bottomShadowGC);
  482. break;
  483. }
  484. default:
  485. assert (0);
  486. }
  487. }
  488. // _input
  489. void _XsMotifSide::_input (XEvent *event)
  490. {
  491. switch (event->type)
  492. {
  493. case ButtonPress:
  494. {
  495. if (event->xbutton.button == 2)
  496. {
  497. XsMoveOutline move (_win->base ( ));
  498. // Start the move
  499. if (move.go ( ) != False)
  500. {
  501. // Relocate the window
  502. _win->setPosition (move.x ( ), move.y ( ));
  503. }
  504. }
  505. else if (event->xbutton.button == 3)
  506. _win->popupMenu ( );
  507. break;
  508. }
  509. case ButtonRelease:
  510. {
  511. switch (event->xbutton.button)
  512. {
  513. case 1:
  514. case 2:
  515. {
  516. _win->raise ( ); // Raise the window
  517. break;
  518. }
  519. }
  520. break;
  521. }
  522. case MotionNotify:
  523. {
  524. // Figure kind of resize we are doing
  525. int dir;
  526. if (_side == Top)
  527. dir = XsResizeOutline::Up;
  528. else if (_side == Bottom)
  529. dir = XsResizeOutline::Down;
  530. else if (_side == Left)
  531. dir = XsResizeOutline::Left;
  532. else if (_side == Right)
  533. dir = XsResizeOutline::Right;
  534. else
  535. assert (0);
  536. XsResizeOutline resize (_win->base ( ), dir);
  537. resize.setMinSize (_win->minWidth ( ), _win->minHeight ( ));
  538. // Start the resize
  539. if (resize.go ( ) != False)
  540. {
  541. // Relocate the window
  542. _win->setPosition (resize.x ( ), resize.y ( ));
  543. _win->setSize (resize.width ( ), resize.height ( ));
  544. }
  545. break;
  546. }
  547. }
  548. }
  549. // _map
  550. void _XsMotifSide::_map ( )
  551. {
  552. // Call the base-class
  553. _XsMotifComponent::_map ( );
  554. // Install the cursor
  555. if (_side == Top)
  556. XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[TopCursor]);
  557. else if (_side == Bottom)
  558. XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[BottomCursor]);
  559. else if (_side == Left)
  560. XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[LeftCursor]);
  561. else if (_side == Right)
  562. XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[RightCursor]);
  563. else
  564. assert (0);
  565. }
  566. // _configure
  567. void _XsMotifSide::_configure (XEvent *event)
  568. {
  569. XConfigureEvent *ce = (XConfigureEvent*)event;
  570. /*
  571. Check if window has been resized. If so, generate an expose event
  572. to redraw its contents.
  573. */
  574. if ((_lastW != ce->width) || (_lastH != ce->height))
  575. {
  576. if ((_base != 0) && XtIsManaged (_base))
  577. XClearArea (XtDisplay (_base), XtWindow (_base), 0, 0, 0, 0, True);
  578. _lastW = ce->width;
  579. _lastH = ce->height;
  580. }
  581. }
  582. // _configureEventHandler
  583. void _XsMotifSide::_configureEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*)
  584. {
  585. if (event->type == ConfigureNotify)
  586. {
  587. _XsMotifSide *obj = (_XsMotifSide*)clientData;
  588. obj->_configure (event);
  589. }
  590. }
  591. /*
  592. ----------------------------------------------------------------------------
  593. _XsMotifButton
  594. */
  595. // Constructor
  596. _XsMotifButton::_XsMotifButton (const char *name, XsMotifWindow *win, Button button) :
  597. _XsMotifComponent (name, win)
  598. {
  599. // Initialize
  600. _pressed = False;
  601. _button = button;
  602. // Configure the component
  603. XtVaSetValues (_base, XmNheight, _buttonSize, XmNwidth, _buttonSize,
  604. XmNborderWidth, (Dimension)0, NULL);
  605. }
  606. // Destructor
  607. _XsMotifButton::~_XsMotifButton ( )
  608. {
  609. // Empty
  610. }
  611. // redraw
  612. void _XsMotifButton::redraw ( )
  613. {
  614. // Make sure component is viewable
  615. if (!XtIsRealized (_base))
  616. return;
  617. // Check if window is viewable
  618. XWindowAttributes attrs;
  619. XGetWindowAttributes (XtDisplay (_base), XtWindow (_base), &attrs);
  620. if (attrs.map_state == IsViewable)
  621. _expose (0); // Just pretend we got an expose event
  622. }
  623. // className
  624. const char *_XsMotifButton::className ( ) const
  625. {
  626. return ("_XsMotifButton");
  627. }
  628. // _expose
  629. void _XsMotifButton::_expose (XEvent *event)
  630. {
  631. if (_topShadowGC == 0) // JACS
  632. return;
  633. Dimension w, h;
  634. // Get the size of the button
  635. XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL);
  636. // Draw the shadow
  637. _drawShadows (0, 0, w, h, 1, _pressed);
  638. // Draw the extra line
  639. _drawLine (1, h - 2, w - 2, h - 2, (_pressed) ? _topShadowGC : _bottomShadowGC);
  640. // Check if we need to draw the decal
  641. if ((_button != Maximize) && (event == 0))
  642. return;
  643. // Compute the decal size
  644. Dimension dw, dh;
  645. Boolean reverse = False;
  646. switch (_button)
  647. {
  648. case Menu:
  649. {
  650. dw = _buttonSize - 6;
  651. dh = 4;
  652. break;
  653. }
  654. case Minimize:
  655. {
  656. dw = dh = 4;
  657. break;
  658. }
  659. case Maximize:
  660. {
  661. dw = _buttonSize - 6;
  662. dh = dw - 1;
  663. if (_win->maximized ( ))
  664. reverse = True;
  665. break;
  666. }
  667. default:
  668. assert (0);
  669. }
  670. // Draw the decal
  671. _drawShadows ((w / 2) - (dw / 2), (h / 2) - (dh / 2), dw, dh, 1, reverse);
  672. }
  673. // _input
  674. void _XsMotifButton::_input (XEvent *event)
  675. {
  676. static Time lastTime = (Time)0;
  677. switch (event->type)
  678. {
  679. case ButtonPress:
  680. {
  681. if (event->xbutton.button == 1)
  682. {
  683. _pressed = True;
  684. if (_button == Menu)
  685. {
  686. // Get double-click time
  687. int multiClick = XtGetMultiClickTime (XtDisplay (_base));
  688. // Check for double-click
  689. if ((event->xbutton.time - lastTime) <= multiClick)
  690. {
  691. _win->close ( );
  692. return;
  693. }
  694. else
  695. lastTime = event->xbutton.time;
  696. // Redraw the button (pushed-in)
  697. redraw ( );
  698. // Popup the menu
  699. _win->popupMenu (False);
  700. // The menu will consume the ButtonRelease, so fake one
  701. _pressed = False;
  702. redraw ( );
  703. }
  704. else if ((_button == Minimize) || (_button == Maximize))
  705. {
  706. redraw ( );
  707. }
  708. }
  709. else if (event->xbutton.button == 2)
  710. {
  711. XsMoveOutline move (_win->base ( ));
  712. // Start the move
  713. if (move.go ( ) != False)
  714. {
  715. // Relocate the window
  716. _win->setPosition (move.x ( ), move.y ( ));
  717. }
  718. }
  719. else if (event->xbutton.button == 3)
  720. _win->popupMenu ( );
  721. break;
  722. }
  723. case ButtonRelease:
  724. {
  725. if (event->xbutton.button == 1)
  726. {
  727. _pressed = False;
  728. // Check if pointer is really in the window
  729. XButtonEvent *b = &event->xbutton;
  730. Dimension width, height;
  731. Boolean inWindow = False;
  732. XtVaGetValues (_base, XmNwidth, &width, XmNheight, &height, NULL);
  733. if ((b->x >= 0) && (b->y >= 0) && (b->x < width) && (b->y < height))
  734. inWindow = True;
  735. if (_button == Minimize)
  736. {
  737. if (inWindow)
  738. {
  739. if (_win->minimized ( ))
  740. _win->restore ( );
  741. else
  742. _win->minimize ( );
  743. }
  744. else
  745. redraw ( );
  746. }
  747. else if (_button == Maximize)
  748. {
  749. if (inWindow)
  750. {
  751. if (_win->maximized ( ))
  752. _win->restore ( );
  753. else
  754. _win->maximize ( );
  755. }
  756. else
  757. redraw ( );
  758. }
  759. }
  760. break;
  761. }
  762. }
  763. }
  764. // _map
  765. void _XsMotifButton::_map ( )
  766. {
  767. // Call the base-class
  768. _XsMotifComponent::_map ( );
  769. // Raise ourself
  770. XRaiseWindow (XtDisplay (_base), XtWindow (_base));
  771. }
  772. /*
  773. ----------------------------------------------------------------------------
  774. _XsMotifTitle
  775. */
  776. XtResource _XsMotifTitle::_resourceList[] = {
  777. {
  778. "title",
  779. "Title",
  780. XmRString,
  781. sizeof (String),
  782. XtOffset (_XsMotifTitle*, _titleString),
  783. XmRImmediate,
  784. NULL
  785. },
  786. {
  787. "titleFont",
  788. "TitleFont",
  789. XmRFontStruct,
  790. sizeof (XFontStruct*),
  791. XtOffset (_XsMotifTitle*, _titleFont),
  792. XmRString,
  793. "-*-helvetica-bold-o-normal-*-14-*-*-*-*-*-iso8859-1"
  794. }
  795. };
  796. // Constructor
  797. _XsMotifTitle::_XsMotifTitle (const char *name, XsMotifWindow *win) :
  798. _XsMotifComponent (name, win)
  799. {
  800. // Initialize
  801. _pressed = False;
  802. _titleString = 0;
  803. _titleFont = 0;
  804. _fontGC = 0;
  805. _lastW = _lastH = -1;
  806. // Get resources
  807. _getResources (_resourceList, XtNumber (_resourceList));
  808. // Copy title string to local memory
  809. if (_titleString != 0)
  810. {
  811. char *tmp = new char[strlen (_titleString) + 1];
  812. strcpy (tmp, _titleString);
  813. _titleString = tmp;
  814. }
  815. // Configure the title
  816. XtVaSetValues (_base, XmNheight, _buttonSize, XmNborderWidth,
  817. (Dimension)0, NULL);
  818. // Install event handler
  819. XtAddEventHandler (_base, StructureNotifyMask, False, _configureEventHandler, (XtPointer)this);
  820. }
  821. // Destructor
  822. _XsMotifTitle::~_XsMotifTitle ( )
  823. {
  824. if (_fontGC)
  825. XtReleaseGC (_base, _fontGC);
  826. delete [] _titleString;
  827. }
  828. // setTitle
  829. void _XsMotifTitle::setTitle (const char *title)
  830. {
  831. assert (title != 0);
  832. delete [] _titleString;
  833. _titleString = new char[strlen (title) + 1];
  834. strcpy (_titleString, title);
  835. }
  836. // className
  837. const char *_XsMotifTitle::className ( ) const
  838. {
  839. return ("_XsMotifTitle");
  840. }
  841. // _componentDestroyed
  842. void _XsMotifTitle::_componentDestroyed ( )
  843. {
  844. // Clean up the GCs
  845. if (_fontGC)
  846. XtReleaseGC (_base, _fontGC);
  847. _fontGC = 0;
  848. // Call base-class
  849. _XsMotifComponent::_componentDestroyed ( );
  850. }
  851. // _redraw
  852. void _XsMotifTitle::_redraw ( )
  853. {
  854. _expose (0); // Just pretend we got an expose event
  855. }
  856. // _expose
  857. void _XsMotifTitle::_expose (XEvent *event)
  858. {
  859. if (_topShadowGC == 0) // JACS
  860. return;
  861. // Clear out the window first
  862. if (event != 0)
  863. XClearWindow (XtDisplay (_base), XtWindow (_base));
  864. Dimension w, h;
  865. // Get the size of the button
  866. XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL);
  867. // Draw the shadow
  868. _drawShadows (0, 0, w, h, 1, _pressed);
  869. // Draw the extra line
  870. _drawLine (1, h - 2, w - 2, h - 2, (_pressed) ? _topShadowGC : _bottomShadowGC);
  871. // If this is an artificial event, no need continuing
  872. if (event == 0)
  873. return;
  874. // Draw the text string
  875. const int LeftOffset = 5;
  876. const int TopOffset = 2;
  877. // Figure out the title
  878. const char *title = (_titleString != 0) ? _titleString : _win->name ( );
  879. if ((title != 0) && (title[0] != '\0'))
  880. {
  881. int len = strlen (title);
  882. XDrawString (XtDisplay (_base), XtWindow (_base), _fontGC,
  883. LeftOffset, TopOffset + _titleFont->ascent, title, len);
  884. }
  885. }
  886. // _input
  887. void _XsMotifTitle::_input (XEvent *event)
  888. {
  889. switch (event->type)
  890. {
  891. case ButtonPress:
  892. {
  893. switch (event->xbutton.button)
  894. {
  895. case 1:
  896. {
  897. _pressed = True;
  898. _redraw ( );
  899. break;
  900. }
  901. case 2:
  902. {
  903. XsMoveOutline move (_win->base ( ));
  904. // Start the move
  905. if (move.go ( ) != False)
  906. {
  907. // Relocate the window
  908. _win->setPosition (move.x ( ), move.y ( ));
  909. }
  910. break;
  911. }
  912. case 3:
  913. {
  914. _win->popupMenu ( );
  915. break;
  916. }
  917. }
  918. break;
  919. }
  920. case ButtonRelease:
  921. {
  922. switch (event->xbutton.button)
  923. {
  924. case 1:
  925. case 2:
  926. {
  927. _pressed = False;
  928. _redraw ( );
  929. _win->raise ( );
  930. break;
  931. }
  932. }
  933. break;
  934. }
  935. case MotionNotify:
  936. {
  937. XsMoveOutline move (_win->base ( ));
  938. // Start the move
  939. if (move.go ( ) != False)
  940. {
  941. // Relocate the window
  942. _win->setPosition (move.x ( ), move.y ( ));
  943. // Redraw the title bar
  944. _pressed = False;
  945. _redraw ( );
  946. }
  947. break;
  948. }
  949. }
  950. }
  951. // _map
  952. void _XsMotifTitle::_map ( )
  953. {
  954. // Call the base-class
  955. _XsMotifComponent::_map ( );
  956. // Raise ourself
  957. XRaiseWindow (XtDisplay (_base), XtWindow (_base));
  958. unsigned long valuemask;
  959. XGCValues values;
  960. Pixel foreground;
  961. Pixel background;
  962. // Get the pixels
  963. XtVaGetValues (_win->base ( ), XmNforeground, &foreground, XmNbackground, &background, NULL);
  964. // Create the font graphics context
  965. valuemask = GCForeground | GCBackground | GCGraphicsExposures | GCFont;
  966. values.foreground = foreground;
  967. values.background = background;
  968. values.font = _titleFont->fid;
  969. values.graphics_exposures = False;
  970. _fontGC = XtGetGC (_base, valuemask, &values);
  971. }
  972. // _configure
  973. void _XsMotifTitle::_configure (XEvent *event)
  974. {
  975. XConfigureEvent *ce = (XConfigureEvent*)event;
  976. /*
  977. Check if window has been resized. If so, generate an expose event
  978. to redraw its contents.
  979. */
  980. if ((_lastW != ce->width) || (_lastH != ce->height))
  981. {
  982. if ((_base != 0) && XtIsManaged (_base))
  983. XClearArea (XtDisplay (_base), XtWindow (_base), 0, 0, 0, 0, True);
  984. _lastW = ce->width;
  985. _lastH = ce->height;
  986. }
  987. }
  988. // _configureEventHandler
  989. void _XsMotifTitle::_configureEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*)
  990. {
  991. if (event->type == ConfigureNotify)
  992. {
  993. _XsMotifTitle *obj = (_XsMotifTitle*)clientData;
  994. obj->_configure (event);
  995. }
  996. }
  997. /*
  998. ----------------------------------------------------------------------------
  999. _XsMotifIcon
  1000. */
  1001. XtResource _XsMotifIcon::_resourceList[] = {
  1002. {
  1003. "iconSize",
  1004. "IconSize",
  1005. XmRDimension,
  1006. sizeof (Dimension),
  1007. XtOffset (_XsMotifIcon*, _iconSize),
  1008. XmRImmediate,
  1009. (XtPointer)IconSize_
  1010. },
  1011. {
  1012. "iconName",
  1013. "IconName",
  1014. XmRString,
  1015. sizeof (String),
  1016. XtOffset (_XsMotifIcon*, _iconName),
  1017. XmRImmediate,
  1018. NULL
  1019. },
  1020. {
  1021. "iconFont",
  1022. "IconFont",
  1023. XmRFontStruct,
  1024. sizeof (XFontStruct*),
  1025. XtOffset (_XsMotifIcon*, _iconFont),
  1026. XmRString,
  1027. "-*-helvetica-bold-r-normal-*-12-*-*-*-*-*-iso8859-1"
  1028. },
  1029. {
  1030. XmNiconX,
  1031. XmCIconX,
  1032. XmRPosition,
  1033. sizeof (Position),
  1034. XtOffset (_XsMotifIcon*, _iconX),
  1035. XmRImmediate,
  1036. (XtPointer)-1
  1037. },
  1038. {
  1039. XmNiconY,
  1040. XmCIconY,
  1041. XmRPosition,
  1042. sizeof (Position),
  1043. XtOffset (_XsMotifIcon*, _iconY),
  1044. XmRImmediate,
  1045. (XtPointer)-1
  1046. }
  1047. };
  1048. // Constructor
  1049. _XsMotifIcon::_XsMotifIcon (const char *name, XsMotifWindow *win, Widget parent) :
  1050. _XsMotifComponent (name, win, parent)
  1051. {
  1052. // Initialize
  1053. _pixmapGC = 0;
  1054. _fontGC = 0;
  1055. _iconName = 0;
  1056. _pixmap = 0;
  1057. _freePixmap = False;
  1058. _width = _height = 0;
  1059. _placed = 0;
  1060. // Get resources
  1061. _getResources (_resourceList, XtNumber (_resourceList));
  1062. // Copy icon name to local memory
  1063. if (_iconName != 0)
  1064. {
  1065. char *tmp = new char[strlen (_iconName) + 1];
  1066. strcpy (tmp, _iconName);
  1067. _iconName = tmp;
  1068. }
  1069. // Configure the icon
  1070. XtVaSetValues (_base, XmNwidth, _iconSize, XmNheight, _iconSize, NULL);
  1071. }
  1072. // Destructor
  1073. _XsMotifIcon::~_XsMotifIcon ( )
  1074. {
  1075. if (_fontGC)
  1076. XtReleaseGC (_base, _fontGC);
  1077. if (_pixmapGC)
  1078. XtReleaseGC (_base, _pixmapGC);
  1079. if (_freePixmap)
  1080. XFreePixmap (XtDisplay (_base), _pixmap);
  1081. delete [] _iconName;
  1082. }
  1083. // show
  1084. void _XsMotifIcon::show ( )
  1085. {
  1086. /*
  1087. Configure the icon position. Either use the position specified
  1088. in the resource, or place the icon at the top-left corner of the
  1089. window.
  1090. */
  1091. if (_placed == False)
  1092. {
  1093. Position x, y;
  1094. if (_iconX == -1)
  1095. {
  1096. XtVaGetValues (_win->base ( ), XmNx, &x, NULL);
  1097. if (x < 0) x = 0;
  1098. _iconX = x;
  1099. }
  1100. else
  1101. x = _iconX;
  1102. if (_iconY == -1)
  1103. {
  1104. XtVaGetValues (_win->base ( ), XmNy, &y, NULL);
  1105. if (y < 0) y = 0;
  1106. _iconY = y;
  1107. }
  1108. else
  1109. y = _iconY;
  1110. XtVaSetValues (_base, XmNx, x, XmNy, y, NULL);
  1111. _placed = True;
  1112. }
  1113. // Call the base class
  1114. _XsMotifComponent::show ( );
  1115. }
  1116. // setIconName
  1117. void _XsMotifIcon::setIconName (const char *iconName)
  1118. {
  1119. assert (iconName != 0);
  1120. delete [] _iconName;
  1121. _iconName = new char[strlen (iconName) + 1];
  1122. strcpy (_iconName, iconName);
  1123. }
  1124. // setPixmap
  1125. void _XsMotifIcon::setPixmap (Pixmap pixmap)
  1126. {
  1127. assert (pixmap != 0);
  1128. // Free the existing pixmap (if necessary)
  1129. if (_freePixmap)
  1130. {
  1131. XFreePixmap (XtDisplay (_base), _pixmap);
  1132. _freePixmap = False;
  1133. }
  1134. // Save the new pixmap
  1135. _pixmap = pixmap;
  1136. // Get the pixmap width and height
  1137. Window dummy;
  1138. int xd, yd;
  1139. unsigned int uw, uh, ub, ud;
  1140. XGetGeometry (XtDisplay (_base), _pixmap, &dummy, &xd, &yd, &uw, &uh, &ub, &ud);
  1141. _width = uw;
  1142. _height = uh;
  1143. }
  1144. // className
  1145. const char *_XsMotifIcon::className ( ) const
  1146. {
  1147. return ("_XsMotifIcon");
  1148. }
  1149. // _componentDestroyed
  1150. void _XsMotifIcon::_componentDestroyed ( )
  1151. {
  1152. // Clear up the GCs
  1153. if (_fontGC)
  1154. XtReleaseGC (_base, _fontGC);
  1155. if (_pixmapGC)
  1156. XtReleaseGC (_base, _pixmapGC);
  1157. if (_freePixmap)
  1158. XFreePixmap (XtDisplay (_base), _pixmap);
  1159. _fontGC = 0;
  1160. _pixmapGC = 0;
  1161. _freePixmap = 0;
  1162. // Call the base-class
  1163. _XsMotifComponent::_componentDestroyed ( );
  1164. }
  1165. // _input
  1166. void _XsMotifIcon::_input (XEvent *event)
  1167. {
  1168. static Time lastTime = (Time)0;
  1169. switch (event->type)
  1170. {
  1171. case ButtonPress:
  1172. {
  1173. switch (event->xbutton.button)
  1174. {
  1175. case 1:
  1176. break;
  1177. case 2:
  1178. {
  1179. XsMoveOutline move (_base);
  1180. // Start the move
  1181. if (move.go ( ) != False)
  1182. {
  1183. // Relocate the window
  1184. _win->setPosition (move.x ( ), move.y ( ));
  1185. }
  1186. break;
  1187. }
  1188. case 3:
  1189. {
  1190. _win->popupMenu ( );
  1191. break;
  1192. }
  1193. }
  1194. break;
  1195. }
  1196. case ButtonRelease:
  1197. {
  1198. switch (event->xbutton.button)
  1199. {
  1200. case 1:
  1201. {
  1202. // Get double-click time
  1203. int multiClick = XtGetMultiClickTime (XtDisplay (_base));
  1204. // Check for double-click
  1205. if ((event->xbutton.time - lastTime) <= multiClick)
  1206. _win->restore ( );
  1207. else
  1208. {
  1209. lastTime = event->xbutton.time;
  1210. _win->raise ( );
  1211. }
  1212. break;
  1213. }
  1214. }
  1215. break;
  1216. }
  1217. case MotionNotify:
  1218. {
  1219. XsMoveOutline move (_base);
  1220. // Start the move
  1221. if (move.go ( ) != False)
  1222. {
  1223. // Relocate the icon
  1224. _win->setPosition (move.x ( ), move.y ( ));
  1225. }
  1226. break;
  1227. }
  1228. }
  1229. }
  1230. // _expose
  1231. void _XsMotifIcon::_expose (XEvent *)
  1232. {
  1233. if (_topShadowGC == 0) // JACS
  1234. return;
  1235. Dimension iconHeight;
  1236. Dimension iconWidth;
  1237. // Compute icon size
  1238. XtVaGetValues (_base, XmNwidth, &iconWidth, XmNheight, &iconHeight, NULL);
  1239. // Draw the shadow
  1240. _drawShadows (0, 0, iconWidth, iconHeight, 2);
  1241. // Figure out the icon string
  1242. const char *iconName = (_iconName != 0) ? _iconName : (_win->title ( ) != 0) ?
  1243. _win->title ( ) : _win->name ( );
  1244. const int fontX = 3;
  1245. const int fontY = 3;
  1246. if ((iconName != 0) && (iconName[0] != '\0'))
  1247. {
  1248. int textWidth;
  1249. int len = strlen (iconName);
  1250. // Compute the text size
  1251. textWidth = XTextWidth (_iconFont, iconName, len);
  1252. // Center the text in the bottom of the icon (or left-justify it)
  1253. int x, y;
  1254. if (textWidth <= (iconWidth - (fontX * 2)))
  1255. x = (iconWidth - (int)textWidth) / 2;
  1256. else
  1257. x = fontX;
  1258. y = (int)iconHeight - _iconFont->descent - fontY;
  1259. // Draw the string
  1260. XDrawString (XtDisplay (_base), XtWindow (_base), _fontGC,
  1261. x, y, iconName, len);
  1262. }
  1263. // Compute label size
  1264. int labelHeight = _iconFont->descent + _iconFont->ascent + (fontY * 2);
  1265. if (labelHeight >= (iconHeight - 6))
  1266. return;
  1267. // Draw the separator
  1268. int sepY = (iconHeight) - labelHeight;
  1269. _drawLine (1, sepY, iconWidth - 2, sepY, _bottomShadowGC);
  1270. _drawLine (1, sepY + 1, iconWidth - 2, sepY + 1, _topShadowGC);
  1271. // Draw the pixmap frame
  1272. const int frameX = 4;
  1273. const int frameY = 4;
  1274. if ((frameX + 6) >= sepY)
  1275. return;
  1276. int frameWidth = iconWidth - (frameX * 2);
  1277. int frameHeight = sepY - frameY - 2;
  1278. _drawShadows (frameX, frameY, frameWidth, frameHeight, 1, True);
  1279. frameWidth -= 2;
  1280. frameHeight -= 2;
  1281. _drawShadows (frameX + 1, frameY + 1, frameWidth, frameHeight, 1);
  1282. frameWidth -= 2;
  1283. frameHeight -= 2;
  1284. // Blit the pixmap
  1285. if (_pixmap != 0)
  1286. {
  1287. if ((frameWidth > 0) && (frameHeight > 0))
  1288. {
  1289. int origX, origY;
  1290. int drawW, drawH;
  1291. // Center the pixmap or top-left orient it
  1292. if (frameWidth > _width)
  1293. {
  1294. origX = (frameWidth - _width) / 2;
  1295. origX += frameX + 2;
  1296. drawW = _width;
  1297. }
  1298. else
  1299. {
  1300. origX = frameX + 2;
  1301. drawW = frameWidth;
  1302. }
  1303. if (frameHeight > _height)
  1304. {
  1305. origY = (frameHeight - _height) / 2;
  1306. origY += frameY + 2;
  1307. drawH = _height;
  1308. }
  1309. else
  1310. {
  1311. origY = frameY + 2;
  1312. drawH = frameHeight;
  1313. }
  1314. XCopyArea (XtDisplay (_base), _pixmap, XtWindow (_base), _pixmapGC,
  1315. 0, 0, drawW, drawH, origX, origY);
  1316. }
  1317. }
  1318. }
  1319. // _map
  1320. void _XsMotifIcon::_map ( )
  1321. {
  1322. unsigned long valuemask;
  1323. XGCValues values;
  1324. Pixel fg;
  1325. Pixel bg;
  1326. int depth;
  1327. // Call the base-class
  1328. _XsMotifComponent::_map ( );
  1329. // Get the icon pixels
  1330. XtVaGetValues (_win->base ( ), XmNdepth, &depth, XmNbackground, &bg,
  1331. XmNforeground, &fg, NULL);
  1332. // Create the default icon pixmap
  1333. if (_pixmap == 0)
  1334. {
  1335. _pixmap = XCreatePixmapFromBitmapData (XtDisplay (_base), XtWindow (_base),
  1336. xs_motif_icon_bits, xs_motif_icon_width, xs_motif_icon_height,
  1337. fg, bg, depth);
  1338. // Set this pixmap
  1339. setPixmap (_pixmap);
  1340. _freePixmap = True;
  1341. // Create the icon pixmap graphics context
  1342. valuemask = GCGraphicsExposures | GCForeground | GCBackground;
  1343. values.graphics_exposures = False;
  1344. values.foreground = fg;
  1345. values.background = bg;
  1346. _pixmapGC = XtGetGC (_base, valuemask, &values);
  1347. }
  1348. // Create the font graphics context
  1349. valuemask = GCForeground | GCBackground | GCGraphicsExposures | GCFont;
  1350. values.foreground = fg;
  1351. values.background = bg;
  1352. values.font = _iconFont->fid;
  1353. values.graphics_exposures = False;
  1354. _fontGC = XtGetGC (_base, valuemask, &values);
  1355. }
  1356. /*
  1357. ----------------------------------------------------------------------------
  1358. _XsMotifMenu
  1359. */
  1360. // Static definitions
  1361. int _XsMotifMenu::_count = 0;
  1362. Cursor _XsMotifMenu::_cursor = None;
  1363. Pixmap _XsMotifMenu::_stipple = None;
  1364. Display *_XsMotifMenu::_dpy = 0;
  1365. // Resources
  1366. XtResource _XsMotifMenu::_resourceList[] = {
  1367. {
  1368. "saveUnder",
  1369. "SaveUnder",
  1370. XmRBoolean,
  1371. sizeof (Boolean),
  1372. XtOffset (_XsMotifMenu*, _saveUnder),
  1373. XmRImmediate,
  1374. (XtPointer)True
  1375. },
  1376. {
  1377. "restoreString",
  1378. "RestoreString",
  1379. XmRString,
  1380. sizeof (String),
  1381. XtOffset (_XsMotifMenu*, _strings[Restore]),
  1382. XmRString,
  1383. "Restore"
  1384. },
  1385. {
  1386. "moveString",
  1387. "MoveString",
  1388. XmRString,
  1389. sizeof (String),
  1390. XtOffset (_XsMotifMenu*, _strings[Move]),
  1391. XmRString,
  1392. "Move"
  1393. },
  1394. {
  1395. "sizeString",
  1396. "SizeString",
  1397. XmRString,
  1398. sizeof (String),
  1399. XtOffset (_XsMotifMenu*, _strings[Size]),
  1400. XmRString,
  1401. "Size"
  1402. },
  1403. {
  1404. "minimizeString",
  1405. "MinimizeString",
  1406. XmRString,
  1407. sizeof (String),
  1408. XtOffset (_XsMotifMenu*, _strings[Minimize]),
  1409. XmRString,
  1410. "Minimize"
  1411. },
  1412. {
  1413. "maximizeString",
  1414. "MaximizeString",
  1415. XmRString,
  1416. sizeof (String),
  1417. XtOffset (_XsMotifMenu*, _strings[Maximize]),
  1418. XmRString,
  1419. "Maximize"
  1420. },
  1421. {
  1422. "raiseString",
  1423. "RaiseString",
  1424. XmRString,
  1425. sizeof (String),
  1426. XtOffset (_XsMotifMenu*, _strings[Raise]),
  1427. XmRString,
  1428. "Raise"
  1429. },
  1430. {
  1431. "lowerString",
  1432. "LowerString",
  1433. XmRString,
  1434. sizeof (String),
  1435. XtOffset (_XsMotifMenu*, _strings[Lower]),
  1436. XmRString,
  1437. "Lower"
  1438. },
  1439. {
  1440. "closeString",
  1441. "CloseString",
  1442. XmRString,
  1443. sizeof (String),
  1444. XtOffset (_XsMotifMenu*, _strings[Close]),
  1445. XmRString,
  1446. "Close"
  1447. },
  1448. {
  1449. "menuFont",
  1450. "menuFont",
  1451. XmRFontStruct,
  1452. sizeof (XFontStruct*),
  1453. XtOffset (_XsMotifMenu*, _menuFont),
  1454. XmRString,
  1455. "-*-helvetica-bold-o-normal-*-14-*-*-*-*-*-iso8859-1"
  1456. }
  1457. };
  1458. // Constructor
  1459. _XsMotifMenu::_XsMotifMenu (const char *name, XsMotifWindow *win) :
  1460. _XsMotifBase (name, win)
  1461. {
  1462. // Create the cursor (if necessary)
  1463. if (_count++ == 0)
  1464. {
  1465. // Create the menu cursor
  1466. _cursor = XCreateFontCursor (XtDisplay (win->base ( )), XC_arrow);
  1467. // Create a stippled pixmap
  1468. Widget parent = _win->base ( );
  1469. Pixel foreground;
  1470. Pixel background;
  1471. int depth;
  1472. XtVaGetValues (parent, XmNforeground, &foreground, XmNbackground,
  1473. &background, XmNdepth, &depth, NULL);
  1474. const int pixmapWidth = 2;
  1475. const int pixmapHeight = 2;
  1476. static unsigned char pixmapBits[] = { 0x02, 0x01 };
  1477. _dpy = XtDisplay (parent);
  1478. _stipple = XCreatePixmapFromBitmapData (_dpy, DefaultRootWindow (_dpy),
  1479. (char*)pixmapBits, pixmapWidth, pixmapHeight, foreground, background,
  1480. depth);
  1481. }
  1482. // Initialize
  1483. _fontGC = 0;
  1484. _grayGC = 0;
  1485. _backgroundGC = 0;
  1486. // Create the component (why doesn't overrideShell work?)
  1487. _base = XtVaCreatePopupShell (_name, topLevelShellWidgetClass,
  1488. XtParent (_win->base ( )), XmNoverrideRedirect, True,
  1489. XmNborderWidth, 1, NULL);
  1490. // Install destroy handler
  1491. _installDestroyHandler ( );
  1492. // Install event handler ('cause we never call _XsMotifBase::show)
  1493. XtAddEventHandler (_base, StructureNotifyMask, False, _mapEventHandler, (XtPointer)this);
  1494. // Get resources
  1495. _getResources (_resourceList, XtNumber (_resourceList));
  1496. // Get the background color
  1497. Pixel bg;
  1498. XtVaGetValues (_win->base ( ), XmNbackground, &bg, NULL);
  1499. // Compute the size of the (largest) menu item
  1500. int textHeight = _menuFont->ascent + _menuFont->descent;
  1501. int textWidth = 0;
  1502. int tmp;
  1503. for (int loop = 0; loop < Num; loop++)
  1504. {
  1505. tmp = XTextWidth (_menuFont, _strings[loop], strlen (_strings[loop]));
  1506. if (tmp > textWidth)
  1507. textWidth = tmp;
  1508. }
  1509. // Put a border around the buttons
  1510. textWidth += (2 * HorizTextOffset);
  1511. textHeight += (2 * VertTextOffset);
  1512. /*
  1513. The menu height is the menu-shadow (1 pixel on top and bottom) + the
  1514. items themselves.
  1515. */
  1516. int menuHeight = (2 * ShadowThickness) + // Top and bottom shadow
  1517. (textHeight * Num); // The menu items
  1518. /*
  1519. The menu width is the menu-shadow (1 pixel on the left and right) +
  1520. the largest menu text (calculated above)
  1521. */
  1522. int menuWidth = (2 * ShadowThickness) + // Left and right shadow
  1523. textWidth; // Largest text item
  1524. // Configure the popup
  1525. XtVaSetValues (_base, XmNsaveUnder, _saveUnder, XmNwidth, menuWidth,
  1526. XmNheight, menuHeight, NULL);
  1527. }
  1528. // Destructor
  1529. _XsMotifMenu::~_XsMotifMenu ( )
  1530. {
  1531. if (_fontGC)
  1532. XtReleaseGC (_base, _fontGC);
  1533. if (_grayGC)
  1534. XtReleaseGC (_base, _grayGC);
  1535. if (_backgroundGC)
  1536. XtReleaseGC (_base, _backgroundGC);
  1537. // Free the pixmap (if necessary)
  1538. if (--_count == 0)
  1539. XFreePixmap (_dpy, _stipple);
  1540. }
  1541. // popup
  1542. void _XsMotifMenu::popup (Boolean atPointer)
  1543. {
  1544. assert (_base != 0);
  1545. Position x, y;
  1546. // Compute the location of the menu.
  1547. if (atPointer)
  1548. {
  1549. unsigned int mask;
  1550. Window win;
  1551. int winX, winY;
  1552. int rootX, rootY;
  1553. // Menu at pointer location
  1554. XQueryPointer (XtDisplay (_base), XtWindow (XtParent (_base)),
  1555. &win, &win, &rootX, &rootY, &winX, &winY, &mask);
  1556. x = (Position)rootX;
  1557. y = (Position)rootY;
  1558. }
  1559. else
  1560. {
  1561. // Menu at top-left corner of client area
  1562. XtTranslateCoords (_win->clientArea ( ), 0, 0, &x, &y);
  1563. }
  1564. // Move the menu
  1565. XtVaSetValues (_base, XmNx, x, XmNy, y, NULL);
  1566. // Initialize the item
  1567. _curItem = NoItem;
  1568. // Pop it up
  1569. XtPopup (_base, XtGrabNone);
  1570. // Grab the pointer
  1571. if (_grabPointer ( ) == FALSE)
  1572. return;
  1573. // Update the menu
  1574. _processEvents ( );
  1575. // Pop the menu down
  1576. XtPopdown (_base);
  1577. // Ungrab the pointer
  1578. _ungrabPointer ( );
  1579. if (_curItem != NoItem)
  1580. {
  1581. /*
  1582. Post a work-proc to process this item. This will allow everything
  1583. to get caught up before we process the menu item
  1584. */
  1585. XtAppContext appContext = XtWidgetToApplicationContext (_base);
  1586. XtAppAddWorkProc (appContext, _workProc, (XtPointer)this);
  1587. }
  1588. }
  1589. // className
  1590. const char *_XsMotifMenu::className ( ) const
  1591. {
  1592. return ("_XsMotifMenu");
  1593. }
  1594. // _componentDestroyed
  1595. void _XsMotifMenu::_componentDestroyed ( )
  1596. {
  1597. // Clean up the GCs
  1598. if (_fontGC)
  1599. XtReleaseGC (_base, _fontGC);
  1600. if (_grayGC)
  1601. XtReleaseGC (_base, _grayGC);
  1602. if (_backgroundGC)
  1603. XtReleaseGC (_base, _backgroundGC);
  1604. _fontGC = 0;
  1605. _grayGC = 0;
  1606. _backgroundGC = 0;
  1607. // Call the base-class
  1608. _XsMotifBase::_componentDestroyed ( );
  1609. }
  1610. // _processEvents
  1611. void _XsMotifMenu::_processEvents ( )
  1612. {
  1613. assert (_base != 0);
  1614. XtAppContext appContext = XtWidgetToApplicationContext (_base);
  1615. XEvent event;
  1616. Display *dpy = XtDisplay (_base);
  1617. int done = 0;
  1618. while (!done)
  1619. {
  1620. XtAppNextEvent (appContext, &event);
  1621. // Process this event
  1622. switch (event.type)
  1623. {
  1624. case ButtonRelease:
  1625. {
  1626. done = 1;
  1627. break;
  1628. }
  1629. case Expose:
  1630. {
  1631. _redrawMenu ( );
  1632. break;
  1633. }
  1634. case MotionNotify:
  1635. {
  1636. XEvent next;
  1637. // Process only the last motion event
  1638. while (XPending (dpy) > 0)
  1639. {
  1640. XPeekEvent (dpy, &next);
  1641. if (next.type != MotionNotify)
  1642. break;
  1643. XtAppNextEvent (appContext, &event);
  1644. }
  1645. // Track the mouse and toggle the menu items
  1646. Item item = _trackPointer ((XMotionEvent*)&event);
  1647. // Unselect the current item (if the item is different)
  1648. if (item != _curItem)
  1649. {
  1650. _toggleItem (_curItem, False);
  1651. // Select the new item
  1652. _toggleItem ((_curItem = item), True);
  1653. }
  1654. break;
  1655. }
  1656. default:
  1657. {
  1658. XtDispatchEvent (&event);
  1659. break;
  1660. }
  1661. }
  1662. }
  1663. }
  1664. // _processItem
  1665. void _XsMotifMenu::_processItem (Item item)
  1666. {
  1667. if (item == NoItem)
  1668. return;
  1669. switch (item)
  1670. {
  1671. case Restore:
  1672. {
  1673. _win->restore ( );
  1674. break;
  1675. }
  1676. case Move:
  1677. {
  1678. Widget base = (_win->minimized ( )) ? _win->icon ( ) : _win->base ( );
  1679. // Warp the pointer to the center of the window
  1680. Dimension width, height;
  1681. XtVaGetValues (base, XmNwidth, &width, XmNheight, &height, NULL);
  1682. XWarpPointer (XtDisplay (_base), None, XtWindow (base), 0, 0, 0, 0,
  1683. (width / 2), (height / 2));
  1684. // Move the window
  1685. XsMoveOutline move (base);
  1686. // Start the move
  1687. if (move.go (True) != False)
  1688. {
  1689. // Relocate the window
  1690. _win->setPosition (move.x ( ), move.y ( ));
  1691. }
  1692. break;
  1693. }
  1694. case Size:
  1695. {
  1696. Widget base = (_win->minimized ( )) ? _win->icon ( ) : _win->base ( );
  1697. // Warp the pointer to the center of the window
  1698. Dimension width, height;
  1699. XtVaGetValues (base, XmNwidth, &width, XmNheight, &height, NULL);
  1700. XWarpPointer (XtDisplay (_base), None, XtWindow (base), 0, 0, 0, 0,
  1701. (width / 2), (height / 2));
  1702. // Resize the window
  1703. XsResizeOutline resize (_win->base ( ), XsResizeOutline::Undetermined);
  1704. resize.setMinSize (_win->minWidth ( ), _win->minHeight ( ));
  1705. // Start the resize
  1706. if (resize.go (True) != False)
  1707. {
  1708. // Relocate the window
  1709. _win->setPosition (resize.x ( ), resize.y ( ));
  1710. _win->setSize (resize.width ( ), resize.height ( ));
  1711. }
  1712. break;
  1713. }
  1714. case Minimize:
  1715. {
  1716. _win->minimize ( );
  1717. break;
  1718. }
  1719. case Maximize:
  1720. {
  1721. _win->maximize ( );
  1722. break;
  1723. }
  1724. case Raise:
  1725. {
  1726. _win->raise ( );
  1727. break;
  1728. }
  1729. case Lower:
  1730. {
  1731. _win->lower ( );
  1732. break;
  1733. }
  1734. case Close:
  1735. {
  1736. _win->close ( );
  1737. break;
  1738. }
  1739. default:
  1740. assert (0);
  1741. }
  1742. }
  1743. // _redrawMenu
  1744. void _XsMotifMenu::_redrawMenu ( )
  1745. {
  1746. Dimension w, h;
  1747. // Get the size of the menu
  1748. XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL);
  1749. // Draw a shadow around the menu
  1750. _drawShadows (0, 0, w, h, ShadowThickness);
  1751. // Cycle and draw all of the elements
  1752. for (int loop = 0; loop < Num; loop++)
  1753. _redrawItem ((Item)loop);
  1754. }
  1755. // _redrawItem
  1756. void _XsMotifMenu::_redrawItem (Item item)
  1757. {
  1758. if (item == NoItem)
  1759. return;
  1760. int x = ShadowThickness + HorizTextOffset;
  1761. int y;
  1762. /*
  1763. Compute the y-position of the element. This will be the size of the
  1764. top-shadow + the items before it + the offset of the item itself
  1765. */
  1766. y = ShadowThickness + // Top shadow
  1767. (item * ((VertTextOffset * 2) + (_menuFont->descent + _menuFont->ascent))) +
  1768. (VertTextOffset + _menuFont->ascent); // The item iteself
  1769. // Figure out the graphics-context
  1770. GC gc;
  1771. if (_win->minimized ( ))
  1772. gc = ((item == Size) || (item == Minimize)) ? _grayGC : _fontGC;
  1773. else if (_win->maximized ( ))
  1774. gc = (item == Maximize) ? _grayGC : _fontGC;
  1775. else
  1776. gc = (item == Restore) ? _grayGC : _fontGC;
  1777. // Draw the string
  1778. XDrawString (XtDisplay (_base), XtWindow (_base), gc, x, y,
  1779. _strings[item], strlen (_strings[item]));
  1780. }
  1781. // _toggleItem
  1782. void _XsMotifMenu::_toggleItem (Item item, Boolean active)
  1783. {
  1784. if (item == NoItem)
  1785. return;
  1786. /*
  1787. Either draw the background of the specified item in the active color
  1788. or the standard background color
  1789. */
  1790. GC gc = (active) ? _to