]> git.saurik.com Git - wxWidgets.git/blob - src/motif/window.cpp
Added wxInfoBar::AddButton().
[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 #ifndef WX_PRECOMP
24 #include "wx/hash.h"
25 #include "wx/log.h"
26 #include "wx/app.h"
27 #include "wx/utils.h"
28 #include "wx/frame.h"
29 #include "wx/dc.h"
30 #include "wx/dcclient.h"
31 #include "wx/button.h"
32 #include "wx/menu.h"
33 #include "wx/settings.h"
34 #include "wx/scrolwin.h"
35 #include "wx/layout.h"
36 #include "wx/menuitem.h"
37 #include "wx/module.h"
38 #endif
39
40 #include "wx/evtloop.h"
41
42 #if wxUSE_DRAG_AND_DROP
43 #include "wx/dnd.h"
44 #endif
45
46 // DoSetSizeIntr and DoMoveWindowIntr
47 // PROBLEM:
48 // under Motif composite controls (such as wxCalendarCtrl or generic wxSpinCtrl
49 // did not work and/or segfaulted because
50 // 1) wxWindow::Create calls SetSize,
51 // which results in a call to DoSetSize much earlier than in the other ports
52 // 2) if wxWindow::Create is called (wxControl::Create calls it)
53 // then DoSetSize is never called, causing layout problems in composite
54 // controls
55 //
56 // SOLUTION:
57 // 1) don't call SetSize, DoSetSize, DoMoveWindow, DoGetPosition,
58 // DoSetPosition directly or indirectly from wxWindow::Create
59 // 2) call DoMoveWindow from DoSetSize, allowing controls to override it
60
61 #ifdef __VMS__
62 #pragma message disable nosimpint
63 #endif
64 #include <Xm/Xm.h>
65
66 #include <Xm/DrawingA.h>
67 #include <Xm/ScrolledW.h>
68 #include <Xm/ScrollBar.h>
69 #include <Xm/Frame.h>
70 #include <Xm/Label.h>
71 #include <Xm/RowColumn.h> // for XmMenuPosition
72 #ifdef __VMS__
73 #pragma message enable nosimpint
74 #endif
75
76 #include "wx/motif/private.h"
77 #include "wx/motif/dcclient.h"
78
79 #include <string.h>
80
81 // ----------------------------------------------------------------------------
82 // global variables for this module
83 // ----------------------------------------------------------------------------
84
85 extern wxHashTable *wxWidgetHashTable;
86 static wxWindow* g_captureWindow = NULL;
87
88
89 // ----------------------------------------------------------------------------
90 // private functions
91 // ----------------------------------------------------------------------------
92
93 static void wxCanvasRepaintProc(Widget, XtPointer, XmDrawingAreaCallbackStruct * cbs);
94 static void wxCanvasInputEvent(Widget drawingArea, XtPointer data, XmDrawingAreaCallbackStruct * cbs);
95 static void wxCanvasMotionEvent(Widget, XButtonEvent * event);
96 static void wxCanvasEnterLeave(Widget drawingArea, XtPointer clientData, XCrossingEvent * event);
97 static void wxScrollBarCallback(Widget widget, XtPointer clientData,
98 XmScrollBarCallbackStruct *cbs);
99 static void wxPanelItemEventHandler(Widget wid,
100 XtPointer client_data,
101 XEvent* event,
102 Boolean *continueToDispatch);
103
104 // unused for now
105 #if 0
106
107 // Helper function for 16-bit fonts
108 static int str16len(const char *s)
109 {
110 int count = 0;
111
112 while (s[0] && s[1]) {
113 count++;
114 s += 2;
115 }
116
117 return count;
118 }
119
120 #endif // 0
121
122 // ----------------------------------------------------------------------------
123 // macros
124 // ----------------------------------------------------------------------------
125
126 #define event_left_is_down(x) ((x)->xbutton.state & Button1Mask)
127 #define event_middle_is_down(x) ((x)->xbutton.state & Button2Mask)
128 #define event_right_is_down(x) ((x)->xbutton.state & Button3Mask)
129
130 // ----------------------------------------------------------------------------
131 // event tables
132 // ----------------------------------------------------------------------------
133
134 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
135
136 BEGIN_EVENT_TABLE(wxWindow, wxWindowBase)
137 EVT_SYS_COLOUR_CHANGED(wxWindow::OnSysColourChanged)
138 END_EVENT_TABLE()
139
140 // ============================================================================
141 // implementation
142 // ============================================================================
143
144 // ----------------------------------------------------------------------------
145 // helper functions
146 // ----------------------------------------------------------------------------
147
148 void wxWindow::UnmanageAndDestroy(WXWidget widget)
149 {
150 Widget w = (Widget)widget;
151 if ( w )
152 {
153 XtUnmanageChild(w);
154 XtDestroyWidget(w);
155 }
156 }
157
158 bool wxWindow::MapOrUnmap(WXWidget widget, bool domap)
159 {
160 Widget w = (Widget)widget;
161 if ( !w )
162 return false;
163
164 // Rationale: a lot of common operations (including but not
165 // limited to moving, resizing and appending items to a listbox)
166 // unmamange the widget, do their work, then manage it again.
167 // This means that, for example adding an item to a listbox will show it,
168 // or that most controls are shown every time they are moved or resized!
169 XtSetMappedWhenManaged( w, domap );
170
171 // if the widget is not unmanaged, it still intercepts
172 // mouse events, even if it is not mapped (and hence invisible)
173 if ( domap )
174 {
175 XtManageChild(w);
176 // XtMapWidget(w);
177 }
178 else
179 {
180 XtUnmanageChild(w);
181 // XtUnmapWidget(w);
182 }
183
184 return true;
185 }
186
187 // ----------------------------------------------------------------------------
188 // constructors
189 // ----------------------------------------------------------------------------
190
191 void wxWindow::Init()
192 {
193 // Motif-specific
194 m_needsRefresh = true;
195 m_mainWidget = (WXWidget) 0;
196
197 m_winCaptured = false;
198
199 m_isShown = true;
200
201 m_hScrollBar =
202 m_vScrollBar =
203 m_borderWidget =
204 m_scrolledWindow =
205 m_drawingArea = (WXWidget) 0;
206
207 m_scrollPosX =
208 m_scrollPosY = 0;
209
210 m_backingPixmap = (WXPixmap) 0;
211 m_pixmapWidth =
212 m_pixmapHeight = 0;
213
214 m_pixmapOffsetX =
215 m_pixmapOffsetY = 0;
216
217 m_lastTS = 0;
218 m_lastButton = 0;
219 }
220
221 // real construction (Init() must have been called before!)
222 bool wxWindow::Create(wxWindow *parent, wxWindowID id,
223 const wxPoint& pos,
224 const wxSize& size,
225 long style,
226 const wxString& name)
227 {
228 // Get default border
229 wxBorder border = GetBorder(style);
230 style &= ~wxBORDER_MASK;
231 style |= border;
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 SendDestroyEvent();
349
350 if (g_captureWindow == this)
351 g_captureWindow = NULL;
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 = 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 wxClientDCImpl * const
879 dcimpl = static_cast<wxClientDCImpl *>(dc.GetImpl());
880 GC const gc = (GC) dcimpl->GetGC();
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, x1, y1, w1, h1, x2, y2);
889
890 dcimpl->SetAutoSetting(true);
891 wxBrush brush(GetBackgroundColour(), wxSOLID);
892 dc.SetBrush(brush); // FIXME: needed?
893
894 wxWindowList::compatibility_iterator cnode = m_children.GetFirst();
895 while (cnode)
896 {
897 wxWindow *child = cnode->GetData();
898 int sx = 0;
899 int sy = 0;
900 child->GetSize( &sx, &sy );
901 wxPoint pos( child->GetPosition() );
902 child->SetSize( pos.x + dx, pos.y + dy, sx, sy, wxSIZE_ALLOW_MINUS_ONE );
903 cnode = cnode->GetNext();
904 }
905
906 // We'll add rectangles to the list of update rectangles according to which
907 // bits we've exposed.
908 wxList updateRects;
909
910 if (dx > 0)
911 {
912 wxRect *rect = new wxRect;
913 rect->x = x;
914 rect->y = y;
915 rect->width = dx;
916 rect->height = h;
917
918 XFillRectangle(display, window, gc, rect->x, rect->y, rect->width, rect->height);
919
920 rect->x = rect->x;
921 rect->y = rect->y;
922 rect->width = rect->width;
923 rect->height = rect->height;
924
925 updateRects.Append((wxObject*) rect);
926 }
927 else if (dx < 0)
928 {
929 wxRect *rect = new wxRect;
930
931 rect->x = x + w + dx;
932 rect->y = y;
933 rect->width = -dx;
934 rect->height = h;
935
936 XFillRectangle(display, window, gc, rect->x, rect->y, rect->width, rect->height);
937
938 rect->x = rect->x;
939 rect->y = rect->y;
940 rect->width = rect->width;
941 rect->height = rect->height;
942
943 updateRects.Append((wxObject*) rect);
944 }
945 if (dy > 0)
946 {
947 wxRect *rect = new wxRect;
948
949 rect->x = x;
950 rect->y = y;
951 rect->width = w;
952 rect->height = dy;
953
954 XFillRectangle(display, window, gc, rect->x, rect->y, rect->width, rect->height);
955
956 rect->x = rect->x;
957 rect->y = rect->y;
958 rect->width = rect->width;
959 rect->height = rect->height;
960
961 updateRects.Append((wxObject*) rect);
962 }
963 else if (dy < 0)
964 {
965 wxRect *rect = new wxRect;
966
967 rect->x = x;
968 rect->y = y + h + dy;
969 rect->width = w;
970 rect->height = -dy;
971
972 XFillRectangle(display, window, gc, rect->x, rect->y, rect->width, rect->height);
973
974 rect->x = rect->x;
975 rect->y = rect->y;
976 rect->width = rect->width;
977 rect->height = rect->height;
978
979 updateRects.Append((wxObject*) rect);
980 }
981 dc.SetBrush(wxNullBrush);
982
983 // Now send expose events
984
985 wxList::compatibility_iterator node = updateRects.GetFirst();
986 while (node)
987 {
988 wxRect* rect = (wxRect*) node->GetData();
989 XExposeEvent event;
990
991 event.type = Expose;
992 event.display = display;
993 event.send_event = True;
994 event.window = window;
995
996 event.x = rect->x;
997 event.y = rect->y;
998 event.width = rect->width;
999 event.height = rect->height;
1000
1001 event.count = 0;
1002
1003 XSendEvent(display, window, False, ExposureMask, (XEvent *)&event);
1004
1005 node = node->GetNext();
1006
1007 }
1008
1009 // Delete the update rects
1010 node = updateRects.GetFirst();
1011 while (node)
1012 {
1013 wxRect* rect = (wxRect*) node->GetData();
1014 delete rect;
1015 node = node->GetNext();
1016 }
1017
1018 XmUpdateDisplay((Widget) GetMainWidget());
1019 }
1020
1021 // ---------------------------------------------------------------------------
1022 // drag and drop
1023 // ---------------------------------------------------------------------------
1024
1025 #if wxUSE_DRAG_AND_DROP
1026
1027 void wxWindow::SetDropTarget(wxDropTarget * WXUNUSED(pDropTarget))
1028 {
1029 // TODO
1030 }
1031
1032 #endif
1033
1034 // Old style file-manager drag&drop
1035 void wxWindow::DragAcceptFiles(bool WXUNUSED(accept))
1036 {
1037 // TODO
1038 }
1039
1040 // ----------------------------------------------------------------------------
1041 // tooltips
1042 // ----------------------------------------------------------------------------
1043
1044 #if wxUSE_TOOLTIPS
1045
1046 void wxWindow::DoSetToolTip(wxToolTip * WXUNUSED(tooltip))
1047 {
1048 // TODO
1049 }
1050
1051 #endif // wxUSE_TOOLTIPS
1052
1053 // ----------------------------------------------------------------------------
1054 // popup menus
1055 // ----------------------------------------------------------------------------
1056
1057 #if wxUSE_MENUS
1058
1059 bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
1060 {
1061 if ( x == wxDefaultCoord && y == wxDefaultCoord )
1062 {
1063 wxPoint mouse = ScreenToClient(wxGetMousePosition());
1064 x = mouse.x; y = mouse.y;
1065 }
1066
1067 Widget widget = (Widget) GetMainWidget();
1068
1069 /* The menuId field seems to be usused, so we'll use it to
1070 indicate whether a menu is popped up or not:
1071 0: Not currently created as a popup
1072 -1: Created as a popup, but not active
1073 1: Active popup.
1074 */
1075
1076 if (menu->GetParent() && (menu->GetId() != -1))
1077 return false;
1078
1079 if (menu->GetMainWidget())
1080 {
1081 menu->DestroyMenu(true);
1082 }
1083
1084 menu->SetId(1); /* Mark as popped-up */
1085 menu->CreateMenu(NULL, widget, menu, 0);
1086 menu->SetInvokingWindow(this);
1087
1088 menu->UpdateUI();
1089
1090 // menu->SetParent(parent);
1091 // parent->children->Append(menu); // Store menu for later deletion
1092
1093 Widget menuWidget = (Widget) menu->GetMainWidget();
1094
1095 int rootX = 0;
1096 int rootY = 0;
1097
1098 int deviceX = x;
1099 int deviceY = y;
1100 /*
1101 if (this->IsKindOf(CLASSINFO(wxCanvas)))
1102 {
1103 wxCanvas *canvas = (wxCanvas *) this;
1104 deviceX = canvas->GetDC ()->LogicalToDeviceX (x);
1105 deviceY = canvas->GetDC ()->LogicalToDeviceY (y);
1106 }
1107 */
1108
1109 Display *display = XtDisplay (widget);
1110 Window rootWindow = RootWindowOfScreen (XtScreen((Widget)widget));
1111 Window thisWindow = XtWindow (widget);
1112 Window childWindow;
1113 XTranslateCoordinates (display, thisWindow, rootWindow, (int) deviceX, (int) deviceY,
1114 &rootX, &rootY, &childWindow);
1115
1116 XButtonPressedEvent event;
1117 event.type = ButtonPress;
1118 event.button = 1;
1119
1120 event.x = deviceX;
1121 event.y = deviceY;
1122
1123 event.x_root = rootX;
1124 event.y_root = rootY;
1125
1126 XmMenuPosition (menuWidget, &event);
1127 XtManageChild (menuWidget);
1128
1129 // The ID of a pop-up menu is 1 when active, and is set to 0 by the
1130 // idle-time destroy routine.
1131 // Waiting until this ID changes causes this function to block until
1132 // the menu has been dismissed and the widgets cleaned up.
1133 // In other words, once this routine returns, it is safe to delete
1134 // the menu object.
1135 // Ian Brown <ian.brown@printsoft.de>
1136
1137 wxEventLoop evtLoop;
1138
1139 while (menu->GetId() == 1)
1140 {
1141 wxDoEventLoopIteration( evtLoop );
1142 }
1143
1144 return true;
1145 }
1146
1147 #endif
1148
1149 // ---------------------------------------------------------------------------
1150 // moving and resizing
1151 // ---------------------------------------------------------------------------
1152
1153 bool wxWindow::PreResize()
1154 {
1155 return true;
1156 }
1157
1158 // Get total size
1159 void wxWindow::DoGetSize(int *x, int *y) const
1160 {
1161 Widget widget = (Widget)( !m_drawingArea ? GetTopWidget() :
1162 ( m_borderWidget ? m_borderWidget :
1163 m_scrolledWindow ? m_scrolledWindow :
1164 m_drawingArea ) );
1165 Dimension xx, yy;
1166
1167 if (widget)
1168 XtVaGetValues( widget,
1169 XmNwidth, &xx,
1170 XmNheight, &yy,
1171 NULL );
1172 if(x) *x = widget ? xx : -1;
1173 if(y) *y = widget ? yy : -1;
1174 }
1175
1176 void wxWindow::DoGetPosition(int *x, int *y) const
1177 {
1178 Widget widget = (Widget)
1179 ( m_drawingArea ?
1180 ( m_borderWidget ? m_borderWidget : m_scrolledWindow ) :
1181 GetTopWidget() );
1182
1183 Position xx, yy;
1184 XtVaGetValues(widget, XmNx, &xx, XmNy, &yy, NULL);
1185
1186 // We may be faking the client origin. So a window that's really at (0, 30)
1187 // may appear (to wxWin apps) to be at (0, 0).
1188 if (GetParent())
1189 {
1190 wxPoint pt(GetParent()->GetClientAreaOrigin());
1191 xx = (Position)(xx - pt.x);
1192 yy = (Position)(yy - pt.y);
1193 }
1194
1195 if(x) *x = xx;
1196 if(y) *y = yy;
1197 }
1198
1199 void wxWindow::DoScreenToClient(int *x, int *y) const
1200 {
1201 Widget widget = (Widget) GetClientWidget();
1202 Display *display = XtDisplay((Widget) GetMainWidget());
1203 Window rootWindow = RootWindowOfScreen(XtScreen(widget));
1204 Window thisWindow = XtWindow(widget);
1205
1206 Window childWindow;
1207 int xx = x ? *x : 0;
1208 int yy = y ? *y : 0;
1209 XTranslateCoordinates(display, rootWindow, thisWindow,
1210 xx, yy, x ? x : &xx, y ? y : &yy,
1211 &childWindow);
1212 }
1213
1214 void wxWindow::DoClientToScreen(int *x, int *y) const
1215 {
1216 Widget widget = (Widget) GetClientWidget();
1217 Display *display = XtDisplay(widget);
1218 Window rootWindow = RootWindowOfScreen(XtScreen(widget));
1219 Window thisWindow = XtWindow(widget);
1220
1221 Window childWindow;
1222 int xx = x ? *x : 0;
1223 int yy = y ? *y : 0;
1224 XTranslateCoordinates(display, thisWindow, rootWindow,
1225 xx, yy, x ? x : &xx, y ? y : &yy,
1226 &childWindow);
1227 }
1228
1229
1230 // Get size *available for subwindows* i.e. excluding menu bar etc.
1231 void wxWindow::DoGetClientSize(int *x, int *y) const
1232 {
1233 Widget widget = (Widget) GetClientWidget();
1234 Dimension xx, yy;
1235 XtVaGetValues(widget, XmNwidth, &xx, XmNheight, &yy, NULL);
1236 if(x) *x = xx; if(y) *y = yy;
1237 }
1238
1239 void wxWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags)
1240 {
1241 DoSetSizeIntr(x, y, width, height, sizeFlags, false);
1242 }
1243
1244 void wxWindow::DoSetSizeIntr(int x, int y, int width, int height,
1245 int sizeFlags, bool fromCtor)
1246 {
1247 // A bit of optimization to help sort out the flickers.
1248 int oldX = -1, oldY = -1, oldW = -1, oldH = -1;
1249
1250 if( !fromCtor )
1251 {
1252 GetSize(& oldW, & oldH);
1253 GetPosition(& oldX, & oldY);
1254 }
1255
1256 if (x == -1)
1257 x = oldX;
1258 if (x == -1)
1259 x = oldY;
1260
1261 if ( !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
1262 {
1263 if ( width == -1 )
1264 width = oldW;
1265 if ( height == -1 )
1266 height = oldH;
1267 }
1268
1269 wxSize size(wxDefaultSize);
1270 if ( width <= 0 )
1271 {
1272 if ( ( sizeFlags & wxSIZE_AUTO_WIDTH ) && !fromCtor )
1273 {
1274 size = DoGetBestSize();
1275 width = size.x;
1276 }
1277 else
1278 {
1279 width = oldW;
1280 }
1281 }
1282
1283 if ( height == -1 )
1284 {
1285 if( ( sizeFlags & wxSIZE_AUTO_HEIGHT ) && !fromCtor )
1286 {
1287 if( size.x == -1 ) size = DoGetBestSize();
1288 height = size.y;
1289 }
1290 else
1291 {
1292 height = oldH;
1293 }
1294 }
1295
1296 if ( x != oldX || y != oldY || width != oldW || height != oldH
1297 || !wxNoOptimize::CanOptimize() )
1298 {
1299 if (m_drawingArea)
1300 {
1301 int flags = 0;
1302
1303 if (x != oldX)
1304 flags |= wxMOVE_X;
1305
1306 if (y != oldY)
1307 flags |= wxMOVE_Y;
1308
1309 if (width > 0)
1310 flags |= wxMOVE_WIDTH;
1311
1312 if (height > 0)
1313 flags |= wxMOVE_HEIGHT;
1314
1315 int xx = x; int yy = y;
1316 AdjustForParentClientOrigin(xx, yy, sizeFlags);
1317 if( !fromCtor )
1318 DoMoveWindow( xx, yy, width, height );
1319 else
1320 DoMoveWindowIntr( xx, yy, width, height, flags );
1321
1322 return;
1323 }
1324
1325 Widget widget = (Widget) GetTopWidget();
1326 if (!widget)
1327 return;
1328
1329 bool managed = XtIsManaged( widget );
1330 if (managed)
1331 XtUnmanageChild(widget);
1332
1333 int xx = x;
1334 int yy = y;
1335 AdjustForParentClientOrigin(xx, yy, sizeFlags);
1336
1337 DoMoveWindow(xx, yy, width, height);
1338
1339 if (managed)
1340 XtManageChild(widget);
1341 }
1342 }
1343
1344 void wxWindow::DoSetClientSize(int width, int height)
1345 {
1346 if (m_drawingArea)
1347 {
1348 Widget drawingArea = (Widget) m_drawingArea;
1349
1350 XtVaSetValues(drawingArea, XmNresizePolicy, XmRESIZE_ANY, NULL);
1351
1352 if (width > -1)
1353 XtVaSetValues(drawingArea, XmNwidth, width, NULL);
1354 if (height > -1)
1355 XtVaSetValues(drawingArea, XmNheight, height, NULL);
1356
1357 XtVaSetValues(drawingArea, XmNresizePolicy, XmRESIZE_NONE, NULL);
1358 return;
1359 }
1360
1361 Widget widget = (Widget) GetTopWidget();
1362
1363 if (width > -1)
1364 XtVaSetValues(widget, XmNwidth, width, NULL);
1365 if (height > -1)
1366 XtVaSetValues(widget, XmNheight, height, NULL);
1367 }
1368
1369 void wxWindow::DoMoveWindowIntr(int xx, int yy, int w, int h,
1370 int flags)
1371 {
1372 if (m_drawingArea)
1373 {
1374 Widget drawingArea = (Widget) m_drawingArea;
1375 Widget borderOrScrolled = m_borderWidget ?
1376 (Widget) m_borderWidget :
1377 (Widget) m_scrolledWindow;
1378
1379 bool managed = XtIsManaged(borderOrScrolled);
1380 if (managed)
1381 XtUnmanageChild (borderOrScrolled);
1382 XtVaSetValues(drawingArea, XmNresizePolicy, XmRESIZE_ANY, NULL);
1383
1384 if (flags & wxMOVE_X)
1385 XtVaSetValues (borderOrScrolled,
1386 XmNx, xx,
1387 NULL);
1388 if (flags & wxMOVE_Y)
1389 XtVaSetValues (borderOrScrolled,
1390 XmNy, yy,
1391 NULL);
1392
1393 if (flags & wxMOVE_WIDTH)
1394 {
1395 if (m_borderWidget)
1396 {
1397 XtVaSetValues ((Widget) m_borderWidget, XmNwidth, w, NULL);
1398 short thick, margin;
1399 XtVaGetValues ((Widget) m_borderWidget,
1400 XmNshadowThickness, &thick,
1401 XmNmarginWidth, &margin,
1402 NULL);
1403 w -= 2 * (thick + margin);
1404 }
1405
1406 if( w < 1 ) w = 1;
1407 XtVaSetValues ((Widget) m_scrolledWindow, XmNwidth, w, NULL);
1408 }
1409
1410 if (flags & wxMOVE_HEIGHT)
1411 {
1412 if (m_borderWidget)
1413 {
1414 XtVaSetValues ((Widget) m_borderWidget, XmNheight, h, NULL);
1415 short thick, margin;
1416 XtVaGetValues ((Widget) m_borderWidget,
1417 XmNshadowThickness, &thick,
1418 XmNmarginHeight, &margin,
1419 NULL);
1420 h -= 2 * (thick + margin);
1421 }
1422
1423 if( h < 1 ) h = 1;
1424 XtVaSetValues ((Widget) m_scrolledWindow, XmNheight, h, NULL);
1425 }
1426
1427 if (managed)
1428 XtManageChild (borderOrScrolled);
1429 XtVaSetValues(drawingArea, XmNresizePolicy, XmRESIZE_NONE, NULL);
1430 }
1431 else
1432 {
1433 if( w < 1 ) w = 1;
1434 if( h < 1 ) h = 1;
1435
1436 XtVaSetValues((Widget)GetTopWidget(),
1437 XmNx, xx,
1438 XmNy, yy,
1439 XmNwidth, w,
1440 XmNheight, h,
1441 NULL);
1442 }
1443 }
1444
1445 void wxWindow::DoMoveWindow(int x, int y, int width, int height)
1446 {
1447 DoMoveWindowIntr (x, y, width, height,
1448 wxMOVE_X|wxMOVE_Y|wxMOVE_WIDTH|wxMOVE_HEIGHT);
1449 }
1450
1451 // ---------------------------------------------------------------------------
1452 // text metrics
1453 // ---------------------------------------------------------------------------
1454
1455 int wxWindow::GetCharHeight() const
1456 {
1457 int height;
1458
1459 if (m_font.Ok())
1460 wxGetTextExtent (GetXDisplay(), m_font, 1.0,
1461 "x", NULL, &height, NULL, NULL);
1462 else
1463 wxGetTextExtent (this, "x", NULL, &height, NULL, NULL);
1464
1465 return height;
1466 }
1467
1468 int wxWindow::GetCharWidth() const
1469 {
1470 int width;
1471
1472 if (m_font.Ok())
1473 wxGetTextExtent (GetXDisplay(), m_font, 1.0,
1474 "x", &width, NULL, NULL, NULL);
1475 else
1476 wxGetTextExtent (this, "x", &width, NULL, NULL, NULL);
1477
1478 return width;
1479 }
1480
1481 void wxWindow::DoGetTextExtent(const wxString& string,
1482 int *x, int *y,
1483 int *descent,
1484 int *externalLeading,
1485 const wxFont *theFont) const
1486 {
1487 const wxFont *fontToUse = theFont ? theFont : &m_font;
1488
1489 if (externalLeading)
1490 *externalLeading = 0;
1491 if (fontToUse->Ok())
1492 wxGetTextExtent (GetXDisplay(), *fontToUse, 1.0,
1493 string, x, y, NULL, descent);
1494 else
1495 wxGetTextExtent (this, string, x, y, NULL, descent);
1496 }
1497
1498 // ----------------------------------------------------------------------------
1499 // painting
1500 // ----------------------------------------------------------------------------
1501
1502 void wxWindow::AddUpdateRect(int x, int y, int w, int h)
1503 {
1504 m_updateRegion.Union( x, y, w, h );
1505 }
1506
1507 void wxWindow::Refresh(bool eraseBack, const wxRect *rect)
1508 {
1509 Widget widget = (Widget) GetMainWidget();
1510 if (!widget)
1511 return;
1512 m_needsRefresh = true;
1513 Display *display = XtDisplay(widget);
1514 Window thisWindow = XtWindow(widget);
1515
1516 XExposeEvent dummyEvent;
1517 int width, height;
1518 GetSize(&width, &height);
1519
1520 dummyEvent.type = Expose;
1521 dummyEvent.display = display;
1522 dummyEvent.send_event = True;
1523 dummyEvent.window = thisWindow;
1524 if (rect)
1525 {
1526 dummyEvent.x = rect->x;
1527 dummyEvent.y = rect->y;
1528 dummyEvent.width = rect->width;
1529 dummyEvent.height = rect->height;
1530 }
1531 else
1532 {
1533 dummyEvent.x = 0;
1534 dummyEvent.y = 0;
1535 dummyEvent.width = width;
1536 dummyEvent.height = height;
1537 }
1538 dummyEvent.count = 0;
1539
1540 if (eraseBack)
1541 {
1542 wxClientDC dc(this);
1543 wxBrush backgroundBrush(GetBackgroundColour(), wxSOLID);
1544 dc.SetBackground(backgroundBrush);
1545
1546 wxClientDCImpl * const
1547 dcimpl = static_cast<wxClientDCImpl *>(dc.GetImpl());
1548 if (rect)
1549 dcimpl->Clear(*rect);
1550 else
1551 dcimpl->Clear();
1552 }
1553
1554 XSendEvent(display, thisWindow, False, ExposureMask, (XEvent *)&dummyEvent);
1555 }
1556
1557 void wxWindow::DoPaint()
1558 {
1559 //TODO : make a temporary gc so we can do the XCopyArea below
1560 if (m_backingPixmap && !m_needsRefresh)
1561 {
1562 wxPaintDC dc(this);
1563
1564 wxPaintDCImpl * const
1565 dcimpl = static_cast<wxPaintDCImpl *>(dc.GetImpl());
1566
1567 GC tempGC = (GC) dcimpl->GetBackingGC();
1568
1569 Widget widget = (Widget) GetMainWidget();
1570
1571 int scrollPosX = 0;
1572 int scrollPosY = 0;
1573
1574 // We have to test whether it's a wxScrolledWindow (hack!) because
1575 // otherwise we don't know how many pixels have been scrolled. We might
1576 // solve this in the future by defining virtual wxWindow functions to get
1577 // the scroll position in pixels. Or, each kind of scrolled window has to
1578 // implement backing stores itself, using generic wxWidgets code.
1579 wxScrolledWindow* scrolledWindow = wxDynamicCast(this, wxScrolledWindow);
1580 if ( scrolledWindow )
1581 {
1582 int x, y;
1583 scrolledWindow->CalcScrolledPosition(0, 0, &x, &y);
1584
1585 scrollPosX = - x;
1586 scrollPosY = - y;
1587 }
1588
1589 // TODO: This could be optimized further by only copying the areas in the
1590 // current update region.
1591
1592 // Only blit the part visible in the client area. The backing pixmap
1593 // always starts at 0, 0 but we may be looking at only a portion of it.
1594 wxSize clientArea = GetClientSize();
1595 int toBlitX = m_pixmapWidth - scrollPosX;
1596 int toBlitY = m_pixmapHeight - scrollPosY;
1597
1598 // Copy whichever is samller, the amount of pixmap we have to copy,
1599 // or the size of the client area.
1600 toBlitX = wxMin(toBlitX, clientArea.x);
1601 toBlitY = wxMin(toBlitY, clientArea.y);
1602
1603 // Make sure we're not negative
1604 toBlitX = wxMax(0, toBlitX);
1605 toBlitY = wxMax(0, toBlitY);
1606
1607 XCopyArea
1608 (
1609 XtDisplay(widget),
1610 (Pixmap) m_backingPixmap,
1611 XtWindow (widget),
1612 tempGC,
1613 scrollPosX, scrollPosY, // Start at the scroll position
1614 toBlitX, toBlitY, // How much of the pixmap to copy
1615 0, 0 // Destination
1616 );
1617 }
1618 else
1619 {
1620 wxWindowDC dc(this);
1621 // Set an erase event first
1622 wxEraseEvent eraseEvent(GetId(), &dc);
1623 eraseEvent.SetEventObject(this);
1624 HandleWindowEvent(eraseEvent);
1625
1626 wxPaintEvent event(GetId());
1627 event.SetEventObject(this);
1628 HandleWindowEvent(event);
1629
1630 m_needsRefresh = false;
1631 }
1632 }
1633
1634 // ----------------------------------------------------------------------------
1635 // event handlers
1636 // ----------------------------------------------------------------------------
1637
1638 // Responds to colour changes: passes event on to children.
1639 void wxWindow::OnSysColourChanged(wxSysColourChangedEvent& event)
1640 {
1641 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
1642 while ( node )
1643 {
1644 // Only propagate to non-top-level windows
1645 wxWindow *win = node->GetData();
1646 if ( win->GetParent() )
1647 {
1648 wxSysColourChangedEvent event2;
1649 event.SetEventObject(win);
1650 win->HandleWindowEvent(event2);
1651 }
1652
1653 node = node->GetNext();
1654 }
1655 }
1656
1657 void wxWindow::OnInternalIdle()
1658 {
1659 // This calls the UI-update mechanism (querying windows for
1660 // menu/toolbar/control state information)
1661 if (wxUpdateUIEvent::CanUpdate(this) && IsShownOnScreen())
1662 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
1663 }
1664
1665 // ----------------------------------------------------------------------------
1666 // accelerators
1667 // ----------------------------------------------------------------------------
1668
1669 bool wxWindow::ProcessAccelerator(wxKeyEvent& event)
1670 {
1671 #if wxUSE_ACCEL
1672 if (!m_acceleratorTable.Ok())
1673 return false;
1674
1675 int count = m_acceleratorTable.GetCount();
1676 wxAcceleratorEntry* entries = m_acceleratorTable.GetEntries();
1677 int i;
1678 for (i = 0; i < count; i++)
1679 {
1680 wxAcceleratorEntry* entry = & (entries[i]);
1681 if (entry->MatchesEvent(event))
1682 {
1683 // Bingo, we have a match. Now find a control that matches the
1684 // entry command id.
1685
1686 // Need to go up to the top of the window hierarchy, since it might
1687 // be e.g. a menu item
1688 wxWindow* parent = this;
1689 while ( parent && !parent->IsTopLevel() )
1690 parent = parent->GetParent();
1691
1692 if (!parent)
1693 return false;
1694
1695 wxFrame* frame = wxDynamicCast(parent, wxFrame);
1696 if ( frame )
1697 {
1698 #if wxUSE_MENUS
1699 // Try for a menu command
1700 if (frame->GetMenuBar())
1701 {
1702 wxMenuItem* item = frame->GetMenuBar()->FindItem(entry->GetCommand());
1703 if (item)
1704 {
1705 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, entry->GetCommand());
1706 commandEvent.SetEventObject(frame);
1707
1708 // If ProcessEvent returns true (it was handled), then
1709 // the calling code will skip the event handling.
1710 return frame->HandleWindowEvent(commandEvent);
1711 }
1712 }
1713 #endif
1714 }
1715
1716 // Find a child matching the command id
1717 wxWindow* child = parent->FindWindow(entry->GetCommand());
1718
1719 // No such child
1720 if (!child)
1721 return false;
1722
1723 // Now we process those kinds of windows that we can.
1724 // For now, only buttons.
1725 if ( wxDynamicCast(child, wxButton) )
1726 {
1727 wxCommandEvent commandEvent (wxEVT_COMMAND_BUTTON_CLICKED, child->GetId());
1728 commandEvent.SetEventObject(child);
1729 return child->HandleWindowEvent(commandEvent);
1730 }
1731
1732 return false;
1733 } // matches event
1734 }// for
1735 #endif
1736
1737 // We didn't match the key event against an accelerator.
1738 return false;
1739 }
1740
1741 // ============================================================================
1742 // Motif-specific stuff from here on
1743 // ============================================================================
1744
1745 // ----------------------------------------------------------------------------
1746 // function which maintain the global hash table mapping Widgets to wxWidgets
1747 // ----------------------------------------------------------------------------
1748
1749 bool wxAddWindowToTable(Widget w, wxWindow *win)
1750 {
1751 const long key = (long)w;
1752 if ( wxWidgetHashTable->Get(key))
1753 {
1754 wxLogDebug("Widget table clash: new widget is %ld, %s",
1755 key, win->GetClassInfo()->GetClassName());
1756 return false;
1757 }
1758
1759 wxWidgetHashTable->Put(key, win);
1760
1761 wxLogTrace("widget", "Widget 0x%p <-> window %p (%s)",
1762 w, win, win->GetClassInfo()->GetClassName());
1763
1764 return true;
1765 }
1766
1767 wxWindow *wxGetWindowFromTable(Widget w)
1768 {
1769 return (wxWindow *)wxWidgetHashTable->Get((long) w);
1770 }
1771
1772 void wxDeleteWindowFromTable(Widget w)
1773 {
1774 wxLogTrace("widget", "Widget 0x%p", (WXWidget)w);
1775
1776 wxWidgetHashTable->Delete((long)w);
1777 }
1778
1779 // ----------------------------------------------------------------------------
1780 // add/remove window from the table
1781 // ----------------------------------------------------------------------------
1782
1783 // Add to hash table, add event handler
1784 bool wxWindow::AttachWidget (wxWindow* WXUNUSED(parent), WXWidget mainWidget,
1785 WXWidget formWidget, int x, int y, int width, int height)
1786 {
1787 wxAddWindowToTable((Widget) mainWidget, this);
1788 XtAddEventHandler( (Widget) mainWidget,
1789 ButtonPressMask | ButtonReleaseMask
1790 | PointerMotionMask,
1791 False,
1792 wxPanelItemEventHandler,
1793 (XtPointer) this);
1794
1795 if (!formWidget)
1796 {
1797 XtTranslations ptr;
1798 XtOverrideTranslations ((Widget) mainWidget,
1799 ptr = XtParseTranslationTable ("<Configure>: resize()"));
1800 XtFree ((char *) ptr);
1801 }
1802
1803 // Some widgets have a parent form widget, e.g. wxRadioBox
1804 if (formWidget)
1805 {
1806 if (!wxAddWindowToTable((Widget) formWidget, this))
1807 return false;
1808
1809 XtTranslations ptr;
1810 XtOverrideTranslations ((Widget) formWidget,
1811 ptr = XtParseTranslationTable ("<Configure>: resize()"));
1812 XtFree ((char *) ptr);
1813 }
1814
1815 if (x == -1)
1816 x = 0;
1817 if (y == -1)
1818 y = 0;
1819 DoSetSize (x, y, width, height, wxSIZE_USE_EXISTING);
1820
1821 return true;
1822 }
1823
1824 // Remove event handler, remove from hash table
1825 bool wxWindow::DetachWidget(WXWidget widget)
1826 {
1827 XtRemoveEventHandler( (Widget) widget,
1828 ButtonPressMask | ButtonReleaseMask
1829 | PointerMotionMask,
1830 False,
1831 wxPanelItemEventHandler,
1832 (XtPointer)this);
1833
1834 wxDeleteWindowFromTable((Widget) widget);
1835 return true;
1836 }
1837
1838 // ----------------------------------------------------------------------------
1839 // Motif-specific accessors
1840 // ----------------------------------------------------------------------------
1841
1842 WXWindow wxWindow::GetClientXWindow() const
1843 {
1844 Widget wMain = (Widget)GetClientWidget();
1845 if ( wMain )
1846 return (WXWindow) XtWindow(wMain);
1847 else
1848 return (WXWindow) 0;
1849 }
1850
1851 // Get the underlying X window
1852 WXWindow wxWindow::GetXWindow() const
1853 {
1854 Widget wMain = (Widget)GetMainWidget();
1855 if ( wMain )
1856 return (WXWindow) XtWindow(wMain);
1857 else
1858 return (WXWindow) 0;
1859 }
1860
1861 // Get the underlying X display
1862 WXDisplay *wxWindow::GetXDisplay() const
1863 {
1864 Widget wMain = (Widget)GetMainWidget();
1865 if ( wMain )
1866 return (WXDisplay*) XtDisplay(wMain);
1867 else
1868 return NULL;
1869 }
1870
1871 WXWidget wxWindow::GetMainWidget() const
1872 {
1873 if (m_drawingArea)
1874 return m_drawingArea;
1875 else
1876 return m_mainWidget;
1877 }
1878
1879 WXWidget wxWindow::GetClientWidget() const
1880 {
1881 if (m_drawingArea != (WXWidget) 0)
1882 return m_drawingArea;
1883 else
1884 return GetMainWidget();
1885 }
1886
1887 WXWidget wxWindow::GetTopWidget() const
1888 {
1889 return GetMainWidget();
1890 }
1891
1892 WXWidget wxWindow::GetLabelWidget() const
1893 {
1894 return GetMainWidget();
1895 }
1896
1897 // ----------------------------------------------------------------------------
1898 // Motif callbacks
1899 // ----------------------------------------------------------------------------
1900
1901 // All widgets should have this as their resize proc.
1902 // OnSize sent to wxWindow via client data.
1903 void wxWidgetResizeProc(Widget w, XConfigureEvent *WXUNUSED(event),
1904 String WXUNUSED(args)[], int *WXUNUSED(num_args))
1905 {
1906 wxWindow *win = wxGetWindowFromTable(w);
1907 if (!win)
1908 return;
1909
1910 if (win->PreResize())
1911 {
1912 wxSize newSize(win->GetSize());
1913 wxSizeEvent sizeEvent(newSize, win->GetId());
1914 sizeEvent.SetEventObject(win);
1915 win->HandleWindowEvent(sizeEvent);
1916 }
1917 }
1918
1919 static void wxCanvasRepaintProc(Widget drawingArea,
1920 XtPointer clientData,
1921 XmDrawingAreaCallbackStruct * cbs)
1922 {
1923 if (!wxGetWindowFromTable(drawingArea))
1924 return;
1925
1926 XEvent * event = cbs->event;
1927 wxWindow * win = (wxWindow *) clientData;
1928
1929 switch (event->type)
1930 {
1931 case Expose:
1932 {
1933 win->AddUpdateRect(event->xexpose.x, event->xexpose.y,
1934 event->xexpose.width, event->xexpose.height);
1935
1936 if (event -> xexpose.count == 0)
1937 {
1938 win->DoPaint();
1939 }
1940 break;
1941 }
1942 }
1943 }
1944
1945 // Unable to deal with Enter/Leave without a separate EventHandler (Motif 1.1.4)
1946 static void wxCanvasEnterLeave(Widget drawingArea,
1947 XtPointer WXUNUSED(clientData),
1948 XCrossingEvent * event)
1949 {
1950 XmDrawingAreaCallbackStruct cbs;
1951 XEvent ev;
1952
1953 ((XCrossingEvent &) ev) = *event;
1954
1955 cbs.reason = XmCR_INPUT;
1956 cbs.event = &ev;
1957
1958 wxCanvasInputEvent(drawingArea, (XtPointer) NULL, &cbs);
1959 }
1960
1961 // Fix to make it work under Motif 1.0 (!)
1962 static void wxCanvasMotionEvent (Widget WXUNUSED(drawingArea),
1963 XButtonEvent *WXUNUSED(event))
1964 {
1965 #if XmVersion <= 1000
1966 XmDrawingAreaCallbackStruct cbs;
1967 XEvent ev;
1968
1969 ev = *((XEvent *) event);
1970 cbs.reason = XmCR_INPUT;
1971 cbs.event = &ev;
1972
1973 wxCanvasInputEvent (drawingArea, (XtPointer) NULL, &cbs);
1974 #endif // XmVersion <= 1000
1975 }
1976
1977 static void wxCanvasInputEvent(Widget drawingArea,
1978 XtPointer WXUNUSED(data),
1979 XmDrawingAreaCallbackStruct * cbs)
1980 {
1981 wxWindow *canvas = wxGetWindowFromTable(drawingArea);
1982 XEvent* xevent = cbs->event;
1983
1984 if (canvas==NULL)
1985 return;
1986
1987 if (cbs->reason != XmCR_INPUT)
1988 return;
1989
1990 switch (xevent->xany.type)
1991 {
1992 case EnterNotify:
1993 case LeaveNotify:
1994 case ButtonPress:
1995 case ButtonRelease:
1996 case MotionNotify:
1997 {
1998 wxMouseEvent wxevent(0);
1999 if (wxTranslateMouseEvent(wxevent, canvas, drawingArea, xevent))
2000 {
2001 canvas->HandleWindowEvent(wxevent);
2002 }
2003 break;
2004 }
2005 case KeyPress:
2006 {
2007 wxKeyEvent event (wxEVT_CHAR);
2008 if (wxTranslateKeyEvent (event, canvas, (Widget) 0, xevent))
2009 {
2010 // Implement wxFrame::OnCharHook by checking ancestor.
2011 wxWindow *parent = canvas;
2012 while (parent && !parent->IsTopLevel())
2013 parent = parent->GetParent();
2014
2015 if (parent)
2016 {
2017 event.SetEventType(wxEVT_CHAR_HOOK);
2018 if (parent->HandleWindowEvent(event))
2019 return;
2020 }
2021
2022 // For simplicity, OnKeyDown is the same as OnChar
2023 // TODO: filter modifier key presses from OnChar
2024 event.SetEventType(wxEVT_KEY_DOWN);
2025
2026 // Only process OnChar if OnKeyDown didn't swallow it
2027 if (!canvas->HandleWindowEvent (event))
2028 {
2029 event.SetEventType(wxEVT_CHAR);
2030 canvas->HandleWindowEvent (event);
2031 }
2032 }
2033 break;
2034 }
2035 case KeyRelease:
2036 {
2037 wxKeyEvent event (wxEVT_KEY_UP);
2038 if (wxTranslateKeyEvent (event, canvas, (Widget) 0, xevent))
2039 {
2040 canvas->HandleWindowEvent (event);
2041 }
2042 break;
2043 }
2044 case FocusIn:
2045 {
2046 if (xevent->xfocus.detail != NotifyPointer)
2047 {
2048 wxFocusEvent event(wxEVT_SET_FOCUS, canvas->GetId());
2049 event.SetEventObject(canvas);
2050 canvas->HandleWindowEvent(event);
2051 }
2052 break;
2053 }
2054 case FocusOut:
2055 {
2056 if (xevent->xfocus.detail != NotifyPointer)
2057 {
2058 wxFocusEvent event(wxEVT_KILL_FOCUS, canvas->GetId());
2059 event.SetEventObject(canvas);
2060 canvas->HandleWindowEvent(event);
2061 }
2062 break;
2063 }
2064 default:
2065 break;
2066 }
2067 }
2068
2069 static void wxPanelItemEventHandler(Widget wid,
2070 XtPointer WXUNUSED(client_data),
2071 XEvent* event,
2072 Boolean *continueToDispatch)
2073 {
2074 // Widget can be a label or the actual widget.
2075
2076 wxWindow *window = wxGetWindowFromTable(wid);
2077 if (window)
2078 {
2079 wxMouseEvent wxevent(0);
2080 if (wxTranslateMouseEvent(wxevent, window, wid, event))
2081 {
2082 window->HandleWindowEvent(wxevent);
2083 }
2084 }
2085
2086 // TODO: probably the key to allowing default behaviour to happen. Say we
2087 // set a m_doDefault flag to false at the start of this function. Then in
2088 // e.g. wxWindow::OnMouseEvent we can call Default() which sets this flag to
2089 // true, indicating that default processing can happen. Thus, behaviour can
2090 // appear to be overridden just by adding an event handler and not calling
2091 // wxWindow::OnWhatever. ALSO, maybe we can use this instead of the current
2092 // way of handling drawing area events, to simplify things.
2093 *continueToDispatch = True;
2094 }
2095
2096 static void wxScrollBarCallback(Widget scrollbar,
2097 XtPointer clientData,
2098 XmScrollBarCallbackStruct *cbs)
2099 {
2100 wxWindow *win = wxGetWindowFromTable(scrollbar);
2101 wxCHECK_RET( win, wxT("invalid widget in scrollbar callback") );
2102
2103 wxOrientation orientation = (wxOrientation)wxPtrToUInt(clientData);
2104
2105 wxEventType eventType = wxEVT_NULL;
2106 switch (cbs->reason)
2107 {
2108 case XmCR_INCREMENT:
2109 {
2110 eventType = wxEVT_SCROLLWIN_LINEDOWN;
2111 break;
2112 }
2113 case XmCR_DECREMENT:
2114 {
2115 eventType = wxEVT_SCROLLWIN_LINEUP;
2116 break;
2117 }
2118 case XmCR_DRAG:
2119 {
2120 eventType = wxEVT_SCROLLWIN_THUMBTRACK;
2121 break;
2122 }
2123 case XmCR_VALUE_CHANGED:
2124 {
2125 eventType = wxEVT_SCROLLWIN_THUMBRELEASE;
2126 break;
2127 }
2128 case XmCR_PAGE_INCREMENT:
2129 {
2130 eventType = wxEVT_SCROLLWIN_PAGEDOWN;
2131 break;
2132 }
2133 case XmCR_PAGE_DECREMENT:
2134 {
2135 eventType = wxEVT_SCROLLWIN_PAGEUP;
2136 break;
2137 }
2138 case XmCR_TO_TOP:
2139 {
2140 eventType = wxEVT_SCROLLWIN_TOP;
2141 break;
2142 }
2143 case XmCR_TO_BOTTOM:
2144 {
2145 eventType = wxEVT_SCROLLWIN_BOTTOM;
2146 break;
2147 }
2148 default:
2149 {
2150 // Should never get here
2151 wxFAIL_MSG("Unknown scroll event.");
2152 break;
2153 }
2154 }
2155
2156 wxScrollWinEvent event(eventType,
2157 cbs->value,
2158 orientation);
2159 event.SetEventObject( win );
2160 win->HandleWindowEvent(event);
2161 }
2162
2163 // For repainting arbitrary windows
2164 void wxUniversalRepaintProc(Widget w, XtPointer WXUNUSED(c_data), XEvent *event, char *)
2165 {
2166 wxWindow* win = wxGetWindowFromTable(w);
2167 if (!win)
2168 return;
2169
2170 switch ( event->type )
2171 {
2172 case Expose:
2173 {
2174 win->AddUpdateRect(event->xexpose.x, event->xexpose.y,
2175 event->xexpose.width, event->xexpose.height);
2176
2177 if ( event->xexpose.count == 0 )
2178 {
2179 win->DoPaint();
2180 }
2181
2182 break;
2183 }
2184 }
2185 }
2186
2187 // ----------------------------------------------------------------------------
2188 // TranslateXXXEvent() functions
2189 // ----------------------------------------------------------------------------
2190
2191 bool wxTranslateMouseEvent(wxMouseEvent& wxevent, wxWindow *win,
2192 Widget widget, const XEvent *xevent)
2193 {
2194 switch (xevent->xany.type)
2195 {
2196 case EnterNotify:
2197 case LeaveNotify:
2198 #if 0
2199 fprintf(stderr, "Widget 0x%p <-> window %p (%s), %s\n",
2200 (WXWidget)widget, win, win->GetClassInfo()->GetClassName(),
2201 (xevent->xany.type == EnterNotify ? "ENTER" : "LEAVE"));
2202 #endif
2203 case ButtonPress:
2204 case ButtonRelease:
2205 case MotionNotify:
2206 {
2207 int eventx = xevent->xbutton.x, eventy = xevent->xbutton.y;
2208
2209 wxEventType eventType = wxEVT_NULL;
2210
2211 if (xevent->xany.type == LeaveNotify)
2212 {
2213 eventType = wxEVT_LEAVE_WINDOW;
2214 }
2215 if (xevent->xany.type == EnterNotify)
2216 {
2217 eventType = wxEVT_ENTER_WINDOW;
2218 }
2219 else if (xevent->xany.type == MotionNotify)
2220 {
2221 eventType = wxEVT_MOTION;
2222
2223 if (xevent->xmotion.is_hint == NotifyHint)
2224 {
2225 Window root, child;
2226 int x_root, y_root;
2227 unsigned int state;
2228 Display *dpy = XtDisplay (widget);
2229
2230 XQueryPointer (dpy, XtWindow (widget),
2231 &root, &child,
2232 &x_root, &y_root, &eventx, &eventy, &state);
2233 }
2234 }
2235 else if (xevent->xany.type == ButtonPress)
2236 {
2237 wxevent.SetTimestamp(xevent->xbutton.time);
2238 int button = 0;
2239 if (xevent->xbutton.button == Button1)
2240 {
2241 eventType = wxEVT_LEFT_DOWN;
2242 button = 1;
2243 }
2244 else if (xevent->xbutton.button == Button2)
2245 {
2246 eventType = wxEVT_MIDDLE_DOWN;
2247 button = 2;
2248 }
2249 else if (xevent->xbutton.button == Button3)
2250 {
2251 eventType = wxEVT_RIGHT_DOWN;
2252 button = 3;
2253 }
2254
2255 // check for a double click
2256 //
2257 long dclickTime = XtGetMultiClickTime(xevent->xany.display);
2258 long ts = wxevent.GetTimestamp();
2259
2260 int buttonLast = win->GetLastClickedButton();
2261 long lastTS = win->GetLastClickTime();
2262 if ( buttonLast && buttonLast == button &&
2263 (ts - lastTS) < dclickTime )
2264 {
2265 // I have a dclick
2266 win->SetLastClick(0, ts);
2267 if ( eventType == wxEVT_LEFT_DOWN )
2268 eventType = wxEVT_LEFT_DCLICK;
2269 else if ( eventType == wxEVT_MIDDLE_DOWN )
2270 eventType = wxEVT_MIDDLE_DCLICK;
2271 else if ( eventType == wxEVT_RIGHT_DOWN )
2272 eventType = wxEVT_RIGHT_DCLICK;
2273 }
2274 else
2275 {
2276 // not fast enough or different button
2277 win->SetLastClick(button, ts);
2278 }
2279 }
2280 else if (xevent->xany.type == ButtonRelease)
2281 {
2282 if (xevent->xbutton.button == Button1)
2283 {
2284 eventType = wxEVT_LEFT_UP;
2285 }
2286 else if (xevent->xbutton.button == Button2)
2287 {
2288 eventType = wxEVT_MIDDLE_UP;
2289 }
2290 else if (xevent->xbutton.button == Button3)
2291 {
2292 eventType = wxEVT_RIGHT_UP;
2293 }
2294 else
2295 return false;
2296 }
2297 else
2298 {
2299 return false;
2300 }
2301
2302 wxevent.SetEventType(eventType);
2303
2304 Position x1, y1;
2305 XtVaGetValues(widget, XmNx, &x1, XmNy, &y1, NULL);
2306
2307 int x2, y2;
2308 win->GetPosition(&x2, &y2);
2309
2310 // The button x/y must be translated to wxWidgets
2311 // window space - the widget might be a label or button,
2312 // within a form.
2313 int dx = 0;
2314 int dy = 0;
2315 if (widget != (Widget)win->GetMainWidget())
2316 {
2317 dx = x1;
2318 dy = y1;
2319 }
2320
2321 wxevent.m_x = eventx + dx;
2322 wxevent.m_y = eventy + dy;
2323
2324 wxevent.m_leftDown = ((eventType == wxEVT_LEFT_DOWN)
2325 || (event_left_is_down (xevent)
2326 && (eventType != wxEVT_LEFT_UP)));
2327 wxevent.m_middleDown = ((eventType == wxEVT_MIDDLE_DOWN)
2328 || (event_middle_is_down (xevent)
2329 && (eventType != wxEVT_MIDDLE_UP)));
2330 wxevent.m_rightDown = ((eventType == wxEVT_RIGHT_DOWN)
2331 || (event_right_is_down (xevent)
2332 && (eventType != wxEVT_RIGHT_UP)));
2333
2334 wxevent.m_shiftDown = (xevent->xbutton.state & ShiftMask) == ShiftMask;
2335 wxevent.m_controlDown = (xevent->xbutton.state & ControlMask) == ControlMask;
2336 wxevent.m_altDown = (xevent->xbutton.state & Mod3Mask) == Mod3Mask;
2337 wxevent.m_metaDown = (xevent->xbutton.state & Mod1Mask) == Mod1Mask;
2338
2339 wxevent.SetId(win->GetId());
2340 wxevent.SetEventObject(win);
2341
2342 return true;
2343 }
2344 }
2345 return false;
2346 }
2347
2348 bool wxTranslateKeyEvent(wxKeyEvent& wxevent, wxWindow *win,
2349 Widget WXUNUSED(widget), const XEvent *xevent)
2350 {
2351 switch (xevent->xany.type)
2352 {
2353 case KeyPress:
2354 case KeyRelease:
2355 {
2356 char buf[20];
2357
2358 KeySym keySym;
2359 (void) XLookupString((XKeyEvent *)xevent, buf, 20, &keySym, NULL);
2360 int id = wxCharCodeXToWX (keySym);
2361 // id may be WXK_xxx code - these are outside ASCII range, so we
2362 // can't just use toupper() on id
2363 if (id >= 'a' && id <= 'z')
2364 id = toupper(id);
2365
2366 if (xevent->xkey.state & ShiftMask)
2367 wxevent.m_shiftDown = true;
2368 if (xevent->xkey.state & ControlMask)
2369 wxevent.m_controlDown = true;
2370 if (xevent->xkey.state & Mod3Mask)
2371 wxevent.m_altDown = true;
2372 if (xevent->xkey.state & Mod1Mask)
2373 wxevent.m_metaDown = true;
2374 wxevent.SetEventObject(win);
2375 wxevent.m_keyCode = id;
2376 wxevent.SetTimestamp(xevent->xkey.time);
2377
2378 wxevent.m_x = xevent->xbutton.x;
2379 wxevent.m_y = xevent->xbutton.y;
2380
2381 if (id > -1)
2382 return true;
2383
2384 return false;
2385 }
2386 default:
2387 break;
2388 }
2389 return false;
2390 }
2391
2392 // ----------------------------------------------------------------------------
2393 // Colour stuff
2394 // ----------------------------------------------------------------------------
2395
2396 #define YAllocColor XAllocColor
2397 XColor g_itemColors[5];
2398 int wxComputeColours (Display *display, const wxColour * back, const wxColour * fore)
2399 {
2400 int result;
2401 static XmColorProc colorProc;
2402
2403 result = wxNO_COLORS;
2404
2405 if (back)
2406 {
2407 g_itemColors[0].red = (unsigned short)(((long) back->Red ()) << 8);
2408 g_itemColors[0].green = (unsigned short)(((long) back->Green ()) << 8);
2409 g_itemColors[0].blue = (unsigned short)(((long) back->Blue ()) << 8);
2410 g_itemColors[0].flags = DoRed | DoGreen | DoBlue;
2411 if (colorProc == (XmColorProc) NULL)
2412 {
2413 // Get a ptr to the actual function
2414 colorProc = XmSetColorCalculation ((XmColorProc) NULL);
2415 // And set it back to motif.
2416 XmSetColorCalculation (colorProc);
2417 }
2418 (*colorProc) (&g_itemColors[wxBACK_INDEX],
2419 &g_itemColors[wxFORE_INDEX],
2420 &g_itemColors[wxSELE_INDEX],
2421 &g_itemColors[wxTOPS_INDEX],
2422 &g_itemColors[wxBOTS_INDEX]);
2423 result = wxBACK_COLORS;
2424 }
2425 if (fore)
2426 {
2427 g_itemColors[wxFORE_INDEX].red = (unsigned short)(((long) fore->Red ()) << 8);
2428 g_itemColors[wxFORE_INDEX].green = (unsigned short)(((long) fore->Green ()) << 8);
2429 g_itemColors[wxFORE_INDEX].blue = (unsigned short)(((long) fore->Blue ()) << 8);
2430 g_itemColors[wxFORE_INDEX].flags = DoRed | DoGreen | DoBlue;
2431 if (result == wxNO_COLORS)
2432 result = wxFORE_COLORS;
2433 }
2434
2435 Display *dpy = display;
2436 Colormap cmap = (Colormap) wxTheApp->GetMainColormap((WXDisplay*) dpy);
2437
2438 if (back)
2439 {
2440 /* 5 Colours to allocate */
2441 for (int i = 0; i < 5; i++)
2442 if (!YAllocColor (dpy, cmap, &g_itemColors[i]))
2443 result = wxNO_COLORS;
2444 }
2445 else if (fore)
2446 {
2447 /* Only 1 colour to allocate */
2448 if (!YAllocColor (dpy, cmap, &g_itemColors[wxFORE_INDEX]))
2449 result = wxNO_COLORS;
2450 }
2451
2452 return result;
2453 }
2454
2455 // Changes the foreground and background colours to be derived from the current
2456 // background colour. To change the foreground colour, you must call
2457 // SetForegroundColour explicitly.
2458 void wxWindow::ChangeBackgroundColour()
2459 {
2460 WXWidget mainWidget = GetMainWidget();
2461 if ( mainWidget )
2462 wxDoChangeBackgroundColour(mainWidget, m_backgroundColour);
2463 if ( m_scrolledWindow && mainWidget != m_scrolledWindow )
2464 wxDoChangeForegroundColour(m_scrolledWindow, m_backgroundColour);
2465 }
2466
2467 void wxWindow::ChangeForegroundColour()
2468 {
2469 WXWidget mainWidget = GetMainWidget();
2470 if ( mainWidget )
2471 wxDoChangeForegroundColour(mainWidget, m_foregroundColour);
2472 if ( m_scrolledWindow && mainWidget != m_scrolledWindow )
2473 wxDoChangeForegroundColour(m_scrolledWindow, m_foregroundColour);
2474 }
2475
2476 bool wxWindow::SetBackgroundColour(const wxColour& col)
2477 {
2478 if ( !wxWindowBase::SetBackgroundColour(col) )
2479 return false;
2480
2481 ChangeBackgroundColour();
2482
2483 return true;
2484 }
2485
2486 bool wxWindow::SetForegroundColour(const wxColour& col)
2487 {
2488 if ( !wxWindowBase::SetForegroundColour(col) )
2489 return false;
2490
2491 ChangeForegroundColour();
2492
2493 return true;
2494 }
2495
2496 void wxWindow::ChangeFont(bool keepOriginalSize)
2497 {
2498 // Note that this causes the widget to be resized back
2499 // to its original size! We therefore have to set the size
2500 // back again. TODO: a better way in Motif?
2501 Widget w = (Widget) GetLabelWidget(); // Usually the main widget
2502 if (w && m_font.Ok())
2503 {
2504 int width, height, width1, height1;
2505 GetSize(& width, & height);
2506
2507 wxDoChangeFont( w, m_font );
2508
2509 GetSize(& width1, & height1);
2510 if (keepOriginalSize && (width != width1 || height != height1))
2511 {
2512 SetSize(wxDefaultCoord, wxDefaultCoord, width, height);
2513 }
2514 }
2515 }
2516
2517 // Post-creation
2518 void wxWindow::PostCreation()
2519 {
2520 ChangeFont();
2521 ChangeForegroundColour();
2522 ChangeBackgroundColour();
2523 }
2524
2525 // Pre-creation
2526 void wxWindow::PreCreation()
2527 {
2528 InheritAttributes();
2529 }
2530
2531 // ----------------------------------------------------------------------------
2532 // global functions
2533 // ----------------------------------------------------------------------------
2534
2535 wxWindow *wxGetActiveWindow()
2536 {
2537 // TODO
2538 wxFAIL_MSG("Not implemented");
2539 return NULL;
2540 }
2541
2542 /* static */
2543 wxWindow *wxWindowBase::GetCapture()
2544 {
2545 return (wxWindow *)g_captureWindow;
2546 }
2547
2548
2549 // Find the wxWindow at the current mouse position, returning the mouse
2550 // position.
2551 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
2552 {
2553 pt = wxGetMousePosition();
2554 return wxFindWindowAtPoint(pt);
2555 }
2556
2557 void wxGetMouseState(int& rootX, int& rootY, unsigned& maskReturn)
2558 {
2559 Display *display = wxGlobalDisplay();
2560 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
2561 Window rootReturn, childReturn;
2562 int winX, winY;
2563
2564 XQueryPointer (display,
2565 rootWindow,
2566 &rootReturn,
2567 &childReturn,
2568 &rootX, &rootY, &winX, &winY, &maskReturn);
2569 }
2570
2571 // Get the current mouse position.
2572 wxPoint wxGetMousePosition()
2573 {
2574 int x, y;
2575 unsigned mask;
2576
2577 wxGetMouseState(x, y, mask);
2578 return wxPoint(x, y);
2579 }
2580
2581 wxMouseState wxGetMouseState()
2582 {
2583 wxMouseState ms;
2584 int x, y;
2585 unsigned mask;
2586
2587 wxGetMouseState(x, y, mask);
2588
2589 ms.SetX(x);
2590 ms.SetY(y);
2591
2592 ms.SetLeftDown(mask & Button1Mask);
2593 ms.SetMiddleDown(mask & Button2Mask);
2594 ms.SetRightDown(mask & Button3Mask);
2595
2596 ms.SetControlDown(mask & ControlMask);
2597 ms.SetShiftDown(mask & ShiftMask);
2598 ms.SetAltDown(mask & Mod3Mask);
2599 ms.SetMetaDown(mask & Mod1Mask);
2600
2601 return ms;
2602 }
2603
2604
2605 #if wxMOTIF_NEW_FONT_HANDLING
2606
2607 #include <Xm/XmP.h>
2608
2609 void wxGetTextExtent(const wxWindow* window, const wxString& str,
2610 int* width, int* height, int* ascent, int* descent)
2611 {
2612 Arg args[2];
2613 int count = 0;
2614 XmRendition rendition = NULL;
2615 XmRenderTable table = NULL;
2616 Widget w = (Widget) window->GetLabelWidget();
2617
2618 XtVaGetValues( w, XmNrenderTable, &table, NULL );
2619 if (table == NULL)
2620 table = XmeGetDefaultRenderTable(w, XmTEXT_RENDER_TABLE);
2621
2622 rendition = XmRenderTableGetRendition( table, "" );
2623 XtSetArg( args[count], XmNfont, 0 ); ++count;
2624 XtSetArg( args[count], XmNfontType, 0 ); ++count;
2625 XmRenditionRetrieve( rendition, args, count );
2626
2627 if (args[1].value == XmFONT_IS_FONTSET)
2628 {
2629 XRectangle ink, logical;
2630 WXFontSet fset = (WXFontSet) args[0].value;
2631
2632 XmbTextExtents( (XFontSet)fset, str.c_str(), str.length(),
2633 &ink, &logical);
2634
2635 if( width ) *width = logical.width;
2636 if( height ) *height = logical.height;
2637 if( ascent ) *ascent = -logical.y;
2638 if( descent ) *descent = logical.height + logical.y;
2639 }
2640 else
2641 {
2642 int direction, ascent2, descent2;
2643 XCharStruct overall;
2644 XFontStruct* fontStruct;
2645
2646 XmeRenderTableGetDefaultFont( table, &fontStruct );
2647 XTextExtents(fontStruct, (const char*)str.c_str(), str.length(),
2648 &direction, &ascent2, &descent2, &overall);
2649
2650 if ( width ) *width = overall.width;
2651 if ( height ) *height = ascent2 + descent2;
2652 if ( descent ) *descent = descent2;
2653 if ( ascent ) *ascent = ascent2;
2654 }
2655 }
2656
2657 #else // if !wxMOTIF_NEW_FONT_HANDLING
2658
2659 void wxGetTextExtent(const wxWindow* window, const wxString& str,
2660 int* width, int* height, int* ascent, int* descent)
2661 {
2662 XmFontList list = NULL;
2663 XmFontContext cxt;
2664 XmFontType type;
2665 Widget w = (Widget) window->GetLabelWidget();
2666
2667 XtVaGetValues( w, XmNfontList, &list, NULL );
2668 XmFontListInitFontContext( &cxt, list );
2669
2670 XmFontListEntry entry = XmFontListNextEntry( cxt );
2671 XmFontListFreeFontContext( cxt );
2672 XtPointer thing = XmFontListEntryGetFont( entry, &type );
2673
2674 if (type == XmFONT_IS_FONTSET)
2675 {
2676 XRectangle ink, logical;
2677
2678 XmbTextExtents( (XFontSet)thing, str.c_str(), str.length(),
2679 &ink, &logical);
2680
2681 if( width ) *width = logical.width;
2682 if( height ) *height = logical.height;
2683 if( ascent ) *ascent = -logical.y;
2684 if( descent ) *descent = logical.height + logical.y;
2685 }
2686 else
2687 {
2688 int direction, ascent2, descent2;
2689 XCharStruct overall;
2690
2691 XTextExtents( (XFontStruct*)thing, (char*)(const char*)str.c_str(), str.length(),
2692 &direction, &ascent2, &descent2, &overall);
2693
2694 if ( width ) *width = overall.width;
2695 if ( height ) *height = ascent2 + descent2;
2696 if ( descent ) *descent = descent2;
2697 if ( ascent ) *ascent = ascent2;
2698 }
2699 }
2700
2701 #endif // !wxMOTIF_NEW_FONT_HANDLING
2702
2703 // ----------------------------------------------------------------------------
2704 // wxNoOptimize: switch off size optimization
2705 // ----------------------------------------------------------------------------
2706
2707 int wxNoOptimize::ms_count = 0;