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