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