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