]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/notebook.cpp
update GTK size hints when window decorations change
[wxWidgets.git] / src / gtk / notebook.cpp
index 2e144a6a0b72b18f9cd0d4b0ffadee663b76b58c..448d7e46384836df1ec1d85788c40daafa05af9b 100644 (file)
@@ -18,7 +18,6 @@
     #include "wx/intl.h"
     #include "wx/log.h"
     #include "wx/utils.h"
-    #include "wx/panel.h"
     #include "wx/msgdlg.h"
     #include "wx/bitmap.h"
 #endif
 #include "wx/imaglist.h"
 #include "wx/fontutil.h"
 
-// FIXME: Use GtkImage instead of GtkPixmap. Don't use gtk_container_border_width
-#include <gtk/gtkversion.h>
-#ifdef GTK_DISABLE_DEPRECATED
-#undef GTK_DISABLE_DEPRECATED
-#endif
-
 #include "wx/gtk/private.h"
-#include "wx/gtk/win_gtk.h"
 
 #include <gdk/gdkkeysyms.h>
 
@@ -88,47 +80,34 @@ WX_DEFINE_LIST(wxGtkNotebookPagesList)
 //-----------------------------------------------------------------------------
 
 extern "C" {
-static void gtk_notebook_page_change_callback(GtkNotebook *WXUNUSED(widget),
-                                              GtkNotebookPage *WXUNUSED(page),
-                                              guint page,
-                                              wxNotebook *notebook )
+static void gtk_notebook_page_changing_callback( GtkNotebook *widget,
+                                                 GtkNotebookPage *WXUNUSED(gpage),
+                                                 guint page,
+                                                 wxNotebook *notebook )
 {
-    // are you trying to call SetSelection() from a notebook event handler?
-    // you shouldn't!
-    wxCHECK_RET( !notebook->m_inSwitchPage,
-                 _T("gtk_notebook_page_change_callback reentered") );
-
-    notebook->m_inSwitchPage = true;
-    if (g_isIdle)
-        wxapp_install_idle_handler();
+    int old = gtk_notebook_get_current_page( widget );
 
-    int old = notebook->GetSelection();
-
-    wxNotebookEvent eventChanging( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING,
-                                   notebook->GetId(), page, old );
-    eventChanging.SetEventObject( notebook );
-
-    if ( (notebook->GetEventHandler()->ProcessEvent(eventChanging)) &&
-         !eventChanging.IsAllowed() )
+    if ( !notebook->SendPageChangingEvent(page) )
     {
-        /* program doesn't allow the page change */
-        g_signal_stop_emission_by_name (notebook->m_widget,
-                                        "switch_page");
+        // program doesn't allow the page change
+        g_signal_stop_emission_by_name(notebook->m_widget, "switch_page");
     }
-    else // change allowed
+    else
     {
-        // make wxNotebook::GetSelection() return the correct (i.e. consistent
-        // with wxNotebookEvent::GetSelection()) value even though the page is
-        // not really changed in GTK+
-        notebook->m_selection = page;
-
-        wxNotebookEvent eventChanged( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
-                                      notebook->GetId(), page, old );
-        eventChanged.SetEventObject( notebook );
-        notebook->GetEventHandler()->ProcessEvent( eventChanged );
+        // the page change event also reports the old page
+        notebook->m_oldSelection = old;
     }
+}
+}
 
-    notebook->m_inSwitchPage = false;
+extern "C" {
+static void gtk_notebook_page_changed_callback( GtkNotebook * WXUNUSED(widget),
+                                                GtkNotebookPage *WXUNUSED(gpage),
+                                                guint WXUNUSED(page),
+                                                wxNotebook *notebook )
+{
+    int old = notebook->m_oldSelection;
+    notebook->SendPageChangedEvent( old );
 }
 }
 
