]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/notebook.cpp
mac paths updated
[wxWidgets.git] / src / gtk / notebook.cpp
index b8dfb49c813dd01d987b9d490fb6abce11c08a5c..7ac1cb4666ff2401ec32bfa4d054b2b06b7afd16 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>
 
@@ -67,13 +59,11 @@ public:
     wxGtkNotebookPage()
     {
         m_image = -1;
-        m_page = (GtkNotebookPage *) NULL;
-        m_box = (GtkWidget *) NULL;
+        m_box = NULL;
     }
 
     wxString           m_text;
     int                m_image;
-    GtkNotebookPage   *m_page;
     GtkLabel          *m_label;
     GtkWidget         *m_box;     // in which the label and image are packed
 };
@@ -88,172 +78,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 = notebook->GetSelection();
+    int old = gtk_notebook_get_current_page( widget );
 
-    wxNotebookEvent eventChanging( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING,
-                                   notebook->GetId(), page, old );
-    eventChanging.SetEventObject( notebook );
-
-    if ( (notebook->GetEventHandler()->ProcessEvent(eventChanging)) &&
-         !eventChanging.IsAllowed() )
-    {
-        /* program doesn't allow the page change */
-        g_signal_stop_emission_by_name (notebook->m_widget,
-                                        "switch_page");
-    }
-    else // change allowed
+    if ( !notebook->SendPageChangingEvent(page) )
     {
-        // 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 );
+        // program doesn't allow the page change
+        g_signal_stop_emission_by_name( widget, "switch_page" );
     }
-
-    notebook->m_inSwitchPage = false;
-}
-}
-
-//-----------------------------------------------------------------------------
-// "size_allocate"
-//-----------------------------------------------------------------------------
-
-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) &&
-        (win->m_height == alloc->height))
-    {
-        return;
-    }
-
-    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)))
+    else
     {
-        gtk_widget_size_allocate( win->m_wxwindow, alloc );
+        // the page change event also reports the old page
+        notebook->m_oldSelection = old;
     }
 }
 }
 
-//-----------------------------------------------------------------------------
-// "realize" from m_widget
-//-----------------------------------------------------------------------------
-
-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 )
+static void gtk_notebook_page_changed_callback( GtkNotebook * WXUNUSED(widget),
+                                                GtkNotebookPage *WXUNUSED(gpage),
+                                                guint WXUNUSED(page),
+                                                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;
+    int old = notebook->m_oldSelection;
+    notebook->SendPageChangedEvent( old );
 }
 }
 
@@ -261,7 +113,7 @@ gtk_notebook_key_press_callback( GtkWidget   *widget,
 // 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 +134,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 +171,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 +189,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,14 +203,8 @@ 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",
-                      G_CALLBACK (gtk_notebook_realized_callback), this);
-
     return true;
 }
 
@@ -366,24 +212,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 +246,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 +254,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 +328,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 +354,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 +367,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 +427,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 +475,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 +489,30 @@ bool wxNotebook::InsertPage( size_t position,
 
     m_pages.Insert(win, position);
 
-    nb_page->m_box = gtk_hbox_new( FALSE, 1 );
-    gtk_container_border_width( GTK_CONTAINER(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 );
+    // 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_page = (GtkNotebookPage*) g_list_last(notebook->children)->data;
+    nb_page->m_box = gtk_hbox_new( FALSE, 1 );
+    gtk_container_set_border_width((GtkContainer*)nb_page->m_box, 2);
 
-    /* set the label image */
-    nb_page->m_image = imageId;
+    gtk_notebook_insert_page(notebook, win->m_widget, nb_page->m_box, position);
 
     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 +526,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 +579,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;
@@ -807,7 +620,7 @@ int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
             wxPoint pos = GetPosition();
             rect.x -= pos.x;
             rect.y -= pos.y;
-            if ( rect.Inside( pt ) )
+            if ( rect.Contains( pt ) )
                 *flags |= wxBK_HITTEST_ONPAGE;
         }
     }
@@ -847,10 +660,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