]> git.saurik.com Git - wxWidgets.git/blob - src/motif/mdi/lib/XsMotifWindow.C
correct positioning of the control and removed workarounds for old MSW bugs
[wxWidgets.git] / src / motif / mdi / lib / XsMotifWindow.C
1 /*
2 Copyright (C) 1996 Scott W. Sadler
3 All rights reserved.
4 */
5
6 /*
7 XsMotifWindow.C
8
9 History
10 03-Mar-96 1.0; Scott W. Sadler (ssadler@cisco.com)
11 Created
12 */
13
14 // Includes
15
16 #include <assert.h>
17 #include <Xm/Form.h>
18 #include <Xm/RowColumn.h>
19 #include <Xm/SeparatoG.h>
20 #include <Xm/PushBG.h>
21 #include <X11/Shell.h>
22 #include <X11/cursorfont.h>
23 #include "XsMotifWindow.h"
24 #include "XsResizeOutline.h"
25 #include "XsMoveOutline.h"
26 #include "xs_motif_icon.xbm"
27
28 // Constants
29
30 const int BorderSize_ = 6;
31 const int ButtonSize_ = 23;
32 const int IconSize_ = 70;
33
34 /*
35 ----------------------------------------------------------------------------
36 _XsMotifBase
37 */
38
39 // Constructor
40
41 _XsMotifBase::_XsMotifBase (const char *name, XsMotifWindow *win) :
42 XsComponent (name)
43 {
44 assert (win != 0);
45
46 // Initialize
47
48 _win = win;
49 _topShadowGC = 0;
50 _bottomShadowGC = 0;
51 }
52
53 // Destructor
54
55 _XsMotifBase::~_XsMotifBase ( )
56 {
57 if (_topShadowGC)
58 XtReleaseGC (_base, _topShadowGC);
59
60 if (_bottomShadowGC)
61 XtReleaseGC (_base, _bottomShadowGC);
62 }
63
64 // show
65
66 void _XsMotifBase::show ( )
67 {
68 assert (_base != 0);
69
70 // Install event handler
71
72 XtAddEventHandler (_base, StructureNotifyMask, False, _mapEventHandler, (XtPointer)this);
73
74 // Call the base-class
75
76 XsComponent::show ( );
77 }
78
79 // className
80
81 const char* _XsMotifBase::className ( ) const
82 {
83 return ("_XsMotifBase");
84 }
85
86 // _componentDestroyed ( )
87
88 void _XsMotifBase::_componentDestroyed ( )
89 {
90
91 // Clean up the GCs
92
93 if (_topShadowGC)
94 XtReleaseGC (_base, _topShadowGC);
95
96 if (_bottomShadowGC)
97 XtReleaseGC (_base, _bottomShadowGC);
98
99 _topShadowGC = 0;
100 _bottomShadowGC = 0;
101
102 // Call the base-class
103
104 XsComponent::_componentDestroyed ( );
105 }
106
107 // _drawShadows
108
109 void _XsMotifBase::_drawShadows (Position x, Position y, Dimension width,
110 Dimension height, Dimension thick, Boolean reverse)
111 {
112 assert (_base != 0);
113 assert (thick > 0);
114
115 const int nsegs = 2;
116 XSegment segs[nsegs];
117 GC topShadowGC;
118 GC bottomShadowGC;
119
120 // Work out the graphics contexts
121
122 topShadowGC = (reverse == False) ? _topShadowGC : _bottomShadowGC;
123 bottomShadowGC = (reverse == False) ? _bottomShadowGC : _topShadowGC;
124
125 for (int loop = 0; loop < thick; loop++)
126 {
127
128 /*
129 TOP SHADOW DRAWING
130 */
131
132 // Across the top
133
134 segs[0].x1 = x + loop;
135 segs[0].y1 = y + loop;
136 segs[0].x2 = x + width - loop - 2;
137 segs[0].y2 = y + loop;
138
139 // Down the left side
140
141 segs[1].x1 = x + loop;
142 segs[1].y1 = y + loop + 1;
143 segs[1].x2 = x + loop;
144 segs[1].y2 = y + height - loop - 2;
145
146 XDrawSegments (XtDisplay (_base), XtWindow (_base), topShadowGC, segs, nsegs);
147
148 /*
149 BOTTOM SHADOW DRAWING
150 */
151
152 // Across the bottom
153
154 segs[0].x1 = x + loop;
155 segs[0].y1 = y + height - loop - 1;
156 segs[0].x2 = x + width - loop - 1;
157 segs[0].y2 = y + height - loop - 1;
158
159 // Down the right side
160
161 segs[1].x1 = x + width - loop - 1;
162 segs[1].y1 = y + loop;
163 segs[1].x2 = x + width - loop - 1;
164 segs[1].y2 = y + height - loop - 1;
165
166 XDrawSegments (XtDisplay (_base), XtWindow (_base), bottomShadowGC, segs, nsegs);
167 }
168 }
169
170 // _drawLine
171
172 void _XsMotifBase::_drawLine (Position x1, Position y1, Position x2, Position y2, GC &gc)
173 {
174 assert (_base != 0);
175 XDrawLine (XtDisplay (_base), XtWindow (_base), gc, x1, y1, x2, y2);
176 }
177
178 // _map
179
180 void _XsMotifBase::_map ( )
181 {
182
183 // Create the graphics contexts
184
185 unsigned long valuemask;
186 XGCValues values;
187 Pixel topShadow;
188 Pixel bottomShadow;
189
190 XtVaGetValues (_win->base ( ), XmNtopShadowColor, &topShadow, XmNbottomShadowColor,
191 &bottomShadow, NULL);
192
193 // Create the graphics contexts
194
195 valuemask = GCForeground | GCLineWidth | GCGraphicsExposures;
196 values.line_width = 0;
197 values.graphics_exposures = False;
198
199 values.foreground = topShadow;
200 _topShadowGC = XtGetGC (_base, valuemask, &values);
201
202 values.foreground = bottomShadow;
203 _bottomShadowGC = XtGetGC (_base, valuemask, &values);
204 }
205
206 // _mapEventHandler
207
208 void _XsMotifBase::_mapEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*)
209 {
210 if (event->type == MapNotify)
211 {
212 _XsMotifBase *obj = (_XsMotifBase*)clientData;
213 obj->_map ( );
214
215 // Remove the event handler
216
217 XtRemoveEventHandler (obj->_base, StructureNotifyMask, False, obj->_mapEventHandler, clientData);
218 }
219 }
220
221 /*
222 ----------------------------------------------------------------------------
223 _XsMotifComponent
224 */
225
226 Cursor _XsMotifComponent::_cursors[_XsMotifComponent::NumCursors];
227
228 int _XsMotifComponent::_mutex = 0;
229
230 XtResource _XsMotifComponent::_resourceList[] = {
231 {
232 "borderSize",
233 "BorderSize",
234 XmRDimension,
235 sizeof (Dimension),
236 XtOffset (_XsMotifComponent*, _borderSize),
237 XmRImmediate,
238 (XtPointer)BorderSize_
239 },
240 {
241 "buttonSize",
242 "ButtonSize",
243 XmRDimension,
244 sizeof (Dimension),
245 XtOffset (_XsMotifComponent*, _buttonSize),
246 XmRImmediate,
247 (XtPointer)ButtonSize_
248 }
249 };
250
251 // Constructor
252
253 _XsMotifComponent::_XsMotifComponent (const char *name, XsMotifWindow *win,
254 Widget parent) : _XsMotifBase (name, win)
255 {
256
257 // Create cursors (if necessary)
258
259 if (_mutex == 0)
260 {
261
262 Display *dpy = XtDisplay (win->base ( ));
263
264 _cursors[TopCursor] = XCreateFontCursor (dpy, XC_top_side);
265 _cursors[BottomCursor] = XCreateFontCursor (dpy, XC_bottom_side);
266 _cursors[LeftCursor] = XCreateFontCursor (dpy, XC_left_side);
267 _cursors[RightCursor] = XCreateFontCursor (dpy, XC_right_side);
268 _cursors[TopLeftCursor] = XCreateFontCursor (dpy, XC_top_left_corner);
269 _cursors[TopRightCursor] = XCreateFontCursor (dpy, XC_top_right_corner);
270 _cursors[BottomLeftCursor] = XCreateFontCursor (dpy, XC_bottom_left_corner);
271 _cursors[BottomRightCursor] = XCreateFontCursor (dpy, XC_bottom_right_corner);
272
273 _mutex = 1;
274 }
275
276 // Create the component
277
278 _base = XtVaCreateWidget (name, widgetClass, (parent != 0) ? parent : _win->base ( ), NULL);
279
280 // Install destroy handler
281
282 _installDestroyHandler ( );
283
284 // Get resources
285
286 _getResources (_resourceList, XtNumber (_resourceList));
287
288 // Compute the corner size
289
290 _cornerSize = _buttonSize + _borderSize;
291
292 // Install event handlers
293
294 XtAddEventHandler (_base, ExposureMask, False, _exposeEventHandler, (XtPointer)this);
295 XtAddEventHandler (_base, ButtonPressMask | ButtonReleaseMask | Button1MotionMask | Button2MotionMask, False, _inputEventHandler, (XtPointer)this);
296 }
297
298 // Destructor
299
300 _XsMotifComponent::~_XsMotifComponent ( )
301 {
302 // Empty
303 }
304
305 // className
306
307 const char* _XsMotifComponent::className ( ) const
308 {
309 return ("_XsMotifComponent");
310 }
311
312 // _input
313
314 void _XsMotifComponent::_input (XEvent*)
315 {
316 // Empty
317 }
318
319 // _exposeEventHandler
320
321 void _XsMotifComponent::_exposeEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*)
322 {
323 _XsMotifComponent *obj = (_XsMotifComponent*)clientData;
324
325 if (event->xexpose.count == 0)
326 obj->_expose (event);
327 }
328
329 // _inputEventHandler
330
331 void _XsMotifComponent::_inputEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*)
332 {
333 _XsMotifComponent *obj = (_XsMotifComponent*)clientData;
334 obj->_input (event);
335 }
336
337 /*
338 ----------------------------------------------------------------------------
339 _XsMotifCorner
340 */
341
342 // Constructor
343
344 _XsMotifCorner::_XsMotifCorner (const char *name, XsMotifWindow *win, Corner corner)
345 : _XsMotifComponent (name, win)
346 {
347
348 // Initialize
349
350 _corner = corner;
351
352 // Configure component
353
354 XtVaSetValues (_base, XmNwidth, _cornerSize, XmNheight, _cornerSize,
355 XmNborderWidth, (Dimension)0, NULL);
356 }
357
358 // Destructor
359
360 _XsMotifCorner::~_XsMotifCorner ( )
361 {
362 // Empty
363 }
364
365 // className
366
367 const char *_XsMotifCorner::className ( ) const
368 {
369 return ("_XsMotifCorner");
370 }
371
372 // _expose
373
374 void _XsMotifCorner::_expose (XEvent*)
375 {
376 Dimension w, h;
377
378 if (_topShadowGC == 0) // JACS
379 return;
380
381 // Get the size of the corner
382
383 XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL);
384
385 // Draw the shadow
386
387 _drawShadows (0, 0, w, h, 1);
388
389 // Draw the extra lines and relief
390
391 switch (_corner)
392 {
393 case TopLeft:
394 {
395 _drawLine (1, 1, w - 2, 1, _topShadowGC);
396 _drawLine (1, 1, 1, h - 2, _topShadowGC);
397
398 // Relief
399
400 _drawLine (_borderSize - 1, _borderSize - 1, _borderSize +
401 _buttonSize - 2, _borderSize - 1, _bottomShadowGC);
402
403 _drawLine (_borderSize - 1, _borderSize - 1, _borderSize - 1,
404 _borderSize + _buttonSize - 2, _bottomShadowGC);
405
406 break;
407 }
408 case TopRight:
409 {
410 _drawLine (1, 1, w - 2, 1, _topShadowGC);
411 _drawLine (w - 2, 1, w - 2, h - 2, _bottomShadowGC);
412
413 // Relief
414
415 _drawLine (0, _borderSize - 1, _buttonSize - 1, _borderSize - 1,
416 _bottomShadowGC);
417
418 _drawLine (w - _borderSize, _borderSize - 1, w - _borderSize,
419 _borderSize + _buttonSize - 2, _topShadowGC);
420
421 break;
422 }
423 case BottomLeft:
424 {
425 _drawLine (1, 1, 1, h - 2, _topShadowGC);
426 _drawLine (1, h - 2, w - 2, h - 2, _bottomShadowGC);
427
428 // Relief
429
430 _drawLine (_borderSize - 1, h - _borderSize, _borderSize +
431 _buttonSize - 2, h - _borderSize, _topShadowGC);
432
433 _drawLine (_borderSize - 1, 1, _borderSize - 1,
434 _buttonSize - 1, _bottomShadowGC);
435
436 break;
437 }
438 case BottomRight:
439 {
440 _drawLine (1, h - 2, w - 2, h - 2, _bottomShadowGC);
441 _drawLine (w - 2, 1, w - 2, h - 2, _bottomShadowGC);
442
443 // Relief
444
445 _drawLine (1, h - _borderSize, _buttonSize, h - _borderSize,
446 _topShadowGC);
447
448 _drawLine (w - _borderSize, 1, w - _borderSize,
449 _buttonSize - 1, _topShadowGC);
450
451 break;
452 }
453 default:
454 assert (0);
455 }
456 }
457
458 // _input
459
460 void _XsMotifCorner::_input (XEvent *event)
461 {
462 switch (event->type)
463 {
464 case ButtonPress:
465 {
466 if (event->xbutton.button == 2)
467 {
468 XsMoveOutline move (_win->base ( ));
469
470 // Start the move
471
472 if (move.go ( ) != False)
473 {
474
475 // Relocate the window
476
477 _win->setPosition (move.x ( ), move.y ( ));
478 }
479 }
480 else if (event->xbutton.button == 3)
481 _win->popupMenu ( );
482
483 break;
484 }
485 case ButtonRelease:
486 {
487 switch (event->xbutton.button)
488 {
489 case 1:
490 case 2:
491 {
492 _win->raise ( ); // Raise the window
493 break;
494 }
495 }
496 break;
497 }
498 case MotionNotify:
499 {
500
501 // Figure kind of resize we are doing
502
503 int dir;
504
505 if (_corner == TopLeft)
506 dir = XsResizeOutline::Up | XsResizeOutline::Left;
507 else if (_corner == TopRight)
508 dir = XsResizeOutline::Up | XsResizeOutline::Right;
509 else if (_corner == BottomLeft)
510 dir = XsResizeOutline::Down | XsResizeOutline::Left;
511 else if (_corner == BottomRight)
512 dir = XsResizeOutline::Down | XsResizeOutline::Right;
513 else
514 assert (0);
515
516 XsResizeOutline resize (_win->base ( ), dir);
517 resize.setMinSize (_win->minWidth ( ), _win->minHeight ( ));
518
519 // Start the resize
520
521 if (resize.go ( ) != False)
522 {
523
524 // Relocate the window
525
526 _win->setPosition (resize.x ( ), resize.y ( ));
527 _win->setSize (resize.width ( ), resize.height ( ));
528 }
529 break;
530 }
531 }
532 }
533
534 // _map
535
536 void _XsMotifCorner::_map ( )
537 {
538
539 // Call the base-class
540
541 _XsMotifComponent::_map ( );
542
543 // Install the cursor
544
545 if (_corner == TopLeft)
546 XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[TopLeftCursor]);
547 else if (_corner == TopRight)
548 XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[TopRightCursor]);
549 else if (_corner == BottomLeft)
550 XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[BottomLeftCursor]);
551 else if (_corner == BottomRight)
552 XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[BottomRightCursor]);
553 else
554 assert (0);
555 }
556
557 /*
558 ----------------------------------------------------------------------------
559 _XsMotifSide
560 */
561
562 // Constructor
563
564 _XsMotifSide::_XsMotifSide (const char *name, XsMotifWindow *win, Side side) :
565 _XsMotifComponent (name, win)
566 {
567
568 // Initialize
569
570 _side = side;
571 _lastW = _lastH = -1;
572
573 // Configure component
574
575 switch (_side)
576 {
577 case Top:
578 case Bottom:
579 {
580 XtVaSetValues (_base, XmNheight, _borderSize, XmNborderWidth,
581 (Dimension)0, NULL);
582 break;
583 }
584 case Left:
585 case Right:
586 {
587 XtVaSetValues (_base, XmNwidth, _borderSize, XmNborderWidth,
588 (Dimension)0, NULL);
589 break;
590 }
591 default:
592 assert (0);
593 }
594
595 // Install event handler
596
597 XtAddEventHandler (_base, StructureNotifyMask, False, _configureEventHandler, (XtPointer)this);
598 }
599
600 // Destructor
601
602 _XsMotifSide::~_XsMotifSide ( )
603 {
604 // Empty
605 }
606
607 // className
608
609 const char *_XsMotifSide::className ( ) const
610 {
611 return ("_XsMotifSide");
612 }
613
614 // _expose
615
616 void _XsMotifSide::_expose (XEvent *event)
617 {
618 if (_topShadowGC == 0) // JACS
619 return;
620
621 // Clear out the window first
622
623 if (event != 0)
624 XClearWindow (XtDisplay (_base), XtWindow (_base));
625
626 Dimension w, h;
627
628 // Get the size of the side
629
630 XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL);
631
632 // Draw the shadow
633
634 _drawShadows (0, 0, w, h, 1);
635
636 // Draw the extra lines
637
638 switch (_side)
639 {
640 case Top:
641 {
642 _drawLine (1, 1, w - 2, 1, _topShadowGC);
643 break;
644 }
645 case Bottom:
646 {
647 _drawLine (1, h - 2, w - 2, h - 2, _bottomShadowGC);
648 break;
649 }
650 case Left:
651 {
652 _drawLine (1, 1, 1, h - 2, _topShadowGC);
653 break;
654 }
655 case Right:
656 {
657 _drawLine (w - 2, 1, w - 2, h - 2, _bottomShadowGC);
658 break;
659 }
660 default:
661 assert (0);
662 }
663 }
664
665 // _input
666
667 void _XsMotifSide::_input (XEvent *event)
668 {
669 switch (event->type)
670 {
671 case ButtonPress:
672 {
673 if (event->xbutton.button == 2)
674 {
675 XsMoveOutline move (_win->base ( ));
676
677 // Start the move
678
679 if (move.go ( ) != False)
680 {
681
682 // Relocate the window
683
684 _win->setPosition (move.x ( ), move.y ( ));
685 }
686 }
687 else if (event->xbutton.button == 3)
688 _win->popupMenu ( );
689
690 break;
691 }
692 case ButtonRelease:
693 {
694 switch (event->xbutton.button)
695 {
696 case 1:
697 case 2:
698 {
699 _win->raise ( ); // Raise the window
700 break;
701 }
702 }
703 break;
704 }
705 case MotionNotify:
706 {
707
708 // Figure kind of resize we are doing
709
710 int dir;
711
712 if (_side == Top)
713 dir = XsResizeOutline::Up;
714 else if (_side == Bottom)
715 dir = XsResizeOutline::Down;
716 else if (_side == Left)
717 dir = XsResizeOutline::Left;
718 else if (_side == Right)
719 dir = XsResizeOutline::Right;
720 else
721 assert (0);
722
723 XsResizeOutline resize (_win->base ( ), dir);
724 resize.setMinSize (_win->minWidth ( ), _win->minHeight ( ));
725
726 // Start the resize
727
728 if (resize.go ( ) != False)
729 {
730
731 // Relocate the window
732
733 _win->setPosition (resize.x ( ), resize.y ( ));
734 _win->setSize (resize.width ( ), resize.height ( ));
735 }
736 break;
737 }
738 }
739 }
740
741 // _map
742
743 void _XsMotifSide::_map ( )
744 {
745
746 // Call the base-class
747
748 _XsMotifComponent::_map ( );
749
750 // Install the cursor
751
752 if (_side == Top)
753 XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[TopCursor]);
754 else if (_side == Bottom)
755 XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[BottomCursor]);
756 else if (_side == Left)
757 XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[LeftCursor]);
758 else if (_side == Right)
759 XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[RightCursor]);
760 else
761 assert (0);
762 }
763
764 // _configure
765
766 void _XsMotifSide::_configure (XEvent *event)
767 {
768 XConfigureEvent *ce = (XConfigureEvent*)event;
769
770 /*
771 Check if window has been resized. If so, generate an expose event
772 to redraw its contents.
773 */
774
775 if ((_lastW != ce->width) || (_lastH != ce->height))
776 {
777 if ((_base != 0) && XtIsManaged (_base))
778 XClearArea (XtDisplay (_base), XtWindow (_base), 0, 0, 0, 0, True);
779
780 _lastW = ce->width;
781 _lastH = ce->height;
782 }
783 }
784
785 // _configureEventHandler
786
787 void _XsMotifSide::_configureEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*)
788 {
789 if (event->type == ConfigureNotify)
790 {
791 _XsMotifSide *obj = (_XsMotifSide*)clientData;
792 obj->_configure (event);
793 }
794 }
795
796 /*
797 ----------------------------------------------------------------------------
798 _XsMotifButton
799 */
800
801 // Constructor
802
803 _XsMotifButton::_XsMotifButton (const char *name, XsMotifWindow *win, Button button) :
804 _XsMotifComponent (name, win)
805 {
806
807 // Initialize
808
809 _pressed = False;
810 _button = button;
811
812 // Configure the component
813
814 XtVaSetValues (_base, XmNheight, _buttonSize, XmNwidth, _buttonSize,
815 XmNborderWidth, (Dimension)0, NULL);
816 }
817
818 // Destructor
819
820 _XsMotifButton::~_XsMotifButton ( )
821 {
822 // Empty
823 }
824
825 // redraw
826
827 void _XsMotifButton::redraw ( )
828 {
829
830 // Make sure component is viewable
831
832 if (!XtIsRealized (_base))
833 return;
834
835 // Check if window is viewable
836
837 XWindowAttributes attrs;
838 XGetWindowAttributes (XtDisplay (_base), XtWindow (_base), &attrs);
839
840 if (attrs.map_state == IsViewable)
841 _expose (0); // Just pretend we got an expose event
842 }
843
844 // className
845
846 const char *_XsMotifButton::className ( ) const
847 {
848 return ("_XsMotifButton");
849 }
850
851 // _expose
852
853 void _XsMotifButton::_expose (XEvent *event)
854 {
855 if (_topShadowGC == 0) // JACS
856 return;
857
858 Dimension w, h;
859
860 // Get the size of the button
861
862 XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL);
863
864 // Draw the shadow
865
866 _drawShadows (0, 0, w, h, 1, _pressed);
867
868 // Draw the extra line
869
870 _drawLine (1, h - 2, w - 2, h - 2, (_pressed) ? _topShadowGC : _bottomShadowGC);
871
872 // Check if we need to draw the decal
873
874 if ((_button != Maximize) && (event == 0))
875 return;
876
877 // Compute the decal size
878
879 Dimension dw, dh;
880 Boolean reverse = False;
881
882 switch (_button)
883 {
884 case Menu:
885 {
886 dw = _buttonSize - 6;
887 dh = 4;
888 break;
889 }
890 case Minimize:
891 {
892 dw = dh = 4;
893 break;
894 }
895 case Maximize:
896 {
897 dw = _buttonSize - 6;
898 dh = dw - 1;
899
900 if (_win->maximized ( ))
901 reverse = True;
902
903 break;
904 }
905 default:
906 assert (0);
907 }
908
909 // Draw the decal
910
911 _drawShadows ((w / 2) - (dw / 2), (h / 2) - (dh / 2), dw, dh, 1, reverse);
912 }
913
914 // _input
915
916 void _XsMotifButton::_input (XEvent *event)
917 {
918 static Time lastTime = (Time)0;
919
920 switch (event->type)
921 {
922 case ButtonPress:
923 {
924 if (event->xbutton.button == 1)
925 {
926 _pressed = True;
927
928 if (_button == Menu)
929 {
930
931 // Get double-click time
932
933 int multiClick = XtGetMultiClickTime (XtDisplay (_base));
934
935 // Check for double-click
936
937 if ((event->xbutton.time - lastTime) <= multiClick)
938 {
939 _win->close ( );
940 return;
941 }
942 else
943 lastTime = event->xbutton.time;
944
945 // Redraw the button (pushed-in)
946
947 redraw ( );
948
949 // Popup the menu
950
951 _win->popupMenu (False);
952
953 // The menu will consume the ButtonRelease, so fake one
954
955 _pressed = False;
956 redraw ( );
957
958 }
959 else if ((_button == Minimize) || (_button == Maximize))
960 {
961 redraw ( );
962 }
963 }
964 else if (event->xbutton.button == 2)
965 {
966 XsMoveOutline move (_win->base ( ));
967
968 // Start the move
969
970 if (move.go ( ) != False)
971 {
972
973 // Relocate the window
974
975 _win->setPosition (move.x ( ), move.y ( ));
976 }
977 }
978 else if (event->xbutton.button == 3)
979 _win->popupMenu ( );
980
981 break;
982 }
983 case ButtonRelease:
984 {
985 if (event->xbutton.button == 1)
986 {
987 _pressed = False;
988
989 // Check if pointer is really in the window
990
991 XButtonEvent *b = &event->xbutton;
992 Dimension width, height;
993 Boolean inWindow = False;
994
995 XtVaGetValues (_base, XmNwidth, &width, XmNheight, &height, NULL);
996 if ((b->x >= 0) && (b->y >= 0) && (b->x < width) && (b->y < height))
997 inWindow = True;
998
999 if (_button == Minimize)
1000 {
1001 if (inWindow)
1002 {
1003 if (_win->minimized ( ))
1004 _win->restore ( );
1005 else
1006 _win->minimize ( );
1007 }
1008 else
1009 redraw ( );
1010 }
1011 else if (_button == Maximize)
1012 {
1013 if (inWindow)
1014 {
1015 if (_win->maximized ( ))
1016 _win->restore ( );
1017 else
1018 _win->maximize ( );
1019 }
1020 else
1021 redraw ( );
1022 }
1023 }
1024 break;
1025 }
1026 }
1027 }
1028
1029 // _map
1030
1031 void _XsMotifButton::_map ( )
1032 {
1033
1034 // Call the base-class
1035
1036 _XsMotifComponent::_map ( );
1037
1038 // Raise ourself
1039
1040 XRaiseWindow (XtDisplay (_base), XtWindow (_base));
1041 }
1042
1043 /*
1044 ----------------------------------------------------------------------------
1045 _XsMotifTitle
1046 */
1047
1048 XtResource _XsMotifTitle::_resourceList[] = {
1049 {
1050 "title",
1051 "Title",
1052 XmRString,
1053 sizeof (String),
1054 XtOffset (_XsMotifTitle*, _titleString),
1055 XmRImmediate,
1056 NULL
1057 },
1058 {
1059 "titleFont",
1060 "TitleFont",
1061 XmRFontStruct,
1062 sizeof (XFontStruct*),
1063 XtOffset (_XsMotifTitle*, _titleFont),
1064 XmRString,
1065 "-*-helvetica-bold-o-normal-*-14-*-*-*-*-*-iso8859-1"
1066 }
1067 };
1068
1069 // Constructor
1070
1071 _XsMotifTitle::_XsMotifTitle (const char *name, XsMotifWindow *win) :
1072 _XsMotifComponent (name, win)
1073 {
1074
1075 // Initialize
1076
1077 _pressed = False;
1078 _titleString = 0;
1079 _titleFont = 0;
1080 _fontGC = 0;
1081 _lastW = _lastH = -1;
1082
1083 // Get resources
1084
1085 _getResources (_resourceList, XtNumber (_resourceList));
1086
1087 // Copy title string to local memory
1088
1089 if (_titleString != 0)
1090 {
1091 char *tmp = new char[strlen (_titleString) + 1];
1092 strcpy (tmp, _titleString);
1093 _titleString = tmp;
1094 }
1095
1096 // Configure the title
1097
1098 XtVaSetValues (_base, XmNheight, _buttonSize, XmNborderWidth,
1099 (Dimension)0, NULL);
1100
1101 // Install event handler
1102
1103 XtAddEventHandler (_base, StructureNotifyMask, False, _configureEventHandler, (XtPointer)this);
1104 }
1105
1106 // Destructor
1107
1108 _XsMotifTitle::~_XsMotifTitle ( )
1109 {
1110 if (_fontGC)
1111 XtReleaseGC (_base, _fontGC);
1112
1113 delete [] _titleString;
1114 }
1115
1116 // setTitle
1117
1118 void _XsMotifTitle::setTitle (const char *title)
1119 {
1120 assert (title != 0);
1121
1122 delete [] _titleString;
1123
1124 _titleString = new char[strlen (title) + 1];
1125 strcpy (_titleString, title);
1126 }
1127
1128 // className
1129
1130 const char *_XsMotifTitle::className ( ) const
1131 {
1132 return ("_XsMotifTitle");
1133 }
1134
1135 // _componentDestroyed
1136
1137 void _XsMotifTitle::_componentDestroyed ( )
1138 {
1139
1140 // Clean up the GCs
1141
1142 if (_fontGC)
1143 XtReleaseGC (_base, _fontGC);
1144
1145 _fontGC = 0;
1146
1147 // Call base-class
1148
1149 _XsMotifComponent::_componentDestroyed ( );
1150 }
1151
1152 // _redraw
1153
1154 void _XsMotifTitle::_redraw ( )
1155 {
1156 _expose (0); // Just pretend we got an expose event
1157 }
1158
1159 // _expose
1160
1161 void _XsMotifTitle::_expose (XEvent *event)
1162 {
1163 if (_topShadowGC == 0) // JACS
1164 return;
1165
1166 // Clear out the window first
1167
1168 if (event != 0)
1169 XClearWindow (XtDisplay (_base), XtWindow (_base));
1170
1171 Dimension w, h;
1172
1173 // Get the size of the button
1174
1175 XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL);
1176
1177 // Draw the shadow
1178
1179 _drawShadows (0, 0, w, h, 1, _pressed);
1180
1181 // Draw the extra line
1182
1183 _drawLine (1, h - 2, w - 2, h - 2, (_pressed) ? _topShadowGC : _bottomShadowGC);
1184
1185 // If this is an artificial event, no need continuing
1186
1187 if (event == 0)
1188 return;
1189
1190 // Draw the text string
1191
1192 const int LeftOffset = 5;
1193 const int TopOffset = 2;
1194
1195 // Figure out the title
1196
1197 const char *title = (_titleString != 0) ? _titleString : _win->name ( );
1198
1199 if ((title != 0) && (title[0] != '\0'))
1200 {
1201 int len = strlen (title);
1202
1203 XDrawString (XtDisplay (_base), XtWindow (_base), _fontGC,
1204 LeftOffset, TopOffset + _titleFont->ascent, title, len);
1205 }
1206 }
1207
1208 // _input
1209
1210 void _XsMotifTitle::_input (XEvent *event)
1211 {
1212 switch (event->type)
1213 {
1214 case ButtonPress:
1215 {
1216 switch (event->xbutton.button)
1217 {
1218 case 1:
1219 {
1220 _pressed = True;
1221 _redraw ( );
1222 break;
1223 }
1224 case 2:
1225 {
1226 XsMoveOutline move (_win->base ( ));
1227
1228 // Start the move
1229
1230 if (move.go ( ) != False)
1231 {
1232
1233 // Relocate the window
1234
1235 _win->setPosition (move.x ( ), move.y ( ));
1236 }
1237 break;
1238 }
1239 case 3:
1240 {
1241 _win->popupMenu ( );
1242 break;
1243 }
1244 }
1245 break;
1246 }
1247 case ButtonRelease:
1248 {
1249 switch (event->xbutton.button)
1250 {
1251 case 1:
1252 case 2:
1253 {
1254 _pressed = False;
1255 _redraw ( );
1256
1257 _win->raise ( );
1258 break;
1259 }
1260 }
1261 break;
1262 }
1263 case MotionNotify:
1264 {
1265 XsMoveOutline move (_win->base ( ));
1266
1267 // Start the move
1268
1269 if (move.go ( ) != False)
1270 {
1271
1272 // Relocate the window
1273
1274 _win->setPosition (move.x ( ), move.y ( ));
1275
1276 // Redraw the title bar
1277
1278 _pressed = False;
1279 _redraw ( );
1280 }
1281 break;
1282 }
1283 }
1284 }
1285
1286 // _map
1287
1288 void _XsMotifTitle::_map ( )
1289 {
1290
1291 // Call the base-class
1292
1293 _XsMotifComponent::_map ( );
1294
1295 // Raise ourself
1296
1297 XRaiseWindow (XtDisplay (_base), XtWindow (_base));
1298
1299 unsigned long valuemask;
1300 XGCValues values;
1301 Pixel foreground;
1302 Pixel background;
1303
1304 // Get the pixels
1305
1306 XtVaGetValues (_win->base ( ), XmNforeground, &foreground, XmNbackground, &background, NULL);
1307
1308 // Create the font graphics context
1309
1310 valuemask = GCForeground | GCBackground | GCGraphicsExposures | GCFont;
1311
1312 values.foreground = foreground;
1313 values.background = background;
1314 values.font = _titleFont->fid;
1315 values.graphics_exposures = False;
1316
1317 _fontGC = XtGetGC (_base, valuemask, &values);
1318 }
1319
1320 // _configure
1321
1322 void _XsMotifTitle::_configure (XEvent *event)
1323 {
1324 XConfigureEvent *ce = (XConfigureEvent*)event;
1325
1326 /*
1327 Check if window has been resized. If so, generate an expose event
1328 to redraw its contents.
1329 */
1330
1331 if ((_lastW != ce->width) || (_lastH != ce->height))
1332 {
1333 if ((_base != 0) && XtIsManaged (_base))
1334 XClearArea (XtDisplay (_base), XtWindow (_base), 0, 0, 0, 0, True);
1335
1336 _lastW = ce->width;
1337 _lastH = ce->height;
1338 }
1339 }
1340
1341 // _configureEventHandler
1342
1343 void _XsMotifTitle::_configureEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*)
1344 {
1345 if (event->type == ConfigureNotify)
1346 {
1347 _XsMotifTitle *obj = (_XsMotifTitle*)clientData;
1348 obj->_configure (event);
1349 }
1350 }
1351
1352 /*
1353 ----------------------------------------------------------------------------
1354 _XsMotifIcon
1355 */
1356
1357 XtResource _XsMotifIcon::_resourceList[] = {
1358 {
1359 "iconSize",
1360 "IconSize",
1361 XmRDimension,
1362 sizeof (Dimension),
1363 XtOffset (_XsMotifIcon*, _iconSize),
1364 XmRImmediate,
1365 (XtPointer)IconSize_
1366 },
1367 {
1368 "iconName",
1369 "IconName",
1370 XmRString,
1371 sizeof (String),
1372 XtOffset (_XsMotifIcon*, _iconName),
1373 XmRImmediate,
1374 NULL
1375 },
1376 {
1377 "iconFont",
1378 "IconFont",
1379 XmRFontStruct,
1380 sizeof (XFontStruct*),
1381 XtOffset (_XsMotifIcon*, _iconFont),
1382 XmRString,
1383 "-*-helvetica-bold-r-normal-*-12-*-*-*-*-*-iso8859-1"
1384 },
1385 {
1386 XmNiconX,
1387 XmCIconX,
1388 XmRPosition,
1389 sizeof (Position),
1390 XtOffset (_XsMotifIcon*, _iconX),
1391 XmRImmediate,
1392 (XtPointer)-1
1393 },
1394 {
1395 XmNiconY,
1396 XmCIconY,
1397 XmRPosition,
1398 sizeof (Position),
1399 XtOffset (_XsMotifIcon*, _iconY),
1400 XmRImmediate,
1401 (XtPointer)-1
1402 }
1403 };
1404
1405 // Constructor
1406
1407 _XsMotifIcon::_XsMotifIcon (const char *name, XsMotifWindow *win, Widget parent) :
1408 _XsMotifComponent (name, win, parent)
1409 {
1410
1411 // Initialize
1412
1413 _pixmapGC = 0;
1414 _fontGC = 0;
1415
1416 _iconName = 0;
1417 _pixmap = 0;
1418 _freePixmap = False;
1419
1420 _width = _height = 0;
1421 _placed = 0;
1422
1423 // Get resources
1424
1425 _getResources (_resourceList, XtNumber (_resourceList));
1426
1427 // Copy icon name to local memory
1428
1429 if (_iconName != 0)
1430 {
1431 char *tmp = new char[strlen (_iconName) + 1];
1432 strcpy (tmp, _iconName);
1433 _iconName = tmp;
1434 }
1435
1436 // Configure the icon
1437
1438 XtVaSetValues (_base, XmNwidth, _iconSize, XmNheight, _iconSize, NULL);
1439 }
1440
1441 // Destructor
1442
1443 _XsMotifIcon::~_XsMotifIcon ( )
1444 {
1445 if (_fontGC)
1446 XtReleaseGC (_base, _fontGC);
1447
1448 if (_pixmapGC)
1449 XtReleaseGC (_base, _pixmapGC);
1450
1451 if (_freePixmap)
1452 XFreePixmap (XtDisplay (_base), _pixmap);
1453
1454 delete [] _iconName;
1455 }
1456
1457 // show
1458
1459 void _XsMotifIcon::show ( )
1460 {
1461
1462 /*
1463 Configure the icon position. Either use the position specified
1464 in the resource, or place the icon at the top-left corner of the
1465 window.
1466 */
1467
1468 if (_placed == False)
1469 {
1470 Position x, y;
1471
1472 if (_iconX == -1)
1473 {
1474 XtVaGetValues (_win->base ( ), XmNx, &x, NULL);
1475 if (x < 0) x = 0;
1476 _iconX = x;
1477 }
1478 else
1479 x = _iconX;
1480
1481 if (_iconY == -1)
1482 {
1483 XtVaGetValues (_win->base ( ), XmNy, &y, NULL);
1484 if (y < 0) y = 0;
1485 _iconY = y;
1486 }
1487 else
1488 y = _iconY;
1489
1490 XtVaSetValues (_base, XmNx, x, XmNy, y, NULL);
1491
1492 _placed = True;
1493 }
1494
1495 // Call the base class
1496
1497 _XsMotifComponent::show ( );
1498 }
1499
1500 // setIconName
1501
1502 void _XsMotifIcon::setIconName (const char *iconName)
1503 {
1504 assert (iconName != 0);
1505
1506 delete [] _iconName;
1507
1508 _iconName = new char[strlen (iconName) + 1];
1509 strcpy (_iconName, iconName);
1510 }
1511
1512 // setPixmap
1513
1514 void _XsMotifIcon::setPixmap (Pixmap pixmap)
1515 {
1516 assert (pixmap != 0);
1517
1518 // Free the existing pixmap (if necessary)
1519
1520 if (_freePixmap)
1521 {
1522 XFreePixmap (XtDisplay (_base), _pixmap);
1523 _freePixmap = False;
1524 }
1525
1526 // Save the new pixmap
1527
1528 _pixmap = pixmap;
1529
1530 // Get the pixmap width and height
1531
1532 Window dummy;
1533 int xd, yd;
1534 unsigned int uw, uh, ub, ud;
1535
1536 XGetGeometry (XtDisplay (_base), _pixmap, &dummy, &xd, &yd, &uw, &uh, &ub, &ud);
1537
1538 _width = uw;
1539 _height = uh;
1540 }
1541
1542 // className
1543
1544 const char *_XsMotifIcon::className ( ) const
1545 {
1546 return ("_XsMotifIcon");
1547 }
1548
1549 // _componentDestroyed
1550
1551 void _XsMotifIcon::_componentDestroyed ( )
1552 {
1553
1554 // Clear up the GCs
1555
1556 if (_fontGC)
1557 XtReleaseGC (_base, _fontGC);
1558
1559 if (_pixmapGC)
1560 XtReleaseGC (_base, _pixmapGC);
1561
1562 if (_freePixmap)
1563 XFreePixmap (XtDisplay (_base), _pixmap);
1564
1565 _fontGC = 0;
1566 _pixmapGC = 0;
1567 _freePixmap = 0;
1568
1569 // Call the base-class
1570
1571 _XsMotifComponent::_componentDestroyed ( );
1572 }
1573
1574 // _input
1575
1576 void _XsMotifIcon::_input (XEvent *event)
1577 {
1578 static Time lastTime = (Time)0;
1579
1580 switch (event->type)
1581 {
1582 case ButtonPress:
1583 {
1584 switch (event->xbutton.button)
1585 {
1586 case 1:
1587 break;
1588
1589 case 2:
1590 {
1591 XsMoveOutline move (_base);
1592
1593 // Start the move
1594
1595 if (move.go ( ) != False)
1596 {
1597
1598 // Relocate the window
1599
1600 _win->setPosition (move.x ( ), move.y ( ));
1601 }
1602 break;
1603 }
1604 case 3:
1605 {
1606 _win->popupMenu ( );
1607 break;
1608 }
1609 }
1610 break;
1611 }
1612 case ButtonRelease:
1613 {
1614 switch (event->xbutton.button)
1615 {
1616 case 1:
1617 {
1618
1619 // Get double-click time
1620
1621 int multiClick = XtGetMultiClickTime (XtDisplay (_base));
1622
1623 // Check for double-click
1624
1625 if ((event->xbutton.time - lastTime) <= multiClick)
1626 _win->restore ( );
1627 else
1628 {
1629 lastTime = event->xbutton.time;
1630 _win->raise ( );
1631 }
1632 break;
1633 }
1634 }
1635 break;
1636 }
1637 case MotionNotify:
1638 {
1639 XsMoveOutline move (_base);
1640
1641 // Start the move
1642
1643 if (move.go ( ) != False)
1644 {
1645
1646 // Relocate the icon
1647
1648 _win->setPosition (move.x ( ), move.y ( ));
1649 }
1650 break;
1651 }
1652 }
1653 }
1654
1655 // _expose
1656
1657 void _XsMotifIcon::_expose (XEvent *)
1658 {
1659 if (_topShadowGC == 0) // JACS
1660 return;
1661
1662 Dimension iconHeight;
1663 Dimension iconWidth;
1664
1665 // Compute icon size
1666
1667 XtVaGetValues (_base, XmNwidth, &iconWidth, XmNheight, &iconHeight, NULL);
1668
1669 // Draw the shadow
1670
1671 _drawShadows (0, 0, iconWidth, iconHeight, 2);
1672
1673 // Figure out the icon string
1674
1675 const char *iconName = (_iconName != 0) ? _iconName : (_win->title ( ) != 0) ?
1676 _win->title ( ) : _win->name ( );
1677
1678 const int fontX = 3;
1679 const int fontY = 3;
1680
1681 if ((iconName != 0) && (iconName[0] != '\0'))
1682 {
1683 int textWidth;
1684 int len = strlen (iconName);
1685
1686 // Compute the text size
1687
1688 textWidth = XTextWidth (_iconFont, iconName, len);
1689
1690 // Center the text in the bottom of the icon (or left-justify it)
1691
1692 int x, y;
1693
1694 if (textWidth <= (iconWidth - (fontX * 2)))
1695 x = (iconWidth - (int)textWidth) / 2;
1696 else
1697 x = fontX;
1698
1699 y = (int)iconHeight - _iconFont->descent - fontY;
1700
1701 // Draw the string
1702
1703 XDrawString (XtDisplay (_base), XtWindow (_base), _fontGC,
1704 x, y, iconName, len);
1705 }
1706
1707 // Compute label size
1708
1709 int labelHeight = _iconFont->descent + _iconFont->ascent + (fontY * 2);
1710
1711 if (labelHeight >= (iconHeight - 6))
1712 return;
1713
1714 // Draw the separator
1715
1716 int sepY = (iconHeight) - labelHeight;
1717
1718 _drawLine (1, sepY, iconWidth - 2, sepY, _bottomShadowGC);
1719 _drawLine (1, sepY + 1, iconWidth - 2, sepY + 1, _topShadowGC);
1720
1721 // Draw the pixmap frame
1722
1723 const int frameX = 4;
1724 const int frameY = 4;
1725
1726 if ((frameX + 6) >= sepY)
1727 return;
1728
1729 int frameWidth = iconWidth - (frameX * 2);
1730 int frameHeight = sepY - frameY - 2;
1731
1732 _drawShadows (frameX, frameY, frameWidth, frameHeight, 1, True);
1733
1734 frameWidth -= 2;
1735 frameHeight -= 2;
1736
1737 _drawShadows (frameX + 1, frameY + 1, frameWidth, frameHeight, 1);
1738
1739 frameWidth -= 2;
1740 frameHeight -= 2;
1741
1742 // Blit the pixmap
1743
1744 if (_pixmap != 0)
1745 {
1746 if ((frameWidth > 0) && (frameHeight > 0))
1747 {
1748 int origX, origY;
1749 int drawW, drawH;
1750
1751 // Center the pixmap or top-left orient it
1752
1753 if (frameWidth > _width)
1754 {
1755 origX = (frameWidth - _width) / 2;
1756 origX += frameX + 2;
1757 drawW = _width;
1758 }
1759 else
1760 {
1761 origX = frameX + 2;
1762 drawW = frameWidth;
1763 }
1764
1765 if (frameHeight > _height)
1766 {
1767 origY = (frameHeight - _height) / 2;
1768 origY += frameY + 2;
1769 drawH = _height;
1770 }
1771 else
1772 {
1773 origY = frameY + 2;
1774 drawH = frameHeight;
1775 }
1776
1777 XCopyArea (XtDisplay (_base), _pixmap, XtWindow (_base), _pixmapGC,
1778 0, 0, drawW, drawH, origX, origY);
1779 }
1780 }
1781 }
1782
1783 // _map
1784
1785 void _XsMotifIcon::_map ( )
1786 {
1787 unsigned long valuemask;
1788 XGCValues values;
1789 Pixel fg;
1790 Pixel bg;
1791 int depth;
1792
1793 // Call the base-class
1794
1795 _XsMotifComponent::_map ( );
1796
1797 // Get the icon pixels
1798
1799 XtVaGetValues (_win->base ( ), XmNdepth, &depth, XmNbackground, &bg,
1800 XmNforeground, &fg, NULL);
1801
1802 // Create the default icon pixmap
1803
1804 if (_pixmap == 0)
1805 {
1806 _pixmap = XCreatePixmapFromBitmapData (XtDisplay (_base), XtWindow (_base),
1807 xs_motif_icon_bits, xs_motif_icon_width, xs_motif_icon_height,
1808 fg, bg, depth);
1809
1810 // Set this pixmap
1811
1812 setPixmap (_pixmap);
1813
1814 _freePixmap = True;
1815
1816 // Create the icon pixmap graphics context
1817
1818 valuemask = GCGraphicsExposures | GCForeground | GCBackground;
1819
1820 values.graphics_exposures = False;
1821 values.foreground = fg;
1822 values.background = bg;
1823
1824 _pixmapGC = XtGetGC (_base, valuemask, &values);
1825 }
1826
1827 // Create the font graphics context
1828
1829 valuemask = GCForeground | GCBackground | GCGraphicsExposures | GCFont;
1830
1831 values.foreground = fg;
1832 values.background = bg;
1833 values.font = _iconFont->fid;
1834 values.graphics_exposures = False;
1835
1836 _fontGC = XtGetGC (_base, valuemask, &values);
1837 }
1838
1839 /*
1840 ----------------------------------------------------------------------------
1841 _XsMotifMenu
1842 */
1843
1844 // Static definitions
1845
1846 int _XsMotifMenu::_count = 0;
1847 Cursor _XsMotifMenu::_cursor = None;
1848 Pixmap _XsMotifMenu::_stipple = None;
1849 Display *_XsMotifMenu::_dpy = 0;
1850
1851 // Resources
1852
1853 XtResource _XsMotifMenu::_resourceList[] = {
1854 {
1855 "saveUnder",
1856 "SaveUnder",
1857 XmRBoolean,
1858 sizeof (Boolean),
1859 XtOffset (_XsMotifMenu*, _saveUnder),
1860 XmRImmediate,
1861 (XtPointer)True
1862 },
1863 {
1864 "restoreString",
1865 "RestoreString",
1866 XmRString,
1867 sizeof (String),
1868 XtOffset (_XsMotifMenu*, _strings[Restore]),
1869 XmRString,
1870 "Restore"
1871 },
1872 {
1873 "moveString",
1874 "MoveString",
1875 XmRString,
1876 sizeof (String),
1877 XtOffset (_XsMotifMenu*, _strings[Move]),
1878 XmRString,
1879 "Move"
1880 },
1881 {
1882 "sizeString",
1883 "SizeString",
1884 XmRString,
1885 sizeof (String),
1886 XtOffset (_XsMotifMenu*, _strings[Size]),
1887 XmRString,
1888 "Size"
1889 },
1890 {
1891 "minimizeString",
1892 "MinimizeString",
1893 XmRString,
1894 sizeof (String),
1895 XtOffset (_XsMotifMenu*, _strings[Minimize]),
1896 XmRString,
1897 "Minimize"
1898 },
1899 {
1900 "maximizeString",
1901 "MaximizeString",
1902 XmRString,
1903 sizeof (String),
1904 XtOffset (_XsMotifMenu*, _strings[Maximize]),
1905 XmRString,
1906 "Maximize"
1907 },
1908 {
1909 "raiseString",
1910 "RaiseString",
1911 XmRString,
1912 sizeof (String),
1913 XtOffset (_XsMotifMenu*, _strings[Raise]),
1914 XmRString,
1915 "Raise"
1916 },
1917 {
1918 "lowerString",
1919 "LowerString",
1920 XmRString,
1921 sizeof (String),
1922 XtOffset (_XsMotifMenu*, _strings[Lower]),
1923 XmRString,
1924 "Lower"
1925 },
1926 {
1927 "closeString",
1928 "CloseString",
1929 XmRString,
1930 sizeof (String),
1931 XtOffset (_XsMotifMenu*, _strings[Close]),
1932 XmRString,
1933 "Close"
1934 },
1935 {
1936 "menuFont",
1937 "menuFont",
1938 XmRFontStruct,
1939 sizeof (XFontStruct*),
1940 XtOffset (_XsMotifMenu*, _menuFont),
1941 XmRString,
1942 "-*-helvetica-bold-o-normal-*-14-*-*-*-*-*-iso8859-1"
1943 }
1944 };
1945
1946 // Constructor
1947
1948 _XsMotifMenu::_XsMotifMenu (const char *name, XsMotifWindow *win) :
1949 _XsMotifBase (name, win)
1950 {
1951
1952 // Create the cursor (if necessary)
1953
1954 if (_count++ == 0)
1955 {
1956
1957 // Create the menu cursor
1958
1959 _cursor = XCreateFontCursor (XtDisplay (win->base ( )), XC_arrow);
1960
1961 // Create a stippled pixmap
1962
1963 Widget parent = _win->base ( );
1964 Pixel foreground;
1965 Pixel background;
1966 int depth;
1967
1968 XtVaGetValues (parent, XmNforeground, &foreground, XmNbackground,
1969 &background, XmNdepth, &depth, NULL);
1970
1971 const int pixmapWidth = 2;
1972 const int pixmapHeight = 2;
1973 static unsigned char pixmapBits[] = { 0x02, 0x01 };
1974
1975 _dpy = XtDisplay (parent);
1976 _stipple = XCreatePixmapFromBitmapData (_dpy, DefaultRootWindow (_dpy),
1977 (char*)pixmapBits, pixmapWidth, pixmapHeight, foreground, background,
1978 depth);
1979 }
1980
1981 // Initialize
1982
1983 _fontGC = 0;
1984 _grayGC = 0;
1985 _backgroundGC = 0;
1986
1987 // Create the component (why doesn't overrideShell work?)
1988
1989 _base = XtVaCreatePopupShell (_name, topLevelShellWidgetClass,
1990 XtParent (_win->base ( )), XmNoverrideRedirect, True,
1991 XmNborderWidth, 1, NULL);
1992
1993 // Install destroy handler
1994
1995 _installDestroyHandler ( );
1996
1997 // Install event handler ('cause we never call _XsMotifBase::show)
1998
1999 XtAddEventHandler (_base, StructureNotifyMask, False, _mapEventHandler, (XtPointer)this);
2000
2001 // Get resources
2002
2003 _getResources (_resourceList, XtNumber (_resourceList));
2004
2005 // Get the background color
2006
2007 Pixel bg;
2008
2009 XtVaGetValues (_win->base ( ), XmNbackground, &bg, NULL);
2010
2011 // Compute the size of the (largest) menu item
2012
2013 int textHeight = _menuFont->ascent + _menuFont->descent;
2014 int textWidth = 0;
2015 int tmp;
2016
2017 for (int loop = 0; loop < Num; loop++)
2018 {
2019 tmp = XTextWidth (_menuFont, _strings[loop], strlen (_strings[loop]));
2020
2021 if (tmp > textWidth)
2022 textWidth = tmp;
2023 }
2024
2025 // Put a border around the buttons
2026
2027 textWidth += (2 * HorizTextOffset);
2028 textHeight += (2 * VertTextOffset);
2029
2030 /*
2031 The menu height is the menu-shadow (1 pixel on top and bottom) + the
2032 items themselves.
2033 */
2034
2035 int menuHeight = (2 * ShadowThickness) + // Top and bottom shadow
2036 (textHeight * Num); // The menu items
2037
2038 /*
2039 The menu width is the menu-shadow (1 pixel on the left and right) +
2040 the largest menu text (calculated above)
2041 */
2042
2043 int menuWidth = (2 * ShadowThickness) + // Left and right shadow
2044 textWidth; // Largest text item
2045
2046 // Configure the popup
2047
2048 XtVaSetValues (_base, XmNsaveUnder, _saveUnder, XmNwidth, menuWidth,
2049 XmNheight, menuHeight, NULL);
2050 }
2051
2052 // Destructor
2053
2054 _XsMotifMenu::~_XsMotifMenu ( )
2055 {
2056 if (_fontGC)
2057 XtReleaseGC (_base, _fontGC);
2058
2059 if (_grayGC)
2060 XtReleaseGC (_base, _grayGC);
2061
2062 if (_backgroundGC)
2063 XtReleaseGC (_base, _backgroundGC);
2064
2065 // Free the pixmap (if necessary)
2066
2067 if (--_count == 0)
2068 XFreePixmap (_dpy, _stipple);
2069 }
2070
2071 // popup
2072
2073 void _XsMotifMenu::popup (Boolean atPointer)
2074 {
2075 assert (_base != 0);
2076
2077 Position x, y;
2078
2079 // Compute the location of the menu.
2080
2081 if (atPointer)
2082 {
2083 unsigned int mask;
2084 Window win;
2085 int winX, winY;
2086 int rootX, rootY;
2087
2088 // Menu at pointer location
2089
2090 XQueryPointer (XtDisplay (_base), XtWindow (XtParent (_base)),
2091 &win, &win, &rootX, &rootY, &winX, &winY, &mask);
2092
2093 x = (Position)rootX;
2094 y = (Position)rootY;
2095 }
2096 else
2097 {
2098
2099 // Menu at top-left corner of client area
2100
2101 XtTranslateCoords (_win->clientArea ( ), 0, 0, &x, &y);
2102 }
2103
2104 // Move the menu
2105
2106 XtVaSetValues (_base, XmNx, x, XmNy, y, NULL);
2107
2108 // Initialize the item
2109
2110 _curItem = NoItem;
2111
2112 // Pop it up
2113
2114 XtPopup (_base, XtGrabNone);
2115
2116 // Grab the pointer
2117
2118 if (_grabPointer ( ) == FALSE)
2119 return;
2120
2121 // Update the menu
2122
2123 _processEvents ( );
2124
2125 // Pop the menu down
2126
2127 XtPopdown (_base);
2128
2129 // Ungrab the pointer
2130
2131 _ungrabPointer ( );
2132
2133 if (_curItem != NoItem)
2134 {
2135
2136 /*
2137 Post a work-proc to process this item. This will allow everything
2138 to get caught up before we process the menu item
2139 */
2140
2141 XtAppContext appContext = XtWidgetToApplicationContext (_base);
2142 XtAppAddWorkProc (appContext, _workProc, (XtPointer)this);
2143 }
2144 }
2145
2146 // className
2147
2148 const char *_XsMotifMenu::className ( ) const
2149 {
2150 return ("_XsMotifMenu");
2151 }
2152
2153 // _componentDestroyed
2154
2155 void _XsMotifMenu::_componentDestroyed ( )
2156 {
2157
2158 // Clean up the GCs
2159
2160 if (_fontGC)
2161 XtReleaseGC (_base, _fontGC);
2162
2163 if (_grayGC)
2164 XtReleaseGC (_base, _grayGC);
2165
2166 if (_backgroundGC)
2167 XtReleaseGC (_base, _backgroundGC);
2168
2169 _fontGC = 0;
2170 _grayGC = 0;
2171 _backgroundGC = 0;
2172
2173 // Call the base-class
2174
2175 _XsMotifBase::_componentDestroyed ( );
2176 }
2177
2178 // _processEvents
2179
2180 void _XsMotifMenu::_processEvents ( )
2181 {
2182 assert (_base != 0);
2183
2184 XtAppContext appContext = XtWidgetToApplicationContext (_base);
2185 XEvent event;
2186 Display *dpy = XtDisplay (_base);
2187 int done = 0;
2188
2189 while (!done)
2190 {
2191 XtAppNextEvent (appContext, &event);
2192
2193 // Process this event
2194
2195 switch (event.type)
2196 {
2197 case ButtonRelease:
2198 {
2199 done = 1;
2200 break;
2201 }
2202 case Expose:
2203 {
2204 _redrawMenu ( );
2205 break;
2206 }
2207 case MotionNotify:
2208 {
2209 XEvent next;
2210
2211 // Process only the last motion event
2212
2213 while (XPending (dpy) > 0)
2214 {
2215 XPeekEvent (dpy, &next);
2216 if (next.type != MotionNotify)
2217 break;
2218 XtAppNextEvent (appContext, &event);
2219 }
2220
2221 // Track the mouse and toggle the menu items
2222
2223 Item item = _trackPointer ((XMotionEvent*)&event);
2224
2225 // Unselect the current item (if the item is different)
2226
2227 if (item != _curItem)
2228 {
2229 _toggleItem (_curItem, False);
2230
2231 // Select the new item
2232
2233 _toggleItem ((_curItem = item), True);
2234 }
2235
2236 break;
2237 }
2238 default:
2239 {
2240 XtDispatchEvent (&event);
2241 break;
2242 }
2243 }
2244 }
2245 }
2246
2247 // _processItem
2248
2249 void _XsMotifMenu::_processItem (Item item)
2250 {
2251 if (item == NoItem)
2252 return;
2253
2254 switch (item)
2255 {
2256 case Restore:
2257 {
2258 _win->restore ( );
2259 break;
2260 }
2261 case Move:
2262 {
2263 Widget base = (_win->minimized ( )) ? _win->icon ( ) : _win->base ( );
2264
2265 // Warp the pointer to the center of the window
2266
2267 Dimension width, height;
2268 XtVaGetValues (base, XmNwidth, &width, XmNheight, &height, NULL);
2269
2270 XWarpPointer (XtDisplay (_base), None, XtWindow (base), 0, 0, 0, 0,
2271 (width / 2), (height / 2));
2272
2273 // Move the window
2274
2275 XsMoveOutline move (base);
2276
2277 // Start the move
2278
2279 if (move.go (True) != False)
2280 {
2281
2282 // Relocate the window
2283
2284 _win->setPosition (move.x ( ), move.y ( ));
2285 }
2286 break;
2287 }
2288 case Size:
2289 {
2290 Widget base = (_win->minimized ( )) ? _win->icon ( ) : _win->base ( );
2291
2292 // Warp the pointer to the center of the window
2293
2294 Dimension width, height;
2295 XtVaGetValues (base, XmNwidth, &width, XmNheight, &height, NULL);
2296
2297 XWarpPointer (XtDisplay (_base), None, XtWindow (base), 0, 0, 0, 0,
2298 (width / 2), (height / 2));
2299
2300 // Resize the window
2301
2302 XsResizeOutline resize (_win->base ( ), XsResizeOutline::Undetermined);
2303 resize.setMinSize (_win->minWidth ( ), _win->minHeight ( ));
2304
2305 // Start the resize
2306
2307 if (resize.go (True) != False)
2308 {
2309
2310 // Relocate the window
2311
2312 _win->setPosition (resize.x ( ), resize.y ( ));
2313 _win->setSize (resize.width ( ), resize.height ( ));
2314 }
2315 break;
2316 }
2317 case Minimize:
2318 {
2319 _win->minimize ( );
2320 break;
2321 }
2322 case Maximize:
2323 {
2324 _win->maximize ( );
2325 break;
2326 }
2327 case Raise:
2328 {
2329 _win->raise ( );
2330 break;
2331 }
2332 case Lower:
2333 {
2334 _win->lower ( );
2335 break;
2336 }
2337 case Close:
2338 {
2339 _win->close ( );
2340 break;
2341 }
2342 default:
2343 assert (0);
2344 }
2345 }
2346
2347 // _redrawMenu
2348
2349 void _XsMotifMenu::_redrawMenu ( )
2350 {
2351 Dimension w, h;
2352
2353 // Get the size of the menu
2354
2355 XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL);
2356
2357 // Draw a shadow around the menu
2358
2359 _drawShadows (0, 0, w, h, ShadowThickness);
2360
2361 // Cycle and draw all of the elements
2362
2363 for (int loop = 0; loop < Num; loop++)
2364 _redrawItem ((Item)loop);
2365 }
2366
2367 // _redrawItem
2368
2369 void _XsMotifMenu::_redrawItem (Item item)
2370 {
2371 if (item == NoItem)
2372 return;
2373
2374 int x = ShadowThickness + HorizTextOffset;
2375 int y;
2376
2377 /*
2378 Compute the y-position of the element. This will be the size of the
2379 top-shadow + the items before it + the offset of the item itself
2380 */
2381
2382 y = ShadowThickness + // Top shadow
2383 (item * ((VertTextOffset * 2) + (_menuFont->descent + _menuFont->ascent))) +
2384 (VertTextOffset + _menuFont->ascent); // The item iteself
2385
2386 // Figure out the graphics-context
2387
2388 GC gc;
2389
2390 if (_win->minimized ( ))
2391 gc = ((item == Size) || (item == Minimize)) ? _grayGC : _fontGC;
2392 else if (_win->maximized ( ))
2393 gc = (item == Maximize) ? _grayGC : _fontGC;
2394 else
2395 gc = (item == Restore) ? _grayGC : _fontGC;
2396
2397 // Draw the string
2398
2399 XDrawString (XtDisplay (_base), XtWindow (_base), gc, x, y,
2400 _strings[item], strlen (_strings[item]));
2401 }
2402
2403 // _toggleItem
2404
2405 void _XsMotifMenu::_toggleItem (Item item, Boolean active)
2406 {
2407 if (item == NoItem)
2408 return;
2409
2410 /*
2411 Either draw the background of the specified item in the active color
2412 or the standard background color
2413 */
2414
2415 GC gc = (active) ? _topShadowGC : _backgroundGC;
2416
2417 // Get the width of the menu
2418
2419 Dimension menuWidth;
2420 XtVaGetValues (_base, XmNwidth, &menuWidth, NULL);
2421
2422 // Compute the location and size of the rectangle
2423
2424 int x, y;
2425 unsigned int width, height;
2426
2427 x = ShadowThickness;
2428 height = ((VertTextOffset * 2) + (_menuFont->descent + _menuFont->ascent));
2429 y = ShadowThickness + (item * height);
2430 width = menuWidth - (2 * ShadowThickness);
2431
2432 // Draw the filled rectangle
2433
2434 XFillRectangle (XtDisplay (_base), XtWindow (_base), gc, x, y, width, height);
2435
2436 // Redraw the text
2437
2438 _redrawItem (item);
2439 }
2440
2441 // _trackPointer
2442
2443 _XsMotifMenu::Item _XsMotifMenu::_trackPointer (XMotionEvent *event)
2444 {
2445 assert (_base != 0);
2446
2447 Dimension menuWidth;
2448 Dimension menuHeight;
2449 Position x, y;
2450
2451 // Get the menu size and position
2452
2453 XtVaGetValues (_base, XmNwidth, &menuWidth, XmNheight, &menuHeight,
2454 XmNx, &x, XmNy, &y, NULL);
2455
2456 // Make sure the pointer is in the menu
2457
2458 if ((event->x_root < x) || (event->x_root > (x + menuWidth)))
2459 return (NoItem);
2460
2461 if ((event->y_root < y) || (event->y_root > (y + menuHeight)))
2462 return (NoItem);
2463
2464 // Make sure the pointer is on the confines of the shadow
2465
2466 if ((event->x < ShadowThickness) || (event->x > (menuWidth - (2 * ShadowThickness))))
2467 return (NoItem);
2468
2469 if ((event->y < ShadowThickness) || (event->y > (menuHeight - (2 * ShadowThickness))))
2470 return (NoItem);
2471
2472 /*
2473 Now we are just concerned with the y-position. Subtract off the
2474 shadow thickness to normalize the location
2475 */
2476
2477 int yPos = event->y - ShadowThickness;
2478
2479 // Compute which item the mouse is in
2480
2481 int itemHeight = (VertTextOffset * 2) + (_menuFont->descent + _menuFont->ascent);
2482
2483 Item item = (Item)(yPos / itemHeight);
2484
2485 // Validate that the item is not grayed-out
2486
2487 if (_win->minimized ( ))
2488 {
2489 if ((item == Size) || (item == Minimize))
2490 item = NoItem;
2491 }
2492 else if (_win->maximized ( ))
2493 {
2494 if (item == Maximize)
2495 item = NoItem;
2496 }
2497 else if (item == Restore)
2498 item = NoItem;
2499
2500 return (item);
2501 }
2502
2503 // _grabPointer
2504
2505 Boolean _XsMotifMenu::_grabPointer ( )
2506 {
2507
2508 // Sync everything up before being grabby
2509
2510 XSync (XtDisplay (_base), False);
2511
2512 // Grab the pointer
2513
2514 if (XGrabPointer (XtDisplay (_base), XtWindow (_base), False,
2515 (unsigned int)(ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
2516 EnterWindowMask | LeaveWindowMask), GrabModeAsync,
2517 GrabModeAsync, None, _cursor, CurrentTime) != GrabSuccess)
2518 {
2519 XBell (XtDisplay (_base), 100);
2520 return (False);
2521 }
2522
2523 return (True);
2524 }
2525
2526 // _ungrabPointer
2527
2528 void _XsMotifMenu::_ungrabPointer ( )
2529 {
2530
2531 // Ungrab the pointer
2532
2533 XUngrabPointer (XtDisplay (_base), CurrentTime);
2534
2535 // Sync everything back up
2536
2537 XSync (XtDisplay (_base), False);
2538 }
2539
2540 // _map
2541
2542 void _XsMotifMenu::_map ( )
2543 {
2544
2545 // Call the base-class
2546
2547 _XsMotifBase::_map ( );
2548
2549 unsigned long valuemask;
2550 XGCValues values;
2551 Pixel foreground;
2552 Pixel background;
2553
2554 // Get the pixels
2555
2556 XtVaGetValues (XtParent (_base), XmNforeground, &foreground, NULL);
2557 XtVaGetValues (_base, XmNbackground, &background, NULL);
2558
2559 // Create the font graphics context
2560
2561 valuemask = GCForeground | GCBackground | GCGraphicsExposures | GCFont;
2562
2563 values.foreground = foreground;
2564 values.background = background;
2565 values.font = _menuFont->fid;
2566 values.graphics_exposures = False;
2567
2568 _fontGC = XtGetGC (_base, valuemask, &values);
2569
2570 // Create the insensitive font graphics context
2571
2572 valuemask |= (GCFillStyle | GCTile);
2573
2574 values.fill_style = FillTiled;
2575 values.tile = _stipple;
2576
2577 _grayGC = XtGetGC (_base, valuemask, &values);
2578
2579 // Create the background contexts
2580
2581 valuemask = GCForeground | GCLineWidth | GCGraphicsExposures;
2582 values.line_width = 0;
2583 values.graphics_exposures = False;
2584 values.foreground = background;
2585
2586 _backgroundGC = XtGetGC (_base, valuemask, &values);
2587 }
2588
2589 // _workProc
2590
2591 Boolean _XsMotifMenu::_workProc (XtPointer clientData)
2592 {
2593 _XsMotifMenu *obj = (_XsMotifMenu*)clientData;
2594 if (obj->_curItem != NoItem)
2595 obj->_processItem (obj->_curItem);
2596
2597 return (True);
2598 }
2599
2600 /*
2601 ----------------------------------------------------------------------------
2602 XsMotifWindow
2603 */
2604
2605 // Static definitions
2606
2607 XtResource XsMotifWindow::_resourceList[] = {
2608 {
2609 "showBorder",
2610 "ShowBorder",
2611 XmRBoolean,
2612 sizeof (Boolean),
2613 XtOffset (XsMotifWindow*, _showBorder),
2614 XmRImmediate,
2615 (XtPointer)True
2616 },
2617 {
2618 "showResize",
2619 "ShowResize",
2620 XmRBoolean,
2621 sizeof (Boolean),
2622 XtOffset (XsMotifWindow*, _showResize),
2623 XmRImmediate,
2624 (XtPointer)True
2625 },
2626 {
2627 "showTitle",
2628 "ShowTitle",
2629 XmRBoolean,
2630 sizeof (Boolean),
2631 XtOffset (XsMotifWindow*, _showTitle),
2632 XmRImmediate,
2633 (XtPointer)True
2634 },
2635 {
2636 "showMenu",
2637 "ShowMenu",
2638 XmRBoolean,
2639 sizeof (Boolean),
2640 XtOffset (XsMotifWindow*, _showMenu),
2641 XmRImmediate,
2642 (XtPointer)True
2643 },
2644 {
2645 "showMinimize",
2646 "ShowMinimize",
2647 XmRBoolean,
2648 sizeof (Boolean),
2649 XtOffset (XsMotifWindow*, _showMinimize),
2650 XmRImmediate,
2651 (XtPointer)True
2652 },
2653 {
2654 "showMaximize",
2655 "ShowMaximize",
2656 XmRBoolean,
2657 sizeof (Boolean),
2658 XtOffset (XsMotifWindow*, _showMaximize),
2659 XmRImmediate,
2660 (XtPointer)True
2661 },
2662 {
2663 "lowerOnIconify",
2664 "LowerOnIconify",
2665 XmRBoolean,
2666 sizeof (Boolean),
2667 XtOffset (XsMotifWindow*, _lowerOnIconify),
2668 XmRImmediate,
2669 (XtPointer)False
2670 },
2671 {
2672 XmNminWidth,
2673 XmCMinWidth,
2674 XmRDimension,
2675 sizeof (Dimension),
2676 XtOffset (XsMotifWindow*, _minW),
2677 XmRImmediate,
2678 (XtPointer)((BorderSize_ + ButtonSize_) * 3)
2679 },
2680 {
2681 XmNmaxWidth,
2682 XmCMaxWidth,
2683 XmRDimension,
2684 sizeof (Dimension),
2685 XtOffset (XsMotifWindow*, _maxW),
2686 XmRImmediate,
2687 (XtPointer)-1
2688 },
2689 {
2690 XmNminHeight,
2691 XmCMinHeight,
2692 XmRDimension,
2693 sizeof (Dimension),
2694 XtOffset (XsMotifWindow*, _minH),
2695 XmRImmediate,
2696 (XtPointer)((BorderSize_ + ButtonSize_) * 3)
2697 },
2698 {
2699 XmNmaxHeight,
2700 XmCMaxHeight,
2701 XmRDimension,
2702 sizeof (Dimension),
2703 XtOffset (XsMotifWindow*, _maxH),
2704 XmRImmediate,
2705 (XtPointer)-1
2706 }
2707 };
2708
2709 // Constructor
2710
2711 XsMotifWindow::XsMotifWindow (const char *name) : XsMDIWindow (name)
2712 {
2713 int loop;
2714
2715 // Initialize
2716
2717 for (loop = 0; loop < _XsMotifSide::Max; loop++)
2718 {
2719 _corners[loop] = 0;
2720 _sides[loop] = 0;
2721 }
2722
2723 for (loop = 0; loop < _XsMotifButton::Max; loop++)
2724 _buttons[loop] = 0;
2725
2726 _title = 0;
2727 _icon = 0;
2728 _menu = 0;
2729
2730 _maximized = False;
2731 _minimized = False;
2732 }
2733
2734 // Destructor
2735
2736 XsMotifWindow::~XsMotifWindow ( )
2737 {
2738 int loop;
2739
2740 for (loop = 0; loop < _XsMotifSide::Max; loop++)
2741 {
2742 delete _corners[loop];
2743 delete _sides[loop];
2744 }
2745
2746 for (loop = 0; loop < _XsMotifButton::Max; loop++)
2747 delete _buttons[loop];
2748
2749 delete _title;
2750 delete _icon;
2751 delete _menu;
2752 }
2753
2754 // raise
2755
2756 void XsMotifWindow::raise ( )
2757 {
2758 Widget w = (_minimized == True) ? _icon->base ( ) : _base;
2759 assert (w != 0);
2760 XRaiseWindow (XtDisplay (w), XtWindow (w));
2761 }
2762
2763 // lower
2764
2765 void XsMotifWindow::lower ( )
2766 {
2767 Widget w = (_minimized == True) ? _icon->base ( ) : _base;
2768 assert (w != 0);
2769 XLowerWindow (XtDisplay (w), XtWindow (w));
2770 }
2771
2772 // minimize
2773
2774 void XsMotifWindow::minimize ( )
2775 {
2776 assert (_base != 0);
2777
2778 // Check if we are already minimized
2779
2780 if (_minimized == True)
2781 return;
2782
2783 // Minimize the window
2784
2785 hide ( );
2786
2787 _minimized = True;
2788
2789 // Lower (if necessary)
2790
2791 if (_lowerOnIconify)
2792 lower ( );
2793
2794 _icon->show ( );
2795 }
2796
2797 // maximize
2798
2799 void XsMotifWindow::maximize ( )
2800 {
2801 assert (_base != 0);
2802
2803 // Check if we are already in this state
2804
2805 if (_maximized == True)
2806 return;
2807
2808 // Restore (if necessary)
2809
2810 if (_minimized)
2811 restore ( );
2812
2813 // Save current dimensions
2814
2815 XtVaGetValues (_base, XmNx, &_savedX, XmNy, &_savedY, XmNwidth,
2816 &_savedWidth, XmNheight, &_savedHeight, NULL);
2817
2818 /*
2819 Constrain the new window size. The size of the maximized window
2820 is equal to the size of the current clip-window of the canvas.
2821 */
2822
2823 const Dimension offset = 5; // Border around max'd window
2824
2825 Widget clipWindow = XtParent (XtParent (_base));
2826 assert (clipWindow != 0);
2827 Dimension clipW, clipH;
2828 Window child;
2829 int newX, newY;
2830
2831 XtVaGetValues (clipWindow, XmNheight, &clipH, XmNwidth, &clipW, NULL);
2832
2833 // Add in offset
2834
2835 if (clipW > (offset * 2))
2836 clipW -= (offset * 2);
2837
2838 if (clipH > (offset * 2))
2839 clipH -= (offset * 2);
2840
2841 // Compute the new window position (map clip-window to work-area)
2842
2843 XTranslateCoordinates (XtDisplay (_base), XtWindow (clipWindow),
2844 XtWindow (XtParent (_base)), (int)offset, (int)offset,
2845 &newX, &newY, &child);
2846
2847 // Set new maximum dimensions
2848
2849 setPosition ((Position)newX, (Position)newY);
2850 setSize (clipW, clipH);
2851
2852 _maximized = True;
2853
2854 // Redraw the maximize button
2855
2856 _buttons[_XsMotifButton::Maximize]->redraw ( );
2857 }
2858
2859 // restore
2860
2861 void XsMotifWindow::restore ( )
2862 {
2863 assert (_base != 0);
2864
2865 // Check if we are already restored
2866
2867 if ((_maximized == False) && (_minimized == False))
2868 return;
2869
2870 // Either un-minimize or un-maximize
2871
2872 if (_minimized)
2873 {
2874
2875 // Restore the window
2876
2877 _icon->hide ( );
2878 _minimized = False;
2879
2880 // If maximized, restore again
2881
2882 if (_maximized)
2883 restore ( );
2884
2885 // Show the window
2886
2887 show ( );
2888 }
2889 else
2890 {
2891
2892 // Restore saved dimensions
2893
2894 setPosition (_savedX, _savedY);
2895 setSize (_savedWidth, _savedHeight);
2896 }
2897 }
2898
2899 // close
2900
2901 void XsMotifWindow::close ( )
2902 {
2903
2904 /*
2905 Don't delete the window (because its not ours to delete).
2906 Just hide it.
2907 */
2908
2909 if (_minimized)
2910 _icon->hide ( );
2911 else
2912 hide ( );
2913 }
2914
2915 // setTitle
2916
2917 void XsMotifWindow::setTitle (const char *title)
2918 {
2919 if (_title != 0)
2920 _title->setTitle (title);
2921 }
2922
2923 // setIconName
2924
2925 void XsMotifWindow::setIconName (const char *iconName)
2926 {
2927 if (_icon != 0)
2928 _icon->setIconName (iconName);
2929 }
2930
2931 // setPixmap
2932
2933 void XsMotifWindow::setPixmap (Pixmap pixmap)
2934 {
2935 if (_icon != 0)
2936 _icon->setPixmap (pixmap);
2937 }
2938
2939 // popupMenu
2940
2941 void XsMotifWindow::popupMenu (Boolean b)
2942 {
2943 if (_menu != 0)
2944 _menu->popup (b);
2945 }
2946
2947 // setPosition
2948
2949 void XsMotifWindow::setPosition (Position x, Position y)
2950 {
2951 if (_base != 0)
2952 {
2953 Widget w = (_minimized == True) ? _icon->base ( ) : _base;
2954 assert (w != 0);
2955 XtVaSetValues (w, XmNx, x, XmNy, y, NULL);
2956 }
2957 else
2958 XsMDIWindow::setPosition (x, y); // Cache the points
2959 }
2960
2961 // setSize
2962
2963 void XsMotifWindow::setSize (Dimension w, Dimension h)
2964 {
2965
2966 // Set the window size
2967
2968 if (_base != 0)
2969 {
2970 if (w < _minW)
2971 w = _minW;
2972 else if ((_maxW != (Dimension)-1) && (w > _maxW))
2973 w = _maxW;
2974
2975 if (h < _minH)
2976 h = _minH;
2977 else if ((_maxH != (Dimension)-1) && (h > _maxH))
2978 h = _maxH;
2979
2980 if (_minimized == False)
2981 XtVaSetValues (_base, XmNwidth, w, XmNheight, h, NULL);
2982
2983 // If window was maximized, change the window state back to normal
2984
2985 if (_maximized == True)
2986 {
2987 _maximized = False;
2988
2989 // Redraw the maximize button
2990
2991 _buttons[_XsMotifButton::Maximize]->redraw ( );
2992 }
2993 }
2994 else
2995 XsMDIWindow::setSize (w, h); // Cache the points
2996 }
2997
2998 // className
2999
3000 const char* XsMotifWindow::className ( ) const
3001 {
3002 return ("XsMotifWindow");
3003 }
3004
3005 // _createWindow
3006
3007 void XsMotifWindow::_createWindow (Widget parent)
3008 {
3009 assert (parent != 0);
3010
3011 // Create the window frame
3012
3013 _base = XtVaCreateWidget (_name, xmFormWidgetClass, parent,
3014 XmNborderWidth, (Dimension)1, NULL);
3015
3016 // Install destroy handler
3017
3018 _installDestroyHandler ( );
3019
3020 // Get resources
3021
3022 _getResources (_resourceList, XtNumber (_resourceList));
3023
3024 /*
3025 Fix configuration inter-dependencies. Here are the rules:
3026
3027 1) If there is no border, then there are no resize handles
3028 2) If there is no title, then there are no buttons (would look stupid)
3029 */
3030
3031 if (_showBorder == False)
3032 _showResize = False;
3033
3034 if (_showTitle == False)
3035 {
3036 _showMenu = False;
3037 _showMinimize = False;
3038 _showMaximize = False;
3039 }
3040
3041 /*
3042 Corners
3043 */
3044
3045 if (_showResize)
3046 {
3047
3048 // Top-Left
3049
3050 _corners[_XsMotifCorner::TopLeft] = new _XsMotifCorner ("topLeft", this, _XsMotifCorner::TopLeft);
3051
3052 XtVaSetValues (_corners[_XsMotifCorner::TopLeft]->base ( ), XmNtopAttachment,
3053 XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment,
3054 XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, NULL);
3055
3056 // Top-Right
3057
3058 _corners[_XsMotifCorner::TopRight] = new _XsMotifCorner ("topRight", this, _XsMotifCorner::TopRight);
3059
3060 XtVaSetValues (_corners[_XsMotifCorner::TopRight]->base ( ), XmNtopAttachment,
3061 XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment,
3062 XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, NULL);
3063
3064 // Bottom-Left
3065
3066 _corners[_XsMotifCorner::BottomLeft] = new _XsMotifCorner ("bottomLeft", this, _XsMotifCorner::BottomLeft);
3067
3068 XtVaSetValues (_corners[_XsMotifCorner::BottomLeft]->base ( ), XmNtopAttachment,
3069 XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment,
3070 XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, NULL);
3071
3072 // Bottom-Right
3073
3074 _corners[_XsMotifCorner::BottomRight] = new _XsMotifCorner ("bottomRight", this, _XsMotifCorner::BottomRight);
3075
3076 XtVaSetValues (_corners[_XsMotifCorner::BottomRight]->base ( ), XmNtopAttachment,
3077 XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment,
3078 XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, NULL);
3079 }
3080
3081 /*
3082 Sides
3083 */
3084
3085 if (_showBorder)
3086 {
3087
3088 // Top
3089
3090 _sides[_XsMotifSide::Top] = new _XsMotifSide ("top", this, _XsMotifSide::Top);
3091
3092 XtVaSetValues (_sides[_XsMotifSide::Top]->base ( ), XmNtopAttachment,
3093 XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, NULL);
3094
3095 if (_showResize)
3096 {
3097 XtVaSetValues (_sides[_XsMotifSide::Top]->base ( ), XmNleftAttachment,
3098 XmATTACH_WIDGET, XmNleftWidget, _corners[_XsMotifCorner::TopLeft]->base ( ),
3099 XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget,
3100 _corners[_XsMotifCorner::TopRight]->base ( ), NULL);
3101 }
3102 else
3103 {
3104 XtVaSetValues (_sides[_XsMotifSide::Top]->base ( ), XmNleftAttachment,
3105 XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL);
3106 }
3107
3108 // Bottom
3109
3110 _sides[_XsMotifSide::Bottom] = new _XsMotifSide ("bottom", this, _XsMotifSide::Bottom);
3111
3112 XtVaSetValues (_sides[_XsMotifSide::Bottom]->base ( ), XmNtopAttachment,
3113 XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, NULL);
3114
3115 if (_showResize)
3116 {
3117 XtVaSetValues (_sides[_XsMotifSide::Bottom]->base ( ), XmNleftAttachment,
3118 XmATTACH_WIDGET, XmNleftWidget, _corners[_XsMotifCorner::BottomLeft]->base ( ),
3119 XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget,
3120 _corners[_XsMotifCorner::BottomRight]->base ( ), NULL);
3121 }
3122 else
3123 {
3124 XtVaSetValues (_sides[_XsMotifSide::Bottom]->base ( ), XmNleftAttachment,
3125 XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL);
3126 }
3127
3128 // Left side
3129
3130 _sides[_XsMotifSide::Left] = new _XsMotifSide ("left", this, _XsMotifSide::Left);
3131
3132 XtVaSetValues (_sides[_XsMotifSide::Left]->base ( ), XmNleftAttachment,
3133 XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, NULL);
3134
3135 if (_showResize)
3136 {
3137 XtVaSetValues (_sides[_XsMotifSide::Left]->base ( ), XmNtopAttachment,
3138 XmATTACH_WIDGET, XmNtopWidget, _corners[_XsMotifCorner::TopLeft]->base ( ),
3139 XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget,
3140 _corners[_XsMotifCorner::BottomLeft]->base ( ), NULL);
3141 }
3142 else
3143 {
3144 XtVaSetValues (_sides[_XsMotifSide::Left]->base ( ), XmNtopAttachment,
3145 XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL);
3146 }
3147
3148 // Right side
3149
3150 _sides[_XsMotifSide::Right] = new _XsMotifSide ("right", this, _XsMotifSide::Right);
3151
3152 XtVaSetValues (_sides[_XsMotifSide::Right]->base ( ), XmNleftAttachment,
3153 XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, NULL);
3154
3155 if (_showResize)
3156 {
3157 XtVaSetValues (_sides[_XsMotifSide::Right]->base ( ), XmNtopAttachment,
3158 XmATTACH_WIDGET, XmNtopWidget, _corners[_XsMotifCorner::TopRight]->base ( ),
3159 XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget,
3160 _corners[_XsMotifCorner::BottomRight]->base ( ), NULL);
3161 }
3162 else
3163 {
3164 XtVaSetValues (_sides[_XsMotifSide::Right]->base ( ), XmNtopAttachment,
3165 XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL);
3166 }
3167 }
3168
3169 // Menu button
3170
3171 if (_showMenu)
3172 {
3173 _buttons[_XsMotifButton::Menu] = new _XsMotifButton ("menu", this, _XsMotifButton::Menu);
3174
3175 XtVaSetValues (_buttons[_XsMotifButton::Menu]->base ( ), XmNbottomAttachment,
3176 XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, NULL);
3177
3178 if (_showBorder)
3179 {
3180 XtVaSetValues (_buttons[_XsMotifButton::Menu]->base ( ), XmNleftAttachment,
3181 XmATTACH_WIDGET, XmNleftWidget, _sides[_XsMotifSide::Left]->base ( ),
3182 XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, _sides[_XsMotifSide::Top]->base ( ),
3183 NULL);
3184 }
3185 else
3186 {
3187 XtVaSetValues (_buttons[_XsMotifButton::Menu]->base ( ), XmNleftAttachment,
3188 XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL);
3189 }
3190 }
3191
3192 // Maximize button
3193
3194 if (_showMaximize)
3195 {
3196 _buttons[_XsMotifButton::Maximize] = new _XsMotifButton ("maximize", this, _XsMotifButton::Maximize);
3197
3198 XtVaSetValues (_buttons[_XsMotifButton::Maximize]->base ( ), XmNbottomAttachment,
3199 XmATTACH_NONE, XmNleftAttachment, XmATTACH_NONE, NULL);
3200
3201 if (_showBorder)
3202 {
3203 XtVaSetValues (_buttons[_XsMotifButton::Maximize]->base ( ), XmNtopAttachment,
3204 XmATTACH_WIDGET, XmNtopWidget, _sides[_XsMotifSide::Top]->base ( ),
3205 XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, _sides[_XsMotifSide::Right]->base ( ),
3206 NULL);
3207 }
3208 else
3209 {
3210 XtVaSetValues (_buttons[_XsMotifButton::Maximize]->base ( ), XmNtopAttachment,
3211 XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL);
3212 }
3213 }
3214
3215 // Minimize button
3216
3217 if (_showMinimize)
3218 {
3219 _buttons[_XsMotifButton::Minimize] = new _XsMotifButton ("minimize", this, _XsMotifButton::Minimize);
3220
3221 XtVaSetValues (_buttons[_XsMotifButton::Minimize]->base ( ),
3222 XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_NONE,
3223 NULL);
3224
3225 if (_showBorder)
3226 {
3227 XtVaSetValues (_buttons[_XsMotifButton::Minimize]->base ( ), XmNtopAttachment,
3228 XmATTACH_WIDGET, XmNtopWidget, _sides[_XsMotifSide::Top]->base ( ),
3229 XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget,
3230 _sides[_XsMotifSide::Right]->base ( ), NULL);
3231 }
3232 else
3233 {
3234 XtVaSetValues (_buttons[_XsMotifButton::Minimize]->base ( ),
3235 XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM,
3236 NULL);
3237 }
3238
3239 if (_showMaximize)
3240 {
3241 XtVaSetValues (_buttons[_XsMotifButton::Minimize]->base ( ),
3242 XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget,
3243 _buttons[_XsMotifButton::Maximize]->base ( ), NULL);
3244 }
3245 }
3246
3247 /*
3248 Titlebar
3249 */
3250
3251 if (_showTitle)
3252 {
3253 _title = new _XsMotifTitle ("title", this);
3254
3255 XtVaSetValues (_title->base ( ), XmNbottomAttachment, XmATTACH_NONE,
3256 NULL);
3257
3258 if (_showBorder)
3259 {
3260 XtVaSetValues (_title->base ( ), XmNtopAttachment, XmATTACH_WIDGET,
3261 XmNtopWidget, _sides[_XsMotifSide::Top]->base ( ),
3262 XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,
3263 _sides[_XsMotifSide::Left]->base ( ), XmNrightAttachment,
3264 XmATTACH_WIDGET, XmNrightWidget, _sides[_XsMotifSide::Right]->base ( ),
3265 NULL);
3266 }
3267 else
3268 {
3269 XtVaSetValues (_title->base ( ), XmNtopAttachment, XmATTACH_FORM,
3270 XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM,
3271 NULL);
3272 }
3273
3274 if (_showMenu)
3275 {
3276 XtVaSetValues (_title->base ( ), XmNleftAttachment, XmATTACH_WIDGET,
3277 XmNleftWidget, _buttons[_XsMotifButton::Menu]->base ( ), NULL);
3278 }
3279
3280 Widget ba = (_buttons[_XsMotifButton::Minimize] != 0) ?
3281 _buttons[_XsMotifButton::Minimize]->base ( ) :
3282 (_buttons[_XsMotifButton::Maximize] != 0) ?
3283 _buttons[_XsMotifButton::Maximize]->base ( ) : 0;
3284
3285 if (ba)
3286 {
3287 XtVaSetValues (_title->base ( ), XmNrightAttachment, XmATTACH_WIDGET,
3288 XmNrightWidget, ba, NULL);
3289 }
3290 }
3291
3292 /*
3293 Icon
3294 */
3295
3296 _icon = new _XsMotifIcon ("icon", this, parent);
3297
3298 /*
3299 Menu
3300 */
3301
3302 _menu = new _XsMotifMenu ("menu", this);
3303
3304 /*
3305 Client Area
3306 */
3307
3308 _clientArea = XtVaCreateWidget ("clientArea", xmFormWidgetClass, _base, NULL);
3309
3310 if (_showBorder)
3311 {
3312 XtVaSetValues (_clientArea, XmNleftAttachment, XmATTACH_WIDGET,
3313 XmNleftWidget, _sides[_XsMotifSide::Left]->base ( ), XmNrightAttachment,
3314 XmATTACH_WIDGET, XmNrightWidget, _sides[_XsMotifSide::Right]->base ( ),
3315 XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget,
3316 _sides[_XsMotifSide::Bottom]->base ( ), NULL);
3317 }
3318 else
3319 {
3320 XtVaSetValues (_clientArea, XmNleftAttachment, XmATTACH_FORM,
3321 XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM,
3322 NULL);
3323 }
3324
3325 Widget topW = (_showTitle) ? _title->base ( ) :
3326 (_showBorder) ? _sides[_XsMotifSide::Top]->base ( ) : 0;
3327
3328 if (topW)
3329 {
3330 XtVaSetValues (_clientArea, XmNtopAttachment, XmATTACH_WIDGET,
3331 XmNtopWidget, topW, NULL);
3332 }
3333 else
3334 XtVaSetValues (_clientArea, XmNtopAttachment, XmATTACH_FORM, NULL);
3335
3336 // Call the class function to create the contents of the window
3337
3338 _buildClientArea (_clientArea);
3339
3340 // Add an event handler to be called when this window is mapped
3341
3342 XtAddEventHandler (_base, StructureNotifyMask, False, _mapEventHandler, (XtPointer)this);
3343
3344 // Show everything
3345
3346 int loop;
3347
3348 for (loop = 0; loop < _XsMotifSide::Max; loop++)
3349 {
3350 if (_corners[loop] != 0)
3351 _corners[loop]->show ( );
3352 if (_sides[loop] != 0)
3353 _sides[loop]->show ( );
3354 }
3355
3356 for (loop = 0; loop < _XsMotifButton::Max; loop++)
3357 {
3358 if (_buttons[loop] != 0)
3359 _buttons[loop]->show ( );
3360 }
3361
3362 if (_title != 0)
3363 _title->show ( );
3364 }
3365
3366 // _mapEvent
3367
3368 void XsMotifWindow::_mapEvent ( )
3369 {
3370
3371 // Raise the client-area
3372
3373 XRaiseWindow (XtDisplay (_clientArea), XtWindow (_clientArea));
3374 }
3375
3376 // _mapEventHandler
3377
3378 void XsMotifWindow::_mapEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*)
3379 {
3380 if (event->type == MapNotify)
3381 {
3382 XsMotifWindow *obj = (XsMotifWindow*)clientData;
3383 obj->_mapEvent ( );
3384 XtRemoveEventHandler (obj->_base, StructureNotifyMask, False, obj->_mapEventHandler, clientData);
3385 }
3386 }