]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/window.cpp
Support renderer::LeftClick() in generic code, removed unsupported RightClick(),...
[wxWidgets.git] / src / gtk / window.cpp
index b65a255afc355aa00e68e85888d7e86ef4dac8aa..5b92e382246a559dc4b781e48f14d36c7fc51a61 100644 (file)
@@ -185,9 +185,11 @@ extern wxCursor   g_globalCursor;
 static wxWindowGTK  *g_captureWindow = (wxWindowGTK*) NULL;
 static bool g_captureWindowHasMouse = false;
 
-// The window that currently has focus or is scheduled to get it in the next
-// event loop iteration
-static wxWindowGTK *gs_focusWindow = NULL;
+// The window that currently has focus:
+static wxWindowGTK *gs_currentFocus = NULL;
+// The window that is scheduled to get focus in the next event loop iteration
+// or NULL if there's no pending focus change:
+static wxWindowGTK *gs_pendingFocus = NULL;
 
 // the window that has deferred focus-out event pending, if any (see
 // GTKAddDeferredFocusOut() for details)
@@ -869,8 +871,18 @@ gtk_window_key_press_callback( GtkWidget *widget,
             int command = ancestor->GetAcceleratorTable()->GetCommand( event );
             if (command != -1)
             {
-                wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
-                ret = ancestor->HandleWindowEvent( command_event );
+                wxCommandEvent menu_event( wxEVT_COMMAND_MENU_SELECTED, command );
+                ret = ancestor->HandleWindowEvent( menu_event );
+
+                if ( !ret )
+                {
+                    // if the accelerator wasn't handled as menu event, try
+                    // it as button click (for compatibility with other
+                    // platforms):
+                    wxCommandEvent button_event( wxEVT_COMMAND_BUTTON_CLICKED, command );
+                    ret = ancestor->HandleWindowEvent( button_event );
+                }
+
                 break;
             }
             if (ancestor->IsTopLevel())
@@ -1372,7 +1384,7 @@ gtk_window_button_press_callback( GtkWidget *widget,
         return TRUE;
 
     if ((event_type == wxEVT_LEFT_DOWN) && !win->IsOfStandardClass() &&
-        (gs_focusWindow != win) /* && win->IsFocusable() */)
+        (gs_currentFocus != win) /* && win->IsFocusable() */)
     {
         win->SetFocus();
     }
@@ -1891,8 +1903,9 @@ public:
 
 wxWindow *wxWindowBase::DoFindFocus()
 {
+    wxWindowGTK *focus = gs_pendingFocus ? gs_pendingFocus : gs_currentFocus;
     // the cast is necessary when we compile in wxUniversal mode
-    return wx_static_cast(wxWindow*, gs_focusWindow);
+    return wx_static_cast(wxWindow*, focus);
 }
 
 //-----------------------------------------------------------------------------
@@ -2127,6 +2140,8 @@ bool wxWindowGTK::Create( wxWindow *parent,
 
     m_focusWidget = m_wxwindow;
 
+    SetCanFocus(AcceptsFocus());
+
     PostCreation();
 
     return true;
@@ -2136,8 +2151,10 @@ wxWindowGTK::~wxWindowGTK()
 {
     SendDestroyEvent();
 
-    if (gs_focusWindow == this)
-        gs_focusWindow = NULL;
+    if (gs_currentFocus == this)
+        gs_currentFocus = NULL;
+    if (gs_pendingFocus == this)
+        gs_pendingFocus = NULL;
 
     if ( gs_deferredFocusOut == this )
         gs_deferredFocusOut = NULL;
@@ -2907,9 +2924,8 @@ bool wxWindowGTK::GTKHandleFocusIn()
     if (m_imData)
         gtk_im_context_focus_in(m_imData->context);
 
-    // NB: SetFocus() does this assignment too, but not all focus changes
-    //     originate from SetFocus() call
-    gs_focusWindow = this;
+    gs_currentFocus = this;
+    gs_pendingFocus = NULL;
 
 #if wxUSE_CARET
     // caret needs to be informed about focus change
@@ -2971,22 +2987,22 @@ void wxWindowGTK::GTKHandleFocusOutNoDeferring()
     if (m_imData)
         gtk_im_context_focus_out(m_imData->context);
 
-    if ( gs_focusWindow != this )
+    if ( gs_currentFocus != this )
     {
-        // Something is terribly wrong, gs_focusWindow is out of sync with the
+        // Something is terribly wrong, gs_currentFocus is out of sync with the
         // real focus. We will reset it to NULL anyway, because after this
         // focus-out event is handled, one of the following with happen:
         //
         // * either focus will go out of the app altogether, in which case
-        //   gs_focusWindow _should_ be NULL
+        //   gs_currentFocus _should_ be NULL
         //
         // * or it goes to another control, in which case focus-in event will
-        //   follow immediately and it will set gs_focusWindow to the right
+        //   follow immediately and it will set gs_currentFocus to the right
         //   value
         wxLogDebug("window %s(%p, %s) lost focus even though it didn't have it",
                    GetClassInfo()->GetClassName(), this, GetLabel());
     }
-    gs_focusWindow = NULL;
+    gs_currentFocus = NULL;
 
 #if wxUSE_CARET
     // caret needs to be informed about focus change
@@ -3037,7 +3053,7 @@ void wxWindowGTK::SetFocus()
     // Because we want to FindFocus() call immediately following
     // foo->SetFocus() to return foo, we have to keep track of "pending" focus
     // ourselves.
-    gs_focusWindow = this;
+    gs_pendingFocus = this;
 
     GtkWidget *widget = m_wxwindow ? m_wxwindow : m_focusWidget;
 
@@ -3827,6 +3843,103 @@ bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
     return true;
 }
 
+// ----------------------------------------------------------------------------
+// Pop-up menu stuff
+// ----------------------------------------------------------------------------
+
+#if wxUSE_MENUS_NATIVE
+
+static void SetInvokingWindow( wxMenu *menu, wxWindow* win )
+{
+    menu->SetInvokingWindow( win );
+
+    wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
+    while (node)
+    {
+        wxMenuItem *menuitem = node->GetData();
+        if (menuitem->IsSubMenu())
+        {
+            SetInvokingWindow( menuitem->GetSubMenu(), win );
+        }
+
+        node = node->GetNext();
+    }
+}
+
+extern "C" {
+static
+void wxPopupMenuPositionCallback( GtkMenu *menu,
+                                  gint *x, gint *y,
+                                  gboolean * WXUNUSED(whatever),
+                                  gpointer user_data )
+{
+    // ensure that the menu appears entirely on screen
+    GtkRequisition req;
+    gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
+
+    wxSize sizeScreen = wxGetDisplaySize();
+    wxPoint *pos = (wxPoint*)user_data;
+
+    gint xmax = sizeScreen.x - req.width,
+         ymax = sizeScreen.y - req.height;
+
+    *x = pos->x < xmax ? pos->x : xmax;
+    *y = pos->y < ymax ? pos->y : ymax;
+}
+}
+
+void wxWindowGTK::DoPopupMenuUpdateUI(wxMenu* menu)
+{
+    menu->UpdateUI();
+}
+
+bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
+{
+    wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
+
+    wxCHECK_MSG( menu != NULL, false, wxT("invalid popup-menu") );
+
+    SetInvokingWindow( menu, this );
+
+    DoPopupMenuUpdateUI(menu);
+
+    wxPoint pos;
+    gpointer userdata;
+    GtkMenuPositionFunc posfunc;
+    if ( x == -1 && y == -1 )
+    {
+        // use GTK's default positioning algorithm
+        userdata = NULL;
+        posfunc = NULL;
+    }
+    else
+    {
+        pos = ClientToScreen(wxPoint(x, y));
+        userdata = &pos;
+        posfunc = wxPopupMenuPositionCallback;
+    }
+
+    menu->m_popupShown = true;
+    gtk_menu_popup(
+                  GTK_MENU(menu->m_menu),
+                  (GtkWidget *) NULL,           // parent menu shell
+                  (GtkWidget *) NULL,           // parent menu item
+                  posfunc,                      // function to position it
+                  userdata,                     // client data
+                  0,                            // button used to activate it
+                  gtk_get_current_event_time()
+                );
+
+    while (menu->m_popupShown)
+    {
+        gtk_main_iteration();
+    }
+
+    return true;
+}
+
+#endif // wxUSE_MENUS_NATIVE
+
 #if wxUSE_DRAG_AND_DROP
 
 void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
@@ -4200,16 +4313,68 @@ GdkWindow* wxWindowGTK::GTKGetDrawingWindow() const
 // freeze/thaw
 // ----------------------------------------------------------------------------
 
+extern "C"
+{
+
+// this is called if we attempted to freeze unrealized widget when it finally
+// is realized (and so can be frozen):
+static void wx_frozen_widget_realize(GtkWidget* w, void* WXUNUSED(data))
+{
+    wxASSERT( w && !GTK_WIDGET_NO_WINDOW(w) );
+    wxASSERT( GTK_WIDGET_REALIZED(w) );
+
+    g_signal_handlers_disconnect_by_func
+    (
+        w,
+        (void*)wx_frozen_widget_realize,
+        NULL
+    );
+
+    gdk_window_freeze_updates(w->window);
+}
+
+} // extern "C"
+
 void wxWindowGTK::GTKFreezeWidget(GtkWidget *w)
 {
-    if ( w && !GTK_WIDGET_NO_WINDOW(w) )
-        gdk_window_freeze_updates(w->window);
+    if ( !w || GTK_WIDGET_NO_WINDOW(w) )
+        return; // window-less widget, cannot be frozen
+
+    if ( !GTK_WIDGET_REALIZED(w) )
+    {
+        // we can't thaw unrealized widgets because they don't have GdkWindow,
+        // so set it up to be done immediately after realization:
+        g_signal_connect_after
+        (
+            w,
+            "realize",
+            G_CALLBACK(wx_frozen_widget_realize),
+            NULL
+        );
+        return;
+    }
+
+    gdk_window_freeze_updates(w->window);
 }
 
 void wxWindowGTK::GTKThawWidget(GtkWidget *w)
 {
-    if ( w && !GTK_WIDGET_NO_WINDOW(w) )
-        gdk_window_thaw_updates(w->window);
+    if ( !w || GTK_WIDGET_NO_WINDOW(w) )
+        return; // window-less widget, cannot be frozen
+
+    if ( !GTK_WIDGET_REALIZED(w) )
+    {
+        // the widget wasn't realized yet, no need to thaw
+        g_signal_handlers_disconnect_by_func
+        (
+            w,
+            (void*)wx_frozen_widget_realize,
+            NULL
+        );
+        return;
+    }
+
+    gdk_window_thaw_updates(w->window);
 }
 
 void wxWindowGTK::DoFreeze()