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