@@ -139,9 +118,6 @@ static void gtk_notebook_page_change_callback(GtkNotebook *WXUNUSED(widget),
 extern "C" {
 static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
 {
-    if (g_isIdle)
-        wxapp_install_idle_handler();
-
     if ((win->m_x == alloc->x) &&
         (win->m_y == alloc->y) &&
         (win->m_width == alloc->width) &&
@@ -151,17 +127,6 @@ static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation*
     }
 
     win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
-
-    /* GTK 1.2 up to version 1.2.5 is broken so that we have to call allocate
-       here in order to make repositioning after resizing to take effect. */
-    if ((gtk_major_version == 1) &&
-        (gtk_minor_version == 2) &&
-        (gtk_micro_version < 6) &&
-        (win->m_wxwindow) &&
-        (GTK_WIDGET_REALIZED(win->m_wxwindow)))
-    {
-        gtk_widget_size_allocate( win->m_wxwindow, alloc );
-    }
 }
 }
 
@@ -173,95 +138,17 @@ extern "C" {
 static void
 gtk_notebook_realized_callback( GtkWidget * WXUNUSED(widget), wxWindow *win )
 {
-    if (g_isIdle)
-        wxapp_install_idle_handler();
-
     /* GTK 1.2 up to version 1.2.5 is broken so that we have to call a queue_resize
        here in order to make repositioning before showing to take effect. */
     gtk_widget_queue_resize( win->m_widget );
 }
 }
 
-//-----------------------------------------------------------------------------
-// "key_press_event"
-//-----------------------------------------------------------------------------
-
-extern "C" {
-static gboolean
-gtk_notebook_key_press_callback( GtkWidget   *widget,
-                                 GdkEventKey *gdk_event,
-                                 wxNotebook  *notebook )
-{
-    if (g_isIdle)
-        wxapp_install_idle_handler();
-
-    if (!notebook->m_hasVMT) return FALSE;
-    if (g_blockEventsOnDrag) return FALSE;
-
-    /* win is a control: tab can be propagated up */
-    if ((gdk_event->keyval == GDK_Left) || (gdk_event->keyval == GDK_Right))
-    {
-        int page;
-        int nMax = notebook->GetPageCount();
-        if ( nMax-- ) // decrement it to get the last valid index
-        {
-            int nSel = notebook->GetSelection();
-
-            // change selection wrapping if it becomes invalid
-            page = (gdk_event->keyval != GDK_Left) ? nSel == nMax ? 0
-                                       : nSel + 1
-                        : nSel == 0 ? nMax
-                                    : nSel - 1;
-        }
-        else // notebook is empty, no next page
-        {
-            return FALSE;
-        }
-
-        // m_selection = page;
-        gtk_notebook_set_current_page( GTK_NOTEBOOK(widget), page );
-
-        g_signal_stop_emission_by_name (widget, "key_press_event");
-        return TRUE;
-    }
-
-    /* win is a control: tab can be propagated up */
-    if ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab))
-    {
-        int sel = notebook->GetSelection();
-        if (sel == -1)
-            return TRUE;
-        wxGtkNotebookPage *nb_page = notebook->GetNotebookPage(sel);
-        wxCHECK_MSG( nb_page, FALSE, _T("invalid selection in wxNotebook") );
-
-        wxNavigationKeyEvent event;
-        event.SetEventObject( notebook );
-        /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
-        event.SetDirection( (gdk_event->keyval == GDK_Tab) );
-        /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
-        event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) ||
-                               (gdk_event->keyval == GDK_Left) || (gdk_event->keyval == GDK_Right) );
-        event.SetCurrentFocus( notebook );
-
-        wxNotebookPage *client = notebook->GetPage(sel);
-        if ( !client->GetEventHandler()->ProcessEvent( event ) )
-        {
-             client->SetFocus();
-        }
-
-        g_signal_stop_emission_by_name (widget, "key_press_event");
-        return TRUE;
-    }
-
-    return FALSE;
-}
-}
-
 //-----------------------------------------------------------------------------
 // InsertChild callback for wxNotebook
 //-----------------------------------------------------------------------------
 
-static void wxInsertChildInNotebook( wxNotebook* parent, wxWindow* child )
+static void wxInsertChildInNotebook(wxWindow* parent, wxWindow* child)
 {
     // Hack Alert! (Part I): This sets the notebook as the parent of the child
     // widget, and takes care of some details such as updating the state and
@@ -282,19 +169,18 @@ static void wxInsertChildInNotebook( wxNotebook* parent, wxWindow* child )
 // wxNotebook
 //-----------------------------------------------------------------------------
 
-IMPLEMENT_DYNAMIC_CLASS(wxNotebook,wxControl)
+IMPLEMENT_DYNAMIC_CLASS(wxNotebook,wxBookCtrlBase)
 
-BEGIN_EVENT_TABLE(wxNotebook, wxControl)
+BEGIN_EVENT_TABLE(wxNotebook, wxBookCtrlBase)
     EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey)
 END_EVENT_TABLE()
 
 void wxNotebook::Init()
 {
     m_padding = 0;
-    m_inSwitchPage = false;
 
     m_imageList = (wxImageList *) NULL;
-    m_selection = -1;
+    m_oldSelection = -1;
     m_themeEnabled = true;
 }
 
