X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c2246a3881e5c3293b70560dde099ee772c86d73..e8fd252ef87d8ff6409d405218ff02c91b980e0a:/src/gtk/window.cpp?ds=sidebyside diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index a8b4ad1e46..0c05229765 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -37,9 +37,14 @@ #include "wx/gtk/private.h" #include "wx/gtk/private/win_gtk.h" -#include + #include +#include +#if GTK_CHECK_VERSION(3,0,0) +#include +#endif + #if !GTK_CHECK_VERSION(2,10,0) // GTK+ can reliably detect Meta key state only since 2.10 when // GDK_META_MASK was introduced -- there wasn't any way to detect it @@ -305,6 +310,9 @@ expose_event_border(GtkWidget* widget, GdkEventExpose* gdk_event, wxWindow* win) if (gdk_event->window != gtk_widget_get_parent_window(win->m_wxwindow)) return false; + if (!win->IsShown()) + return false; + const GtkAllocation& alloc = win->m_wxwindow->allocation; const int x = alloc.x; const int y = alloc.y; @@ -677,15 +685,57 @@ static void wxFillOtherKeyEventFields(wxKeyEvent& event, event.SetTimestamp( gdk_event->time ); event.SetId(win->GetId()); + event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0; event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0; event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0; event.m_metaDown = (gdk_event->state & GDK_META_MASK) != 0; + + // Normally we take the state of modifiers directly from the low level GDK + // event but unfortunately GDK uses a different convention from MSW for the + // key events corresponding to the modifier keys themselves: in it, when + // e.g. Shift key is pressed, GDK_SHIFT_MASK is not set while it is set + // when Shift is released. Under MSW the situation is exactly reversed and + // the modifier corresponding to the key is set when it is pressed and + // unset when it is released. To ensure consistent behaviour between + // platforms (and because it seems to make slightly more sense, although + // arguably both behaviours are reasonable) we follow MSW here. + // + // Final notice: we set the flags to the desired value instead of just + // inverting them because they are not set correctly (i.e. in the same way + // as for the real events generated by the user) for wxUIActionSimulator- + // produced events and it seems better to keep that class code the same + // among all platforms and fix the discrepancy here instead of adding + // wxGTK-specific code to wxUIActionSimulator. + const bool isPress = gdk_event->type == GDK_KEY_PRESS; + switch ( gdk_event->keyval ) + { + case GDK_Shift_L: + case GDK_Shift_R: + event.m_shiftDown = isPress; + break; + + case GDK_Control_L: + case GDK_Control_R: + event.m_controlDown = isPress; + break; + + case GDK_Alt_L: + case GDK_Alt_R: + event.m_altDown = isPress; + break; + + case GDK_Meta_L: + case GDK_Meta_R: + case GDK_Super_L: + case GDK_Super_R: + event.m_metaDown = isPress; + break; + } + event.m_rawCode = (wxUint32) gdk_event->keyval; - event.m_rawFlags = 0; -#if wxUSE_UNICODE - event.m_uniChar = gdk_keyval_to_unicode(gdk_event->keyval); -#endif + event.m_rawFlags = gdk_event->hardware_keycode; + wxGetMousePosition( &x, &y ); win->ScreenToClient( &x, &y ); event.m_x = x; @@ -788,16 +838,21 @@ wxTranslateGTKKeyEventToWx(wxKeyEvent& event, if ( !key_code ) return false; - // now fill all the other fields - wxFillOtherKeyEventFields(event, win, gdk_event); - event.m_keyCode = key_code; + #if wxUSE_UNICODE - if ( gdk_event->type == GDK_KEY_PRESS || gdk_event->type == GDK_KEY_RELEASE ) + event.m_uniChar = gdk_keyval_to_unicode(key_code ? key_code : keysym); + if ( !event.m_uniChar && event.m_keyCode <= WXK_DELETE ) { - event.m_uniChar = key_code; + // Set Unicode key code to the ASCII equivalent for compatibility. E.g. + // let RETURN generate the key event with both key and Unicode key + // codes of 13. + event.m_uniChar = event.m_keyCode; } -#endif +#endif // wxUSE_UNICODE + + // now fill all the other fields + wxFillOtherKeyEventFields(event, win, gdk_event); return true; } @@ -819,6 +874,41 @@ struct wxGtkIMData } }; +namespace +{ + +// Send wxEVT_CHAR_HOOK event to the parent of the window and if it wasn't +// processed, send wxEVT_CHAR to the window itself. Return true if either of +// them was handled. +bool +SendCharHookAndCharEvents(const wxKeyEvent& event, wxWindow *win) +{ + // wxEVT_CHAR_HOOK must be sent to the top level parent window to allow it + // to handle key events in all of its children unless the mouse is captured + // in which case we consider that the keyboard should be "captured" too. + if ( !g_captureWindow ) + { + wxWindow * const parent = wxGetTopLevelParent(win); + if ( parent ) + { + // We need to make a copy of the event object because it is + // modified while it's handled, notably its WasProcessed() flag + // is set after it had been processed once. + wxKeyEvent eventCharHook(event); + eventCharHook.SetEventType(wxEVT_CHAR_HOOK); + if ( parent->HandleWindowEvent(eventCharHook) ) + return true; + } + } + + // As above, make a copy of the event first. + wxKeyEvent eventChar(event); + eventChar.SetEventType(wxEVT_CHAR); + return win->HandleWindowEvent(eventChar); +} + +} // anonymous namespace + extern "C" { static gboolean gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget), @@ -846,8 +936,10 @@ gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget), return_after_IM = true; } - if ((!ret) && (win->m_imData != NULL)) + if (!ret && win->m_imData) { + win->m_imData->lastKeyEvent = gdk_event; + // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API // docs, if IM filter returns true, no further processing should be done. // we should send the key_down event anyway. @@ -935,21 +1027,7 @@ gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget), #endif } - // Implement OnCharHook by checking ancestor top level windows - wxWindow *parent = win; - while (parent && !parent->IsTopLevel()) - parent = parent->GetParent(); - if (parent) - { - event.SetEventType( wxEVT_CHAR_HOOK ); - ret = parent->HandleWindowEvent( event ); - } - - if (!ret) - { - event.SetEventType(wxEVT_CHAR); - ret = win->HandleWindowEvent( event ); - } + ret = SendCharHookAndCharEvents(event, win); } } @@ -981,13 +1059,6 @@ gtk_wxwindow_commit_cb (GtkIMContext * WXUNUSED(context), if( data.empty() ) return; - bool ret = false; - - // Implement OnCharHook by checking ancestor top level windows - wxWindow *parent = window; - while (parent && !parent->IsTopLevel()) - parent = parent->GetParent(); - for( wxString::const_iterator pstr = data.begin(); pstr != data.end(); ++pstr ) { #if wxUSE_UNICODE @@ -1015,17 +1086,7 @@ gtk_wxwindow_commit_cb (GtkIMContext * WXUNUSED(context), #endif } - if (parent) - { - event.SetEventType( wxEVT_CHAR_HOOK ); - ret = parent->HandleWindowEvent( event ); - } - - if (!ret) - { - event.SetEventType(wxEVT_CHAR); - ret = window->HandleWindowEvent( event ); - } + SendCharHookAndCharEvents(event, window); } } } @@ -1845,6 +1906,8 @@ gtk_window_realized_callback(GtkWidget* widget, wxWindow* win) wxWindowCreateEvent event( win ); event.SetEventObject( win ); win->GTKProcessEvent( event ); + + win->GTKUpdateCursor(true, false); } //----------------------------------------------------------------------------- @@ -1994,9 +2057,7 @@ wxMouseState wxGetMouseState() // method #ifdef __WXUNIVERSAL__ IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase) -#else // __WXGTK__ - IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase) -#endif // __WXUNIVERSAL__/__WXGTK__ +#endif // __WXUNIVERSAL__ void wxWindowGTK::Init() { @@ -2563,8 +2624,7 @@ void wxWindowGTK::OnInternalIdle() m_needsStyleChange = false; } - if (wxUpdateUIEvent::CanUpdate(this) && IsShownOnScreen()) - UpdateWindowUI(wxUPDATE_UI_FROMIDLE); + wxWindowBase::OnInternalIdle(); } void wxWindowGTK::DoGetSize( int *width, int *height ) const @@ -2638,10 +2698,9 @@ void wxWindowGTK::DoGetClientSize( int *width, int *height ) const } } - int border_x, border_y; - WX_PIZZA(m_wxwindow)->get_border_widths(border_x, border_y); - w -= 2 * border_x; - h -= 2 * border_y; + const wxSize sizeBorders = DoGetBorderSize(); + w -= sizeBorders.x; + h -= sizeBorders.y; if (w < 0) w = 0; @@ -2653,6 +2712,17 @@ void wxWindowGTK::DoGetClientSize( int *width, int *height ) const if (height) *height = h; } +wxSize wxWindowGTK::DoGetBorderSize() const +{ + if ( !m_wxwindow ) + return wxWindowBase::DoGetBorderSize(); + + int x, y; + WX_PIZZA(m_wxwindow)->get_border_widths(x, y); + + return 2*wxSize(x, y); +} + void wxWindowGTK::DoGetPosition( int *x, int *y ) const { wxCHECK_RET( (m_widget != NULL), wxT("invalid window") ); @@ -3402,37 +3472,22 @@ void wxWindowGTK::GTKUpdateCursor(bool update_self /*=true*/, bool recurse /*=tr wxCursor cursor(g_globalCursor.Ok() ? g_globalCursor : GetCursor()); if ( cursor.Ok() ) { - if (m_wxwindow && (m_wxwindow != m_widget)) + wxArrayGdkWindows windowsThis; + GdkWindow* window = GTKGetWindow(windowsThis); + if (window) + gdk_window_set_cursor( window, cursor.GetCursor() ); + else { - wxArrayGdkWindows windowsThis; - GdkWindow* window = GTKGetDrawingWindow(); - if (window) - gdk_window_set_cursor( window, cursor.GetCursor() ); - else + const size_t count = windowsThis.size(); + for ( size_t n = 0; n < count; n++ ) { - const size_t count = windowsThis.size(); - for ( size_t n = 0; n < count; n++ ) + GdkWindow *win = windowsThis[n]; + // It can be zero if the window has not been realized yet. + if ( win ) { - GdkWindow *win = windowsThis[n]; - if ( !win ) - { - wxFAIL_MSG(wxT("NULL window returned by GTKGetWindow()?")); - continue; - } gdk_window_set_cursor(win, cursor.GetCursor()); } } - - window = m_widget->window; - if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget))) - gdk_window_set_cursor( window, cursor.GetCursor() ); - - } - else if ( m_widget ) - { - GdkWindow *window = m_widget->window; - if ( window && !GTK_WIDGET_NO_WINDOW(m_widget) ) - gdk_window_set_cursor( window, cursor.GetCursor() ); } } } @@ -3733,19 +3788,23 @@ void wxWindowGTK::DoSetToolTip( wxToolTip *tip ) { GtkWidget *w = GetConnectWidget(); wxToolTip::GTKApply(w, NULL); -#if GTK_CHECK_VERSION(2, 12, 0) - // Just applying NULL doesn't work on 2.12.0, so also use - // gtk_widget_set_has_tooltip. It is part of the new GtkTooltip API - // but seems also to work with the old GtkTooltips. - if (gtk_check_version(2, 12, 0) == NULL) - gtk_widget_set_has_tooltip(w, FALSE); -#endif } } void wxWindowGTK::GTKApplyToolTip( GtkTooltips *tips, const gchar *tip ) { - gtk_tooltips_set_tip(tips, GetConnectWidget(), tip, NULL); + GtkWidget *w = GetConnectWidget(); + +#if GTK_CHECK_VERSION(2, 12, 0) + if (!gtk_check_version(2, 12, 0)) + { + gtk_widget_set_tooltip_text (w, tip); + } + else +#endif + { + gtk_tooltips_set_tip(tips, w, tip, NULL); + } } #endif // wxUSE_TOOLTIPS @@ -4388,7 +4447,7 @@ GdkWindow* wxWindowGTK::GTKGetDrawingWindow() const { GdkWindow* window = NULL; if (m_wxwindow) - window = WX_PIZZA(m_wxwindow)->m_draw_window; + window = m_wxwindow->window; return window; }