]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/mdi.cpp
refactor wxDocChildFrame and wxDocMDIChildFrame to use wxDocChildFrameAny intead...
[wxWidgets.git] / src / gtk / mdi.cpp
index 99bcb7ede4992aa0ac66b3e30fea4a7c49a5b9fc..9511b2e22ddba44abddbaf1d8559db0188412a83 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        mdi.cpp
+// Name:        src/gtk/mdi.cpp
 // Purpose:
 // Author:      Robert Roebling
 // Id:          $Id$
@@ -7,91 +7,72 @@
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
-#ifdef __GNUG__
-#pragma implementation "mdi.h"
-#endif
-
-#include "wx/mdi.h"
-
-#if wxUSE_MDI_ARCHITECTURE
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
 
-#include "wx/dialog.h"
-#include "wx/menu.h"
-#include "wx/intl.h"
-
-#include <glib.h>
-#include <gdk/gdk.h>
-#include <gtk/gtk.h>
-#include "wx/gtk/win_gtk.h"
-
-//-----------------------------------------------------------------------------
-// constants
-//-----------------------------------------------------------------------------
+#if wxUSE_MDI
 
-const int wxMENU_HEIGHT = 27;
-
-//-----------------------------------------------------------------------------
-// idle system
-//-----------------------------------------------------------------------------
-
-extern void wxapp_install_idle_handler();
-extern bool g_isIdle;
+#include "wx/mdi.h"
 
-//-----------------------------------------------------------------------------
-// globals
-//-----------------------------------------------------------------------------
+#ifndef WX_PRECOMP
+    #include "wx/intl.h"
+    #include "wx/menu.h"
+#endif
 
-extern wxList wxPendingDelete;
+#include "wx/gtk/private.h"
 
 //-----------------------------------------------------------------------------
 // "switch_page"
 //-----------------------------------------------------------------------------
 
+extern "C" {
 static void
 gtk_mdi_page_change_callback( GtkNotebook *WXUNUSED(widget),
                               GtkNotebookPage *page,
                               gint WXUNUSED(page_num),
                               wxMDIParentFrame *parent )
 {
-    if (g_isIdle)
-        wxapp_install_idle_handler();
-
     // send deactivate event to old child
 
     wxMDIChildFrame *child = parent->GetActiveChild();
     if (child)
     {
-        wxActivateEvent event1( wxEVT_ACTIVATE, FALSE, child->GetId() );
+        wxActivateEvent event1( wxEVT_ACTIVATE, false, child->GetId() );
         event1.SetEventObject( child);
-        child->GetEventHandler()->ProcessEvent( event1 );
+        child->HandleWindowEvent( event1 );
     }
 
     // send activate event to new child
 
-    wxMDIClientWindow *client_window = parent->GetClientWindow();
-    if (!client_window)
+    wxMDIClientWindowBase *client_window = parent->GetClientWindow();
+    if ( !client_window )
         return;
 
-    child = (wxMDIChildFrame*) NULL;
+    child = NULL;
 
-    wxNode *node = client_window->GetChildren().First();
-    while (node)
+    wxWindowList::compatibility_iterator node = client_window->GetChildren().GetFirst();
+    while ( node )
     {
-        wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
-        if (child_frame->m_page == page)
+        wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
+
+        // child_frame can be NULL when this is called from dtor, probably
+        // because g_signal_connect (m_widget, "switch_page", (see below)
+        // isn't deleted early enough
+        if ( child_frame && child_frame->m_page == page )
         {
             child = child_frame;
             break;
         }
-        node = node->Next();
+        node = node->GetNext();
     }
 
     if (!child)
          return;
 
-    wxActivateEvent event2( wxEVT_ACTIVATE, TRUE, child->GetId() );
+    wxActivateEvent event2( wxEVT_ACTIVATE, true, child->GetId() );
     event2.SetEventObject( child);
-    child->GetEventHandler()->ProcessEvent( event2 );
+    child->HandleWindowEvent( event2 );
+}
 }
 
 //-----------------------------------------------------------------------------
