+#endif
+
+// ---------------------------------------------------------------------------
+// moving and resizing
+// ---------------------------------------------------------------------------
+
+bool wxWindow::PreResize()
+{
+ return true;
+}
+
+// Get total size
+void wxWindow::DoGetSize(int *x, int *y) const
+{
+ Widget widget = (Widget)( !m_drawingArea ? GetTopWidget() :
+ ( m_borderWidget ? m_borderWidget :
+ m_scrolledWindow ? m_scrolledWindow :
+ m_drawingArea ) );
+ Dimension xx, yy;
+
+ if (widget)
+ XtVaGetValues( widget,
+ XmNwidth, &xx,
+ XmNheight, &yy,
+ NULL );
+ if(x) *x = widget ? xx : -1;
+ if(y) *y = widget ? yy : -1;
+}
+
+void wxWindow::DoGetPosition(int *x, int *y) const
+{
+ Widget widget = (Widget)
+ ( m_drawingArea ?
+ ( m_borderWidget ? m_borderWidget : m_scrolledWindow ) :
+ GetTopWidget() );
+
+ Position xx, yy;
+ XtVaGetValues(widget, XmNx, &xx, XmNy, &yy, NULL);
+
+ // We may be faking the client origin. So a window that's really at (0, 30)
+ // may appear (to wxWin apps) to be at (0, 0).
+ if (GetParent())
+ {
+ wxPoint pt(GetParent()->GetClientAreaOrigin());
+ xx = (Position)(xx - pt.x);
+ yy = (Position)(yy - pt.y);
+ }
+
+ if(x) *x = xx;
+ if(y) *y = yy;
+}
+
+void wxWindow::DoScreenToClient(int *x, int *y) const
+{
+ Widget widget = (Widget) GetClientWidget();
+ Display *display = XtDisplay((Widget) GetMainWidget());
+ Window rootWindow = RootWindowOfScreen(XtScreen(widget));
+ Window thisWindow = XtWindow(widget);
+
+ Window childWindow;
+ int xx = x ? *x : 0;
+ int yy = y ? *y : 0;
+ XTranslateCoordinates(display, rootWindow, thisWindow,
+ xx, yy, x ? x : &xx, y ? y : &yy,
+ &childWindow);
+}
+
+void wxWindow::DoClientToScreen(int *x, int *y) const
+{
+ Widget widget = (Widget) GetClientWidget();
+ Display *display = XtDisplay(widget);
+ Window rootWindow = RootWindowOfScreen(XtScreen(widget));
+ Window thisWindow = XtWindow(widget);
+
+ Window childWindow;
+ int xx = x ? *x : 0;
+ int yy = y ? *y : 0;
+ XTranslateCoordinates(display, thisWindow, rootWindow,
+ xx, yy, x ? x : &xx, y ? y : &yy,
+ &childWindow);
+}
+
+
+// Get size *available for subwindows* i.e. excluding menu bar etc.
+void wxWindow::DoGetClientSize(int *x, int *y) const
+{
+ Widget widget = (Widget) GetClientWidget();
+ Dimension xx, yy;
+ XtVaGetValues(widget, XmNwidth, &xx, XmNheight, &yy, NULL);
+ if(x) *x = xx; if(y) *y = yy;
+}
+
+void wxWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags)
+{
+ DoSetSizeIntr(x, y, width, height, sizeFlags, false);
+}
+
+void wxWindow::DoSetSizeIntr(int x, int y, int width, int height,
+ int sizeFlags, bool fromCtor)
+{
+ // A bit of optimization to help sort out the flickers.
+ int oldX = -1, oldY = -1, oldW = -1, oldH = -1;
+
+ if( !fromCtor )
+ {
+ GetSize(& oldW, & oldH);
+ GetPosition(& oldX, & oldY);
+ }
+
+ if (x == -1)
+ x = oldX;
+ if (x == -1)
+ x = oldY;
+
+ if ( !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
+ {
+ if ( width == -1 )
+ width = oldW;
+ if ( height == -1 )
+ height = oldH;
+ }
+
+ wxSize size(wxDefaultSize);
+ if ( width <= 0 )
+ {
+ if ( ( sizeFlags & wxSIZE_AUTO_WIDTH ) && !fromCtor )
+ {
+ size = DoGetBestSize();
+ width = size.x;
+ }
+ else
+ {
+ width = oldW;
+ }
+ }
+
+ if ( height == -1 )
+ {
+ if( ( sizeFlags & wxSIZE_AUTO_HEIGHT ) && !fromCtor )
+ {
+ if( size.x == -1 ) size = DoGetBestSize();
+ height = size.y;
+ }
+ else
+ {
+ height = oldH;
+ }
+ }
+
+ if ( x != oldX || y != oldY || width != oldW || height != oldH
+ || !wxNoOptimize::CanOptimize() )
+ {
+ if (m_drawingArea)
+ {
+ int flags = 0;
+
+ if (x != oldX)
+ flags |= wxMOVE_X;
+
+ if (y != oldY)
+ flags |= wxMOVE_Y;
+
+ if (width > 0)
+ flags |= wxMOVE_WIDTH;
+
+ if (height > 0)
+ flags |= wxMOVE_HEIGHT;
+
+ int xx = x; int yy = y;
+ AdjustForParentClientOrigin(xx, yy, sizeFlags);
+ if( !fromCtor )
+ DoMoveWindow( xx, yy, width, height );
+ else
+ DoMoveWindowIntr( xx, yy, width, height, flags );
+
+ return;
+ }
+
+ Widget widget = (Widget) GetTopWidget();
+ if (!widget)
+ return;
+
+ bool managed = XtIsManaged( widget );
+ if (managed)
+ XtUnmanageChild(widget);
+
+ int xx = x;
+ int yy = y;
+ AdjustForParentClientOrigin(xx, yy, sizeFlags);
+
+ DoMoveWindow(xx, yy, width, height);
+
+ if (managed)
+ XtManageChild(widget);
+ }
+}
+
+void wxWindow::DoSetClientSize(int width, int height)
+{
+ if (m_drawingArea)
+ {
+ Widget drawingArea = (Widget) m_drawingArea;
+
+ XtVaSetValues(drawingArea, XmNresizePolicy, XmRESIZE_ANY, NULL);
+
+ if (width > -1)
+ XtVaSetValues(drawingArea, XmNwidth, width, NULL);
+ if (height > -1)
+ XtVaSetValues(drawingArea, XmNheight, height, NULL);
+
+ XtVaSetValues(drawingArea, XmNresizePolicy, XmRESIZE_NONE, NULL);
+ return;
+ }
+
+ Widget widget = (Widget) GetTopWidget();
+
+ if (width > -1)
+ XtVaSetValues(widget, XmNwidth, width, NULL);
+ if (height > -1)
+ XtVaSetValues(widget, XmNheight, height, NULL);
+}
+
+void wxWindow::DoMoveWindowIntr(int xx, int yy, int w, int h,
+ int flags)
+{
+ if (m_drawingArea)
+ {
+ Widget drawingArea = (Widget) m_drawingArea;
+ Widget borderOrScrolled = m_borderWidget ?
+ (Widget) m_borderWidget :
+ (Widget) m_scrolledWindow;
+
+ bool managed = XtIsManaged(borderOrScrolled);
+ if (managed)
+ XtUnmanageChild (borderOrScrolled);
+ XtVaSetValues(drawingArea, XmNresizePolicy, XmRESIZE_ANY, NULL);
+
+ if (flags & wxMOVE_X)
+ XtVaSetValues (borderOrScrolled,
+ XmNx, xx,
+ NULL);
+ if (flags & wxMOVE_Y)
+ XtVaSetValues (borderOrScrolled,
+ XmNy, yy,
+ NULL);
+
+ if (flags & wxMOVE_WIDTH)
+ {
+ if (m_borderWidget)
+ {
+ XtVaSetValues ((Widget) m_borderWidget, XmNwidth, w, NULL);
+ short thick, margin;
+ XtVaGetValues ((Widget) m_borderWidget,
+ XmNshadowThickness, &thick,
+ XmNmarginWidth, &margin,
+ NULL);
+ w -= 2 * (thick + margin);
+ }
+
+ if( w < 1 ) w = 1;
+ XtVaSetValues ((Widget) m_scrolledWindow, XmNwidth, w, NULL);
+ }
+
+ if (flags & wxMOVE_HEIGHT)
+ {
+ if (m_borderWidget)
+ {
+ XtVaSetValues ((Widget) m_borderWidget, XmNheight, h, NULL);
+ short thick, margin;
+ XtVaGetValues ((Widget) m_borderWidget,
+ XmNshadowThickness, &thick,
+ XmNmarginHeight, &margin,
+ NULL);
+ h -= 2 * (thick + margin);
+ }
+
+ if( h < 1 ) h = 1;
+ XtVaSetValues ((Widget) m_scrolledWindow, XmNheight, h, NULL);
+ }
+
+ if (managed)
+ XtManageChild (borderOrScrolled);
+ XtVaSetValues(drawingArea, XmNresizePolicy, XmRESIZE_NONE, NULL);
+ }
+ else
+ {
+ if( w < 1 ) w = 1;
+ if( h < 1 ) h = 1;
+
+ XtVaSetValues((Widget)GetTopWidget(),
+ XmNx, xx,
+ XmNy, yy,
+ XmNwidth, w,
+ XmNheight, h,
+ NULL);
+ }
+}
+
+void wxWindow::DoMoveWindow(int x, int y, int width, int height)
+{
+ DoMoveWindowIntr (x, y, width, height,
+ wxMOVE_X|wxMOVE_Y|wxMOVE_WIDTH|wxMOVE_HEIGHT);
+}
+
+// ---------------------------------------------------------------------------
+// text metrics
+// ---------------------------------------------------------------------------
+
+int wxWindow::GetCharHeight() const
+{
+ int height;
+
+ if (m_font.Ok())
+ wxGetTextExtent (GetXDisplay(), m_font, 1.0,
+ "x", NULL, &height, NULL, NULL);
+ else
+ wxGetTextExtent (this, "x", NULL, &height, NULL, NULL);
+
+ return height;
+}
+
+int wxWindow::GetCharWidth() const
+{
+ int width;
+
+ if (m_font.Ok())
+ wxGetTextExtent (GetXDisplay(), m_font, 1.0,
+ "x", &width, NULL, NULL, NULL);
+ else
+ wxGetTextExtent (this, "x", &width, NULL, NULL, NULL);
+
+ return width;
+}
+
+void wxWindow::GetTextExtent(const wxString& string,
+ int *x, int *y,
+ int *descent, int *externalLeading,
+ const wxFont *theFont) const
+{
+ const wxFont *fontToUse = theFont ? theFont : &m_font;
+
+ if (externalLeading)
+ *externalLeading = 0;
+ if (fontToUse->Ok())
+ wxGetTextExtent (GetXDisplay(), *fontToUse, 1.0,
+ string, x, y, NULL, descent);
+ else
+ wxGetTextExtent (this, string, x, y, NULL, descent);
+}
+
+// ----------------------------------------------------------------------------
+// painting
+// ----------------------------------------------------------------------------
+
+void wxWindow::AddUpdateRect(int x, int y, int w, int h)
+{
+ m_updateRegion.Union( x, y, w, h );
+}
+
+void wxWindow::Refresh(bool eraseBack, const wxRect *rect)
+{
+ Widget widget = (Widget) GetMainWidget();
+ if (!widget)
+ return;
+ m_needsRefresh = true;
+ Display *display = XtDisplay(widget);
+ Window thisWindow = XtWindow(widget);
+
+ XExposeEvent dummyEvent;
+ int width, height;
+ GetSize(&width, &height);
+
+ dummyEvent.type = Expose;
+ dummyEvent.display = display;
+ dummyEvent.send_event = True;
+ dummyEvent.window = thisWindow;
+ if (rect)
+ {
+ dummyEvent.x = rect->x;
+ dummyEvent.y = rect->y;
+ dummyEvent.width = rect->width;
+ dummyEvent.height = rect->height;
+ }
+ else
+ {
+ dummyEvent.x = 0;
+ dummyEvent.y = 0;
+ dummyEvent.width = width;
+ dummyEvent.height = height;
+ }
+ dummyEvent.count = 0;
+
+ if (eraseBack)
+ {
+ wxClientDC dc(this);
+ wxBrush backgroundBrush(GetBackgroundColour(), wxSOLID);
+ dc.SetBackground(backgroundBrush);
+ if (rect)
+ dc.Clear(*rect);
+ else
+ dc.Clear();
+ }
+
+ XSendEvent(display, thisWindow, False, ExposureMask, (XEvent *)&dummyEvent);
+}
+
+void wxWindow::DoPaint()
+{
+ //TODO : make a temporary gc so we can do the XCopyArea below
+ if (m_backingPixmap && !m_needsRefresh)
+ {
+ wxPaintDC dc(this);
+
+ GC tempGC = (GC) dc.GetBackingGC();
+
+ Widget widget = (Widget) GetMainWidget();
+
+ int scrollPosX = 0;
+ int scrollPosY = 0;
+
+ // We have to test whether it's a wxScrolledWindow (hack!) because
+ // otherwise we don't know how many pixels have been scrolled. We might
+ // solve this in the future by defining virtual wxWindow functions to get
+ // the scroll position in pixels. Or, each kind of scrolled window has to
+ // implement backing stores itself, using generic wxWidgets code.
+ wxScrolledWindow* scrolledWindow = wxDynamicCast(this, wxScrolledWindow);
+ if ( scrolledWindow )
+ {
+ int x, y;
+ scrolledWindow->CalcScrolledPosition(0, 0, &x, &y);
+
+ scrollPosX = - x;
+ scrollPosY = - y;
+ }
+
+ // TODO: This could be optimized further by only copying the areas in the
+ // current update region.
+
+ // Only blit the part visible in the client area. The backing pixmap
+ // always starts at 0, 0 but we may be looking at only a portion of it.
+ wxSize clientArea = GetClientSize();
+ int toBlitX = m_pixmapWidth - scrollPosX;
+ int toBlitY = m_pixmapHeight - scrollPosY;
+
+ // Copy whichever is samller, the amount of pixmap we have to copy,
+ // or the size of the client area.
+ toBlitX = wxMin(toBlitX, clientArea.x);
+ toBlitY = wxMin(toBlitY, clientArea.y);
+
+ // Make sure we're not negative
+ toBlitX = wxMax(0, toBlitX);
+ toBlitY = wxMax(0, toBlitY);
+
+ XCopyArea
+ (
+ XtDisplay(widget),
+ (Pixmap) m_backingPixmap,
+ XtWindow (widget),
+ tempGC,
+ scrollPosX, scrollPosY, // Start at the scroll position
+ toBlitX, toBlitY, // How much of the pixmap to copy
+ 0, 0 // Destination
+ );
+ }
+ else
+ {
+ wxWindowDC dc(this);
+ // Set an erase event first
+ wxEraseEvent eraseEvent(GetId(), &dc);
+ eraseEvent.SetEventObject(this);
+ GetEventHandler()->ProcessEvent(eraseEvent);
+
+ wxPaintEvent event(GetId());
+ event.SetEventObject(this);
+ GetEventHandler()->ProcessEvent(event);
+
+ m_needsRefresh = false;
+ }
+}
+
+// ----------------------------------------------------------------------------
+// event handlers
+// ----------------------------------------------------------------------------
+
+// Responds to colour changes: passes event on to children.
+void wxWindow::OnSysColourChanged(wxSysColourChangedEvent& event)
+{
+ wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+ while ( node )
+ {
+ // Only propagate to non-top-level windows
+ wxWindow *win = node->GetData();
+ if ( win->GetParent() )
+ {
+ wxSysColourChangedEvent event2;
+ event.SetEventObject(win);
+ win->GetEventHandler()->ProcessEvent(event2);
+ }
+
+ node = node->GetNext();
+ }
+}
+
+void wxWindow::OnInternalIdle()
+{
+ // This calls the UI-update mechanism (querying windows for
+ // menu/toolbar/control state information)
+ if (wxUpdateUIEvent::CanUpdate(this))
+ UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
+}
+
+// ----------------------------------------------------------------------------
+// accelerators
+// ----------------------------------------------------------------------------
+
+bool wxWindow::ProcessAccelerator(wxKeyEvent& event)
+{
+#if wxUSE_ACCEL
+ if (!m_acceleratorTable.Ok())
+ return false;
+
+ int count = m_acceleratorTable.GetCount();
+ wxAcceleratorEntry* entries = m_acceleratorTable.GetEntries();
+ int i;
+ for (i = 0; i < count; i++)
+ {
+ wxAcceleratorEntry* entry = & (entries[i]);
+ if (entry->MatchesEvent(event))
+ {
+ // Bingo, we have a match. Now find a control that matches the
+ // entry command id.
+
+ // Need to go up to the top of the window hierarchy, since it might
+ // be e.g. a menu item
+ wxWindow* parent = this;
+ while ( parent && !parent->IsTopLevel() )
+ parent = parent->GetParent();
+
+ if (!parent)
+ return false;
+
+ wxFrame* frame = wxDynamicCast(parent, wxFrame);
+ if ( frame )
+ {
+#if wxUSE_MENUS
+ // Try for a menu command
+ if (frame->GetMenuBar())
+ {
+ wxMenuItem* item = frame->GetMenuBar()->FindItem(entry->GetCommand());
+ if (item)
+ {
+ wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, entry->GetCommand());
+ commandEvent.SetEventObject(frame);
+
+ // If ProcessEvent returns true (it was handled), then
+ // the calling code will skip the event handling.
+ return frame->GetEventHandler()->ProcessEvent(commandEvent);
+ }
+ }
+#endif
+ }
+
+ // Find a child matching the command id
+ wxWindow* child = parent->FindWindow(entry->GetCommand());
+
+ // No such child
+ if (!child)
+ return false;
+
+ // Now we process those kinds of windows that we can.
+ // For now, only buttons.
+ if ( wxDynamicCast(child, wxButton) )
+ {
+ wxCommandEvent commandEvent (wxEVT_COMMAND_BUTTON_CLICKED, child->GetId());
+ commandEvent.SetEventObject(child);
+ return child->GetEventHandler()->ProcessEvent(commandEvent);
+ }
+
+ return false;
+ } // matches event
+ }// for
+#endif
+
+ // We didn't match the key event against an accelerator.
+ return false;
+}
+
+// ============================================================================
+// Motif-specific stuff from here on
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// function which maintain the global hash table mapping Widgets to wxWidgets
+// ----------------------------------------------------------------------------
+
+bool wxAddWindowToTable(Widget w, wxWindow *win)
+{
+ const long key = (long)w;
+ if ( wxWidgetHashTable->Get(key))
+ {
+ wxLogDebug("Widget table clash: new widget is %ld, %s",
+ key, win->GetClassInfo()->GetClassName());
+ return false;
+ }
+
+ wxWidgetHashTable->Put(key, win);
+
+ wxLogTrace("widget", "Widget 0x%p <-> window %p (%s)",
+ w, win, win->GetClassInfo()->GetClassName());
+
+ return true;
+}
+
+wxWindow *wxGetWindowFromTable(Widget w)
+{
+ return (wxWindow *)wxWidgetHashTable->Get((long) w);
+}
+
+void wxDeleteWindowFromTable(Widget w)
+{
+ wxLogTrace("widget", "Widget 0x%p", (WXWidget)w);
+
+ wxWidgetHashTable->Delete((long)w);
+}
+
+// ----------------------------------------------------------------------------
+// add/remove window from the table
+// ----------------------------------------------------------------------------
+
+// Add to hash table, add event handler
+bool wxWindow::AttachWidget (wxWindow* WXUNUSED(parent), WXWidget mainWidget,
+ WXWidget formWidget, int x, int y, int width, int height)
+{
+ wxAddWindowToTable((Widget) mainWidget, this);
+ XtAddEventHandler( (Widget) mainWidget,
+ ButtonPressMask | ButtonReleaseMask
+ | PointerMotionMask,
+ False,
+ wxPanelItemEventHandler,
+ (XtPointer) this);
+
+ if (!formWidget)
+ {
+ XtTranslations ptr;
+ XtOverrideTranslations ((Widget) mainWidget,
+ ptr = XtParseTranslationTable ("<Configure>: resize()"));
+ XtFree ((char *) ptr);
+ }
+
+ // Some widgets have a parent form widget, e.g. wxRadioBox
+ if (formWidget)
+ {
+ if (!wxAddWindowToTable((Widget) formWidget, this))
+ return false;
+
+ XtTranslations ptr;
+ XtOverrideTranslations ((Widget) formWidget,
+ ptr = XtParseTranslationTable ("<Configure>: resize()"));
+ XtFree ((char *) ptr);
+ }
+
+ if (x == -1)
+ x = 0;
+ if (y == -1)
+ y = 0;
+ DoSetSize (x, y, width, height, wxSIZE_USE_EXISTING);
+
+ return true;