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