+ }
+
+ // GDK sends surplus button down event
+ // before a double click event. We
+ // need to filter these out.
+ if (gdk_event->type == GDK_BUTTON_PRESS)
+ {
+ GdkEvent *peek_event = gdk_event_peek();
+ if (peek_event)
+ {
+ if ((peek_event->type == GDK_2BUTTON_PRESS) ||
+ (peek_event->type == GDK_3BUTTON_PRESS))
+ {
+ gdk_event_free( peek_event );
+ return TRUE;
+ }
+ else
+ {
+ gdk_event_free( peek_event );
+ }
+ }
+ }
+
+ wxEventType event_type = wxEVT_NULL;
+
+ if (gdk_event->button == 1)
+ {
+ switch (gdk_event->type)
+ {
+ case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
+ case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
+ case GDK_3BUTTON_PRESS: return FALSE;
+ default: break;
+ }
+ }
+ else if (gdk_event->button == 2)
+ {
+ switch (gdk_event->type)
+ {
+ case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
+ case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
+ default: break;
+ }
+ }
+ else if (gdk_event->button == 3)
+ {
+ switch (gdk_event->type)
+ {
+ case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
+ case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
+ default: break;
+ }
+ }
+ else if (gdk_event->button == 4)
+ {
+ switch (gdk_event->type)
+ {
+ case GDK_BUTTON_PRESS: event_type = wxEVT_MOUSEWHEEL; break;
+ default: break;
+ }
+ }
+ else if (gdk_event->button == 5)
+ {
+ switch (gdk_event->type)
+ {
+ case GDK_BUTTON_PRESS: event_type = wxEVT_MOUSEWHEEL; break;
+ default: break;
+ }
+ }
+
+ if ( event_type == wxEVT_NULL )
+ {
+ // unknown mouse button or click type
+ return FALSE;
+ }
+
+ wxMouseEvent event( event_type );
+ InitMouseEvent( win, event, gdk_event );
+
+ AdjustEventButtonState(event);
+
+ // wxListBox actually get mouse events from the item, so we need to give it
+ // a chance to correct this
+ win->FixUpMouseEvent(widget, event.m_x, event.m_y);
+
+ // find the correct window to send the event too: it may be a different one
+ // from the one which got it at GTK+ level because some control don't have
+ // their own X window and thus cannot get any events.
+ if ( !g_captureWindow )
+ win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
+
+ gs_timeLastClick = gdk_event->time;
+
+/*
+ wxPrintf( wxT("2) OnButtonPress from ") );
+ if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
+ wxPrintf( win->GetClassInfo()->GetClassName() );
+ wxPrintf( wxT(".\n") );
+*/
+
+#ifndef __WXGTK20__
+ if (event_type == wxEVT_LEFT_DCLICK)
+ {
+ // GTK 1.2 crashes when intercepting double
+ // click events from both wxSpinButton and
+ // wxSpinCtrl
+ if (GTK_IS_SPIN_BUTTON(win->m_widget))
+ {
+ // Just disable this event for now.
+ return FALSE;
+ }
+ }
+#endif
+
+ if (win->GetEventHandler()->ProcessEvent( event ))
+ {
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "button_release_event"
+//-----------------------------------------------------------------------------
+
+static gint gtk_window_button_release_callback( GtkWidget *widget,
+ GdkEventButton *gdk_event,
+ wxWindowGTK *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ if (!win->m_hasVMT) return FALSE;
+ if (g_blockEventsOnDrag) return FALSE;
+ if (g_blockEventsOnScroll) return FALSE;
+
+ if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
+
+ wxEventType event_type = wxEVT_NULL;
+
+ switch (gdk_event->button)
+ {
+ case 1:
+ event_type = wxEVT_LEFT_UP;
+ break;
+
+ case 2:
+ event_type = wxEVT_MIDDLE_UP;
+ break;
+
+ case 3:
+ event_type = wxEVT_RIGHT_UP;
+ break;
+
+ default:
+ // unknwon button, don't process
+ return FALSE;
+ }
+
+ wxMouseEvent event( event_type );
+ InitMouseEvent( win, event, gdk_event );
+
+ AdjustEventButtonState(event);
+
+ // same wxListBox hack as above
+ win->FixUpMouseEvent(widget, event.m_x, event.m_y);
+
+ if ( event_type == wxEVT_RIGHT_UP )
+ {
+ // generate a "context menu" event: this is similar to wxEVT_RIGHT_UP
+ // except that:
+ //
+ // (a) it's a command event and so is propagated to the parent
+ // (b) under MSW it can be generated from kbd too
+ // (c) it uses screen coords (because of (a))
+ wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU,
+ win->GetId(),
+ win->ClientToScreen(event.GetPosition()));
+ (void)win->GetEventHandler()->ProcessEvent(evtCtx);
+ }
+
+ if ( !g_captureWindow )
+ win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
+
+ if (win->GetEventHandler()->ProcessEvent( event ))
+ {
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "motion_notify_event"
+//-----------------------------------------------------------------------------
+
+static gint gtk_window_motion_notify_callback( GtkWidget *widget,
+ GdkEventMotion *gdk_event,
+ wxWindowGTK *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ if (!win->m_hasVMT) return FALSE;
+ if (g_blockEventsOnDrag) return FALSE;
+ if (g_blockEventsOnScroll) return FALSE;
+
+ if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
+
+ if (gdk_event->is_hint)
+ {
+ int x = 0;
+ int y = 0;
+ GdkModifierType state;
+ gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
+ gdk_event->x = x;
+ gdk_event->y = y;
+ }
+
+/*
+ printf( "OnMotion from " );
+ if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
+ printf( win->GetClassInfo()->GetClassName() );
+ printf( ".\n" );
+*/
+
+ wxMouseEvent event( wxEVT_MOTION );
+ InitMouseEvent(win, event, gdk_event);
+
+ if ( g_captureWindow )
+ {
+ // synthetize a mouse enter or leave event if needed
+ GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
+ // This seems to be necessary and actually been added to
+ // GDK itself in version 2.0.X
+ gdk_flush();
+
+ bool hasMouse = winUnderMouse == gdk_event->window;
+ if ( hasMouse != g_captureWindowHasMouse )
+ {
+ // the mouse changed window
+ g_captureWindowHasMouse = hasMouse;
+
+ wxMouseEvent event(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
+ : wxEVT_LEAVE_WINDOW);
+ InitMouseEvent(win, event, gdk_event);
+ event.SetEventObject(win);
+ win->GetEventHandler()->ProcessEvent(event);
+ }
+ }
+ else // no capture
+ {
+ win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
+ }
+
+ if (win->GetEventHandler()->ProcessEvent( event ))
+ {
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+#ifdef __WXGTK20__
+//-----------------------------------------------------------------------------
+// "mouse_wheel_event"
+//-----------------------------------------------------------------------------
+
+static gint gtk_window_wheel_callback (GtkWidget * widget,
+ GdkEventScroll * gdk_event,
+ wxWindowGTK * win)
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ wxEventType event_type = wxEVT_NULL;
+ if (gdk_event->direction == GDK_SCROLL_UP)
+ event_type = wxEVT_MOUSEWHEEL;
+ else if (gdk_event->direction == GDK_SCROLL_DOWN)
+ event_type = wxEVT_MOUSEWHEEL;
+ else
+ return FALSE;
+
+ wxMouseEvent event( event_type );
+ // Can't use InitMouse macro because scroll events don't have button
+ event.SetTimestamp( gdk_event->time );
+ event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
+ event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
+ event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
+ event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
+ event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
+ event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
+ event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
+ if (gdk_event->direction == GDK_SCROLL_UP)
+ event.m_wheelRotation = 120;
+ else
+ event.m_wheelRotation = -120;
+
+ wxPoint pt = win->GetClientAreaOrigin();
+ event.m_x = (wxCoord)gdk_event->x - pt.x;
+ event.m_y = (wxCoord)gdk_event->y - pt.y;
+
+ event.SetEventObject( win );
+ event.SetId( win->GetId() );
+ event.SetTimestamp( gdk_event->time );
+
+ if (win->GetEventHandler()->ProcessEvent( event ))
+ {
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "scroll_event" );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// "focus_in_event"
+//-----------------------------------------------------------------------------
+
+// send the wxChildFocusEvent and wxFocusEvent, common code of
+// gtk_window_focus_in_callback() and SetFocus()
+static bool DoSendFocusEvents(wxWindow *win)
+{
+ // Notify the parent keeping track of focus for the kbd navigation
+ // purposes that we got it.
+ wxChildFocusEvent eventChildFocus(win);
+ (void)win->GetEventHandler()->ProcessEvent(eventChildFocus);
+
+ wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId());
+ eventFocus.SetEventObject(win);
+
+ return win->GetEventHandler()->ProcessEvent(eventFocus);
+}
+
+static gint gtk_window_focus_in_callback( GtkWidget *widget,
+ GdkEvent *WXUNUSED(event),
+ wxWindow *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ if (!win->m_hasVMT) return FALSE;
+ if (g_blockEventsOnDrag) return FALSE;
+
+ switch ( g_sendActivateEvent )
+ {
+ case -1:
+ // we've got focus from outside, synthetize wxActivateEvent
+ g_sendActivateEvent = 1;
+ break;
+
+ case 0:
+ // another our window just lost focus, it was already ours before
+ // - don't send any wxActivateEvent
+ g_sendActivateEvent = -1;
+ break;
+ }
+
+ g_focusWindowLast =
+ g_focusWindow = win;
+
+ wxLogTrace(TRACE_FOCUS,
+ _T("%s: focus in"), win->GetName().c_str());
+
+#ifdef HAVE_XIM
+ if (win->m_ic)
+ gdk_im_begin(win->m_ic, win->m_wxwindow->window);
+#endif
+
+#if wxUSE_CARET
+ // caret needs to be informed about focus change
+ wxCaret *caret = win->GetCaret();
+ if ( caret )
+ {
+ caret->OnSetFocus();
+ }
+#endif // wxUSE_CARET
+
+ g_activeFrameLostFocus = FALSE;
+
+ wxWindowGTK *active = wxGetTopLevelParent(win);
+ if ( active != g_activeFrame )
+ {
+ if ( g_activeFrame )
+ {
+ wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame);
+ wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
+ event.SetEventObject(g_activeFrame);
+ g_activeFrame->GetEventHandler()->ProcessEvent(event);
+ }
+
+ wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active);
+ g_activeFrame = active;
+ wxActivateEvent event(wxEVT_ACTIVATE, TRUE, g_activeFrame->GetId());
+ event.SetEventObject(g_activeFrame);
+ g_activeFrame->GetEventHandler()->ProcessEvent(event);
+
+ // Don't send focus events in addition to activate
+ // if (win == g_activeFrame)
+ // return TRUE;
+ }
+
+ // does the window itself think that it has the focus?
+ if ( !win->m_hasFocus )
+ {
+ // not yet, notify it
+ win->m_hasFocus = TRUE;
+
+ if ( DoSendFocusEvents(win) )
+ {
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "focus_out_event"
+//-----------------------------------------------------------------------------
+
+static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk_event, wxWindowGTK *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ if (!win->m_hasVMT) return FALSE;
+ if (g_blockEventsOnDrag) return FALSE;
+
+ wxLogTrace( TRACE_FOCUS,
+ _T("%s: focus out"), win->GetName().c_str() );
+
+ if ( !g_activeFrameLostFocus && g_activeFrame )
+ {
+ // VZ: commenting this out because it does happen (although not easy
+ // to reproduce, I only see it when using wxMiniFrame and not
+ // always) and makes using Mahogany quite annoying
+#if 0
+ wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame,
+ wxT("unfocusing window that hasn't gained focus properly") );
+#endif // 0
+
+ g_activeFrameLostFocus = TRUE;
+ }
+
+ // if the focus goes out of our app alltogether, OnIdle() will send
+ // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
+ // g_sendActivateEvent to -1
+ g_sendActivateEvent = 0;
+
+ wxWindowGTK *winFocus = wxFindFocusedChild(win);
+ if ( winFocus )
+ win = winFocus;
+
+ g_focusWindow = (wxWindowGTK *)NULL;
+
+#ifdef HAVE_XIM
+ if (win->m_ic)
+ gdk_im_end();
+#endif
+
+#if wxUSE_CARET
+ // caret needs to be informed about focus change
+ wxCaret *caret = win->GetCaret();
+ if ( caret )
+ {
+ caret->OnKillFocus();
+ }
+#endif // wxUSE_CARET
+
+ // don't send the window a kill focus event if it thinks that it doesn't
+ // have focus already
+ if ( win->m_hasFocus )
+ {
+ win->m_hasFocus = FALSE;
+
+ wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
+ event.SetEventObject( win );
+
+ if (win->GetEventHandler()->ProcessEvent( event ))
+ {
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "enter_notify_event"
+//-----------------------------------------------------------------------------
+
+static
+gint gtk_window_enter_callback( GtkWidget *widget,
+ GdkEventCrossing *gdk_event,
+ wxWindowGTK *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ if (!win->m_hasVMT) return FALSE;
+ if (g_blockEventsOnDrag) return FALSE;
+
+ // Event was emitted after a grab
+ if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
+
+ if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
+
+ int x = 0;
+ int y = 0;
+ GdkModifierType state = (GdkModifierType)0;
+
+ gdk_window_get_pointer( widget->window, &x, &y, &state );
+
+ wxMouseEvent event( wxEVT_ENTER_WINDOW );
+ InitMouseEvent(win, event, gdk_event);
+ wxPoint pt = win->GetClientAreaOrigin();
+ event.m_x = x + pt.x;
+ event.m_y = y + pt.y;
+
+ if (win->GetEventHandler()->ProcessEvent( event ))
+ {
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "leave_notify_event"
+//-----------------------------------------------------------------------------
+
+static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ if (!win->m_hasVMT) return FALSE;
+ if (g_blockEventsOnDrag) return FALSE;
+
+ // Event was emitted after an ungrab
+ if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
+
+ if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
+
+ wxMouseEvent event( wxEVT_LEAVE_WINDOW );
+ event.SetTimestamp( gdk_event->time );
+ event.SetEventObject( win );
+
+ int x = 0;
+ int y = 0;
+ GdkModifierType state = (GdkModifierType)0;
+
+ gdk_window_get_pointer( widget->window, &x, &y, &state );
+
+ event.m_shiftDown = (state & GDK_SHIFT_MASK) != 0;
+ event.m_controlDown = (state & GDK_CONTROL_MASK) != 0;
+ event.m_altDown = (state & GDK_MOD1_MASK) != 0;
+ event.m_metaDown = (state & GDK_MOD2_MASK) != 0;
+ event.m_leftDown = (state & GDK_BUTTON1_MASK) != 0;
+ event.m_middleDown = (state & GDK_BUTTON2_MASK) != 0;
+ event.m_rightDown = (state & GDK_BUTTON3_MASK) != 0;