@@ -102,12 +83,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
 
 void wxMDIParentFrame::Init()
 {
-    m_justInserted = FALSE;
-    m_clientWindow = (wxMDIClientWindow *) NULL;
-}
-
-wxMDIParentFrame::~wxMDIParentFrame()
-{
+    m_justInserted = false;
 }
 
 bool wxMDIParentFrame::Create(wxWindow *parent,
@@ -118,36 +94,19 @@ bool wxMDIParentFrame::Create(wxWindow *parent,
                               long style,
                               const wxString& name )
 {
-    wxFrame::Create( parent, id, title, pos, size, style, name );
+    if ( !wxFrame::Create( parent, id, title, pos, size, style, name ) )
+        return false;
 
-    OnCreateClient();
+    m_clientWindow = OnCreateClient();
+    if ( !m_clientWindow->CreateClient(this, GetWindowStyleFlag()) )
+        return false;
 
-    return TRUE;
-}
-
-void wxMDIParentFrame::GtkOnSize( int x, int y, int width, int height )
-{
-    wxFrame::GtkOnSize( x, y, width, height );
-
-    wxMDIChildFrame *child_frame = GetActiveChild();
-    if (!child_frame) return;
-
-    wxMenuBar *menu_bar = child_frame->m_menuBar;
-    if (!menu_bar) return;
-    if (!menu_bar->m_widget) return;
-
-    menu_bar->m_x = 0;
-    menu_bar->m_y = 0;
-    menu_bar->m_width = m_width;
-    menu_bar->m_height = wxMENU_HEIGHT;
-    gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
-                          menu_bar->m_widget,
-                          0, 0, m_width, wxMENU_HEIGHT );
+    return true;
 }
 
 void wxMDIParentFrame::OnInternalIdle()
 {
-    /* if a an MDI child window has just been inserted
+    /* if a MDI child window has just been inserted
        it has to be brought to the top in idle time. we
        simply set the last notebook page active as new
        pages can only be appended at the end */
@@ -155,22 +114,32 @@ void wxMDIParentFrame::OnInternalIdle()
     if (m_justInserted)
     {
         GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
-        gtk_notebook_set_page( notebook, g_list_length( notebook->children ) - 1 );
+        gtk_notebook_set_current_page( notebook, g_list_length( notebook->children ) - 1 );
 
-        m_justInserted = FALSE;
+        /* need to set the menubar of the child */
+        wxMDIChildFrame *active_child_frame = GetActiveChild();
+        if (active_child_frame != NULL)
+        {
+            wxMenuBar *menu_bar = active_child_frame->m_menuBar;
+            if (menu_bar)
+            {
+                menu_bar->SetInvokingWindow(active_child_frame);
+            }
+        }
+        m_justInserted = false;
         return;
     }
 
     wxFrame::OnInternalIdle();
 
     wxMDIChildFrame *active_child_frame = GetActiveChild();
-    bool visible_child_menu = FALSE;
+    bool visible_child_menu = false;
 
-    wxNode *node = m_clientWindow->GetChildren().First();
+    wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
     while (node)
     {
-        wxObject *child = node->Data();
-        wxMDIChildFrame *child_frame = wxDynamicCast(child, wxMDIChildFrame);
+        wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
+
         if ( child_frame )
         {
             wxMenuBar *menu_bar = child_frame->m_menuBar;
@@ -178,20 +147,15 @@ void wxMDIParentFrame::OnInternalIdle()
             {
                 if (child_frame == active_child_frame)
                 {
-                    if (menu_bar->Show(TRUE))
+                    if (menu_bar->Show(true))
                     {
-                        menu_bar->m_width = m_width;
-                        menu_bar->m_height = wxMENU_HEIGHT;
-                        gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
-                                            menu_bar->m_widget,
-                                            0, 0, m_width, wxMENU_HEIGHT );
                         menu_bar->SetInvokingWindow( child_frame );
                     }
-                    visible_child_menu = TRUE;
+                    visible_child_menu = true;
                 }
                 else
                 {
-                    if (menu_bar->Show(FALSE))
+                    if (menu_bar->Show(false))
                     {
                         menu_bar->UnsetInvokingWindow( child_frame );
                     }
@@ -199,7 +163,7 @@ void wxMDIParentFrame::OnInternalIdle()
             }
         }
 
-        node = node->Next();
+        node = node->GetNext();
     }
 
     /* show/hide parent menu bar as required */
@@ -208,66 +172,69 @@ void wxMDIParentFrame::OnInternalIdle()
     {
         if (visible_child_menu)
         {
-            m_frameMenuBar->Show( FALSE );
+            m_frameMenuBar->Show( false );
             m_frameMenuBar->UnsetInvokingWindow( this );
         }
         else
         {
-            m_frameMenuBar->Show( TRUE );
+            m_frameMenuBar->Show( true );
             m_frameMenuBar->SetInvokingWindow( this );
-
-            m_frameMenuBar->m_width = m_width;
-            m_frameMenuBar->m_height = wxMENU_HEIGHT;
-            gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
-                                m_frameMenuBar->m_widget,
-                                0, 0, m_width, wxMENU_HEIGHT );
         }
     }
 }
 
