X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4bb6408c2631988fab9925014c6619358bf867de..dcf40a56e7b09fc5472edc1d4471e7954c0da40d:/src/motif/window.cpp diff --git a/src/motif/window.cpp b/src/motif/window.cpp index 4287512e6f..5e8e991bef 100644 --- a/src/motif/window.cpp +++ b/src/motif/window.cpp @@ -36,10 +36,31 @@ #endif #include + +#include +#include +#include +#include +#include + #include "wx/motif/private.h" #include +#define SCROLL_MARGIN 4 +void wxCanvasRepaintProc (Widget, XtPointer, XmDrawingAreaCallbackStruct * cbs); +void wxCanvasInputEvent (Widget drawingArea, XtPointer data, XmDrawingAreaCallbackStruct * cbs); +void wxCanvasMotionEvent (Widget, XButtonEvent * event); +void wxCanvasEnterLeave (Widget drawingArea, XtPointer clientData, XCrossingEvent * event); +void wxPanelItemEventHandler (Widget wid, + XtPointer client_data, + XEvent* event, + Boolean *continueToDispatch); + +#define event_left_is_down(x) ((x)->xbutton.state & Button1Mask) +#define event_middle_is_down(x) ((x)->xbutton.state & Button2Mask) +#define event_right_is_down(x) ((x)->xbutton.state & Button3Mask) + extern wxList wxPendingDelete; #if !USE_SHARED_LIBRARY @@ -87,18 +108,87 @@ wxWindow::wxWindow() m_pDropTarget = NULL; #endif - /// MOTIF-specific + /// Motif-specific m_mainWidget = (WXWidget) 0; m_button1Pressed = FALSE; m_button2Pressed = FALSE; m_button3Pressed = FALSE; m_winCaptured = FALSE; m_isShown = TRUE; + m_hScrollBar = (WXWidget) 0; + m_vScrollBar = (WXWidget) 0; + m_borderWidget = (WXWidget) 0; + m_scrolledWindow = (WXWidget) 0; + m_drawingArea = (WXWidget) 0; + m_hScroll = FALSE; + m_vScroll = FALSE; + m_hScrollingEnabled = FALSE; + m_vScrollingEnabled = FALSE; + m_backingPixmap = (WXPixmap) 0; + m_pixmapWidth = 0; + m_pixmapHeight = 0; + m_pixmapOffsetX = 0; + m_pixmapOffsetY = 0; + m_lastTS = 0; + m_lastButton = 0; + m_canAddEventHandler = FALSE; } // Destructor wxWindow::~wxWindow() { + //// Motif-specific + + if (GetMainWidget()) + DetachWidget(GetMainWidget()); // Removes event handlers + + // If m_drawingArea, we're a fully-fledged window with drawing area, scrollbars etc. (what wxCanvas used to be) + if (m_drawingArea) + { + // Destroy children before destroying self + DestroyChildren(); + + if (m_backingPixmap) + XFreePixmap (XtDisplay ((Widget) GetMainWidget()), (Pixmap) m_backingPixmap); + + Widget w = (Widget) m_drawingArea; + wxDeleteWindowFromTable(w); + + if (w) + XtDestroyWidget(w); + m_mainWidget = (WXWidget) 0; + + // Only if we're _really_ a canvas (not a dialog box/panel) + if (m_scrolledWindow) + { + wxDeleteWindowFromTable((Widget) m_scrolledWindow); + } + + if (m_hScrollBar) + { + XtUnmanageChild ((Widget) m_hScrollBar); + XtDestroyWidget ((Widget) m_hScrollBar); + } + if (m_vScrollBar) + { + XtUnmanageChild ((Widget) m_vScrollBar); + XtDestroyWidget ((Widget) m_vScrollBar); + } + if (m_scrolledWindow) + { + XtUnmanageChild ((Widget) m_scrolledWindow); + XtDestroyWidget ((Widget) m_scrolledWindow); + } + + if (m_borderWidget) + { + XtDestroyWidget ((Widget) m_borderWidget); + m_borderWidget = (WXWidget) 0; + } + } + + //// Generic stuff + // Have to delete constraints/sizer FIRST otherwise // sizers may try to look at deleted windows as they // delete themselves. @@ -174,11 +264,9 @@ bool wxWindow::Create(wxWindow *parent, wxWindowID id, m_sizerParent = NULL; m_autoLayout = FALSE; m_windowValidator = NULL; - #if USE_DRAG_AND_DROP m_pDropTarget = NULL; #endif - m_caretWidth = 0; m_caretHeight = 0; m_caretEnabled = FALSE; m_caretShown = FALSE; @@ -188,6 +276,30 @@ bool wxWindow::Create(wxWindow *parent, wxWindowID id, m_maxSizeY = -1; m_defaultItem = NULL; m_windowParent = NULL; + + // Motif-specific + m_canAddEventHandler = FALSE; + m_mainWidget = (WXWidget) 0; + m_button1Pressed = FALSE; + m_button2Pressed = FALSE; + m_button3Pressed = FALSE; + m_winCaptured = FALSE; + m_isShown = TRUE; + m_hScrollBar = (WXWidget) 0; + m_vScrollBar = (WXWidget) 0; + m_borderWidget = (WXWidget) 0; + m_scrolledWindow = (WXWidget) 0; + m_drawingArea = (WXWidget) 0; + m_hScroll = FALSE; + m_vScroll = FALSE; + m_hScrollingEnabled = FALSE; + m_vScrollingEnabled = FALSE; + m_backingPixmap = (WXPixmap) 0; + m_pixmapWidth = 0; + m_pixmapHeight = 0; + m_pixmapOffsetX = 0; + m_pixmapOffsetY = 0; + if (!parent) return FALSE; @@ -214,7 +326,92 @@ bool wxWindow::Create(wxWindow *parent, wxWindowID id, else m_windowId = id; - // TODO: create the window + //// TODO: we should probably optimize by only creating a + //// a drawing area if we have one or more scrollbars (wxVSCROLL/wxHSCROLL). + //// But for now, let's simplify things by always creating the + //// drawing area, since otherwise the translations are different. + + // New translations for getting mouse motion feedback + String translations = + ": wxCanvasMotionEvent() DrawingAreaInput() ManagerGadgetButtonMotion()\n\ + : wxCanvasMotionEvent() DrawingAreaInput() ManagerGadgetButtonMotion()\n\ + : wxCanvasMotionEvent() DrawingAreaInput() ManagerGadgetButtonMotion()\n\ + : wxCanvasMotionEvent() DrawingAreaInput() ManagerGadgetButtonMotion()\n\ + : DrawingAreaInput() ManagerGadgetArm()\n\ + : DrawingAreaInput() ManagerGadgetArm()\n\ + : DrawingAreaInput() ManagerGadgetArm()\n\ + : DrawingAreaInput() ManagerGadgetActivate()\n\ + : DrawingAreaInput() ManagerGadgetActivate()\n\ + : DrawingAreaInput() ManagerGadgetActivate()\n\ + : wxCanvasMotionEvent() DrawingAreaInput()\n\ + : wxCanvasMotionEvent() DrawingAreaInput()\n\ + : wxCanvasMotionEvent() DrawingAreaInput()\n\ + : DrawingAreaInput()"; + + XtActionsRec actions[1]; + actions[0].string = "wxCanvasMotionEvent"; + actions[0].proc = (XtActionProc) wxCanvasMotionEvent; + XtAppAddActions ((XtAppContext) wxTheApp->GetAppContext(), actions, 1); + + Widget parentWidget = (Widget) parent->GetClientWidget(); + if (style & wxBORDER) + m_borderWidget = (WXWidget) XtVaCreateManagedWidget ("canvasBorder", + xmFrameWidgetClass, parentWidget, + XmNshadowType, XmSHADOW_IN, + NULL); + + m_scrolledWindow = (WXWidget) XtVaCreateManagedWidget ("scrolledWindow", + xmScrolledWindowWidgetClass, m_borderWidget ? (Widget) m_borderWidget : parentWidget, + XmNspacing, 0, + XmNscrollingPolicy, XmAPPLICATION_DEFINED, + NULL); + + XtTranslations ptr; + m_drawingArea = (WXWidget) XtVaCreateWidget ((char*) (const char*) name, + xmDrawingAreaWidgetClass, (Widget) m_scrolledWindow, + XmNunitType, XmPIXELS, +// XmNresizePolicy, XmRESIZE_ANY, + XmNresizePolicy, XmRESIZE_NONE, + XmNmarginHeight, 0, + XmNmarginWidth, 0, + XmNtranslations, ptr = XtParseTranslationTable (translations), + NULL); + /* + if (GetWindowStyleFlag() & wxOVERRIDE_KEY_TRANSLATIONS) + { + XtFree ((char *) ptr); + ptr = XtParseTranslationTable (": DrawingAreaInput()"); + XtOverrideTranslations ((Widget) m_drawingArea, ptr); + XtFree ((char *) ptr); + } + */ + + wxAddWindowToTable((Widget) m_drawingArea, this); + wxAddWindowToTable((Widget) m_scrolledWindow, this); + + /* + * This order is very important in Motif 1.2.1 + * + */ + + XtRealizeWidget ((Widget) m_scrolledWindow); + XtRealizeWidget ((Widget) m_drawingArea); + XtManageChild ((Widget) m_drawingArea); + + XtOverrideTranslations ((Widget) m_drawingArea, + ptr = XtParseTranslationTable (": resize()")); + XtFree ((char *) ptr); + + XtAddCallback ((Widget) m_drawingArea, XmNexposeCallback, (XtCallbackProc) wxCanvasRepaintProc, (XtPointer) this); + XtAddCallback ((Widget) m_drawingArea, XmNinputCallback, (XtCallbackProc) wxCanvasInputEvent, (XtPointer) this); + + /* TODO? + display = XtDisplay (scrolledWindow); + xwindow = XtWindow (drawingArea); + */ + + XtAddEventHandler ((Widget) m_drawingArea, PointerMotionHintMask | EnterWindowMask | LeaveWindowMask | FocusChangeMask, + False, (XtEventHandler) wxCanvasEnterLeave, (XtPointer) this); return TRUE; } @@ -309,7 +506,13 @@ void wxWindow::DragAcceptFiles(bool accept) // Get total size void wxWindow::GetSize(int *x, int *y) const { - Widget widget = (Widget) GetMainWidget(); + if (m_drawingArea) + { + CanvasGetSize(x, y); + return; + } + + Widget widget = (Widget) GetTopWidget(); Dimension xx, yy; XtVaGetValues(widget, XmNwidth, &xx, XmNheight, &yy, NULL); *x = xx; *y = yy; @@ -317,7 +520,12 @@ void wxWindow::GetSize(int *x, int *y) const void wxWindow::GetPosition(int *x, int *y) const { - Widget widget = (Widget) GetMainWidget(); + if (m_drawingArea) + { + CanvasGetPosition(x, y); + return; + } + Widget widget = (Widget) GetTopWidget(); Position xx, yy; XtVaGetValues(widget, XmNx, &xx, XmNy, &yy, NULL); *x = xx; *y = yy; @@ -330,7 +538,7 @@ void wxWindow::ScreenToClient(int *x, int *y) const void wxWindow::ClientToScreen(int *x, int *y) const { - Widget widget = (Widget) GetMainWidget(); + Widget widget = (Widget) GetClientWidget(); Display *display = XtDisplay(widget); Window rootWindow = RootWindowOfScreen(XtScreen(widget)); Window thisWindow; @@ -369,7 +577,7 @@ void wxWindow::SetCursor(const wxCursor& cursor) // Get size *available for subwindows* i.e. excluding menu bar etc. void wxWindow::GetClientSize(int *x, int *y) const { - Widget widget = (Widget) GetMainWidget(); + Widget widget = (Widget) GetTopWidget(); Dimension xx, yy; XtVaGetValues(widget, XmNwidth, &xx, XmNheight, &yy, NULL); *x = xx; *y = yy; @@ -377,7 +585,18 @@ void wxWindow::GetClientSize(int *x, int *y) const void wxWindow::SetSize(int x, int y, int width, int height, int sizeFlags) { - Widget widget = (Widget) GetMainWidget(); + if (m_drawingArea) + { + CanvasSetSize(x, y, width, height, sizeFlags); + return; + } + Widget widget = (Widget) GetTopWidget(); + if (!widget) + return; + + bool managed = XtIsManaged( widget ); + if (managed) + XtUnmanageChild(widget); if (x > -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) XtVaSetValues(widget, XmNx, x, NULL); @@ -388,6 +607,9 @@ void wxWindow::SetSize(int x, int y, int width, int height, int sizeFlags) if (height > -1) XtVaSetValues(widget, XmNheight, height, NULL); + if (managed) + XtManageChild(widget); + wxSizeEvent sizeEvent(wxSize(width, height), GetId()); sizeEvent.SetEventObject(this); @@ -396,7 +618,13 @@ void wxWindow::SetSize(int x, int y, int width, int height, int sizeFlags) void wxWindow::SetClientSize(int width, int height) { - Widget widget = (Widget) GetMainWidget(); + if (m_drawingArea) + { + CanvasSetClientSize(width, height); + return; + } + + Widget widget = (Widget) GetTopWidget(); if (width > -1) XtVaSetValues(widget, XmNwidth, width, NULL); @@ -429,12 +657,37 @@ void wxWindow::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) bool wxWindow::Show(bool show) { + if (show) + { + if (m_borderWidget || m_scrolledWindow) + { + XtMapWidget(m_borderWidget ? (Widget) m_borderWidget : (Widget) m_scrolledWindow); + } + else + { + XtMapWidget((Widget) GetTopWidget()); + } + } + else + { + if (m_borderWidget || m_scrolledWindow) + { + XtUnmapWidget(m_borderWidget ? (Widget) m_borderWidget : (Widget) m_scrolledWindow); + } + else + { + XtUnmapWidget((Widget) GetTopWidget()); + } + } + + /* Window xwin = (Window) GetXWindow(); Display *xdisp = (Display*) GetXDisplay(); if (show) XMapWindow(xdisp, xwin); else XUnmapWindow(xdisp, xwin); + */ m_isShown = show; @@ -640,9 +893,9 @@ void wxWindow::Centre(int direction) } // Coordinates relative to the window -void wxWindow::WarpPointer (int x_pos, int y_pos) +void wxWindow::WarpPointer (int x, int y) { - // TODO + XWarpPointer (XtDisplay((Widget) GetClientWidget()), None, XtWindow((Widget) GetClientWidget()), 0, 0, 0, 0, x, y); } void wxWindow::OnEraseBackground(wxEraseEvent& event) @@ -836,6 +1089,17 @@ void wxWindow::MakeModal(bool modal) } } +// If nothing defined for this, try the parent. +// E.g. we may be a button loaded from a resource, with no callback function +// defined. +void wxWindow::OnCommand(wxWindow& win, wxCommandEvent& event) +{ + if (GetEventHandler()->ProcessEvent(event) ) + return; + if (m_windowParent) + m_windowParent->GetEventHandler()->OnCommand(win, event); +} + void wxWindow::SetConstraints(wxLayoutConstraints *c) { if (m_constraints) @@ -1383,15 +1647,15 @@ void wxWindow::OnIdle(wxIdleEvent& event) // Raise the window to the top of the Z order void wxWindow::Raise() { - Window window = XtWindow((Widget) GetMainWidget()); - XRaiseWindow(XtDisplay((Widget) GetMainWidget()), window); + Window window = XtWindow((Widget) GetTopWidget()); + XRaiseWindow(XtDisplay((Widget) GetTopWidget()), window); } // Lower the window to the bottom of the Z order void wxWindow::Lower() { - Window window = XtWindow((Widget) GetMainWidget()); - XLowerWindow(XtDisplay((Widget) GetMainWidget()), window); + Window window = XtWindow((Widget) GetTopWidget()); + XLowerWindow(XtDisplay((Widget) GetTopWidget()), window); } bool wxWindow::AcceptsFocus() const @@ -1482,28 +1746,921 @@ wxWindow *wxGetWindowFromTable(Widget w) void wxDeleteWindowFromTable(Widget w) { -#if DEBUG -// printf("Deleting widget %ld\n", w); -#endif -// wxWindow *win = (wxWindow *)wxWidgetHashTable->Get ((long) w); - wxWidgetHashTable->Delete((long)w); } // Get the underlying X window and display WXWindow wxWindow::GetXWindow() const { - return (WXWindow) XtWindow((Widget) GetMainWidget()); + return (WXWindow) XtWindow((Widget) GetMainWidget()); } WXDisplay *wxWindow::GetXDisplay() const { - return (WXDisplay*) XtDisplay((Widget) GetMainWidget()); + return (WXDisplay*) XtDisplay((Widget) GetMainWidget()); } WXWidget wxWindow::GetMainWidget() const { - return m_mainWidget; + if (m_drawingArea) + return m_drawingArea; + else + return m_mainWidget; +} + +WXWidget wxWindow::GetClientWidget() const +{ + if (m_drawingArea != (WXWidget) 0) + return m_drawingArea; + else + return GetMainWidget(); +} + +WXWidget wxWindow::GetTopWidget() const +{ + return GetMainWidget(); +} + +void wxCanvasRepaintProc (Widget drawingArea, XtPointer clientData, + XmDrawingAreaCallbackStruct * cbs) +{ + if (!wxWidgetHashTable->Get ((long) (Widget) drawingArea)) + return; + + XEvent * event = cbs->event; + wxWindow * canvas = (wxWindow *) clientData; + Display * display = (Display *) canvas->GetXDisplay(); + // GC gc = (GC) canvas->GetDC()->gc; + + switch (event->type) + { + case Expose: + { + /* TODO + wxCanvasDC* canvasDC = canvas->GetDC(); + if (canvasDC) + { + if (canvasDC->onpaint_reg) + XDestroyRegion(canvasDC->onpaint_reg); + canvasDC->onpaint_reg = XCreateRegion(); + + } + */ + + int n = canvas->m_updateRects.Number(); + XRectangle* xrects = new XRectangle[n]; + int i; + for (i = 0; i < canvas->m_updateRects.Number(); i++) + { + wxRect* rect = (wxRect*) canvas->m_updateRects.Nth(i)->Data(); + xrects[i].x = rect->x; + xrects[i].y = rect->y; + xrects[i].width = rect->width; + xrects[i].height = rect->height; + /* TODO (?) Actually ignore it I think. + if (canvasDC) + XUnionRectWithRegion(&(xrects[i]), canvasDC->onpaint_reg, + canvasDC->onpaint_reg); + */ + } + /* TODO must clip the area being repainted. So we need a gc. + * Alternatively, wxPaintDC must do the clipping + * when it's created. + XSetClipRectangles(display, gc, 0, 0, xrects, n, Unsorted); + */ + + canvas->DoPaint() ; // xrects, n); + delete[] xrects; + + canvas->m_updateRects.Clear(); + + /* + if (canvasDC) + { + XDestroyRegion(canvasDC->onpaint_reg); + canvasDC->onpaint_reg = NULL; + } + + XGCValues gc_val; + gc_val.clip_mask = None; + XChangeGC(display, gc, GCClipMask, &gc_val); + */ + + break; + } + default: + { + cout << "\n\nNew Event ! is = " << event -> type << "\n"; + break; + } + } +} + +// Unable to deal with Enter/Leave without a separate EventHandler (Motif 1.1.4) +void +wxCanvasEnterLeave (Widget drawingArea, XtPointer clientData, XCrossingEvent * event) +{ + XmDrawingAreaCallbackStruct cbs; + XEvent ev; + + //if (event->mode!=NotifyNormal) + // return ; + +// ev = *((XEvent *) event); // Causes Purify error (copying too many bytes) + ((XCrossingEvent &) ev) = *event; + + cbs.reason = XmCR_INPUT; + cbs.event = &ev; + + wxCanvasInputEvent (drawingArea, (XtPointer) NULL, &cbs); +} + +// Fix to make it work under Motif 1.0 (!) +void wxCanvasMotionEvent (Widget drawingArea, XButtonEvent * event) +{ +#if XmVersion<=1000 + + XmDrawingAreaCallbackStruct cbs; + XEvent ev; + + //ev.xbutton = *event; + ev = *((XEvent *) event); + cbs.reason = XmCR_INPUT; + cbs.event = &ev; + + wxCanvasInputEvent (drawingArea, (XtPointer) NULL, &cbs); +#endif +} + +void wxCanvasInputEvent (Widget drawingArea, XtPointer data, XmDrawingAreaCallbackStruct * cbs) +{ + wxWindow *canvas = (wxWindow *) wxWidgetHashTable->Get ((long) (Widget) drawingArea); + XEvent local_event; + + if (canvas==NULL) + return ; + + if (cbs->reason != XmCR_INPUT) + return; + + local_event = *(cbs->event); // We must keep a copy! + + switch (local_event.xany.type) + { + case EnterNotify: + case LeaveNotify: + case ButtonPress: + case ButtonRelease: + case MotionNotify: + { + wxEventType eventType = wxEVT_NULL; + + if (local_event.xany.type == EnterNotify) + { + //if (local_event.xcrossing.mode!=NotifyNormal) + // return ; // Ignore grab events + eventType = wxEVT_ENTER_WINDOW; +// canvas->GetEventHandler()->OnSetFocus(); + } + else if (local_event.xany.type == LeaveNotify) + { + //if (local_event.xcrossing.mode!=NotifyNormal) + // return ; // Ignore grab events + eventType = wxEVT_LEAVE_WINDOW; +// canvas->GetEventHandler()->OnKillFocus(); + } + else if (local_event.xany.type == MotionNotify) + { + eventType = wxEVT_MOTION; + if (local_event.xmotion.is_hint == NotifyHint) + { + Window root, child; + Display *dpy = XtDisplay (drawingArea); + + XQueryPointer (dpy, XtWindow (drawingArea), + &root, &child, + &local_event.xmotion.x_root, + &local_event.xmotion.y_root, + &local_event.xmotion.x, + &local_event.xmotion.y, + &local_event.xmotion.state); + } + else + { + } + } + + else if (local_event.xany.type == ButtonPress) + { + if (local_event.xbutton.button == Button1) + { + eventType = wxEVT_LEFT_DOWN; + canvas->m_button1Pressed = TRUE; + } + else if (local_event.xbutton.button == Button2) + { + eventType = wxEVT_MIDDLE_DOWN; + canvas->m_button2Pressed = TRUE; + } + else if (local_event.xbutton.button == Button3) + { + eventType = wxEVT_RIGHT_DOWN; + canvas->m_button3Pressed = TRUE; + } + } + else if (local_event.xany.type == ButtonRelease) + { + if (local_event.xbutton.button == Button1) + { + eventType = wxEVT_LEFT_UP; + canvas->m_button1Pressed = FALSE; + } + else if (local_event.xbutton.button == Button2) + { + eventType = wxEVT_MIDDLE_UP; + canvas->m_button2Pressed = FALSE; + } + else if (local_event.xbutton.button == Button3) + { + eventType = wxEVT_RIGHT_UP; + canvas->m_button3Pressed = FALSE; + } + } + + wxMouseEvent wxevent (eventType); + wxevent.m_eventHandle = (char *) &local_event; + + wxevent.m_leftDown = ((eventType == wxEVT_LEFT_DOWN) + || (event_left_is_down (&local_event) + && (eventType != wxEVT_LEFT_UP))); + wxevent.m_middleDown = ((eventType == wxEVT_MIDDLE_DOWN) + || (event_middle_is_down (&local_event) + && (eventType != wxEVT_MIDDLE_UP))); + wxevent.m_rightDown = ((eventType == wxEVT_RIGHT_DOWN) + || (event_right_is_down (&local_event) + && (eventType != wxEVT_RIGHT_UP))); + + wxevent.m_shiftDown = local_event.xbutton.state & ShiftMask; + wxevent.m_controlDown = local_event.xbutton.state & ControlMask; + wxevent.m_altDown = local_event.xbutton.state & Mod3Mask; + wxevent.m_metaDown = local_event.xbutton.state & Mod1Mask; + wxevent.SetTimestamp(local_event.xbutton.time); + + // Now check if we need to translate this event into a double click + if (TRUE) // canvas->doubleClickAllowed) + { + if (wxevent.ButtonDown()) + { + long dclickTime = XtGetMultiClickTime((Display*) wxGetDisplay()) ; + + // get button and time-stamp + int button = 0; + if (wxevent.LeftDown()) button = 1; + else if (wxevent.MiddleDown()) button = 2; + else if (wxevent.RightDown()) button = 3; + long ts = wxevent.GetTimestamp(); + // check, if single or double click + if (canvas->m_lastButton && canvas->m_lastButton==button && (ts - canvas->m_lastTS) < dclickTime) + { + // I have a dclick + canvas->m_lastButton = 0; + switch ( eventType ) + { + case wxEVT_LEFT_DOWN: + wxevent.SetEventType(wxEVT_LEFT_DCLICK); + break; + case wxEVT_MIDDLE_DOWN: + wxevent.SetEventType(wxEVT_MIDDLE_DCLICK); + break; + case wxEVT_RIGHT_DOWN: + wxevent.SetEventType(wxEVT_RIGHT_DCLICK); + break; + + default : + break; + } + + } + else + { + // not fast enough or different button + canvas->m_lastTS = ts; + canvas->m_lastButton = button; + } + } + } + + wxevent.SetId(canvas->GetId()); + wxevent.SetEventObject(canvas); + canvas->GetEventHandler()->ProcessEvent (wxevent); + /* + if (eventType == wxEVT_ENTER_WINDOW || + eventType == wxEVT_LEAVE_WINDOW || + eventType == wxEVT_MOTION + ) + return; + */ + break; + } + case KeyPress: + { + KeySym keySym; +// XComposeStatus compose; +// (void) XLookupString ((XKeyEvent *) & local_event, wxBuffer, 20, &keySym, &compose); + (void) XLookupString ((XKeyEvent *) & local_event, wxBuffer, 20, &keySym, NULL); + int id = wxCharCodeXToWX (keySym); + + wxKeyEvent event (wxEVT_CHAR); + + if (local_event.xkey.state & ShiftMask) + event.m_shiftDown = TRUE; + if (local_event.xkey.state & ControlMask) + event.m_controlDown = TRUE; + if (local_event.xkey.state & Mod3Mask) + event.m_altDown = TRUE; + if (local_event.xkey.state & Mod1Mask) + event.m_metaDown = TRUE; + event.SetEventObject(canvas); + event.m_keyCode = id; + event.SetTimestamp(local_event.xkey.time); + + if (id > -1) + { + // Implement wxFrame::OnCharHook by checking ancestor. + wxWindow *parent = canvas->GetParent(); + while (parent && !parent->IsKindOf(CLASSINFO(wxFrame))) + parent = parent->GetParent(); + + if (parent) + { + event.SetEventType(wxEVT_CHAR_HOOK); + if (parent->GetEventHandler()->ProcessEvent(event)) + return; + event.SetEventType(wxEVT_CHAR); + } + + canvas->GetEventHandler()->ProcessEvent (event); + } + break; + } + case FocusIn: + { + if (local_event.xfocus.detail != NotifyPointer) + { + wxFocusEvent event(wxEVT_SET_FOCUS, canvas->GetId()); + event.SetEventObject(canvas); + canvas->GetEventHandler()->ProcessEvent(event); + } + break; + } + case FocusOut: + { + if (local_event.xfocus.detail != NotifyPointer) + { + wxFocusEvent event(wxEVT_KILL_FOCUS, canvas->GetId()); + event.SetEventObject(canvas); + canvas->GetEventHandler()->ProcessEvent(event); + } + break; + } + default: + break; + } +} + +void wxWindow::DoPaint() +{ + //TODO : make a temporary gc so we can do the XCopyArea below + if (0) // m_backingPixmap) + { + /* + Widget drawingArea = (Widget) m_drawingArea; + // int orig = GetDC()->GetLogicalFunction(); + // GetDC()->SetLogicalFunction (wxCOPY); + + // TODO: it may not be necessary to store m_pixmapOffsetX/Y; we + // should be able to calculate them. + XCopyArea (XtDisplay (drawingArea), m_backingPixmap, XtWindow (drawingArea), GetDC ()->gc, + m_pixmapOffsetX, m_pixmapOffsetY, + m_pixmapWidth, m_pixmapHeight, + 0, 0); + + // GetDC()->SetLogicalFunction (orig); + */ + } + else + { + wxPaintEvent event(GetId()); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); + } +} + +// SetSize, but as per old wxCanvas (with drawing widget etc.) +void wxWindow::CanvasSetSize (int x, int y, int w, int h, int sizeFlags) +{ + Widget drawingArea = (Widget) m_drawingArea; + bool managed = XtIsManaged(m_borderWidget ? (Widget) m_borderWidget : (Widget) m_scrolledWindow); + + if (managed) + XtUnmanageChild (m_borderWidget ? (Widget) m_borderWidget : (Widget) m_scrolledWindow); + XtVaSetValues((Widget) m_drawingArea, XmNresizePolicy, XmRESIZE_ANY, NULL); + + if (x > -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) + { + XtVaSetValues (m_borderWidget ? (Widget) m_borderWidget : (Widget) m_scrolledWindow, + XmNx, x, NULL); + } + + if (y > -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) + { + XtVaSetValues (m_borderWidget ? (Widget) m_borderWidget : (Widget) m_scrolledWindow, + XmNy, y, NULL); + } + + if (w > -1) + { + 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); + } + + XtVaSetValues ((Widget) m_scrolledWindow, XmNwidth, w, NULL); + + Dimension spacing; + Widget sbar; + XtVaGetValues ((Widget) m_scrolledWindow, + XmNspacing, &spacing, + XmNverticalScrollBar, &sbar, + NULL); + Dimension wsbar; + if (sbar) + XtVaGetValues (sbar, XmNwidth, &wsbar, NULL); + else + wsbar = 0; + + w -= (spacing + wsbar); + + XtVaSetValues ((Widget) m_drawingArea, XmNwidth, w, NULL); + } + if (h > -1) + { + 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); + } + + XtVaSetValues ((Widget) m_scrolledWindow, XmNheight, h, NULL); + + Dimension spacing; + Widget sbar; + XtVaGetValues ((Widget) m_scrolledWindow, + XmNspacing, &spacing, + XmNhorizontalScrollBar, &sbar, + NULL); + Dimension wsbar; + if (sbar) + XtVaGetValues (sbar, XmNheight, &wsbar, NULL); + else + wsbar = 0; + + h -= (spacing + wsbar); + + XtVaSetValues ((Widget) m_drawingArea, XmNheight, h, NULL); + } + if (managed) + XtManageChild (m_borderWidget ? (Widget) m_borderWidget : (Widget) m_scrolledWindow); + XtVaSetValues((Widget) m_drawingArea, XmNresizePolicy, XmRESIZE_NONE, NULL); + + int ww, hh; + GetClientSize (&ww, &hh); + wxSizeEvent sizeEvent(wxSize(ww, hh), GetId()); + sizeEvent.SetEventObject(this); + + GetEventHandler()->ProcessEvent(sizeEvent); +} + +void wxWindow::CanvasSetClientSize (int w, int h) +{ + Widget drawingArea = (Widget) m_drawingArea; + + XtVaSetValues((Widget) m_drawingArea, XmNresizePolicy, XmRESIZE_ANY, NULL); + + if (w > -1) + XtVaSetValues ((Widget) m_drawingArea, XmNwidth, w, NULL); + if (h > -1) + XtVaSetValues ((Widget) m_drawingArea, XmNheight, h, NULL); + /* TODO: is this necessary? + allowRepainting = FALSE; + + XSync (XtDisplay (drawingArea), FALSE); + XEvent event; + while (XtAppPending (wxTheApp->appContext)) + { + XFlush (XtDisplay (drawingArea)); + XtAppNextEvent (wxTheApp->appContext, &event); + XtDispatchEvent (&event); + } + */ + + XtVaSetValues((Widget) m_drawingArea, XmNresizePolicy, XmRESIZE_NONE, NULL); + + /* TODO + allowRepainting = TRUE; + DoRefresh (); + */ + + wxSizeEvent sizeEvent(wxSize(w, h), GetId()); + sizeEvent.SetEventObject(this); + + GetEventHandler()->ProcessEvent(sizeEvent); +} + +void wxWindow::CanvasGetClientSize (int *w, int *h) const +{ + // Must return the same thing that was set via SetClientSize + Dimension xx, yy; + XtVaGetValues ((Widget) m_drawingArea, XmNwidth, &xx, XmNheight, &yy, NULL); + *w = xx; + *h = yy; +} + +void wxWindow::CanvasGetSize (int *w, int *h) const +{ + Dimension xx, yy; + if ((Widget) m_borderWidget) + XtVaGetValues ((Widget) m_borderWidget, XmNwidth, &xx, XmNheight, &yy, NULL); + else if ((Widget) m_scrolledWindow) + XtVaGetValues ((Widget) m_scrolledWindow, XmNwidth, &xx, XmNheight, &yy, NULL); + else + XtVaGetValues ((Widget) m_drawingArea, XmNwidth, &xx, XmNheight, &yy, NULL); + + *w = xx; + *h = yy; +} + +void wxWindow::CanvasGetPosition (int *x, int *y) const +{ + Position xx, yy; + XtVaGetValues (m_borderWidget ? (Widget) m_borderWidget : (Widget) m_scrolledWindow, XmNx, &xx, XmNy, &yy, NULL); + *x = xx; + *y = yy; +} + +// Add to hash table, add event handler +bool wxWindow::AttachWidget (wxWindow* parent, WXWidget mainWidget, + WXWidget formWidget, int x, int y, int width, int height) +{ + wxAddWindowToTable((Widget) mainWidget, this); + if (CanAddEventHandler()) + { + XtAddEventHandler((Widget) mainWidget, + ButtonPressMask | ButtonReleaseMask | PointerMotionMask, // | KeyPressMask, + False, + wxPanelItemEventHandler, + (XtPointer) this); + } + + if (!formWidget) + { + XtTranslations ptr; + XtOverrideTranslations ((Widget) mainWidget, + ptr = XtParseTranslationTable (": 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 (": resize()")); + XtFree ((char *) ptr); + } + + if (x == -1) + x = 0; + if (y == -1) + y = 0; + SetSize (x, y, width, height); + + return TRUE; +} + +// Remove event handler, remove from hash table +bool wxWindow::DetachWidget(WXWidget widget) +{ + if (CanAddEventHandler()) + { + XtRemoveEventHandler((Widget) widget, + ButtonPressMask | ButtonReleaseMask | PointerMotionMask, // | KeyPressMask, + False, + wxPanelItemEventHandler, + (XtPointer)this); + } + + wxDeleteWindowFromTable((Widget) widget); + return TRUE; +} + +void wxPanelItemEventHandler (Widget wid, + XtPointer client_data, + XEvent* event, + Boolean *continueToDispatch) +{ + // Widget can be a label or the actual widget. + + wxWindow *window = (wxWindow *)wxWidgetHashTable->Get((long)wid); + if (window) + { + wxMouseEvent wxevent(0); + if (wxTranslateMouseEvent(wxevent, window, wid, event)) + { + window->GetEventHandler()->ProcessEvent(wxevent); + } + } + // TODO: probably the key to allowing default behaviour + // to happen. + // Say we set a m_doDefault flag to FALSE at the start of this + // function. Then in e.g. wxWindow::OnMouseEvent we can + // call Default() which sets this flag to TRUE, indicating + // that default processing can happen. Thus, behaviour can appear + // to be overridden just by adding an event handler and not calling + // wxWindow::OnWhatever. + // ALSO, maybe we can use this instead of the current way of handling + // drawing area events, to simplify things. + *continueToDispatch = True; +} + +bool wxTranslateMouseEvent(wxMouseEvent& wxevent, wxWindow *win, Widget widget, XEvent *xevent) +{ + switch (xevent->xany.type) + { + case EnterNotify: + case LeaveNotify: + case ButtonPress: + case ButtonRelease: + case MotionNotify: + { + wxEventType eventType = wxEVT_NULL; + + if (xevent->xany.type == LeaveNotify) + { + win->m_button1Pressed = FALSE; + win->m_button2Pressed = FALSE; + win->m_button3Pressed = FALSE; + return FALSE; + } + else if (xevent->xany.type == MotionNotify) + { + eventType = wxEVT_MOTION; + } + else if (xevent->xany.type == ButtonPress) + { + if (xevent->xbutton.button == Button1) + { + eventType = wxEVT_LEFT_DOWN; + win->m_button1Pressed = TRUE; + } + else if (xevent->xbutton.button == Button2) + { + eventType = wxEVT_MIDDLE_DOWN; + win->m_button2Pressed = TRUE; + } + else if (xevent->xbutton.button == Button3) + { + eventType = wxEVT_RIGHT_DOWN; + win->m_button3Pressed = TRUE; + } + } + else if (xevent->xany.type == ButtonRelease) + { + if (xevent->xbutton.button == Button1) + { + eventType = wxEVT_LEFT_UP; + win->m_button1Pressed = FALSE; + } + else if (xevent->xbutton.button == Button2) + { + eventType = wxEVT_MIDDLE_UP; + win->m_button2Pressed = FALSE; + } + else if (xevent->xbutton.button == Button3) + { + eventType = wxEVT_RIGHT_UP; + win->m_button3Pressed = FALSE; + } + else return FALSE; + } + else return FALSE; + + wxevent.m_eventHandle = (char *)xevent; + wxevent.SetEventType(eventType); + + Position x1, y1; + XtVaGetValues(widget, XmNx, &x1, XmNy, &y1, NULL); + + int x2, y2; + win->GetPosition(&x2, &y2); + + // The button x/y must be translated to wxWindows + // window space - the widget might be a label or button, + // within a form. + int dx = 0; + int dy = 0; + if (widget != (Widget)win->GetMainWidget()) + { + dx = x1; + dy = y1; + } + + wxevent.m_x = xevent->xbutton.x + dx; + wxevent.m_y = xevent->xbutton.y + dy; + + wxevent.m_leftDown = ((eventType == wxEVT_LEFT_DOWN) + || (event_left_is_down (xevent) + && (eventType != wxEVT_LEFT_UP))); + wxevent.m_middleDown = ((eventType == wxEVT_MIDDLE_DOWN) + || (event_middle_is_down (xevent) + && (eventType != wxEVT_MIDDLE_UP))); + wxevent.m_rightDown = ((eventType == wxEVT_RIGHT_DOWN) + || (event_right_is_down (xevent) + && (eventType != wxEVT_RIGHT_UP))); + + wxevent.m_shiftDown = xevent->xbutton.state & ShiftMask; + wxevent.m_controlDown = xevent->xbutton.state & ControlMask; + return TRUE; + } + } + return FALSE; +} + +bool wxTranslateKeyEvent(wxKeyEvent& wxevent, wxWindow *win, Widget widget, XEvent *xevent) +{ + switch (xevent->xany.type) + { + case KeyPress: + { + char buf[20]; + + KeySym keySym; +// XComposeStatus compose; +// (void) XLookupString ((XKeyEvent *) xevent, buf, 20, &keySym, &compose); + (void) XLookupString ((XKeyEvent *) xevent, buf, 20, &keySym, NULL); + int id = wxCharCodeXToWX (keySym); + + if (xevent->xkey.state & ShiftMask) + wxevent.m_shiftDown = TRUE; + if (xevent->xkey.state & ControlMask) + wxevent.m_controlDown = TRUE; + if (xevent->xkey.state & Mod3Mask) + wxevent.m_altDown = TRUE; + if (xevent->xkey.state & Mod1Mask) + wxevent.m_metaDown = TRUE; + wxevent.SetEventObject(win); + wxevent.m_keyCode = id; + wxevent.SetTimestamp(xevent->xkey.time); + + wxevent.m_x = xevent->xbutton.x; + wxevent.m_y = xevent->xbutton.y; + + if (id > -1) + return TRUE; + else + return FALSE; + break; + } + default: + break; + } + return FALSE; } +// TODO From wxWin 1.68. What does it do exactly? +#define YAllocColor XAllocColor + +XColor itemColors[5]; +int wxComputeColors (Display *display, wxColour * back, wxColour * fore) +{ + int result; + static XmColorProc colorProc; + + result = wxNO_COLORS; + if (back) + { + itemColors[0].red = (((long) back->Red ()) << 8); + itemColors[0].green = (((long) back->Green ()) << 8); + itemColors[0].blue = (((long) back->Blue ()) << 8); + itemColors[0].flags = DoRed | DoGreen | DoBlue; + if (colorProc == (XmColorProc) NULL) + { + // Get a ptr to the actual function + colorProc = XmSetColorCalculation ((XmColorProc) NULL); + // And set it back to motif. + XmSetColorCalculation (colorProc); + } + (*colorProc) (&itemColors[wxBACK_INDEX], + &itemColors[wxFORE_INDEX], + &itemColors[wxSELE_INDEX], + &itemColors[wxTOPS_INDEX], + &itemColors[wxBOTS_INDEX]); + result = wxBACK_COLORS; + } + if (fore) + { + itemColors[wxFORE_INDEX].red = (((long) fore->Red ()) << 8); + itemColors[wxFORE_INDEX].green = (((long) fore->Green ()) << 8); + itemColors[wxFORE_INDEX].blue = (((long) fore->Blue ()) << 8); + itemColors[wxFORE_INDEX].flags = DoRed | DoGreen | DoBlue; + if (result == wxNO_COLORS) + result = wxFORE_COLORS; + } + + Display *dpy = display; + Colormap cmap = (Colormap) wxTheApp->GetMainColormap((WXDisplay*) dpy); + + if (back) + { + /* 5 Colours to allocate */ + for (int i = 0; i < 5; i++) + if (!YAllocColor (dpy, cmap, &itemColors[i])) + result = wxNO_COLORS; + } + else if (fore) + { + /* Only 1 colour to allocate */ + if (!YAllocColor (dpy, cmap, &itemColors[wxFORE_INDEX])) + result = wxNO_COLORS; + } + + return (result); + +} + +void wxWindow::ChangeColour(WXWidget widget) +{ + // TODO +#if 0 + int change; + + // TODO: how to determine whether we can change this item's colours? + // We used to have wxUSER_COLOURS. Now perhaps we assume we always + // can change it. + // if (!(parent->GetWindowStyleFlag() & wxUSER_COLOURS)) + // return; + + change = wxComputeColors (XtDisplay((Widget)widget), panel->GetBackgroundColour(), + panel->GetLabelColour()); + if (change == wxBACK_COLORS) + XtVaSetValues ((Widget) widget, + XmNbackground, itemColors[wxBACK_INDEX].pixel, + XmNtopShadowColor, itemColors[wxTOPS_INDEX].pixel, + XmNbottomShadowColor, itemColors[wxBOTS_INDEX].pixel, + XmNforeground, itemColors[wxFORE_INDEX].pixel, + NULL); + else if (change == wxFORE_COLORS) + XtVaSetValues (formWidget, + XmNforeground, itemColors[wxFORE_INDEX].pixel, + NULL); + + change = wxComputeColors (XtDisplay((Widget)formWidget), GetBackgroundColour(), GetLabelColour()); + if (change == wxBACK_COLORS) + XtVaSetValues (labelWidget, + XmNbackground, itemColors[wxBACK_INDEX].pixel, + XmNtopShadowColor, itemColors[wxTOPS_INDEX].pixel, + XmNbottomShadowColor, itemColors[wxBOTS_INDEX].pixel, + XmNarmColor, itemColors[wxSELE_INDEX].pixel, + XmNforeground, itemColors[wxFORE_INDEX].pixel, + NULL); + else if (change == wxFORE_COLORS) + XtVaSetValues (labelWidget, + XmNforeground, itemColors[wxFORE_INDEX].pixel, + NULL); +#endif +} + +void wxWindow::ChangeFont(WXWidget widget) +{ + /* TODO + if (widget && GetFont() && GetFont()->IsOk()) + XtVaSetValues ((Widget) widget, + XmNfontList, GetFont()->GetInternalFont (), + NULL); + */ +}