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