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