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