call RemoveChild() in ~wxWindowBase instead of doing it in each ~wxWindow for each...
[wxWidgets.git] / src / motif / window.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: windows.cpp
3 // Purpose: wxWindow
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "window.h"
22 #endif
23
24 #ifdef __VMS
25 #define XtDisplay XTDISPLAY
26 #define XtWindow XTWINDOW
27 #define XtScreen XTSCREEN
28 #endif
29
30 #include "wx/setup.h"
31 #include "wx/menu.h"
32 #include "wx/dc.h"
33 #include "wx/dcclient.h"
34 #include "wx/utils.h"
35 #include "wx/app.h"
36 #include "wx/layout.h"
37 #include "wx/button.h"
38 #include "wx/settings.h"
39 #include "wx/frame.h"
40 #include "wx/scrolwin.h"
41 #include "wx/module.h"
42 #include "wx/menuitem.h"
43 #include "wx/log.h"
44 #include "wx/evtloop.h"
45 #include "wx/hash.h"
46
47 #if wxUSE_DRAG_AND_DROP
48 #include "wx/dnd.h"
49 #endif
50
51 // DoSetSizeIntr and DoMoveWindowIntr
52 // PROBLEM:
53 // under Motif composite controls (such as wxCalendarCtrl or generic wxSpinCtrl
54 // did nott work and/or segfaulted because
55 // 1) wxWindow::Create calls SetSize,
56 // which results in a call to DoSetSize much earlier than in the other ports
57 // 2) if wxWindow::Create is called (wxControl::Create calls it)
58 // then DoSetSize is never called, causing layout problems in composite
59 // controls
60 //
61 // SOLUTION:
62 // 1) don't call SetSize, DoSetSize, DoMoveWindow, DoGetPosition,
63 // DoSetPosition directly or indirectly from wxWindow::Create
64 // 2) call DoMoveWindow from DoSetSize, allowing controls to override it
65
66 #ifdef __VMS__
67 #pragma message disable nosimpint
68 #endif
69 #include <Xm/Xm.h>
70
71 #include <Xm/DrawingA.h>
72 #include <Xm/ScrolledW.h>
73 #include <Xm/ScrollBar.h>
74 #include <Xm/Frame.h>
75 #include <Xm/Label.h>
76 #include <Xm/RowColumn.h> // for XmMenuPosition
77 #ifdef __VMS__
78 #pragma message enable nosimpint
79 #endif
80
81 #include "wx/motif/private.h"
82
83 #include <string.h>
84
85 // ----------------------------------------------------------------------------
86 // constants
87 // ----------------------------------------------------------------------------
88
89 static const int SCROLL_MARGIN = 4;
90
91 // ----------------------------------------------------------------------------
92 // global variables for this module
93 // ----------------------------------------------------------------------------
94
95 extern wxHashTable *wxWidgetHashTable;
96 static wxWindow* g_captureWindow = NULL;
97
98
99 // ----------------------------------------------------------------------------
100 // private functions
101 // ----------------------------------------------------------------------------
102
103 static void wxCanvasRepaintProc(Widget, XtPointer, XmDrawingAreaCallbackStruct * cbs);
104 static void wxCanvasInputEvent(Widget drawingArea, XtPointer data, XmDrawingAreaCallbackStruct * cbs);
105 static void wxCanvasMotionEvent(Widget, XButtonEvent * event);
106 static void wxCanvasEnterLeave(Widget drawingArea, XtPointer clientData, XCrossingEvent * event);
107 static void wxScrollBarCallback(Widget widget, XtPointer clientData,
108 XmScrollBarCallbackStruct *cbs);
109 static void wxPanelItemEventHandler(Widget wid,
110 XtPointer client_data,
111 XEvent* event,
112 Boolean *continueToDispatch);
113
114 // unused for now
115 #if 0
116
117 // Helper function for 16-bit fonts
118 static int str16len(const char *s)
119 {
120 int count = 0;
121
122 while (s[0] && s[1]) {
123 count++;
124 s += 2;
125 }
126
127 return count;
128 }
129
130 #endif // 0
131
132 // ----------------------------------------------------------------------------
133 // macros
134 // ----------------------------------------------------------------------------
135
136 #define event_left_is_down(x) ((x)->xbutton.state & Button1Mask)
137 #define event_middle_is_down(x) ((x)->xbutton.state & Button2Mask)
138 #define event_right_is_down(x) ((x)->xbutton.state & Button3Mask)
139
140 // ----------------------------------------------------------------------------
141 // event tables
142 // ----------------------------------------------------------------------------
143
144 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
145
146 BEGIN_EVENT_TABLE(wxWindow, wxWindowBase)
147 EVT_SYS_COLOUR_CHANGED(wxWindow::OnSysColourChanged)
148 END_EVENT_TABLE()
149
150 // ============================================================================
151 // implementation
152 // ============================================================================
153
154 // ----------------------------------------------------------------------------
155 // helper functions
156 // ----------------------------------------------------------------------------
157
158 void wxWindow::UnmanageAndDestroy(WXWidget widget)
159 {
160 Widget w = (Widget)widget;
161 if ( w )
162 {
163 XtUnmanageChild(w);
164 XtDestroyWidget(w);
165 }
166 }
167
168 bool wxWindow::MapOrUnmap(WXWidget widget, bool domap)
169 {
170 Widget w = (Widget)widget;
171 if ( !w )
172 return FALSE;
173
174 // Rationale: a lot of common operations (including but not
175 // limited to moving, resizing and appending items to a listbox)
176 // unmamange the widget, do their work, then manage it again.
177 // This means that, for example adding an item to a listbox will show it,
178 // or that most controls are shown every time they are moved or resized!
179 XtSetMappedWhenManaged( w, domap );
180
181 // if the widget is not unmanaged, it still intercepts
182 // mouse events, even if it is not mapped (and hence invisible)
183 if ( domap )
184 {
185 XtManageChild(w);
186 // XtMapWidget(w);
187 }
188 else
189 {
190 XtUnmanageChild(w);
191 // XtUnmapWidget(w);
192 }
193
194 return TRUE;
195 }
196
197 // ----------------------------------------------------------------------------
198 // constructors
199 // ----------------------------------------------------------------------------
200
201 void wxWindow::Init()
202 {
203 // generic initializations first
204 InitBase();
205
206 // Motif-specific
207 m_needsRefresh = TRUE;
208 m_mainWidget = (WXWidget) 0;
209
210 m_winCaptured = FALSE;
211
212 m_isShown = TRUE;
213 m_isBeingDeleted = FALSE;
214
215 m_hScrollBar =
216 m_vScrollBar =
217 m_borderWidget =
218 m_scrolledWindow =
219 m_drawingArea = (WXWidget) 0;
220
221 m_scrollPosX =
222 m_scrollPosY = 0;
223
224 m_backingPixmap = (WXPixmap) 0;
225 m_pixmapWidth =
226 m_pixmapHeight = 0;
227
228 m_pixmapOffsetX =
229 m_pixmapOffsetY = 0;
230
231 m_lastTS = 0;
232 m_lastButton = 0;
233 }
234
235 // real construction (Init() must have been called before!)
236 bool wxWindow::Create(wxWindow *parent, wxWindowID id,
237 const wxPoint& pos,
238 const wxSize& size,
239 long style,
240 const wxString& name)
241 {
242 wxCHECK_MSG( parent, FALSE, "can't create wxWindow without parent" );
243
244 CreateBase(parent, id, pos, size, style, wxDefaultValidator, name);
245
246 parent->AddChild(this);
247
248 m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
249 m_foregroundColour = *wxBLACK;
250
251 //// TODO: we should probably optimize by only creating a
252 //// a drawing area if we have one or more scrollbars (wxVSCROLL/wxHSCROLL).
253 //// But for now, let's simplify things by always creating the
254 //// drawing area, since otherwise the translations are different.
255
256 // New translations for getting mouse motion feedback
257 static const String translations =
258 "<Btn1Motion>: wxCanvasMotionEvent() DrawingAreaInput() ManagerGadgetButtonMotion()\n\
259 <Btn2Motion>: wxCanvasMotionEvent() DrawingAreaInput() ManagerGadgetButtonMotion()\n\
260 <Btn3Motion>: wxCanvasMotionEvent() DrawingAreaInput() ManagerGadgetButtonMotion()\n\
261 <BtnMotion>: wxCanvasMotionEvent() DrawingAreaInput() ManagerGadgetButtonMotion()\n\
262 <Btn1Down>: DrawingAreaInput() ManagerGadgetArm()\n\
263 <Btn2Down>: DrawingAreaInput() ManagerGadgetArm()\n\
264 <Btn3Down>: DrawingAreaInput() ManagerGadgetArm()\n\
265 <Btn1Up>: DrawingAreaInput() ManagerGadgetActivate()\n\
266 <Btn2Up>: DrawingAreaInput() ManagerGadgetActivate()\n\
267 <Btn3Up>: DrawingAreaInput() ManagerGadgetActivate()\n\
268 <Motion>: wxCanvasMotionEvent() DrawingAreaInput()\n\
269 <EnterWindow>: wxCanvasMotionEvent() DrawingAreaInput()\n\
270 <LeaveWindow>: wxCanvasMotionEvent() DrawingAreaInput()\n\
271 <Key>: DrawingAreaInput()";
272
273 XtActionsRec actions[1];
274 actions[0].string = "wxCanvasMotionEvent";
275 actions[0].proc = (XtActionProc) wxCanvasMotionEvent;
276 XtAppAddActions ((XtAppContext) wxTheApp->GetAppContext(), actions, 1);
277
278 Widget parentWidget = (Widget) parent->GetClientWidget();
279 m_borderWidget = wxCreateBorderWidget( (WXWidget)parentWidget, style );
280
281 m_scrolledWindow = (WXWidget)XtVaCreateManagedWidget
282 (
283 "scrolledWindow",
284 xmScrolledWindowWidgetClass,
285 m_borderWidget ? (Widget) m_borderWidget
286 : parentWidget,
287 XmNresizePolicy, XmRESIZE_NONE,
288 XmNspacing, 0,
289 XmNscrollingPolicy, XmAPPLICATION_DEFINED,
290 //XmNscrollBarDisplayPolicy, XmAS_NEEDED,
291 NULL
292 );
293
294 XtTranslations ptr = XtParseTranslationTable(translations);
295 m_drawingArea = (WXWidget)XtVaCreateWidget
296 (
297 name,
298 xmDrawingAreaWidgetClass, (Widget) m_scrolledWindow,
299 XmNunitType, XmPIXELS,
300 // XmNresizePolicy, XmRESIZE_ANY,
301 XmNresizePolicy, XmRESIZE_NONE,
302 XmNmarginHeight, 0,
303 XmNmarginWidth, 0,
304 XmNtranslations, ptr,
305 NULL
306 );
307 XtFree((char *) ptr);
308
309 #if 0
310 if (GetWindowStyleFlag() & wxOVERRIDE_KEY_TRANSLATIONS)
311 {
312 ptr = XtParseTranslationTable ("<Key>: DrawingAreaInput()");
313 XtOverrideTranslations ((Widget) m_drawingArea, ptr);
314 XtFree ((char *) ptr);
315 }
316 #endif // 0
317
318 wxAddWindowToTable((Widget) m_drawingArea, this);
319 wxAddWindowToTable((Widget) m_scrolledWindow, this);
320
321 // This order is very important in Motif 1.2.1
322 XtRealizeWidget ((Widget) m_scrolledWindow);
323 XtRealizeWidget ((Widget) m_drawingArea);
324 XtManageChild ((Widget) m_drawingArea);
325
326 ptr = XtParseTranslationTable("<Configure>: resize()");
327 XtOverrideTranslations((Widget) m_drawingArea, ptr);
328 XtFree ((char *) ptr);
329
330 XtAddCallback ((Widget) m_drawingArea, XmNexposeCallback, (XtCallbackProc) wxCanvasRepaintProc, (XtPointer) this);
331 XtAddCallback ((Widget) m_drawingArea, XmNinputCallback, (XtCallbackProc) wxCanvasInputEvent, (XtPointer) this);
332
333 XtAddEventHandler(
334 (Widget)m_drawingArea,
335 PointerMotionHintMask | EnterWindowMask |
336 LeaveWindowMask | FocusChangeMask,
337 False,
338 (XtEventHandler) wxCanvasEnterLeave,
339 (XtPointer) this
340 );
341
342 // Scrolled widget needs to have its colour changed or we get a little blue
343 // square where the scrollbars abutt
344 wxColour backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
345 wxDoChangeBackgroundColour(m_scrolledWindow, backgroundColour, TRUE);
346 wxDoChangeBackgroundColour(m_drawingArea, backgroundColour, TRUE);
347
348 XmScrolledWindowSetAreas(
349 (Widget)m_scrolledWindow,
350 (Widget) 0, (Widget) 0,
351 (Widget) m_drawingArea);
352
353 // Without this, the cursor may not be restored properly (e.g. in splitter
354 // sample).
355 SetCursor(*wxSTANDARD_CURSOR);
356 SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
357 DoSetSizeIntr(pos.x, pos.y, size.x,size.y, wxSIZE_AUTO, TRUE);
358 return TRUE;
359 }
360
361 // Destructor
362 wxWindow::~wxWindow()
363 {
364 if (g_captureWindow == this)
365 g_captureWindow = NULL;
366
367 m_isBeingDeleted = TRUE;
368
369 // Motif-specific actions first
370 WXWidget wMain = GetMainWidget();
371 if ( wMain )
372 {
373 // Removes event handlers
374 DetachWidget(wMain);
375 }
376
377 // If m_drawingArea, we're a fully-fledged window with drawing area,
378 // scrollbars etc. (what wxCanvas used to be)
379 if ( m_drawingArea )
380 {
381 // Destroy children before destroying self
382 DestroyChildren();
383
384 if (m_backingPixmap)
385 XFreePixmap (XtDisplay ((Widget) GetMainWidget()), (Pixmap) m_backingPixmap);
386
387 Widget w = (Widget) m_drawingArea;
388 wxDeleteWindowFromTable(w);
389
390 if (w)
391 {
392 XtDestroyWidget(w);
393 m_drawingArea = (WXWidget) 0;
394 }
395
396 // Only if we're _really_ a canvas (not a dialog box/panel)
397 if (m_scrolledWindow)
398 {
399 wxDeleteWindowFromTable((Widget) m_scrolledWindow);
400 }
401
402 if (m_hScrollBar)
403 {
404 wxDeleteWindowFromTable((Widget) m_hScrollBar);
405 XtUnmanageChild((Widget) m_hScrollBar);
406 }
407 if (m_vScrollBar)
408 {
409 wxDeleteWindowFromTable((Widget) m_vScrollBar);
410 XtUnmanageChild((Widget) m_vScrollBar);
411 }
412
413 if (m_hScrollBar)
414 XtDestroyWidget((Widget) m_hScrollBar);
415 if (m_vScrollBar)
416 XtDestroyWidget((Widget) m_vScrollBar);
417
418 UnmanageAndDestroy(m_scrolledWindow);
419
420 if (m_borderWidget)
421 {
422 XtDestroyWidget ((Widget) m_borderWidget);
423 m_borderWidget = (WXWidget) 0;
424 }
425 }
426 else // Why wasn't this here before? JACS 8/3/2000
427 DestroyChildren();
428
429
430 // Destroy the window
431 if (GetMainWidget())
432 {
433 // If this line (XtDestroyWidget) causes a crash, you may comment it out.
434 // Child widgets will get destroyed automatically when a frame
435 // or dialog is destroyed, but before that you may get some memory
436 // leaks and potential layout problems if you delete and then add
437 // child windows.
438
439 // GRG, Feb/2000: commented this out when adding support for
440 // wxSCROLL[WIN]_THUMBRELEASE events. Also it was reported
441 // that this call crashed wxMotif under OS/2, so it seems
442 // that leaving it out is the right thing to do.
443 // SN, Feb/2000: newgrid/griddemo shows why it is needed :-(
444 XtDestroyWidget((Widget) GetMainWidget());
445 SetMainWidget((WXWidget) NULL);
446 }
447 }
448
449 // ----------------------------------------------------------------------------
450 // scrollbar management
451 // ----------------------------------------------------------------------------
452
453 WXWidget wxWindow::DoCreateScrollBar(WXWidget parent,
454 wxOrientation orientation,
455 void (*callback)())
456 {
457 int orient = ( orientation & wxHORIZONTAL ) ? XmHORIZONTAL : XmVERTICAL;
458 Widget sb =
459 XtVaCreateManagedWidget( "scrollBarWidget",
460 xmScrollBarWidgetClass, (Widget)parent,
461 XmNorientation, orient,
462 XmNincrement, 1,
463 XmNvalue, 0,
464 NULL );
465
466 XtPointer o = (XtPointer)orientation;
467 XtCallbackProc cb = (XtCallbackProc)callback;
468
469 XtAddCallback( sb, XmNvalueChangedCallback, cb, o );
470 XtAddCallback( sb, XmNdragCallback, cb, o );
471 XtAddCallback( sb, XmNincrementCallback, cb, o );
472 XtAddCallback( sb, XmNdecrementCallback, cb, o );
473 XtAddCallback( sb, XmNpageIncrementCallback, cb, o );
474 XtAddCallback( sb, XmNpageDecrementCallback, cb, o );
475 XtAddCallback( sb, XmNtoTopCallback, cb, o );
476 XtAddCallback( sb, XmNtoBottomCallback, cb, o );
477
478 return (WXWidget)sb;
479 }
480
481 // Helper function
482 void wxWindow::CreateScrollbar(wxOrientation orientation)
483 {
484 wxCHECK_RET( m_drawingArea, "this window can't have scrollbars" );
485
486 XtVaSetValues( (Widget) m_scrolledWindow,
487 XmNresizePolicy, XmRESIZE_NONE,
488 NULL );
489
490 wxColour backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
491 // Add scrollbars if required
492 if (orientation == wxHORIZONTAL)
493 {
494 m_hScrollBar = DoCreateScrollBar( m_scrolledWindow, wxHORIZONTAL,
495 (void (*)())wxScrollBarCallback );
496
497 wxDoChangeBackgroundColour(m_hScrollBar, backgroundColour, TRUE);
498
499 XtRealizeWidget( (Widget)m_hScrollBar );
500
501 XtVaSetValues((Widget) m_scrolledWindow,
502 XmNhorizontalScrollBar, (Widget) m_hScrollBar,
503 NULL);
504
505 wxAddWindowToTable( (Widget)m_hScrollBar, this );
506 }
507 else if (orientation == wxVERTICAL)
508 {
509 m_vScrollBar = DoCreateScrollBar( m_scrolledWindow, wxVERTICAL,
510 (void (*)())wxScrollBarCallback );
511
512 wxDoChangeBackgroundColour(m_vScrollBar, backgroundColour, TRUE);
513
514 XtRealizeWidget((Widget)m_vScrollBar);
515
516 XtVaSetValues((Widget) m_scrolledWindow,
517 XmNverticalScrollBar, (Widget) m_vScrollBar,
518 NULL);
519
520 wxAddWindowToTable( (Widget)m_vScrollBar, this );
521 }
522
523 XtVaSetValues( (Widget) m_scrolledWindow,
524 XmNresizePolicy, XmRESIZE_ANY,
525 NULL );
526 }
527
528 void wxWindow::DestroyScrollbar(wxOrientation orientation)
529 {
530 wxCHECK_RET( m_drawingArea, "this window can't have scrollbars" );
531
532 XtVaSetValues((Widget) m_scrolledWindow,
533 XmNresizePolicy, XmRESIZE_NONE,
534 NULL);
535 String stringSB = orientation == wxHORIZONTAL ?
536 XmNhorizontalScrollBar : XmNverticalScrollBar;
537 WXWidget* widgetSB = orientation == wxHORIZONTAL ?
538 &m_hScrollBar : &m_vScrollBar;
539
540 if( *widgetSB )
541 {
542 wxDeleteWindowFromTable( (Widget)*widgetSB );
543 XtDestroyWidget( (Widget)*widgetSB );
544 *widgetSB = (WXWidget)NULL;
545 }
546
547 XtVaSetValues( (Widget)m_scrolledWindow,
548 stringSB, (Widget) 0,
549 NULL );
550
551 XtVaSetValues((Widget) m_scrolledWindow,
552 XmNresizePolicy, XmRESIZE_ANY,
553 NULL);
554 }
555
556 // ---------------------------------------------------------------------------
557 // basic operations
558 // ---------------------------------------------------------------------------
559
560 void wxWindow::SetFocus()
561 {
562 Widget wMain = (Widget) GetMainWidget();
563 XmProcessTraversal(wMain, XmTRAVERSE_CURRENT);
564 XmProcessTraversal((Widget) GetMainWidget(), XmTRAVERSE_CURRENT);
565 }
566
567 // Get the window with the focus
568 wxWindow *wxWindowBase::FindFocus()
569 {
570 // TODO Problems:
571 // (1) Can there be multiple focussed widgets in an application?
572 // In which case we need to find the top-level window that's
573 // currently active.
574 // (2) The widget with the focus may not be in the widget table
575 // depending on which widgets I put in the table
576 wxWindow *winFocus = (wxWindow *)NULL;
577 for ( wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
578 node;
579 node = node->GetNext() )
580 {
581 wxWindow *win = node->GetData();
582
583 Widget w = XmGetFocusWidget ((Widget) win->GetTopWidget());
584
585 if (w != (Widget) NULL)
586 {
587 winFocus = wxGetWindowFromTable(w);
588 if ( winFocus )
589 break;
590 }
591 }
592
593 return winFocus;
594 }
595
596 bool wxWindow::Enable(bool enable)
597 {
598 if ( !wxWindowBase::Enable(enable) )
599 return FALSE;
600
601 Widget wMain = (Widget)GetMainWidget();
602 if ( wMain )
603 {
604 XtSetSensitive(wMain, enable);
605 XmUpdateDisplay(wMain);
606 }
607
608 return TRUE;
609 }
610
611 bool wxWindow::Show(bool show)
612 {
613 if ( !wxWindowBase::Show(show) )
614 return FALSE;
615
616 if (m_borderWidget || m_scrolledWindow)
617 {
618 MapOrUnmap(m_borderWidget ? m_borderWidget : m_scrolledWindow, show);
619 // MapOrUnmap(m_drawingArea, show);
620 }
621 else
622 {
623 if ( !MapOrUnmap(GetTopWidget(), show) )
624 MapOrUnmap(GetMainWidget(), show);
625 }
626
627 return TRUE;
628 }
629
630 // Raise the window to the top of the Z order
631 void wxWindow::Raise()
632 {
633 Widget wTop = (Widget) GetTopWidget();
634 Window window = XtWindow(wTop);
635 XRaiseWindow(XtDisplay(wTop), window);
636 }
637
638 // Lower the window to the bottom of the Z order
639 void wxWindow::Lower()
640 {
641 Widget wTop = (Widget) GetTopWidget();
642 Window window = XtWindow(wTop);
643 XLowerWindow(XtDisplay(wTop), window);
644 }
645
646 void wxWindow::SetTitle(const wxString& title)
647 {
648 XtVaSetValues((Widget)GetMainWidget(), XmNtitle, title.c_str(), NULL);
649 }
650
651 wxString wxWindow::GetTitle() const
652 {
653 char *title;
654 XtVaGetValues((Widget)GetMainWidget(), XmNtitle, &title, NULL);
655
656 return wxString(title);
657 }
658
659 void wxWindow::DoCaptureMouse()
660 {
661 g_captureWindow = this;
662 if ( m_winCaptured )
663 return;
664
665 Widget wMain = (Widget)GetMainWidget();
666 if ( wMain )
667 XtAddGrab(wMain, TRUE, FALSE);
668
669 m_winCaptured = TRUE;
670 }
671
672 void wxWindow::DoReleaseMouse()
673 {
674 g_captureWindow = NULL;
675 if ( !m_winCaptured )
676 return;
677
678 Widget wMain = (Widget)GetMainWidget();
679 if ( wMain )
680 XtRemoveGrab(wMain);
681
682 m_winCaptured = FALSE;
683 }
684
685 bool wxWindow::SetFont(const wxFont& font)
686 {
687 if ( !wxWindowBase::SetFont(font) )
688 {
689 // nothing to do
690 return FALSE;
691 }
692
693 ChangeFont();
694
695 return TRUE;
696 }
697
698 bool wxWindow::SetCursor(const wxCursor& cursor)
699 {
700 if ( !wxWindowBase::SetCursor(cursor) )
701 {
702 // no change
703 return FALSE;
704 }
705
706 // wxASSERT_MSG( m_cursor.Ok(),
707 // wxT("cursor must be valid after call to the base version"));
708 wxCursor* cursor2 = NULL;
709 if (m_cursor.Ok())
710 cursor2 = & m_cursor;
711 else
712 cursor2 = wxSTANDARD_CURSOR;
713
714 WXDisplay *dpy = GetXDisplay();
715 WXCursor x_cursor = cursor2->GetXCursor(dpy);
716
717 Widget w = (Widget) GetMainWidget();
718 Window win = XtWindow(w);
719 XDefineCursor((Display*) dpy, win, (Cursor) x_cursor);
720
721 return TRUE;
722 }
723
724 // Coordinates relative to the window
725 void wxWindow::WarpPointer (int x, int y)
726 {
727 Widget wClient = (Widget)GetClientWidget();
728
729 XWarpPointer(XtDisplay(wClient), None, XtWindow(wClient), 0, 0, 0, 0, x, y);
730 }
731
732 // ---------------------------------------------------------------------------
733 // scrolling stuff
734 // ---------------------------------------------------------------------------
735
736 int wxWindow::GetScrollPos(int orient) const
737 {
738 if (orient == wxHORIZONTAL)
739 return m_scrollPosX;
740 else
741 return m_scrollPosY;
742
743 #if 0
744 Widget scrollBar = (Widget) ((orient == wxHORIZONTAL) ? m_hScrollBar : m_vScrollBar);
745 if (scrollBar)
746 {
747 int pos;
748 XtVaGetValues(scrollBar, XmNvalue, &pos, NULL);
749 return pos;
750 }
751 else
752 return 0;
753 #endif // 0
754 }
755
756 // This now returns the whole range, not just the number of positions that we
757 // can scroll.
758 int wxWindow::GetScrollRange(int orient) const
759 {
760 Widget scrollBar = (Widget)GetScrollbar((wxOrientation)orient);
761 wxCHECK_MSG( scrollBar, 0, "no such scrollbar" );
762
763 int range = 0;
764 if (scrollBar)
765 XtVaGetValues(scrollBar, XmNmaximum, &range, NULL);
766 return range;
767 }
768
769 int wxWindow::GetScrollThumb(int orient) const
770 {
771 Widget scrollBar = (Widget)GetScrollbar((wxOrientation)orient);
772 wxCHECK_MSG( scrollBar, 0, "no such scrollbar" );
773
774 int thumb;
775 XtVaGetValues(scrollBar, XmNsliderSize, &thumb, NULL);
776 return thumb;
777 }
778
779 void wxWindow::SetScrollPos(int orient, int pos, bool WXUNUSED(refresh))
780 {
781 Widget scrollBar = (Widget)GetScrollbar((wxOrientation)orient);
782
783 if ( scrollBar )
784 {
785 XtVaSetValues (scrollBar, XmNvalue, pos, NULL);
786 }
787
788 SetInternalScrollPos((wxOrientation)orient, pos);
789 }
790
791 // New function that will replace some of the above.
792 void wxWindow::SetScrollbar(int orient, int pos, int thumbVisible,
793 int range, bool WXUNUSED(refresh))
794 {
795 int oldW, oldH;
796 GetSize(& oldW, & oldH);
797
798 if (range == 0)
799 range = 1;
800 if (thumbVisible == 0)
801 thumbVisible = 1;
802
803 if (thumbVisible > range)
804 thumbVisible = range;
805
806 // Save the old state to see if it changed
807 WXWidget oldScrollBar = GetScrollbar((wxOrientation)orient);
808
809 if (orient == wxHORIZONTAL)
810 {
811 if (thumbVisible == range)
812 {
813 if (m_hScrollBar)
814 DestroyScrollbar(wxHORIZONTAL);
815 }
816 else
817 {
818 if (!m_hScrollBar)
819 CreateScrollbar(wxHORIZONTAL);
820 }
821 }
822 if (orient == wxVERTICAL)
823 {
824 if (thumbVisible == range)
825 {
826 if (m_vScrollBar)
827 DestroyScrollbar(wxVERTICAL);
828 }
829 else
830 {
831 if (!m_vScrollBar)
832 CreateScrollbar(wxVERTICAL);
833 }
834 }
835 WXWidget newScrollBar = GetScrollbar((wxOrientation)orient);
836
837 if (oldScrollBar != newScrollBar)
838 {
839 // This is important! Without it, scrollbars misbehave badly.
840 XtUnrealizeWidget((Widget) m_scrolledWindow);
841 XmScrolledWindowSetAreas ((Widget) m_scrolledWindow, (Widget) m_hScrollBar, (Widget) m_vScrollBar, (Widget) m_drawingArea);
842 XtRealizeWidget((Widget) m_scrolledWindow);
843 XtManageChild((Widget) m_scrolledWindow);
844 }
845
846 if (newScrollBar)
847 {
848 XtVaSetValues((Widget) newScrollBar,
849 XmNvalue, pos,
850 XmNminimum, 0,
851 XmNmaximum, range,
852 XmNsliderSize, thumbVisible,
853 NULL);
854 }
855
856 SetInternalScrollPos((wxOrientation)orient, pos);
857
858 int newW, newH;
859 GetSize(& newW, & newH);
860
861 // Adjusting scrollbars can resize the canvas accidentally
862 if (newW != oldW || newH != oldH)
863 SetSize(-1, -1, oldW, oldH);
864 }
865
866 // Does a physical scroll
867 void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect)
868 {
869 int x, y, w, h;
870 if (rect)
871 {
872 // Use specified rectangle
873 x = rect->x; y = rect->y; w = rect->width; h = rect->height;
874 }
875 else
876 {
877 // Use whole client area
878 x = 0; y = 0;
879 GetClientSize(& w, & h);
880 }
881
882 int x1 = (dx >= 0) ? x : x - dx;
883 int y1 = (dy >= 0) ? y : y - dy;
884 int w1 = w - abs(dx);
885 int h1 = h - abs(dy);
886 int x2 = (dx >= 0) ? x + dx : x;
887 int y2 = (dy >= 0) ? y + dy : y;
888
889 wxClientDC dc(this);
890
891 dc.SetLogicalFunction (wxCOPY);
892
893 Widget widget = (Widget) GetMainWidget();
894 Window window = XtWindow(widget);
895 Display* display = XtDisplay(widget);
896
897 XCopyArea(display, window, window, (GC) dc.GetGC(),
898 x1, y1, w1, h1, x2, y2);
899
900 dc.SetAutoSetting(TRUE);
901 wxBrush brush(GetBackgroundColour(), wxSOLID);
902 dc.SetBrush(brush); // FIXME: needed?
903
904 wxWindowList::compatibility_iterator cnode = m_children.GetFirst();
905 while (cnode)
906 {
907 wxWindow *child = cnode->GetData();
908 int sx = 0;
909 int sy = 0;
910 child->GetSize( &sx, &sy );
911 wxPoint pos( child->GetPosition() );
912 child->SetSize( pos.x + dx, pos.y + dy, sx, sy, wxSIZE_ALLOW_MINUS_ONE );
913 cnode = cnode->GetNext();
914 }
915
916 // We'll add rectangles to the list of update rectangles according to which
917 // bits we've exposed.
918 wxList updateRects;
919
920 if (dx > 0)
921 {
922 wxRect *rect = new wxRect;
923 rect->x = x;
924 rect->y = y;
925 rect->width = dx;
926 rect->height = h;
927
928 XFillRectangle(display, window,
929 (GC) dc.GetGC(), rect->x, rect->y, rect->width, rect->height);
930
931 rect->x = rect->x;
932 rect->y = rect->y;
933 rect->width = rect->width;
934 rect->height = rect->height;
935
936 updateRects.Append((wxObject*) rect);
937 }
938 else if (dx < 0)
939 {
940 wxRect *rect = new wxRect;
941
942 rect->x = x + w + dx;
943 rect->y = y;
944 rect->width = -dx;
945 rect->height = h;
946
947 XFillRectangle(display, window,
948 (GC) dc.GetGC(), rect->x, rect->y, rect->width,
949 rect->height);
950
951 rect->x = rect->x;
952 rect->y = rect->y;
953 rect->width = rect->width;
954 rect->height = rect->height;
955
956 updateRects.Append((wxObject*) rect);
957 }
958 if (dy > 0)
959 {
960 wxRect *rect = new wxRect;
961
962 rect->x = x;
963 rect->y = y;
964 rect->width = w;
965 rect->height = dy;
966
967 XFillRectangle(display, window,
968 (GC) dc.GetGC(), rect->x, rect->y, rect->width, rect->height);
969
970 rect->x = rect->x;
971 rect->y = rect->y;
972 rect->width = rect->width;
973 rect->height = rect->height;
974
975 updateRects.Append((wxObject*) rect);
976 }
977 else if (dy < 0)
978 {
979 wxRect *rect = new wxRect;
980
981 rect->x = x;
982 rect->y = y + h + dy;
983 rect->width = w;
984 rect->height = -dy;
985
986 XFillRectangle(display, window,
987 (GC) dc.GetGC(), rect->x, rect->y, rect->width, rect->height);
988
989 rect->x = rect->x;
990 rect->y = rect->y;
991 rect->width = rect->width;
992 rect->height = rect->height;
993
994 updateRects.Append((wxObject*) rect);
995 }
996 dc.SetBrush(wxNullBrush);
997
998 // Now send expose events
999
1000 wxList::compatibility_iterator node = updateRects.GetFirst();
1001 while (node)
1002 {
1003 wxRect* rect = (wxRect*) node->GetData();
1004 XExposeEvent event;
1005
1006 event.type = Expose;
1007 event.display = display;
1008 event.send_event = True;
1009 event.window = window;
1010
1011 event.x = rect->x;
1012 event.y = rect->y;
1013 event.width = rect->width;
1014 event.height = rect->height;
1015
1016 event.count = 0;
1017
1018 XSendEvent(display, window, False, ExposureMask, (XEvent *)&event);
1019
1020 node = node->GetNext();
1021
1022 }
1023
1024 // Delete the update rects
1025 node = updateRects.GetFirst();
1026 while (node)
1027 {
1028 wxRect* rect = (wxRect*) node->GetData();
1029 delete rect;
1030 node = node->GetNext();
1031 }
1032
1033 XmUpdateDisplay((Widget) GetMainWidget());
1034 }
1035
1036 // ---------------------------------------------------------------------------
1037 // drag and drop
1038 // ---------------------------------------------------------------------------
1039
1040 #if wxUSE_DRAG_AND_DROP
1041
1042 void wxWindow::SetDropTarget(wxDropTarget * WXUNUSED(pDropTarget))
1043 {
1044 // TODO
1045 }
1046
1047 #endif
1048
1049 // Old style file-manager drag&drop
1050 void wxWindow::DragAcceptFiles(bool WXUNUSED(accept))
1051 {
1052 // TODO
1053 }
1054
1055 // ----------------------------------------------------------------------------
1056 // tooltips
1057 // ----------------------------------------------------------------------------
1058
1059 #if wxUSE_TOOLTIPS
1060
1061 void wxWindow::DoSetToolTip(wxToolTip * WXUNUSED(tooltip))
1062 {
1063 // TODO
1064 }
1065
1066 #endif // wxUSE_TOOLTIPS
1067
1068 // ----------------------------------------------------------------------------
1069 // popup menus
1070 // ----------------------------------------------------------------------------
1071
1072 #if wxUSE_MENUS
1073
1074 bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
1075 {
1076 Widget widget = (Widget) GetMainWidget();
1077
1078 /* The menuId field seems to be usused, so we'll use it to
1079 indicate whether a menu is popped up or not:
1080 0: Not currently created as a popup
1081 -1: Created as a popup, but not active
1082 1: Active popup.
1083 */
1084
1085 if (menu->GetParent() && (menu->GetId() != -1))
1086 return FALSE;
1087
1088 if (menu->GetMainWidget())
1089 {
1090 menu->DestroyMenu(TRUE);
1091 }
1092
1093 menu->SetId(1); /* Mark as popped-up */
1094 menu->CreateMenu(NULL, widget, menu);
1095 menu->SetInvokingWindow(this);
1096
1097 menu->UpdateUI();
1098
1099 // menu->SetParent(parent);
1100 // parent->children->Append(menu); // Store menu for later deletion
1101
1102 Widget menuWidget = (Widget) menu->GetMainWidget();
1103
1104 int rootX = 0;
1105 int rootY = 0;
1106
1107 int deviceX = x;
1108 int deviceY = y;
1109 /*
1110 if (this->IsKindOf(CLASSINFO(wxCanvas)))
1111 {
1112 wxCanvas *canvas = (wxCanvas *) this;
1113 deviceX = canvas->GetDC ()->LogicalToDeviceX (x);
1114 deviceY = canvas->GetDC ()->LogicalToDeviceY (y);
1115 }
1116 */
1117
1118 Display *display = XtDisplay (widget);
1119 Window rootWindow = RootWindowOfScreen (XtScreen((Widget)widget));
1120 Window thisWindow = XtWindow (widget);
1121 Window childWindow;
1122 XTranslateCoordinates (display, thisWindow, rootWindow, (int) deviceX, (int) deviceY,
1123 &rootX, &rootY, &childWindow);
1124
1125 XButtonPressedEvent event;
1126 event.type = ButtonPress;
1127 event.button = 1;
1128
1129 event.x = deviceX;
1130 event.y = deviceY;
1131
1132 event.x_root = rootX;
1133 event.y_root = rootY;
1134
1135 XmMenuPosition (menuWidget, &event);
1136 XtManageChild (menuWidget);
1137
1138 // The ID of a pop-up menu is 1 when active, and is set to 0 by the
1139 // idle-time destroy routine.
1140 // Waiting until this ID changes causes this function to block until
1141 // the menu has been dismissed and the widgets cleaned up.
1142 // In other words, once this routine returns, it is safe to delete
1143 // the menu object.
1144 // Ian Brown <ian.brown@printsoft.de>
1145
1146 wxEventLoop evtLoop;
1147
1148 while (menu->GetId() == 1)
1149 {
1150 wxDoEventLoopIteration( evtLoop );
1151 }
1152
1153 return TRUE;
1154 }
1155
1156 #endif
1157
1158 // ---------------------------------------------------------------------------
1159 // moving and resizing
1160 // ---------------------------------------------------------------------------
1161
1162 bool wxWindow::PreResize()
1163 {
1164 return TRUE;
1165 }
1166
1167 // Get total size
1168 void wxWindow::DoGetSize(int *x, int *y) const
1169 {
1170 Widget widget = (Widget)( !m_drawingArea ? GetTopWidget() :
1171 ( m_borderWidget ? m_borderWidget :
1172 m_scrolledWindow ? m_scrolledWindow :
1173 m_drawingArea ) );
1174 Dimension xx, yy;
1175
1176 XtVaGetValues( widget,
1177 XmNwidth, &xx,
1178 XmNheight, &yy,
1179 NULL );
1180 if(x) *x = xx;
1181 if(y) *y = yy;
1182 }
1183
1184 void wxWindow::DoGetPosition(int *x, int *y) const
1185 {
1186 Widget widget = (Widget)
1187 ( m_drawingArea ?
1188 ( m_borderWidget ? m_borderWidget : m_scrolledWindow ) :
1189 GetTopWidget() );
1190
1191 Position xx, yy;
1192 XtVaGetValues(widget, XmNx, &xx, XmNy, &yy, NULL);
1193
1194 // We may be faking the client origin. So a window that's really at (0, 30)
1195 // may appear (to wxWin apps) to be at (0, 0).
1196 if (GetParent())
1197 {
1198 wxPoint pt(GetParent()->GetClientAreaOrigin());
1199 xx -= pt.x;
1200 yy -= pt.y;
1201 }
1202
1203 if(x) *x = xx;
1204 if(y) *y = yy;
1205 }
1206
1207 void wxWindow::DoScreenToClient(int *x, int *y) const
1208 {
1209 Widget widget = (Widget) GetClientWidget();
1210 Display *display = XtDisplay((Widget) GetMainWidget());
1211 Window rootWindow = RootWindowOfScreen(XtScreen(widget));
1212 Window thisWindow = XtWindow(widget);
1213
1214 Window childWindow;
1215 int xx = *x;
1216 int yy = *y;
1217 XTranslateCoordinates(display, rootWindow, thisWindow, xx, yy, x, y, &childWindow);
1218 }
1219
1220 void wxWindow::DoClientToScreen(int *x, int *y) const
1221 {
1222 Widget widget = (Widget) GetClientWidget();
1223 Display *display = XtDisplay(widget);
1224 Window rootWindow = RootWindowOfScreen(XtScreen(widget));
1225 Window thisWindow = XtWindow(widget);
1226
1227 Window childWindow;
1228 int xx = *x;
1229 int yy = *y;
1230 XTranslateCoordinates(display, thisWindow, rootWindow, xx, yy, x, y, &childWindow);
1231 }
1232
1233
1234 // Get size *available for subwindows* i.e. excluding menu bar etc.
1235 void wxWindow::DoGetClientSize(int *x, int *y) const
1236 {
1237 Widget widget = (Widget) GetClientWidget();
1238 Dimension xx, yy;
1239 XtVaGetValues(widget, XmNwidth, &xx, XmNheight, &yy, NULL);
1240 if(x) *x = xx; if(y) *y = yy;
1241 }
1242
1243 void wxWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags)
1244 {
1245 DoSetSizeIntr(x, y, width, height, sizeFlags, FALSE);
1246 }
1247
1248 void wxWindow::DoSetSizeIntr(int x, int y, int width, int height,
1249 int sizeFlags, bool fromCtor)
1250 {
1251 // A bit of optimization to help sort out the flickers.
1252 int oldX = -1, oldY = -1, oldW = -1, oldH = -1;
1253 if( !fromCtor )
1254 {
1255 GetSize(& oldW, & oldH);
1256 GetPosition(& oldX, & oldY);
1257 }
1258
1259 if ( !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
1260 {
1261 if ( x == -1 )
1262 x = oldX;
1263 if ( y == -1 )
1264 y = oldY;
1265 }
1266
1267 wxSize size(-1, -1);
1268 if ( width <= 0 )
1269 {
1270 if ( ( sizeFlags & wxSIZE_AUTO_WIDTH ) && !fromCtor )
1271 {
1272 size = DoGetBestSize();
1273 width = size.x;
1274 }
1275 else
1276 {
1277 width = oldW;
1278 }
1279 }
1280
1281 if ( height == -1 )
1282 {
1283 if( ( sizeFlags & wxSIZE_AUTO_HEIGHT ) && !fromCtor )
1284 {
1285 if( size.x == -1 ) size = DoGetBestSize();
1286 height = size.y;
1287 }
1288 else
1289 {
1290 height = oldH;
1291 }
1292 }
1293
1294 if ( x != oldX || y != oldY || width != oldW || height != oldH
1295 || !wxNoOptimize::CanOptimize() )
1296 {
1297 if (m_drawingArea)
1298 {
1299 int flags = 0;
1300
1301 if (x > -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
1302 flags |= wxMOVE_X;
1303
1304 if (y > -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
1305 flags |= wxMOVE_Y;
1306
1307 if (width > 0)
1308 flags |= wxMOVE_WIDTH;
1309
1310 if (height > 0)
1311 flags |= wxMOVE_HEIGHT;
1312
1313 int xx = x; int yy = y;
1314 AdjustForParentClientOrigin(xx, yy, sizeFlags);
1315 if( !fromCtor )
1316 DoMoveWindow( xx, yy, width, height );
1317 else
1318 DoMoveWindowIntr( xx, yy, width, height, flags );
1319
1320 return;
1321 }
1322
1323 Widget widget = (Widget) GetTopWidget();
1324 if (!widget)
1325 return;
1326
1327 bool managed = XtIsManaged( widget );
1328 if (managed)
1329 XtUnmanageChild(widget);
1330
1331 int xx = x;
1332 int yy = y;
1333 AdjustForParentClientOrigin(xx, yy, sizeFlags);
1334
1335 DoMoveWindow(xx, yy, width, height);
1336
1337 if (managed)
1338 XtManageChild(widget);
1339 }
1340 }
1341
1342 void wxWindow::DoSetClientSize(int width, int height)
1343 {
1344 if (m_drawingArea)
1345 {
1346 Widget drawingArea = (Widget) m_drawingArea;
1347
1348 XtVaSetValues(drawingArea, XmNresizePolicy, XmRESIZE_ANY, NULL);
1349
1350 if (width > -1)
1351 XtVaSetValues(drawingArea, XmNwidth, width, NULL);
1352 if (height > -1)
1353 XtVaSetValues(drawingArea, XmNheight, height, NULL);
1354
1355 XtVaSetValues(drawingArea, XmNresizePolicy, XmRESIZE_NONE, NULL);
1356 return;
1357 }
1358
1359 Widget widget = (Widget) GetTopWidget();
1360
1361 if (width > -1)
1362 XtVaSetValues(widget, XmNwidth, width, NULL);
1363 if (height > -1)
1364 XtVaSetValues(widget, XmNheight, height, NULL);
1365 }
1366
1367 // For implementation purposes - sometimes decorations make the client area
1368 // smaller
1369 wxPoint wxWindow::GetClientAreaOrigin() const
1370 {
1371 return wxPoint(0, 0);
1372 }
1373
1374 void wxWindow::DoMoveWindowIntr(int xx, int yy, int w, int h,
1375 int flags)
1376 {
1377 if (m_drawingArea)
1378 {
1379 Widget drawingArea = (Widget) m_drawingArea;
1380 Widget borderOrScrolled = m_borderWidget ?
1381 (Widget) m_borderWidget :
1382 (Widget) m_scrolledWindow;
1383
1384 bool managed = XtIsManaged(borderOrScrolled);
1385 if (managed)
1386 XtUnmanageChild (borderOrScrolled);
1387 XtVaSetValues(drawingArea, XmNresizePolicy, XmRESIZE_ANY, NULL);
1388
1389 if (flags & wxMOVE_X)
1390 XtVaSetValues (borderOrScrolled,
1391 XmNx, xx,
1392 NULL);
1393 if (flags & wxMOVE_Y)
1394 XtVaSetValues (borderOrScrolled,
1395 XmNy, yy,
1396 NULL);
1397
1398 if (flags & wxMOVE_WIDTH)
1399 {
1400 if (m_borderWidget)
1401 {
1402 XtVaSetValues ((Widget) m_borderWidget, XmNwidth, w, NULL);
1403 short thick, margin;
1404 XtVaGetValues ((Widget) m_borderWidget,
1405 XmNshadowThickness, &thick,
1406 XmNmarginWidth, &margin,
1407 NULL);
1408 w -= 2 * (thick + margin);
1409 }
1410
1411 if( w < 1 ) w = 1;
1412 XtVaSetValues ((Widget) m_scrolledWindow, XmNwidth, w, NULL);
1413 }
1414
1415 if (flags & wxMOVE_HEIGHT)
1416 {
1417 if (m_borderWidget)
1418 {
1419 XtVaSetValues ((Widget) m_borderWidget, XmNheight, h, NULL);
1420 short thick, margin;
1421 XtVaGetValues ((Widget) m_borderWidget,
1422 XmNshadowThickness, &thick,
1423 XmNmarginHeight, &margin,
1424 NULL);
1425 h -= 2 * (thick + margin);
1426 }
1427
1428 if( h < 1 ) h = 1;
1429 XtVaSetValues ((Widget) m_scrolledWindow, XmNheight, h, NULL);
1430 }
1431
1432 if (managed)
1433 XtManageChild (borderOrScrolled);
1434 XtVaSetValues(drawingArea, XmNresizePolicy, XmRESIZE_NONE, NULL);
1435 }
1436 else
1437 {
1438 if( w < 1 ) w = 1;
1439 if( h < 1 ) h = 1;
1440
1441 XtVaSetValues((Widget)GetTopWidget(),
1442 XmNx, xx,
1443 XmNy, yy,
1444 XmNwidth, w,
1445 XmNheight, h,
1446 NULL);
1447 }
1448 }
1449
1450 void wxWindow::DoMoveWindow(int x, int y, int width, int height)
1451 {
1452 DoMoveWindowIntr (x, y, width, height,
1453 wxMOVE_X|wxMOVE_Y|wxMOVE_WIDTH|wxMOVE_HEIGHT);
1454 }
1455
1456 // ---------------------------------------------------------------------------
1457 // text metrics
1458 // ---------------------------------------------------------------------------
1459
1460 int wxWindow::GetCharHeight() const
1461 {
1462 wxCHECK_MSG( m_font.Ok(), 0, "valid window font needed" );
1463
1464 WXFontStructPtr pFontStruct = m_font.GetFontStruct(1.0, GetXDisplay());
1465
1466 int direction, ascent, descent;
1467 XCharStruct overall;
1468 XTextExtents ((XFontStruct*) pFontStruct, "x", 1, &direction, &ascent,
1469 &descent, &overall);
1470
1471 // return (overall.ascent + overall.descent);
1472 return (ascent + descent);
1473 }
1474
1475 int wxWindow::GetCharWidth() const
1476 {
1477 wxCHECK_MSG( m_font.Ok(), 0, "valid window font needed" );
1478
1479 WXFontStructPtr pFontStruct = m_font.GetFontStruct(1.0, GetXDisplay());
1480
1481 int direction, ascent, descent;
1482 XCharStruct overall;
1483 XTextExtents ((XFontStruct*) pFontStruct, "x", 1, &direction, &ascent,
1484 &descent, &overall);
1485
1486 return overall.width;
1487 }
1488
1489 void wxWindow::GetTextExtent(const wxString& string,
1490 int *x, int *y,
1491 int *descent, int *externalLeading,
1492 const wxFont *theFont) const
1493 {
1494 wxFont *fontToUse = (wxFont *)theFont;
1495 if (!fontToUse)
1496 fontToUse = (wxFont *) & m_font;
1497
1498 wxCHECK_RET( fontToUse->Ok(), "valid window font needed" );
1499
1500 WXFontStructPtr pFontStruct = fontToUse->GetFontStruct(1.0, GetXDisplay());
1501
1502 int direction, ascent, descent2;
1503 XCharStruct overall;
1504 int slen = string.Len();
1505
1506 #if 0
1507 if (use16)
1508 XTextExtents16((XFontStruct*) pFontStruct, (XChar2b *) (char*) (const char*) string, slen, &direction,
1509 &ascent, &descent2, &overall);
1510 #endif
1511
1512 XTextExtents((XFontStruct*) pFontStruct, string, slen,
1513 &direction, &ascent, &descent2, &overall);
1514
1515 if ( x )
1516 *x = (overall.width);
1517 if ( y )
1518 *y = (ascent + descent2);
1519 if (descent)
1520 *descent = descent2;
1521 if (externalLeading)
1522 *externalLeading = 0;
1523
1524 }
1525
1526 // ----------------------------------------------------------------------------
1527 // painting
1528 // ----------------------------------------------------------------------------
1529
1530 void wxWindow::AddUpdateRect(int x, int y, int w, int h)
1531 {
1532 m_updateRegion.Union( x, y, w, h );
1533 }
1534
1535 void wxWindow::Refresh(bool eraseBack, const wxRect *rect)
1536 {
1537 m_needsRefresh = TRUE;
1538 Display *display = XtDisplay((Widget) GetMainWidget());
1539 Window thisWindow = XtWindow((Widget) GetMainWidget());
1540
1541 XExposeEvent dummyEvent;
1542 int width, height;
1543 GetSize(&width, &height);
1544
1545 dummyEvent.type = Expose;
1546 dummyEvent.display = display;
1547 dummyEvent.send_event = True;
1548 dummyEvent.window = thisWindow;
1549 if (rect)
1550 {
1551 dummyEvent.x = rect->x;
1552 dummyEvent.y = rect->y;
1553 dummyEvent.width = rect->width;
1554 dummyEvent.height = rect->height;
1555 }
1556 else
1557 {
1558 dummyEvent.x = 0;
1559 dummyEvent.y = 0;
1560 dummyEvent.width = width;
1561 dummyEvent.height = height;
1562 }
1563 dummyEvent.count = 0;
1564
1565 if (eraseBack)
1566 {
1567 wxClientDC dc(this);
1568 wxBrush backgroundBrush(GetBackgroundColour(), wxSOLID);
1569 dc.SetBackground(backgroundBrush);
1570 if (rect)
1571 dc.Clear(*rect);
1572 else
1573 dc.Clear();
1574 }
1575
1576 XSendEvent(display, thisWindow, False, ExposureMask, (XEvent *)&dummyEvent);
1577 }
1578
1579 void wxWindow::DoPaint()
1580 {
1581 //TODO : make a temporary gc so we can do the XCopyArea below
1582 if (m_backingPixmap && !m_needsRefresh)
1583 {
1584 wxPaintDC dc(this);
1585
1586 GC tempGC = (GC) dc.GetBackingGC();
1587
1588 Widget widget = (Widget) GetMainWidget();
1589
1590 int scrollPosX = 0;
1591 int scrollPosY = 0;
1592
1593 // We have to test whether it's a wxScrolledWindow (hack!) because
1594 // otherwise we don't know how many pixels have been scrolled. We might
1595 // solve this in the future by defining virtual wxWindow functions to get
1596 // the scroll position in pixels. Or, each kind of scrolled window has to
1597 // implement backing stores itself, using generic wxWindows code.
1598 wxScrolledWindow* scrolledWindow = wxDynamicCast(this, wxScrolledWindow);
1599 if ( scrolledWindow )
1600 {
1601 int x, y;
1602 scrolledWindow->CalcScrolledPosition(0, 0, &x, &y);
1603
1604 scrollPosX = - x;
1605 scrollPosY = - y;
1606 }
1607
1608 // TODO: This could be optimized further by only copying the areas in the
1609 // current update region.
1610
1611 // Only blit the part visible in the client area. The backing pixmap
1612 // always starts at 0, 0 but we may be looking at only a portion of it.
1613 wxSize clientArea = GetClientSize();
1614 int toBlitX = m_pixmapWidth - scrollPosX;
1615 int toBlitY = m_pixmapHeight - scrollPosY;
1616
1617 // Copy whichever is samller, the amount of pixmap we have to copy,
1618 // or the size of the client area.
1619 toBlitX = wxMin(toBlitX, clientArea.x);
1620 toBlitY = wxMin(toBlitY, clientArea.y);
1621
1622 // Make sure we're not negative
1623 toBlitX = wxMax(0, toBlitX);
1624 toBlitY = wxMax(0, toBlitY);
1625
1626 XCopyArea
1627 (
1628 XtDisplay(widget),
1629 (Pixmap) m_backingPixmap,
1630 XtWindow (widget),
1631 tempGC,
1632 scrollPosX, scrollPosY, // Start at the scroll position
1633 toBlitX, toBlitY, // How much of the pixmap to copy
1634 0, 0 // Destination
1635 );
1636 }
1637 else
1638 {
1639 wxWindowDC dc(this);
1640 // Set an erase event first
1641 wxEraseEvent eraseEvent(GetId(), &dc);
1642 eraseEvent.SetEventObject(this);
1643 GetEventHandler()->ProcessEvent(eraseEvent);
1644
1645 wxPaintEvent event(GetId());
1646 event.SetEventObject(this);
1647 GetEventHandler()->ProcessEvent(event);
1648
1649 m_needsRefresh = FALSE;
1650 }
1651 }
1652
1653 // ----------------------------------------------------------------------------
1654 // event handlers
1655 // ----------------------------------------------------------------------------
1656
1657 // Responds to colour changes: passes event on to children.
1658 void wxWindow::OnSysColourChanged(wxSysColourChangedEvent& event)
1659 {
1660 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
1661 while ( node )
1662 {
1663 // Only propagate to non-top-level windows
1664 wxWindow *win = node->GetData();
1665 if ( win->GetParent() )
1666 {
1667 wxSysColourChangedEvent event2;
1668 event.m_eventObject = win;
1669 win->GetEventHandler()->ProcessEvent(event2);
1670 }
1671
1672 node = node->GetNext();
1673 }
1674 }
1675
1676 void wxWindow::OnInternalIdle()
1677 {
1678 // This calls the UI-update mechanism (querying windows for
1679 // menu/toolbar/control state information)
1680 if (wxUpdateUIEvent::CanUpdate(this))
1681 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
1682 }
1683
1684 // ----------------------------------------------------------------------------
1685 // accelerators
1686 // ----------------------------------------------------------------------------
1687
1688 bool wxWindow::ProcessAccelerator(wxKeyEvent& event)
1689 {
1690 #if wxUSE_ACCEL
1691 if (!m_acceleratorTable.Ok())
1692 return FALSE;
1693
1694 int count = m_acceleratorTable.GetCount();
1695 wxAcceleratorEntry* entries = m_acceleratorTable.GetEntries();
1696 int i;
1697 for (i = 0; i < count; i++)
1698 {
1699 wxAcceleratorEntry* entry = & (entries[i]);
1700 if (entry->MatchesEvent(event))
1701 {
1702 // Bingo, we have a match. Now find a control that matches the
1703 // entry command id.
1704
1705 // Need to go up to the top of the window hierarchy, since it might
1706 // be e.g. a menu item
1707 wxWindow* parent = this;
1708 while ( parent && !parent->IsTopLevel() )
1709 parent = parent->GetParent();
1710
1711 if (!parent)
1712 return FALSE;
1713
1714 wxFrame* frame = wxDynamicCast(parent, wxFrame);
1715 if ( frame )
1716 {
1717 #if wxUSE_MENUS
1718 // Try for a menu command
1719 if (frame->GetMenuBar())
1720 {
1721 wxMenuItem* item = frame->GetMenuBar()->FindItem(entry->GetCommand());
1722 if (item)
1723 {
1724 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, entry->GetCommand());
1725 commandEvent.SetEventObject(frame);
1726
1727 // If ProcessEvent returns TRUE (it was handled), then
1728 // the calling code will skip the event handling.
1729 return frame->GetEventHandler()->ProcessEvent(commandEvent);
1730 }
1731 }
1732 #endif
1733 }
1734
1735 // Find a child matching the command id
1736 wxWindow* child = parent->FindWindow(entry->GetCommand());
1737
1738 // No such child
1739 if (!child)
1740 return FALSE;
1741
1742 // Now we process those kinds of windows that we can.
1743 // For now, only buttons.
1744 if ( wxDynamicCast(child, wxButton) )
1745 {
1746 wxCommandEvent commandEvent (wxEVT_COMMAND_BUTTON_CLICKED, child->GetId());
1747 commandEvent.SetEventObject(child);
1748 return child->GetEventHandler()->ProcessEvent(commandEvent);
1749 }
1750
1751 return FALSE;
1752 } // matches event
1753 }// for
1754 #endif
1755
1756 // We didn't match the key event against an accelerator.
1757 return FALSE;
1758 }
1759
1760 // ============================================================================
1761 // Motif-specific stuff from here on
1762 // ============================================================================
1763
1764 // ----------------------------------------------------------------------------
1765 // function which maintain the global hash table mapping Widgets to wxWindows
1766 // ----------------------------------------------------------------------------
1767
1768 bool wxAddWindowToTable(Widget w, wxWindow *win)
1769 {
1770 wxWindow *oldItem = NULL;
1771 if ((oldItem = (wxWindow *)wxWidgetHashTable->Get ((long) w)))
1772 {
1773 wxLogDebug("Widget table clash: new widget is %ld, %s",
1774 (long)w, win->GetClassInfo()->GetClassName());
1775 return FALSE;
1776 }
1777
1778 wxWidgetHashTable->Put((long) w, win);
1779
1780 wxLogTrace("widget", "Widget 0x%p <-> window %p (%s)",
1781 (WXWidget)w, win, win->GetClassInfo()->GetClassName());
1782
1783 return TRUE;
1784 }
1785
1786 wxWindow *wxGetWindowFromTable(Widget w)
1787 {
1788 return (wxWindow *)wxWidgetHashTable->Get((long) w);
1789 }
1790
1791 void wxDeleteWindowFromTable(Widget w)
1792 {
1793 wxLogTrace("widget", "Widget 0x%p", (WXWidget)w);
1794
1795 wxWidgetHashTable->Delete((long)w);
1796 }
1797
1798 // ----------------------------------------------------------------------------
1799 // add/remove window from the table
1800 // ----------------------------------------------------------------------------
1801
1802 // Add to hash table, add event handler
1803 bool wxWindow::AttachWidget (wxWindow* WXUNUSED(parent), WXWidget mainWidget,
1804 WXWidget formWidget, int x, int y, int width, int height)
1805 {
1806 wxAddWindowToTable((Widget) mainWidget, this);
1807 XtAddEventHandler( (Widget) mainWidget,
1808 ButtonPressMask | ButtonReleaseMask
1809 | PointerMotionMask,
1810 False,
1811 wxPanelItemEventHandler,
1812 (XtPointer) this);
1813
1814 if (!formWidget)
1815 {
1816 XtTranslations ptr;
1817 XtOverrideTranslations ((Widget) mainWidget,
1818 ptr = XtParseTranslationTable ("<Configure>: resize()"));
1819 XtFree ((char *) ptr);
1820 }
1821
1822 // Some widgets have a parent form widget, e.g. wxRadioBox
1823 if (formWidget)
1824 {
1825 if (!wxAddWindowToTable((Widget) formWidget, this))
1826 return FALSE;
1827
1828 XtTranslations ptr;
1829 XtOverrideTranslations ((Widget) formWidget,
1830 ptr = XtParseTranslationTable ("<Configure>: resize()"));
1831 XtFree ((char *) ptr);
1832 }
1833
1834 if (x == -1)
1835 x = 0;
1836 if (y == -1)
1837 y = 0;
1838 SetSize (x, y, width, height);
1839
1840 return TRUE;
1841 }
1842
1843 // Remove event handler, remove from hash table
1844 bool wxWindow::DetachWidget(WXWidget widget)
1845 {
1846 XtRemoveEventHandler( (Widget) widget,
1847 ButtonPressMask | ButtonReleaseMask
1848 | PointerMotionMask,
1849 False,
1850 wxPanelItemEventHandler,
1851 (XtPointer)this);
1852
1853 wxDeleteWindowFromTable((Widget) widget);
1854 return TRUE;
1855 }
1856
1857 // ----------------------------------------------------------------------------
1858 // Motif-specific accessors
1859 // ----------------------------------------------------------------------------
1860
1861 WXWindow wxWindow::GetClientXWindow() const
1862 {
1863 Widget wMain = (Widget)GetClientWidget();
1864 if ( wMain )
1865 return (WXWindow) XtWindow(wMain);
1866 else
1867 return (WXWindow) 0;
1868 }
1869
1870 // Get the underlying X window
1871 WXWindow wxWindow::GetXWindow() const
1872 {
1873 Widget wMain = (Widget)GetMainWidget();
1874 if ( wMain )
1875 return (WXWindow) XtWindow(wMain);
1876 else
1877 return (WXWindow) 0;
1878 }
1879
1880 // Get the underlying X display
1881 WXDisplay *wxWindow::GetXDisplay() const
1882 {
1883 Widget wMain = (Widget)GetMainWidget();
1884 if ( wMain )
1885 return (WXDisplay*) XtDisplay(wMain);
1886 else
1887 return (WXDisplay*) NULL;
1888 }
1889
1890 WXWidget wxWindow::GetMainWidget() const
1891 {
1892 if (m_drawingArea)
1893 return m_drawingArea;
1894 else
1895 return m_mainWidget;
1896 }
1897
1898 WXWidget wxWindow::GetClientWidget() const
1899 {
1900 if (m_drawingArea != (WXWidget) 0)
1901 return m_drawingArea;
1902 else
1903 return GetMainWidget();
1904 }
1905
1906 WXWidget wxWindow::GetTopWidget() const
1907 {
1908 return GetMainWidget();
1909 }
1910
1911 WXWidget wxWindow::GetLabelWidget() const
1912 {
1913 return GetMainWidget();
1914 }
1915
1916 // ----------------------------------------------------------------------------
1917 // Motif callbacks
1918 // ----------------------------------------------------------------------------
1919
1920 // All widgets should have this as their resize proc.
1921 // OnSize sent to wxWindow via client data.
1922 void wxWidgetResizeProc(Widget w, XConfigureEvent *WXUNUSED(event),
1923 String WXUNUSED(args)[], int *WXUNUSED(num_args))
1924 {
1925 wxWindow *win = wxGetWindowFromTable(w);
1926 if (!win)
1927 return;
1928
1929 if (win->PreResize())
1930 {
1931 int width, height;
1932 win->GetSize(&width, &height);
1933 wxSizeEvent sizeEvent(wxSize(width, height), win->GetId());
1934 sizeEvent.SetEventObject(win);
1935 win->GetEventHandler()->ProcessEvent(sizeEvent);
1936 }
1937 }
1938
1939 static void wxCanvasRepaintProc(Widget drawingArea,
1940 XtPointer clientData,
1941 XmDrawingAreaCallbackStruct * cbs)
1942 {
1943 if (!wxGetWindowFromTable(drawingArea))
1944 return;
1945
1946 XEvent * event = cbs->event;
1947 wxWindow * win = (wxWindow *) clientData;
1948
1949 switch (event->type)
1950 {
1951 case Expose:
1952 {
1953 win->AddUpdateRect(event->xexpose.x, event->xexpose.y,
1954 event->xexpose.width, event->xexpose.height);
1955
1956 if (event -> xexpose.count == 0)
1957 {
1958 win->DoPaint();
1959 }
1960 break;
1961 }
1962 }
1963 }
1964
1965 // Unable to deal with Enter/Leave without a separate EventHandler (Motif 1.1.4)
1966 static void wxCanvasEnterLeave(Widget drawingArea,
1967 XtPointer WXUNUSED(clientData),
1968 XCrossingEvent * event)
1969 {
1970 XmDrawingAreaCallbackStruct cbs;
1971 XEvent ev;
1972
1973 ((XCrossingEvent &) ev) = *event;
1974
1975 cbs.reason = XmCR_INPUT;
1976 cbs.event = &ev;
1977
1978 wxCanvasInputEvent(drawingArea, (XtPointer) NULL, &cbs);
1979 }
1980
1981 // Fix to make it work under Motif 1.0 (!)
1982 static void wxCanvasMotionEvent (Widget WXUNUSED(drawingArea),
1983 XButtonEvent *WXUNUSED(event))
1984 {
1985 #if XmVersion <= 1000
1986 XmDrawingAreaCallbackStruct cbs;
1987 XEvent ev;
1988
1989 ev = *((XEvent *) event);
1990 cbs.reason = XmCR_INPUT;
1991 cbs.event = &ev;
1992
1993 wxCanvasInputEvent (drawingArea, (XtPointer) NULL, &cbs);
1994 #endif // XmVersion <= 1000
1995 }
1996
1997 static void wxCanvasInputEvent(Widget drawingArea,
1998 XtPointer WXUNUSED(data),
1999 XmDrawingAreaCallbackStruct * cbs)
2000 {
2001 wxWindow *canvas = wxGetWindowFromTable(drawingArea);
2002 XEvent local_event;
2003
2004 if (canvas==NULL)
2005 return;
2006
2007 if (cbs->reason != XmCR_INPUT)
2008 return;
2009
2010 local_event = *(cbs->event); // We must keep a copy!
2011
2012 switch (local_event.xany.type)
2013 {
2014 case EnterNotify:
2015 case LeaveNotify:
2016 case ButtonPress:
2017 case ButtonRelease:
2018 case MotionNotify:
2019 {
2020 wxMouseEvent wxevent;
2021 if(wxTranslateMouseEvent(wxevent, canvas, drawingArea, &local_event))
2022 {
2023 canvas->GetEventHandler()->ProcessEvent(wxevent);
2024 }
2025 break;
2026 }
2027 case KeyPress:
2028 {
2029 wxKeyEvent event (wxEVT_CHAR);
2030 if (wxTranslateKeyEvent (event, canvas, (Widget) 0, &local_event))
2031 {
2032 // Implement wxFrame::OnCharHook by checking ancestor.
2033 wxWindow *parent = canvas;
2034 while (parent && !parent->IsTopLevel())
2035 parent = parent->GetParent();
2036
2037 if (parent)
2038 {
2039 event.SetEventType(wxEVT_CHAR_HOOK);
2040 if (parent->GetEventHandler()->ProcessEvent(event))
2041 return;
2042 }
2043
2044 // For simplicity, OnKeyDown is the same as OnChar
2045 // TODO: filter modifier key presses from OnChar
2046 event.SetEventType(wxEVT_KEY_DOWN);
2047
2048 // Only process OnChar if OnKeyDown didn't swallow it
2049 if (!canvas->GetEventHandler()->ProcessEvent (event))
2050 {
2051 event.SetEventType(wxEVT_CHAR);
2052 canvas->GetEventHandler()->ProcessEvent (event);
2053 }
2054 }
2055 break;
2056 }
2057 case KeyRelease:
2058 {
2059 wxKeyEvent event (wxEVT_KEY_UP);
2060 if (wxTranslateKeyEvent (event, canvas, (Widget) 0, &local_event))
2061 {
2062 canvas->GetEventHandler()->ProcessEvent (event);
2063 }
2064 break;
2065 }
2066 case FocusIn:
2067 {
2068 if (local_event.xfocus.detail != NotifyPointer)
2069 {
2070 wxFocusEvent event(wxEVT_SET_FOCUS, canvas->GetId());
2071 event.SetEventObject(canvas);
2072 canvas->GetEventHandler()->ProcessEvent(event);
2073 }
2074 break;
2075 }
2076 case FocusOut:
2077 {
2078 if (local_event.xfocus.detail != NotifyPointer)
2079 {
2080 wxFocusEvent event(wxEVT_KILL_FOCUS, canvas->GetId());
2081 event.SetEventObject(canvas);
2082 canvas->GetEventHandler()->ProcessEvent(event);
2083 }
2084 break;
2085 }
2086 default:
2087 break;
2088 }
2089 }
2090
2091 static void wxPanelItemEventHandler(Widget wid,
2092 XtPointer WXUNUSED(client_data),
2093 XEvent* event,
2094 Boolean *continueToDispatch)
2095 {
2096 // Widget can be a label or the actual widget.
2097
2098 wxWindow *window = wxGetWindowFromTable(wid);
2099 if (window)
2100 {
2101 wxMouseEvent wxevent(0);
2102 if (wxTranslateMouseEvent(wxevent, window, wid, event))
2103 {
2104 window->GetEventHandler()->ProcessEvent(wxevent);
2105 }
2106 }
2107
2108 // TODO: probably the key to allowing default behaviour to happen. Say we
2109 // set a m_doDefault flag to FALSE at the start of this function. Then in
2110 // e.g. wxWindow::OnMouseEvent we can call Default() which sets this flag to
2111 // TRUE, indicating that default processing can happen. Thus, behaviour can
2112 // appear to be overridden just by adding an event handler and not calling
2113 // wxWindow::OnWhatever. ALSO, maybe we can use this instead of the current
2114 // way of handling drawing area events, to simplify things.
2115 *continueToDispatch = True;
2116 }
2117
2118 static void wxScrollBarCallback(Widget scrollbar,
2119 XtPointer clientData,
2120 XmScrollBarCallbackStruct *cbs)
2121 {
2122 wxWindow *win = wxGetWindowFromTable(scrollbar);
2123 wxOrientation orientation = (wxOrientation)(int)clientData;
2124
2125 wxEventType eventType = wxEVT_NULL;
2126 switch (cbs->reason)
2127 {
2128 case XmCR_INCREMENT:
2129 {
2130 eventType = wxEVT_SCROLLWIN_LINEDOWN;
2131 break;
2132 }
2133 case XmCR_DECREMENT:
2134 {
2135 eventType = wxEVT_SCROLLWIN_LINEUP;
2136 break;
2137 }
2138 case XmCR_DRAG:
2139 {
2140 eventType = wxEVT_SCROLLWIN_THUMBTRACK;
2141 break;
2142 }
2143 case XmCR_VALUE_CHANGED:
2144 {
2145 eventType = wxEVT_SCROLLWIN_THUMBRELEASE;
2146 break;
2147 }
2148 case XmCR_PAGE_INCREMENT:
2149 {
2150 eventType = wxEVT_SCROLLWIN_PAGEDOWN;
2151 break;
2152 }
2153 case XmCR_PAGE_DECREMENT:
2154 {
2155 eventType = wxEVT_SCROLLWIN_PAGEUP;
2156 break;
2157 }
2158 case XmCR_TO_TOP:
2159 {
2160 eventType = wxEVT_SCROLLWIN_TOP;
2161 break;
2162 }
2163 case XmCR_TO_BOTTOM:
2164 {
2165 eventType = wxEVT_SCROLLWIN_BOTTOM;
2166 break;
2167 }
2168 default:
2169 {
2170 // Should never get here
2171 wxFAIL_MSG("Unknown scroll event.");
2172 break;
2173 }
2174 }
2175
2176 wxScrollWinEvent event(eventType,
2177 cbs->value,
2178 orientation);
2179 event.SetEventObject( win );
2180 win->GetEventHandler()->ProcessEvent(event);
2181 }
2182
2183 // For repainting arbitrary windows
2184 void wxUniversalRepaintProc(Widget w, XtPointer WXUNUSED(c_data), XEvent *event, char *)
2185 {
2186 Window window;
2187 Display *display;
2188
2189 wxWindow* win = wxGetWindowFromTable(w);
2190 if (!win)
2191 return;
2192
2193 switch(event -> type)
2194 {
2195 case Expose:
2196 {
2197 window = (Window) win -> GetXWindow();
2198 display = (Display *) win -> GetXDisplay();
2199
2200 win->AddUpdateRect(event->xexpose.x, event->xexpose.y,
2201 event->xexpose.width, event->xexpose.height);
2202
2203 if (event -> xexpose.count == 0)
2204 {
2205 win->DoPaint();
2206 }
2207
2208 break;
2209 }
2210 }
2211 }
2212
2213 // ----------------------------------------------------------------------------
2214 // TranslateXXXEvent() functions
2215 // ----------------------------------------------------------------------------
2216
2217 bool wxTranslateMouseEvent(wxMouseEvent& wxevent, wxWindow *win,
2218 Widget widget, XEvent *xevent)
2219 {
2220 switch (xevent->xany.type)
2221 {
2222 case EnterNotify:
2223 case LeaveNotify:
2224 #if 0
2225 fprintf(stderr, "Widget 0x%p <-> window %p (%s), %s\n",
2226 (WXWidget)widget, win, win->GetClassInfo()->GetClassName(),
2227 (xevent->xany.type == EnterNotify ? "ENTER" : "LEAVE"));
2228 #endif
2229 case ButtonPress:
2230 case ButtonRelease:
2231 case MotionNotify:
2232 {
2233 wxEventType eventType = wxEVT_NULL;
2234
2235 if (xevent->xany.type == LeaveNotify)
2236 {
2237 eventType = wxEVT_LEAVE_WINDOW;
2238 }
2239 if (xevent->xany.type == EnterNotify)
2240 {
2241 eventType = wxEVT_ENTER_WINDOW;
2242 }
2243 else if (xevent->xany.type == MotionNotify)
2244 {
2245 eventType = wxEVT_MOTION;
2246 }
2247 else if (xevent->xany.type == ButtonPress)
2248 {
2249 wxevent.SetTimestamp(xevent->xbutton.time);
2250 int button = 0;
2251 if (xevent->xbutton.button == Button1)
2252 {
2253 eventType = wxEVT_LEFT_DOWN;
2254 button = 1;
2255 }
2256 else if (xevent->xbutton.button == Button2)
2257 {
2258 eventType = wxEVT_MIDDLE_DOWN;
2259 button = 2;
2260 }
2261 else if (xevent->xbutton.button == Button3)
2262 {
2263 eventType = wxEVT_RIGHT_DOWN;
2264 button = 3;
2265 }
2266
2267 // check for a double click
2268 //
2269 long dclickTime = XtGetMultiClickTime(xevent->xany.display);
2270 long ts = wxevent.GetTimestamp();
2271
2272 int buttonLast = win->GetLastClickedButton();
2273 long lastTS = win->GetLastClickTime();
2274 if ( buttonLast && buttonLast == button &&
2275 (ts - lastTS) < dclickTime )
2276 {
2277 // I have a dclick
2278 win->SetLastClick(0, ts);
2279 if ( eventType == wxEVT_LEFT_DOWN )
2280 eventType = wxEVT_LEFT_DCLICK;
2281 else if ( eventType == wxEVT_MIDDLE_DOWN )
2282 eventType = wxEVT_MIDDLE_DCLICK;
2283 else if ( eventType == wxEVT_RIGHT_DOWN )
2284 eventType = wxEVT_RIGHT_DCLICK;
2285 }
2286 else
2287 {
2288 // not fast enough or different button
2289 win->SetLastClick(button, ts);
2290 }
2291 }
2292 else if (xevent->xany.type == ButtonRelease)
2293 {
2294 if (xevent->xbutton.button == Button1)
2295 {
2296 eventType = wxEVT_LEFT_UP;
2297 }
2298 else if (xevent->xbutton.button == Button2)
2299 {
2300 eventType = wxEVT_MIDDLE_UP;
2301 }
2302 else if (xevent->xbutton.button == Button3)
2303 {
2304 eventType = wxEVT_RIGHT_UP;
2305 }
2306 else
2307 return FALSE;
2308 }
2309 else
2310 {
2311 return FALSE;
2312 }
2313
2314 wxevent.SetEventType(eventType);
2315
2316 Position x1, y1;
2317 XtVaGetValues(widget, XmNx, &x1, XmNy, &y1, NULL);
2318
2319 int x2, y2;
2320 win->GetPosition(&x2, &y2);
2321
2322 // The button x/y must be translated to wxWindows
2323 // window space - the widget might be a label or button,
2324 // within a form.
2325 int dx = 0;
2326 int dy = 0;
2327 if (widget != (Widget)win->GetMainWidget())
2328 {
2329 dx = x1;
2330 dy = y1;
2331 }
2332
2333 wxevent.m_x = xevent->xbutton.x + dx;
2334 wxevent.m_y = xevent->xbutton.y + dy;
2335
2336 wxevent.m_leftDown = ((eventType == wxEVT_LEFT_DOWN)
2337 || (event_left_is_down (xevent)
2338 && (eventType != wxEVT_LEFT_UP)));
2339 wxevent.m_middleDown = ((eventType == wxEVT_MIDDLE_DOWN)
2340 || (event_middle_is_down (xevent)
2341 && (eventType != wxEVT_MIDDLE_UP)));
2342 wxevent.m_rightDown = ((eventType == wxEVT_RIGHT_DOWN)
2343 || (event_right_is_down (xevent)
2344 && (eventType != wxEVT_RIGHT_UP)));
2345
2346 wxevent.m_shiftDown = xevent->xbutton.state & ShiftMask;
2347 wxevent.m_controlDown = xevent->xbutton.state & ControlMask;
2348 wxevent.m_altDown = xevent->xbutton.state & Mod3Mask;
2349 wxevent.m_metaDown = xevent->xbutton.state & Mod1Mask;
2350
2351 wxevent.SetId(win->GetId());
2352 wxevent.SetEventObject(win);
2353
2354 return TRUE;
2355 }
2356 }
2357 return FALSE;
2358 }
2359
2360 bool wxTranslateKeyEvent(wxKeyEvent& wxevent, wxWindow *win,
2361 Widget WXUNUSED(widget), XEvent *xevent)
2362 {
2363 switch (xevent->xany.type)
2364 {
2365 case KeyPress:
2366 case KeyRelease:
2367 {
2368 char buf[20];
2369
2370 KeySym keySym;
2371 (void) XLookupString((XKeyEvent *)xevent, buf, 20, &keySym, NULL);
2372 int id = wxCharCodeXToWX (keySym);
2373 // id may be WXK_xxx code - these are outside ASCII range, so we
2374 // can't just use toupper() on id
2375 if (id >= 'a' && id <= 'z')
2376 id = toupper(id);
2377
2378 if (xevent->xkey.state & ShiftMask)
2379 wxevent.m_shiftDown = TRUE;
2380 if (xevent->xkey.state & ControlMask)
2381 wxevent.m_controlDown = TRUE;
2382 if (xevent->xkey.state & Mod3Mask)
2383 wxevent.m_altDown = TRUE;
2384 if (xevent->xkey.state & Mod1Mask)
2385 wxevent.m_metaDown = TRUE;
2386 wxevent.SetEventObject(win);
2387 wxevent.m_keyCode = id;
2388 wxevent.SetTimestamp(xevent->xkey.time);
2389
2390 wxevent.m_x = xevent->xbutton.x;
2391 wxevent.m_y = xevent->xbutton.y;
2392
2393 if (id > -1)
2394 return TRUE;
2395 else
2396 return FALSE;
2397 break;
2398 }
2399 default:
2400 break;
2401 }
2402 return FALSE;
2403 }
2404
2405 // ----------------------------------------------------------------------------
2406 // Colour stuff
2407 // ----------------------------------------------------------------------------
2408
2409 #define YAllocColor XAllocColor
2410 XColor g_itemColors[5];
2411 int wxComputeColours (Display *display, wxColour * back, wxColour * fore)
2412 {
2413 int result;
2414 static XmColorProc colorProc;
2415
2416 result = wxNO_COLORS;
2417
2418 if (back)
2419 {
2420 g_itemColors[0].red = (((long) back->Red ()) << 8);
2421 g_itemColors[0].green = (((long) back->Green ()) << 8);
2422 g_itemColors[0].blue = (((long) back->Blue ()) << 8);
2423 g_itemColors[0].flags = DoRed | DoGreen | DoBlue;
2424 if (colorProc == (XmColorProc) NULL)
2425 {
2426 // Get a ptr to the actual function
2427 colorProc = XmSetColorCalculation ((XmColorProc) NULL);
2428 // And set it back to motif.
2429 XmSetColorCalculation (colorProc);
2430 }
2431 (*colorProc) (&g_itemColors[wxBACK_INDEX],
2432 &g_itemColors[wxFORE_INDEX],
2433 &g_itemColors[wxSELE_INDEX],
2434 &g_itemColors[wxTOPS_INDEX],
2435 &g_itemColors[wxBOTS_INDEX]);
2436 result = wxBACK_COLORS;
2437 }
2438 if (fore)
2439 {
2440 g_itemColors[wxFORE_INDEX].red = (((long) fore->Red ()) << 8);
2441 g_itemColors[wxFORE_INDEX].green = (((long) fore->Green ()) << 8);
2442 g_itemColors[wxFORE_INDEX].blue = (((long) fore->Blue ()) << 8);
2443 g_itemColors[wxFORE_INDEX].flags = DoRed | DoGreen | DoBlue;
2444 if (result == wxNO_COLORS)
2445 result = wxFORE_COLORS;
2446 }
2447
2448 Display *dpy = display;
2449 Colormap cmap = (Colormap) wxTheApp->GetMainColormap((WXDisplay*) dpy);
2450
2451 if (back)
2452 {
2453 /* 5 Colours to allocate */
2454 for (int i = 0; i < 5; i++)
2455 if (!YAllocColor (dpy, cmap, &g_itemColors[i]))
2456 result = wxNO_COLORS;
2457 }
2458 else if (fore)
2459 {
2460 /* Only 1 colour to allocate */
2461 if (!YAllocColor (dpy, cmap, &g_itemColors[wxFORE_INDEX]))
2462 result = wxNO_COLORS;
2463 }
2464
2465 return result;
2466 }
2467
2468 // Changes the foreground and background colours to be derived from the current
2469 // background colour. To change the foreground colour, you must call
2470 // SetForegroundColour explicitly.
2471 void wxWindow::ChangeBackgroundColour()
2472 {
2473 WXWidget mainWidget = GetMainWidget();
2474 if ( mainWidget )
2475 wxDoChangeBackgroundColour(mainWidget, m_backgroundColour);
2476 }
2477
2478 void wxWindow::ChangeForegroundColour()
2479 {
2480 WXWidget mainWidget = GetMainWidget();
2481 if ( mainWidget )
2482 wxDoChangeForegroundColour(mainWidget, m_foregroundColour);
2483 if ( m_scrolledWindow && mainWidget != m_scrolledWindow )
2484 wxDoChangeForegroundColour(m_scrolledWindow, m_foregroundColour);
2485 }
2486
2487 bool wxWindow::SetBackgroundColour(const wxColour& col)
2488 {
2489 if ( !wxWindowBase::SetBackgroundColour(col) )
2490 return FALSE;
2491
2492 ChangeBackgroundColour();
2493
2494 return TRUE;
2495 }
2496
2497 bool wxWindow::SetForegroundColour(const wxColour& col)
2498 {
2499 if ( !wxWindowBase::SetForegroundColour(col) )
2500 return FALSE;
2501
2502 ChangeForegroundColour();
2503
2504 return TRUE;
2505 }
2506
2507 void wxWindow::ChangeFont(bool keepOriginalSize)
2508 {
2509 // Note that this causes the widget to be resized back
2510 // to its original size! We therefore have to set the size
2511 // back again. TODO: a better way in Motif?
2512 Widget w = (Widget) GetLabelWidget(); // Usually the main widget
2513 if (w && m_font.Ok())
2514 {
2515 int width, height, width1, height1;
2516 GetSize(& width, & height);
2517
2518 wxDoChangeFont( GetLabelWidget(), m_font );
2519
2520 GetSize(& width1, & height1);
2521 if (keepOriginalSize && (width != width1 || height != height1))
2522 {
2523 SetSize(-1, -1, width, height);
2524 }
2525 }
2526 }
2527
2528 // ----------------------------------------------------------------------------
2529 // global functions
2530 // ----------------------------------------------------------------------------
2531
2532 wxWindow *wxGetActiveWindow()
2533 {
2534 // TODO
2535 wxFAIL_MSG("Not implemented");
2536 return NULL;
2537 }
2538
2539 /* static */
2540 wxWindow *wxWindowBase::GetCapture()
2541 {
2542 return (wxWindow *)g_captureWindow;
2543 }
2544
2545
2546 // Find the wxWindow at the current mouse position, returning the mouse
2547 // position.
2548 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
2549 {
2550 return wxFindWindowAtPoint(wxGetMousePosition());
2551 }
2552
2553 // Get the current mouse position.
2554 wxPoint wxGetMousePosition()
2555 {
2556 Display *display = wxGlobalDisplay();
2557 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
2558 Window rootReturn, childReturn;
2559 int rootX, rootY, winX, winY;
2560 unsigned int maskReturn;
2561
2562 XQueryPointer (display,
2563 rootWindow,
2564 &rootReturn,
2565 &childReturn,
2566 &rootX, &rootY, &winX, &winY, &maskReturn);
2567 return wxPoint(rootX, rootY);
2568 }
2569
2570
2571 // ----------------------------------------------------------------------------
2572 // wxNoOptimize: switch off size optimization
2573 // ----------------------------------------------------------------------------
2574
2575 int wxNoOptimize::ms_count = 0;
2576