]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/window.cpp
Use wxFS_SEEKABLE flag loading images.
[wxWidgets.git] / src / gtk / window.cpp
index 209f7be8199b849cc28eaabd1f9389e324fbd67e..1e4523f340272f80d631e5f32598ee704218a08b 100644 (file)
@@ -680,15 +680,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;
@@ -791,16 +833,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;
 }
@@ -822,6 +869,37 @@ 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.
+    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),
@@ -849,8 +927,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.
@@ -938,21 +1018,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);
         }
     }
 
@@ -984,13 +1050,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
@@ -1018,17 +1077,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);
     }
 }
 }
@@ -3745,7 +3794,18 @@ void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
 
 void wxWindowGTK::GTKApplyToolTip( GtkTooltips *tips, const gchar *tip )
 {
-    gtk_tooltips_set_tip(tips, GetConnectWidget(), tip, NULL);
+    GtkWidget *w = GetConnectWidget();
+    gtk_tooltips_set_tip(tips, w, tip, NULL);
+
+#if GTK_CHECK_VERSION(2, 12, 0)
+    if ( !tip || tip[0] == '\0' )
+    {
+        // Just applying empty tool tip doesn't work on 2.12.0, so also use
+        // gtk_widget_set_has_tooltip.
+        if (gtk_check_version(2, 12, 0) == NULL)
+            gtk_widget_set_has_tooltip(w, FALSE);
+    }
+#endif
 }
 #endif // wxUSE_TOOLTIPS