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