]> git.saurik.com Git - wxWidgets.git/blame - src/motif/mdi/lib/XsMotifWindow.C
added wxDisplayFactoryX11 ctor body
[wxWidgets.git] / src / motif / mdi / lib / XsMotifWindow.C
CommitLineData
8704bf74
JS
1/*
2 Copyright (C) 1996 Scott W. Sadler
3 All rights reserved.
4*/
5
6/*
7 XsMotifWindow.C
8
9 History
0d57be45 10 03-Mar-96 1.0; Scott W. Sadler (ssadler@cisco.com)
8704bf74
JS
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
30const int BorderSize_ = 6;
31const int ButtonSize_ = 23;
32const 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
66void _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
81const char* _XsMotifBase::className ( ) const
82{
83 return ("_XsMotifBase");
84}
85
86// _componentDestroyed ( )
87
88void _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
109void _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
172void _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
180void _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
208void _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
226Cursor _XsMotifComponent::_cursors[_XsMotifComponent::NumCursors];
227
228int _XsMotifComponent::_mutex = 0;
229
230XtResource _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
307const char* _XsMotifComponent::className ( ) const
308{
309 return ("_XsMotifComponent");
310}
311
312// _input
313
314void _XsMotifComponent::_input (XEvent*)
315{
316 // Empty
317}
318
319// _exposeEventHandler
320
321void _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
331void _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
367const char *_XsMotifCorner::className ( ) const
368{
369 return ("_XsMotifCorner");
370}
371
372// _expose
373
374void _XsMotifCorner::_expose (XEvent*)
375{
376 Dimension w, h;
377
8aa04e8b
JS
378 if (_topShadowGC == 0) // JACS
379 return;
380
8704bf74
JS
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
460void _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
536void _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
609const char *_XsMotifSide::className ( ) const
610{
611 return ("_XsMotifSide");
612}
613
614// _expose
615
616void _XsMotifSide::_expose (XEvent *event)
617{
8aa04e8b
JS
618 if (_topShadowGC == 0) // JACS
619 return;
8704bf74
JS
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
667void _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
743void _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
766void _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
787void _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
827void _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
846const char *_XsMotifButton::className ( ) const
847{
848 return ("_XsMotifButton");
849}
850
851// _expose
852
853void _XsMotifButton::_expose (XEvent *event)
854{
8aa04e8b
JS
855 if (_topShadowGC == 0) // JACS
856 return;
857
8704bf74
JS
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
916void _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
1031void _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
1048XtResource _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
1118void _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
1130const char *_XsMotifTitle::className ( ) const
1131{
1132 return ("_XsMotifTitle");
1133}
1134
1135// _componentDestroyed
1136
1137void _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
1154void _XsMotifTitle::_redraw ( )
1155{
1156 _expose (0); // Just pretend we got an expose event
1157}
1158
1159// _expose
1160
1161void _XsMotifTitle::_expose (XEvent *event)
1162{
8aa04e8b
JS
1163 if (_topShadowGC == 0) // JACS
1164 return;
8704bf74
JS
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
1210void _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
1288void _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
1322void _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
1343void _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
1357XtResource _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
1459void _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
1502void _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
1514void _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
1544const char *_XsMotifIcon::className ( ) const
1545{
1546 return ("_XsMotifIcon");
1547}
1548
1549// _componentDestroyed
1550
1551void _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
1576void _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
1657void _XsMotifIcon::_expose (XEvent *)
1658{
8aa04e8b
JS
1659 if (_topShadowGC == 0) // JACS
1660 return;
1661
8704bf74
JS
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
1785void _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
1846int _XsMotifMenu::_count = 0;
1847Cursor _XsMotifMenu::_cursor = None;
1848Pixmap _XsMotifMenu::_stipple = None;
1849Display *_XsMotifMenu::_dpy = 0;
1850
1851// Resources
1852
1853XtResource _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
2073void _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
2148const char *_XsMotifMenu::className ( ) const
2149{
2150 return ("_XsMotifMenu");
2151}
2152
2153// _componentDestroyed
2154
2155void _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
2180void _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
2249void _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
2349void _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
2369void _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
2405void _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
2505Boolean _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
2528void _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
2542void _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
2591Boolean _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
2607XtResource 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
2711XsMotifWindow::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
2736XsMotifWindow::~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
2756void 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
2765void 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
2774void 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
2799void 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
2861void 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);
8704bf74
JS
2896 }
2897}
2898
2899// close
2900
2901void 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
2917void XsMotifWindow::setTitle (const char *title)
2918{
2919 if (_title != 0)
2920 _title->setTitle (title);
2921}
2922
2923// setIconName
2924
2925void XsMotifWindow::setIconName (const char *iconName)
2926{
2927 if (_icon != 0)
2928 _icon->setIconName (iconName);
2929}
2930
2931// setPixmap
2932
2933void XsMotifWindow::setPixmap (Pixmap pixmap)
2934{
2935 if (_icon != 0)
2936 _icon->setPixmap (pixmap);
2937}
2938
2939// popupMenu
2940
2941void XsMotifWindow::popupMenu (Boolean b)
2942{
2943 if (_menu != 0)
2944 _menu->popup (b);
2945}
2946
2947// setPosition
2948
2949void 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
2963void 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);
0d57be45
JS
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 }
8704bf74
JS
2993 }
2994 else
2995 XsMDIWindow::setSize (w, h); // Cache the points
2996}
2997
2998// className
2999
3000const char* XsMotifWindow::className ( ) const
3001{
3002 return ("XsMotifWindow");
3003}
3004
3005// _createWindow
3006
3007void 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
3368void XsMotifWindow::_mapEvent ( )
3369{
3370
3371// Raise the client-area
3372
3373 XRaiseWindow (XtDisplay (_clientArea), XtWindow (_clientArea));
3374}
3375
3376// _mapEventHandler
3377
3378void 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}