@@ -320,9 +206,7 @@ bool wxNotebook::Create(wxWindow *parent, wxWindowID id,
                         const wxPoint& pos, const wxSize& size,
                         long style, const wxString& name )
 {
-    m_needParent = true;
-    m_acceptsFocus = true;
-    m_insertCallback = (wxInsertChildFunction)wxInsertChildInNotebook;
+    m_insertCallback = wxInsertChildInNotebook;
 
     if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT )
         style |= wxBK_TOP;
@@ -340,7 +224,10 @@ bool wxNotebook::Create(wxWindow *parent, wxWindowID id,
     gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
 
     g_signal_connect (m_widget, "switch_page",
-                      G_CALLBACK (gtk_notebook_page_change_callback), this);
+                      G_CALLBACK (gtk_notebook_page_changing_callback), this);
+
+    g_signal_connect_after (m_widget, "switch_page",
+                      G_CALLBACK (gtk_notebook_page_changed_callback), this);
 
     m_parent->DoAddChild( this );
 
@@ -351,9 +238,6 @@ bool wxNotebook::Create(wxWindow *parent, wxWindowID id,
     if (m_windowStyle & wxBK_BOTTOM)
         gtk_notebook_set_tab_pos( GTK_NOTEBOOK(m_widget), GTK_POS_BOTTOM );
 
-    g_signal_connect (m_widget, "key_press_event",
-                      G_CALLBACK (gtk_notebook_key_press_callback), this);
-
     PostCreation(size);
 
     g_signal_connect (m_widget, "realize",
@@ -366,24 +250,7 @@ int wxNotebook::GetSelection() const
 {
     wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid notebook") );
 
-    if ( m_selection == -1 )
-    {
-        GList *nb_pages = GTK_NOTEBOOK(m_widget)->children;
-
-        if (g_list_length(nb_pages) != 0)
-        {
-            GtkNotebook *notebook = GTK_NOTEBOOK(m_widget);
-
-            gpointer cur = notebook->cur_page;
-            if ( cur != NULL )
-            {
-                wxConstCast(this, wxNotebook)->m_selection =
-                    g_list_index( nb_pages, cur );
-            }
-        }
-    }
-
-    return m_selection;
+    return gtk_notebook_get_current_page( GTK_NOTEBOOK(m_widget) );
 }
 
 wxString wxNotebook::GetPageText( size_t page ) const
@@ -417,7 +284,7 @@ wxGtkNotebookPage* wxNotebook::GetNotebookPage( int page ) const
     return m_pagesData.Item(page)->GetData();
 }
 
-int wxNotebook::SetSelection( size_t page )
+int wxNotebook::DoSetSelection( size_t page, int flags )
 {
     wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid notebook") );
 
@@ -425,10 +292,26 @@ int wxNotebook::SetSelection( size_t page )
 
     int selOld = GetSelection();
 
-    // cache the selection
-    m_selection = page;
+    if ( !(flags & SetSelection_SendEvent) )
+    {
+        g_signal_handlers_block_by_func(m_widget,
+            (gpointer)gtk_notebook_page_changing_callback, this);
+
+        g_signal_handlers_block_by_func(m_widget,
+            (gpointer)gtk_notebook_page_changed_callback, this);
+    }
+
     gtk_notebook_set_current_page( GTK_NOTEBOOK(m_widget), page );
 
+    if ( !(flags & SetSelection_SendEvent) )
+    {
+        g_signal_handlers_unblock_by_func(m_widget,
+            (gpointer)gtk_notebook_page_changing_callback, this);
+
+        g_signal_handlers_unblock_by_func(m_widget,
+            (gpointer)gtk_notebook_page_changed_callback, this);
+    }
+
     wxNotebookPage *client = GetPage(page);
     if ( client )
         client->SetFocus();
@@ -483,7 +366,7 @@ bool wxNotebook::SetPageImage( size_t page, int image )
         GList *child = gtk_container_get_children(GTK_CONTAINER(nb_page->m_box));
         while (child)
         {
-            if (GTK_IS_PIXMAP(child->data))
+            if (GTK_IS_IMAGE(child->data))
             {
                 pixmapwid = GTK_WIDGET(child->data);
                 break;
@@ -509,17 +392,11 @@ bool wxNotebook::SetPageImage( size_t page, int image )
 
     /* Construct the new pixmap */
     const wxBitmap *bmp = m_imageList->GetBitmapPtr(image);
-    GdkPixmap *pixmap = bmp->GetPixmap();
-    GdkBitmap *mask = (GdkBitmap*) NULL;
-    if ( bmp->GetMask() )
-    {
-        mask = bmp->GetMask()->GetBitmap();
-    }
 
     if (pixmapwid == NULL)
     {
         /* Case 3) No old pixmap. Create a new one and prepend it to the hbox */
-        pixmapwid = gtk_pixmap_new (pixmap, mask );
+        pixmapwid = gtk_image_new_from_pixbuf(bmp->GetPixbuf());
 
         /* CHECKME: Are these pack flags okay? */
         gtk_box_pack_start(GTK_BOX(nb_page->m_box), pixmapwid, FALSE, FALSE, m_padding);
@@ -528,7 +405,7 @@ bool wxNotebook::SetPageImage( size_t page, int image )
     else
     {
         /* Case 4) Simply replace the pixmap */
-        gtk_pixmap_set(GTK_PIXMAP(pixmapwid), pixmap, mask);
+        gtk_image_set_from_pixbuf((GtkImage*)pixmapwid, bmp->GetPixbuf());
     }
 
     nb_page->m_image = image;
@@ -588,36 +465,30 @@ bool wxNotebook::DeleteAllPages()
 
 wxNotebookPage *wxNotebook::DoRemovePage( size_t page )
 {
-    if ( m_selection != -1 && (size_t)m_selection >= page )
-    {
-        // the index will become invalid after the page is deleted
-        m_selection = -1;
-    }
-
-    wxNotebookPage *client = wxNotebookBase::DoRemovePage(page);
+    // We cannot remove the page yet, as GTK sends the "switch_page"
+    // signal before it has removed the notebook-page from its
+    // corresponding list. Thus, if we were to remove the page from
+    // m_pages at this point, the two lists of pages would be out
+    // of sync during the PAGE_CHANGING/PAGE_CHANGED events.
+    wxNotebookPage *client = GetPage(page);
     if ( !client )
         return NULL;
 
     gtk_widget_ref( client->m_widget );
     gtk_widget_unrealize( client->m_widget );
-    gtk_widget_unparent( client->m_widget );
-
-    // gtk_notebook_remove_page() sends "switch_page" signal with some strange
-    // new page index (when deleting selected page 0, new page is 1 although,
-    // clearly, the selection should stay 0), so suppress this
-    g_signal_handlers_disconnect_by_func (m_widget,
-                                          (gpointer) gtk_notebook_page_change_callback,
-                                          this);
 
+    // we don't need to unparent the client->m_widget; GTK+ will do
+    // that for us (and will throw a warning if we do it!)
     gtk_notebook_remove_page( GTK_NOTEBOOK(m_widget), page );
 
-    g_signal_connect (m_widget, "switch_page",
-                      G_CALLBACK (gtk_notebook_page_change_callback), this);
+    // It's safe to remove the page now.
+    wxASSERT_MSG(GetPage(page) == client, wxT("pages changed during delete"));
+    wxNotebookBase::DoRemovePage(page);
 
     wxGtkNotebookPage* p = GetNotebookPage(page);
     m_pagesData.DeleteObject(p);
     delete p;
-
+    
     return client;
 }
 
@@ -642,11 +513,6 @@ bool wxNotebook::InsertPage( size_t position,
     // hand here.
     win->m_widget->parent = NULL;
 
-    // don't receive switch page during addition
-    g_signal_handlers_disconnect_by_func (m_widget,
-                                          (gpointer) gtk_notebook_page_change_callback,
-                                          this);
-
     if (m_themeEnabled)
         win->SetThemeEnabled(true);
 
@@ -661,43 +527,36 @@ bool wxNotebook::InsertPage( size_t position,
 
     m_pages.Insert(win, position);
 
+    // set the label image and text
+    // this must be done before adding the page, as GetPageText
+    // and GetPageImage will otherwise return wrong values in
+    // the page-changed event that results from inserting the
+    // first page.
+    nb_page->m_image = imageId;
+    nb_page->m_text = wxStripMenuCodes(text);
+
     nb_page->m_box = gtk_hbox_new( FALSE, 1 );
-    gtk_container_border_width( GTK_CONTAINER(nb_page->m_box), 2 );
+    gtk_container_set_border_width((GtkContainer*)nb_page->m_box, 2);
 
     g_signal_connect (win->m_widget, "size_allocate",
                       G_CALLBACK (gtk_page_size_callback), win);
 
-    gtk_notebook_insert_page( notebook, win->m_widget, nb_page->m_box, position );
-
-    nb_page->m_page = (GtkNotebookPage*) g_list_last(notebook->children)->data;
+    gint idx = gtk_notebook_insert_page(notebook, win->m_widget,
+                                        nb_page->m_box, position);
 
-    /* set the label image */
-    nb_page->m_image = imageId;
+    nb_page->m_page = (GtkNotebookPage *)gtk_notebook_get_nth_page(notebook, idx);
 
     if (imageId != -1)
     {
         wxASSERT( m_imageList != NULL );
 
         const wxBitmap *bmp = m_imageList->GetBitmapPtr(imageId);
-        GdkPixmap *pixmap = bmp->GetPixmap();
-        GdkBitmap *mask = (GdkBitmap*) NULL;
-        if ( bmp->GetMask() )
-        {
-            mask = bmp->GetMask()->GetBitmap();
-        }
-
-        GtkWidget *pixmapwid = gtk_pixmap_new (pixmap, mask );
-
+        GtkWidget* pixmapwid = gtk_image_new_from_pixbuf(bmp->GetPixbuf());
         gtk_box_pack_start(GTK_BOX(nb_page->m_box), pixmapwid, FALSE, FALSE, m_padding);
-
         gtk_widget_show(pixmapwid);
     }
 
     /* set the label text */
-
-    nb_page->m_text = text;
-    if (nb_page->m_text.empty()) nb_page->m_text = wxEmptyString;
-
     nb_page->m_label = GTK_LABEL( gtk_label_new(wxGTK_CONV(nb_page->m_text)) );
     gtk_box_pack_end( GTK_BOX(nb_page->m_box), GTK_WIDGET(nb_page->m_label), FALSE, FALSE, m_padding );
 
@@ -711,14 +570,12 @@ bool wxNotebook::InsertPage( size_t position,
 
     /* show the label */
     gtk_widget_show( GTK_WIDGET(nb_page->m_label) );
+
     if (select && (m_pagesData.GetCount() > 1))
     {
-      SetSelection( position );
+        SetSelection( position );
     }
 
-    g_signal_connect (m_widget, "switch_page",
-                      G_CALLBACK (gtk_notebook_page_change_callback), this);
-
     InvalidateBestSize();
     return true;
 }
@@ -766,7 +623,7 @@ int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
                 GList *children = gtk_container_get_children(GTK_CONTAINER(box));
                 for ( GList *child = children; child; child = child->next )
                 {
-                    if ( GTK_IS_PIXMAP(child->data) )
+                    if (GTK_IS_IMAGE(child->data))
                     {
                         pixmap = GTK_WIDGET(child->data);
                         break;
@@ -778,15 +635,15 @@ int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
 
                 if ( pixmap && IsPointInsideWidget(pt, pixmap, x, y) )
                 {
-                    *flags = wxNB_HITTEST_ONICON;
+                    *flags = wxBK_HITTEST_ONICON;
                 }
                 else if ( IsPointInsideWidget(pt, GTK_WIDGET(nb_page->m_label), x, y) )
                 {
-                    *flags = wxNB_HITTEST_ONLABEL;
+                    *flags = wxBK_HITTEST_ONLABEL;
                 }
                 else
                 {
-                    *flags = wxNB_HITTEST_ONITEM;
+                    *flags = wxBK_HITTEST_ONITEM;
                 }
             }
 
@@ -795,7 +652,22 @@ int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
     }
 
     if ( flags )
-        *flags = wxNB_HITTEST_NOWHERE;
+    {
+        *flags = wxBK_HITTEST_NOWHERE;
+        wxWindowBase * page = GetCurrentPage();
+        if ( page )
+        {
+            // rect origin is in notebook's parent coordinates
+            wxRect rect = page->GetRect();
+
+            // adjust it to the notebook's coordinates
+            wxPoint pos = GetPosition();
+            rect.x -= pos.x;
+            rect.y -= pos.y;
+            if ( rect.Contains( pt ) )
+                *flags |= wxBK_HITTEST_ONPAGE;
+        }
+    }
 
     return wxNOT_FOUND;
 }
@@ -832,10 +704,12 @@ void wxNotebook::DoApplyWidgetStyle(GtkRcStyle *style)
         gtk_widget_modify_style(GTK_WIDGET(GetNotebookPage(i)->m_label), style);
 }
 
-bool wxNotebook::IsOwnGtkWindow( GdkWindow *window )
+GdkWindow *wxNotebook::GTKGetWindow(wxArrayGdkWindows& windows) const
 {
-    return ((m_widget->window == window) ||
-            GTK_NOTEBOOK(m_widget)->event_window == window);
+    windows.push_back(m_widget->window);
+    windows.push_back(GTK_NOTEBOOK(m_widget)->event_window);
+
+    return NULL;
 }
 
 // static