-void wxMDIParentFrame::DoGetClientSize(int *width, int *height ) const
+void wxMDIParentFrame::DoGetClientSize(int* width, int* height) const
 {
-    wxFrame::DoGetClientSize( width, height );
+    wxFrame::DoGetClientSize(width, height);
+
+    if (height)
+    {
+        wxMDIChildFrame* active_child_frame = GetActiveChild();
+        if (active_child_frame)
+        {
+            wxMenuBar* menubar = active_child_frame->m_menuBar;
+            if (menubar && menubar->IsShown())
+            {
+                GtkRequisition req;
+                gtk_widget_size_request(menubar->m_widget, &req);
+                *height -= req.height;
+                if (*height < 0) *height = 0;
+            }
+        }
+    }
 }
 
 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
 {
-    if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
+    if (!m_clientWindow) return NULL;
 
     GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
-    if (!notebook) return (wxMDIChildFrame*) NULL;
+    if (!notebook) return NULL;
 
-#if (GTK_MINOR_VERSION > 0)
     gint i = gtk_notebook_get_current_page( notebook );
-#else
-    gint i = gtk_notebook_current_page( notebook );
-#endif
-    if (i < 0) return (wxMDIChildFrame*) NULL;
+    if (i < 0) return NULL;
 
     GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
-    if (!page) return (wxMDIChildFrame*) NULL;
+    if (!page) return NULL;
 
-    wxNode *node = m_clientWindow->GetChildren().First();
+    wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
     while (node)
     {
-        wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
+        if ( wxPendingDelete.Member(node->GetData()) )
+            return NULL;
+
+        wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
+
+        if (!child_frame)
+            return NULL;
+
         if (child_frame->m_page == page)
             return child_frame;
-        node = node->Next();
-    }
-
-    return (wxMDIChildFrame*) NULL;
-}
 
-wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
-{
-    return m_clientWindow;
-}
+        node = node->GetNext();
+    }
 
-wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
-{
-    m_clientWindow = new wxMDIClientWindow( this );
-    return m_clientWindow;
+    return NULL;
 }
 
 void wxMDIParentFrame::ActivateNext()
@@ -293,51 +260,40 @@ BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
     EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
 END_EVENT_TABLE()
 
-wxMDIChildFrame::wxMDIChildFrame()
+void wxMDIChildFrame::Init()
 {
-    m_menuBar = (wxMenuBar *) NULL;
-    m_page = (GtkNotebookPage *) NULL;
+    m_menuBar = NULL;
+    m_page = NULL;
 }
 
-wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
-      wxWindowID id, const wxString& title,
-      const wxPoint& WXUNUSED(pos), const wxSize& size,
-      long style, const wxString& name )
-{
-    m_menuBar = (wxMenuBar *) NULL;
-    m_page = (GtkNotebookPage *) NULL;
-    Create( parent, id, title, wxDefaultPosition, size, style, name );
-}
-
-wxMDIChildFrame::~wxMDIChildFrame()
-{
-    if (m_menuBar)
-        delete m_menuBar;
-}
-
-bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
-      wxWindowID id, const wxString& title,
-      const wxPoint& WXUNUSED(pos), const wxSize& size,
-      long style, const wxString& name )
+bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
+                             wxWindowID id,
+                             const wxString& title,
+                             const wxPoint& WXUNUSED(pos),
+                             const wxSize& size,
+                             long style,
+                             const wxString& name)
 {
+    m_mdiParent = parent;
     m_title = title;
 
-    return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
+    return wxWindow::Create(parent->GetClientWindow(), id,
+                            wxDefaultPosition, size,
+                            style, name);
 }
 
-void wxMDIChildFrame::DoGetClientSize( int *width, int *height ) const
+wxMDIChildFrame::~wxMDIChildFrame()
 {
-    wxWindow::DoGetClientSize( width, height );
-}
+    delete m_menuBar;
 
-void wxMDIChildFrame::AddChild( wxWindowBase *child )
-{
-    wxWindow::AddChild(child);
+    // wxMDIClientWindow does not get redrawn properly after last child is removed
+    if (m_parent && m_parent->GetChildren().size() <= 1)
+        gtk_widget_queue_draw(m_parent->m_widget);
 }
 
 void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
 {
-    wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
+    wxASSERT_MSG( m_menuBar == NULL, "Only one menubar allowed" );
 
     m_menuBar = menu_bar;
 
@@ -348,9 +304,18 @@ void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
         m_menuBar->SetParent( mdi_frame );
 
         /* insert the invisible menu bar into the _parent_ mdi frame */
-        gtk_pizza_put( GTK_PIZZA(mdi_frame->m_mainWidget),
-                         m_menuBar->m_widget,
-                         0, 0,  mdi_frame->m_width, wxMENU_HEIGHT );
+        m_menuBar->Show(false);
+        gtk_box_pack_start(GTK_BOX(mdi_frame->m_mainWidget), m_menuBar->m_widget, false, false, 0);
+        gtk_box_reorder_child(GTK_BOX(mdi_frame->m_mainWidget), m_menuBar->m_widget, 0);
+
+        gulong handler_id = g_signal_handler_find(
+            m_menuBar->m_widget,
+            GSignalMatchType(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DATA),
+            g_signal_lookup("size_request", GTK_TYPE_WIDGET),
+            0, NULL, NULL, m_menuBar);
+        if (handler_id != 0)
+            g_signal_handler_disconnect(m_menuBar->m_widget, handler_id);
+        gtk_widget_set_size_request(m_menuBar->m_widget, -1, -1);
     }
 }
 
@@ -359,19 +324,22 @@ wxMenuBar *wxMDIChildFrame::GetMenuBar() const
     return m_menuBar;
 }
 
+GtkNotebook *wxMDIChildFrame::GTKGetNotebook() const
+{
+    wxMDIClientWindow * const
+        client = wxStaticCast(GetParent(), wxMDIClientWindow);
+    wxCHECK( client, NULL );
+
+    return GTK_NOTEBOOK(client->m_widget);
+}
+
 void wxMDIChildFrame::Activate()
 {
-#if defined(__WXGTK20__) || (GTK_MINOR_VERSION > 0)
-    wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
-    GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
+    GtkNotebook * const notebook = GTKGetNotebook();
+    wxCHECK_RET( notebook, "no parent notebook?" );
+
     gint pageno = gtk_notebook_page_num( notebook, m_widget );
-    gtk_notebook_set_page( notebook, pageno );
-#else // GTK+ 1.0
-    // the only way I can see to do this under gtk+ 1.0.X would
-    // be to keep track of page numbers, start at first and
-    // do "next" enough times to get to this page number - messy
-    // - J. Russell Smyth
-#endif
+    gtk_notebook_set_current_page( notebook, pageno );
 }
 
 void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
