+ XtRemoveEventHandler((Widget) widget,
+ ButtonPressMask | ButtonReleaseMask | PointerMotionMask, // | KeyPressMask,
+ False,
+ wxPanelItemEventHandler,
+ (XtPointer)this);
+ }
+
+ wxDeleteWindowFromTable((Widget) widget);
+ return TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// Motif-specific accessors
+// ----------------------------------------------------------------------------
+
+// Get the underlying X window
+WXWindow wxWindow::GetXWindow() const
+{
+ Widget wMain = (Widget)GetMainWidget();
+ if ( wMain )
+ return (WXWindow) XtWindow(wMain);
+ else
+ return (WXWindow) 0;
+}
+
+// Get the underlying X display
+WXDisplay *wxWindow::GetXDisplay() const
+{
+ Widget wMain = (Widget)GetMainWidget();
+ if ( wMain )
+ return (WXDisplay*) XtDisplay(wMain);
+ else
+ return (WXDisplay*) NULL;
+}
+
+WXWidget wxWindow::GetMainWidget() const
+{
+ 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();
+}
+
+WXWidget wxWindow::GetLabelWidget() const
+{
+ return GetMainWidget();
+}
+
+// ----------------------------------------------------------------------------
+// Motif callbacks
+// ----------------------------------------------------------------------------
+
+// All widgets should have this as their resize proc.
+// OnSize sent to wxWindow via client data.
+void wxWidgetResizeProc(Widget w, XConfigureEvent *WXUNUSED(event), String WXUNUSED(args)[], int *WXUNUSED(num_args))
+{
+ wxWindow *win = wxGetWindowFromTable(w);
+ if (!win)
+ return;
+
+ if (win->PreResize())
+ {
+ int width, height;
+ win->GetSize(&width, &height);
+ wxSizeEvent sizeEvent(wxSize(width, height), win->GetId());
+ sizeEvent.SetEventObject(win);
+ win->GetEventHandler()->ProcessEvent(sizeEvent);
+ }
+}
+
+static void wxCanvasRepaintProc(Widget drawingArea,
+ XtPointer clientData,
+ XmDrawingAreaCallbackStruct * cbs)
+{
+ if (!wxGetWindowFromTable(drawingArea))
+ return;
+
+ XEvent * event = cbs->event;
+ wxWindow * win = (wxWindow *) clientData;
+
+ switch (event->type)
+ {
+ case Expose:
+ {
+ win->AddUpdateRect(event->xexpose.x, event->xexpose.y,
+ event->xexpose.width, event->xexpose.height);
+
+ if (event -> xexpose.count == 0)
+ {
+ win->DoPaint();
+ win->ClearUpdateRects();
+ }
+ break;
+ }
+ }
+}
+
+// Unable to deal with Enter/Leave without a separate EventHandler (Motif 1.1.4)
+static void wxCanvasEnterLeave(Widget drawingArea,
+ XtPointer WXUNUSED(clientData),
+ XCrossingEvent * event)
+{
+ XmDrawingAreaCallbackStruct cbs;
+ XEvent ev;
+
+ ((XCrossingEvent &) ev) = *event;
+
+ cbs.reason = XmCR_INPUT;
+ cbs.event = &ev;
+
+ wxCanvasInputEvent(drawingArea, (XtPointer) NULL, &cbs);
+}
+
+// Fix to make it work under Motif 1.0 (!)
+static void wxCanvasMotionEvent (Widget WXUNUSED(drawingArea), XButtonEvent * WXUNUSED(event))
+{
+#if XmVersion <= 1000
+ XmDrawingAreaCallbackStruct cbs;
+ XEvent ev;
+
+ ev = *((XEvent *) event);
+ cbs.reason = XmCR_INPUT;
+ cbs.event = &ev;
+
+ wxCanvasInputEvent (drawingArea, (XtPointer) NULL, &cbs);
+#endif // XmVersion <= 1000
+}
+
+static void wxCanvasInputEvent(Widget drawingArea,
+ XtPointer WXUNUSED(data),
+ XmDrawingAreaCallbackStruct * cbs)
+{
+ wxWindow *canvas = wxGetWindowFromTable(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:
+ {
+ // FIXME: most of this mouse event code is more or less
+ // duplicated in wxTranslateMouseEvent
+ //
+ 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.xcrossingr.mode!=NotifyNormal)
+ // return ; // Ignore grab events
+ eventType = wxEVT_LEAVE_WINDOW;
+ // canvas->GetEventHandler()->OnKillFocus();
+ }
+ else if (local_event.xany.type == MotionNotify)
+ {
+ eventType = wxEVT_MOTION;
+ }
+
+ else if (local_event.xany.type == ButtonPress)
+ {
+ if (local_event.xbutton.button == Button1)
+ {
+ eventType = wxEVT_LEFT_DOWN;
+ canvas->SetButton1(TRUE);
+ }
+ else if (local_event.xbutton.button == Button2)
+ {
+ eventType = wxEVT_MIDDLE_DOWN;
+ canvas->SetButton2(TRUE);
+ }
+ else if (local_event.xbutton.button == Button3)
+ {
+ eventType = wxEVT_RIGHT_DOWN;
+ canvas->SetButton3(TRUE);
+ }
+ }
+ else if (local_event.xany.type == ButtonRelease)
+ {
+ if (local_event.xbutton.button == Button1)
+ {
+ eventType = wxEVT_LEFT_UP;
+ canvas->SetButton1(FALSE);
+ }
+ else if (local_event.xbutton.button == Button2)
+ {
+ eventType = wxEVT_MIDDLE_UP;
+ canvas->SetButton2(FALSE);
+ }
+ else if (local_event.xbutton.button == Button3)
+ {
+ eventType = wxEVT_RIGHT_UP;
+ canvas->SetButton3(FALSE);
+ }
+ }
+
+ wxMouseEvent wxevent (eventType);
+
+ 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);
+
+ if ( 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
+ {
+ }
+ }
+
+ // 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
+ int buttonLast = canvas->GetLastClickedButton();
+ long lastTS = canvas->GetLastClickTime();
+ if ( buttonLast && buttonLast == button && (ts - lastTS) < dclickTime )
+ {
+ // I have a dclick
+ canvas->SetLastClick(0, ts);
+
+ wxEventType typeDouble;
+ if ( eventType == wxEVT_LEFT_DOWN )
+ typeDouble = wxEVT_LEFT_DCLICK;
+ else if ( eventType == wxEVT_MIDDLE_DOWN )
+ typeDouble = wxEVT_MIDDLE_DCLICK;
+ else if ( eventType == wxEVT_RIGHT_DOWN )
+ typeDouble = wxEVT_RIGHT_DCLICK;
+ else
+ typeDouble = wxEVT_NULL;
+
+ if ( typeDouble != wxEVT_NULL )
+ {
+ wxevent.SetEventType(typeDouble);
+ }
+ }
+ else
+ {
+ // not fast enough or different button
+ canvas->SetLastClick(button, ts);
+ }
+ }
+ }
+
+ wxevent.SetId(canvas->GetId());
+ wxevent.SetEventObject(canvas);
+ wxevent.m_x = local_event.xbutton.x;
+ wxevent.m_y = local_event.xbutton.y;
+ canvas->GetEventHandler()->ProcessEvent (wxevent);
+#if 0
+ if (eventType == wxEVT_ENTER_WINDOW ||
+ eventType == wxEVT_LEAVE_WINDOW ||
+ eventType == wxEVT_MOTION
+ )
+ return;
+#endif // 0
+ break;
+ }
+ case KeyPress:
+ {
+ KeySym keySym;
+ static char buf[100];
+#if 0
+ XComposeStatus compose;
+ (void) XLookupString ((XKeyEvent *) & local_event, buf, 20, &keySym, &compose);
+#endif // 0
+
+ (void) XLookupString ((XKeyEvent *) & local_event, buf, 20, &keySym, NULL);
+ int id = wxCharCodeXToWX (keySym);
+
+ wxEventType eventType = wxEVT_CHAR;
+
+ wxKeyEvent event (eventType);
+
+ 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;
+ }
+
+ // For simplicity, OnKeyDown is the same as OnChar
+ // TODO: filter modifier key presses from OnChar
+ event.SetEventType(wxEVT_KEY_DOWN);
+
+ // Only process OnChar if OnKeyDown didn't swallow it
+ if (!canvas->GetEventHandler()->ProcessEvent (event))
+ {
+ event.SetEventType(wxEVT_CHAR);
+ canvas->GetEventHandler()->ProcessEvent (event);
+ }
+ }
+ break;
+ }
+ case KeyRelease:
+ {
+ static char buf[100];
+ KeySym keySym;
+ (void) XLookupString ((XKeyEvent *) & local_event, buf, 20, &keySym, NULL);
+ int id = wxCharCodeXToWX (keySym);
+
+ wxKeyEvent event (wxEVT_KEY_UP);
+
+ 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)
+ {
+ 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;
+ }
+}
+
+static void wxPanelItemEventHandler(Widget wid,
+ XtPointer WXUNUSED(client_data),
+ XEvent* event,
+ Boolean *continueToDispatch)
+{
+ // Widget can be a label or the actual widget.
+
+ wxWindow *window = wxGetWindowFromTable(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;
+}
+
+static void wxScrollBarCallback(Widget scrollbar,
+ XtPointer clientData,
+ XmScrollBarCallbackStruct *cbs)
+{
+ wxWindow *win = wxGetWindowFromTable(scrollbar);
+ int orientation = (int) clientData;
+
+ wxEventType eventType = wxEVT_NULL;
+ switch (cbs->reason)
+ {
+ case XmCR_INCREMENT:
+ {
+ eventType = wxEVT_SCROLLWIN_LINEDOWN;
+ break;
+ }
+ case XmCR_DECREMENT:
+ {
+ eventType = wxEVT_SCROLLWIN_LINEUP;
+ break;
+ }
+ case XmCR_DRAG:
+ {
+ eventType = wxEVT_SCROLLWIN_THUMBTRACK;
+ break;
+ }
+ case XmCR_VALUE_CHANGED:
+ {
+ eventType = wxEVT_SCROLLWIN_THUMBRELEASE;
+ break;
+ }
+ case XmCR_PAGE_INCREMENT:
+ {
+ eventType = wxEVT_SCROLLWIN_PAGEDOWN;
+ break;
+ }
+ case XmCR_PAGE_DECREMENT:
+ {
+ eventType = wxEVT_SCROLLWIN_PAGEUP;
+ break;
+ }
+ case XmCR_TO_TOP:
+ {
+ eventType = wxEVT_SCROLLWIN_TOP;
+ break;
+ }
+ case XmCR_TO_BOTTOM:
+ {
+ eventType = wxEVT_SCROLLWIN_BOTTOM;
+ break;
+ }
+ default:
+ {
+ // Should never get here
+ wxFAIL_MSG("Unknown scroll event.");
+ break;
+ }