-// ----------------------------------------------------------------------------
-// event handlers
-// ----------------------------------------------------------------------------
-
-// Responds to colour changes: passes event on to children.
-void wxWindow::OnSysColourChanged(wxSysColourChangedEvent& event)
-{
- wxWindowList::Node *node = GetChildren().GetFirst();
- while ( node )
- {
- // Only propagate to non-top-level windows
- wxWindow *win = node->GetData();
- if ( win->GetParent() )
- {
- wxSysColourChangedEvent event2;
- event.m_eventObject = win;
- win->GetEventHandler()->ProcessEvent(event2);
- }
-
- node = node->GetNext();
- }
-}
-
-void wxWindow::OnIdle(wxIdleEvent& WXUNUSED(event))
-{
- // This calls the UI-update mechanism (querying windows for
- // menu/toolbar/control state information)
- UpdateWindowUI();
-}
-
-// ----------------------------------------------------------------------------
-// accelerators
-// ----------------------------------------------------------------------------
-
-bool wxWindow::ProcessAccelerator(wxKeyEvent& event)
-{
- 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 )
- {
- // 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);
- }
- }
- }
-
- // 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
-
- // 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 wxWindows
-// ----------------------------------------------------------------------------
-
-bool wxAddWindowToTable(Widget w, wxWindow *win)
-{
- wxWindow *oldItem = NULL;
- if ((oldItem = (wxWindow *)wxWidgetHashTable->Get ((long) w)))
- {
- wxLogDebug("Widget table clash: new widget is %ld, %s",
- (long)w, win->GetClassInfo()->GetClassName());
- return FALSE;
- }
-
- wxWidgetHashTable->Put((long) w, win);
-
- wxLogTrace("widget", "Widget 0x%08x <-> window %p (%s)",
- w, win, win->GetClassInfo()->GetClassName());
-
- return TRUE;
-}
-
-wxWindow *wxGetWindowFromTable(Widget w)
-{
- return (wxWindow *)wxWidgetHashTable->Get((long) w);
-}
-
-void wxDeleteWindowFromTable(Widget 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);
- if (CanAddEventHandler())
- {
- XtAddEventHandler((Widget) mainWidget,
- ButtonPressMask | ButtonReleaseMask | PointerMotionMask, // | KeyPressMask,
- 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;
- 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;
-}
-
-// ----------------------------------------------------------------------------
-// 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;
-#if 0
- XComposeStatus compose;
- (void) XLookupString ((XKeyEvent *) & local_event, wxBuffer, 20, &keySym, &compose);
-#endif // 0
-
- (void) XLookupString ((XKeyEvent *) & local_event, wxBuffer, 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:
- {
- KeySym keySym;
- (void) XLookupString ((XKeyEvent *) & local_event, wxBuffer, 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;
- }