@@ -382,7 +350,7 @@ void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
 {
 #if wxUSE_STATUSBAR
     wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
-    if ( !ShowMenuHelp(mdi_frame->GetStatusBar(), event.GetMenuId()) )
+    if ( !ShowMenuHelp(event.GetMenuId()) )
     {
         // we don't have any help text for this item, but may be the MDI frame
         // does?
@@ -398,102 +366,62 @@ void wxMDIChildFrame::SetTitle( const wxString &title )
 
     m_title = title;
 
-    wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
-    GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
-    gtk_notebook_set_tab_label_text(notebook, m_widget, title.mbc_str());
+    GtkNotebook * const notebook = GTKGetNotebook();
+    wxCHECK_RET( notebook, "no parent notebook?" );
+    gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
 }
 
 //-----------------------------------------------------------------------------
-// "size_allocate"
+// wxMDIClientWindow
 //-----------------------------------------------------------------------------
 
-static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
-{
-    if (g_isIdle) wxapp_install_idle_handler();
+IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxWindow)
 
-    if ((win->m_x == alloc->x) &&
-        (win->m_y == alloc->y) &&
-        (win->m_width == alloc->width) &&
-        (win->m_height == alloc->height) &&
-        (win->m_sizeSet))
+bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style)
+{
+    if ( !PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
+         !CreateBase( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
+                       style, wxDefaultValidator, "wxMDIClientWindow" ))
     {
-        return;
+        wxFAIL_MSG( "wxMDIClientWindow creation failed" );
+        return false;
     }
 
-    win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
-}
-
-//-----------------------------------------------------------------------------
-// InsertChild callback for wxMDIClientWindow
-//-----------------------------------------------------------------------------
-
-static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
-{
-    wxString s = child->m_title;
-    if (s.IsNull()) s = _("MDI child");
-
-    GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
-    gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
-
-    gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
-      GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
-
-    GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
-
-    gtk_notebook_append_page( notebook, child->m_widget, label_widget );
-
-    child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
+    m_widget = gtk_notebook_new();
+    g_object_ref(m_widget);
 
-    wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
-    parent_frame->m_justInserted = TRUE;
-}
+    g_signal_connect (m_widget, "switch_page",
+                      G_CALLBACK (gtk_mdi_page_change_callback), parent);
 
-//-----------------------------------------------------------------------------
-// wxMDIClientWindow
-//-----------------------------------------------------------------------------
+    gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
 
-IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
+    m_parent->DoAddChild( this );
 
-wxMDIClientWindow::wxMDIClientWindow()
-{
-}
+    PostCreation();
 
-wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
-{
-    CreateClient( parent, style );
-}
+    Show( true );
 
-wxMDIClientWindow::~wxMDIClientWindow()
-{
+    return true;
 }
 
-bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
+void wxMDIClientWindow::AddChildGTK(wxWindowGTK* child)
 {
-    m_needParent = TRUE;
+    wxMDIChildFrame* child_frame = static_cast<wxMDIChildFrame*>(child);
+    wxString s = child_frame->GetTitle();
+    if ( s.empty() )
+        s = _("MDI child");
 
-    m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
-
-    if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
-        !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
-    {
-        wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
-        return FALSE;
-    }
-
-    m_widget = gtk_notebook_new();
-
-    gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page",
-      GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback), (gpointer)parent );
-
-    gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
+    GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
+    gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
 
-    m_parent->DoAddChild( this );
+    GtkNotebook* notebook = GTK_NOTEBOOK(m_widget);
 
-    PostCreation();
+    gtk_notebook_append_page( notebook, child->m_widget, label_widget );
 
-    Show( TRUE );
+    child_frame->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
 
-    return TRUE;
+    wxMDIParentFrame* parent_frame = static_cast<wxMDIParentFrame*>(GetParent());
+    parent_frame->m_justInserted = true;
 }
 
-#endif
+#endif // wxUSE_MDI