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