]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/menu.cpp
partially working wxTaskBarIcon for X11
[wxWidgets.git] / src / gtk / menu.cpp
index af7bc81726915262303304e8ccf597c1d874aede..16a8f31d6ce319b39ace415a8dcf5e2f7a7d5a92 100644 (file)
@@ -145,7 +145,7 @@ static wxString wxReplaceUnderscore( const wxString& title )
 #endif
         else
         {
 #endif
         else
         {
-#if __WXGTK12__
+#ifdef __WXGTK12__
             if ( *pc == wxT('_') )
             {
                 // underscores must be doubled to prevent them from being
             if ( *pc == wxT('_') )
             {
                 // underscores must be doubled to prevent them from being
@@ -161,6 +161,25 @@ static wxString wxReplaceUnderscore( const wxString& title )
     return str;
 }
 
     return str;
 }
 
+//-----------------------------------------------------------------------------
+// activate message from GTK
+//-----------------------------------------------------------------------------
+
+static void gtk_menu_open_callback( GtkWidget *widget, wxMenu *menu )
+{
+    if (g_isIdle) wxapp_install_idle_handler();
+
+    wxMenuEvent event( wxEVT_MENU_OPEN, -1 );
+    event.SetEventObject( menu );
+
+    wxEvtHandler* handler = menu->GetEventHandler();
+    if (handler && handler->ProcessEvent(event))
+        return;
+
+    wxWindow *win = menu->GetInvokingWindow();
+    if (win) win->GetEventHandler()->ProcessEvent( event );
+}
+
 //-----------------------------------------------------------------------------
 // wxMenuBar
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 // wxMenuBar
 //-----------------------------------------------------------------------------
@@ -322,7 +341,7 @@ void wxMenuBar::UnsetInvokingWindow( wxWindow *win )
     while (top_frame->GetParent() && !(top_frame->IsTopLevel()))
         top_frame = top_frame->GetParent();
 
     while (top_frame->GetParent() && !(top_frame->IsTopLevel()))
         top_frame = top_frame->GetParent();
 
-    /* support for native key accelerators indicated by underscroes */
+    // support for native key accelerators indicated by underscroes
     gtk_accel_group_detach( m_accel, ACCEL_OBJ_CAST(top_frame->m_widget) );
 #endif // GTK+ 1.2.1+
 
     gtk_accel_group_detach( m_accel, ACCEL_OBJ_CAST(top_frame->m_widget) );
 #endif // GTK+ 1.2.1+
 
@@ -347,17 +366,17 @@ bool wxMenuBar::GtkAppend(wxMenu *menu, const wxString& title)
 {
     wxString str( wxReplaceUnderscore( title ) );
 
 {
     wxString str( wxReplaceUnderscore( title ) );
 
-    /* this doesn't have much effect right now */
+    // This doesn't have much effect right now.
     menu->SetTitle( str );
 
     menu->SetTitle( str );
 
-    /* GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has. */
+    // GTK 1.2.0 doesn't have gtk_item_factory_get_item(), but GTK 1.2.1 has.
 #if GTK_CHECK_VERSION(1, 2, 1)
 
     wxString buf;
     buf << wxT('/') << str.c_str();
 
 #if GTK_CHECK_VERSION(1, 2, 1)
 
     wxString buf;
     buf << wxT('/') << str.c_str();
 
-    /* local buffer in multibyte form */
-    char cbuf[400]; 
+    // local buffer in multibyte form
+    char cbuf[400];
     strcpy(cbuf, wxGTK_CONV(buf) );
 
     GtkItemFactoryEntry entry;
     strcpy(cbuf, wxGTK_CONV(buf) );
 
     GtkItemFactoryEntry entry;
@@ -367,8 +386,8 @@ bool wxMenuBar::GtkAppend(wxMenu *menu, const wxString& title)
     entry.callback_action = 0;
     entry.item_type = (char *)"<Branch>";
 
     entry.callback_action = 0;
     entry.item_type = (char *)"<Branch>";
 
-    gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 );  /* what is 2 ? */
-    /* in order to get the pointer to the item we need the item text _without_ underscores */
+    gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 );  // what is 2 ?
+    // in order to get the pointer to the item we need the item text _without_ underscores
     wxString tmp = wxT("<main>/");
     const wxChar *pc;
     for ( pc = str; *pc != wxT('\0'); pc++ )
     wxString tmp = wxT("<main>/");
     const wxChar *pc;
     for ( pc = str; *pc != wxT('\0'); pc++ )
@@ -392,6 +411,10 @@ bool wxMenuBar::GtkAppend(wxMenu *menu, const wxString& title)
 
 #endif
 
 
 #endif
 
+    gtk_signal_connect( GTK_OBJECT(menu->m_owner), "activate",
+                        GTK_SIGNAL_FUNC(gtk_menu_open_callback),
+                        (gpointer)menu );
+
     // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
     // addings menu later on.
     if (m_invokingWindow)
     // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
     // addings menu later on.
     if (m_invokingWindow)
@@ -404,7 +427,7 @@ bool wxMenuBar::GtkAppend(wxMenu *menu, const wxString& title)
             //               see (and refactor :) similar code in Remove
             //               below.
 
             //               see (and refactor :) similar code in Remove
             //               below.
 
-        wxFrame        *frame = wxDynamicCast( m_invokingWindow, wxFrame );
+        wxFrame *frame = wxDynamicCast( m_invokingWindow, wxFrame );
 
         if( frame )
             frame->UpdateMenuBarSize();
 
         if( frame )
             frame->UpdateMenuBarSize();
@@ -471,10 +494,10 @@ static wxMenu *CopyMenu (wxMenu *menu)
         else
           menucopy->Append (itemid, text, CopyMenu(submenu),
                             menu->GetHelpString(itemid));
         else
           menucopy->Append (itemid, text, CopyMenu(submenu),
                             menu->GetHelpString(itemid));
-    
+
         node = node->GetNext();
     }
         node = node->GetNext();
     }
-  
+
     return menucopy;
 }
 
     return menucopy;
 }
 
@@ -511,9 +534,9 @@ wxMenu *wxMenuBar::Remove(size_t pos)
     {
             // OPTIMISE ME:  see comment in GtkAppend
 
     {
             // OPTIMISE ME:  see comment in GtkAppend
 
-       wxFrame *frame = wxDynamicCast( m_invokingWindow, wxFrame );
+    wxFrame *frame = wxDynamicCast( m_invokingWindow, wxFrame );
 
 
-       if( frame )
+    if( frame )
             frame->UpdateMenuBarSize();
     }
 
             frame->UpdateMenuBarSize();
     }
 
@@ -684,7 +707,7 @@ static void gtk_menu_clicked_callback( GtkWidget *widget, wxMenu *menu )
     if (item->IsCheckable())
     {
         bool isReallyChecked = item->IsChecked(),
     if (item->IsCheckable())
     {
         bool isReallyChecked = item->IsChecked(),
-             isInternallyChecked = item->wxMenuItemBase::IsChecked();
+            isInternallyChecked = item->wxMenuItemBase::IsChecked();
 
         // ensure that the internal state is always consistent with what is
         // shown on the screen
 
         // ensure that the internal state is always consistent with what is
         // shown on the screen
@@ -697,11 +720,36 @@ static void gtk_menu_clicked_callback( GtkWidget *widget, wxMenu *menu )
         {
             return;
         }
         {
             return;
         }
+    }
+
 
 
-        // the user pressed on the menu item: report the event below
+    // Is this menu on a menubar?  (possibly nested)
+    wxFrame* frame = NULL;
+    wxMenu*  pm = menu;
+    while ( pm && !frame )
+    {
+        if ( pm->IsAttached() )
+            frame = pm->GetMenuBar()->GetFrame();
+        pm = pm->GetParent();
     }
 
     }
 
-    menu->SendEvent(id, item->IsCheckable() ? item->IsChecked() : -1);
+    if (frame)
+    {
+        // If it is attached then let the frame send the event.
+        // Don't call frame->ProcessCommand(id) because it toggles
+        // checkable items and we've already done that above.
+        wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id);
+        commandEvent.SetEventObject(frame);
+        if (item->IsCheckable())
+            commandEvent.SetInt(item->IsChecked());
+
+        frame->GetEventHandler()->ProcessEvent(commandEvent);
+    }
+    else
+    {
+        // otherwise let the menu have it
+        menu->SendEvent(id, item->IsCheckable() ? item->IsChecked() : -1);
+    }
 }
 
 //-----------------------------------------------------------------------------
 }
 
 //-----------------------------------------------------------------------------
@@ -722,7 +770,8 @@ static void gtk_menu_hilight_callback( GtkWidget *widget, wxMenu *menu )
     wxMenuEvent event( wxEVT_MENU_HIGHLIGHT, id );
     event.SetEventObject( menu );
 
     wxMenuEvent event( wxEVT_MENU_HIGHLIGHT, id );
     event.SetEventObject( menu );
 
-    if (menu->GetEventHandler()->ProcessEvent(event))
+    wxEvtHandler* handler = menu->GetEventHandler();
+    if (handler && handler->ProcessEvent(event))
         return;
 
     wxWindow *win = menu->GetInvokingWindow();
         return;
 
     wxWindow *win = menu->GetInvokingWindow();
@@ -747,7 +796,8 @@ static void gtk_menu_nolight_callback( GtkWidget *widget, wxMenu *menu )
     wxMenuEvent event( wxEVT_MENU_HIGHLIGHT, -1 );
     event.SetEventObject( menu );
 
     wxMenuEvent event( wxEVT_MENU_HIGHLIGHT, -1 );
     event.SetEventObject( menu );
 
-    if (menu->GetEventHandler()->ProcessEvent(event))
+    wxEvtHandler* handler = menu->GetEventHandler();
+    if (handler && handler->ProcessEvent(event))
         return;
 
     wxWindow *win = menu->GetInvokingWindow();
         return;
 
     wxWindow *win = menu->GetInvokingWindow();
@@ -839,9 +889,12 @@ wxString wxMenuItemBase::GetLabelFromText(const wxString& text)
             // "&" is doubled to indicate "&" instead of accelerator
             continue;
         }
             // "&" is doubled to indicate "&" instead of accelerator
             continue;
         }
-        
+
         label += *pc;
     }
         label += *pc;
     }
+
+    // wxPrintf( L"text %s label %s\n", text.c_str(), label.c_str() );
+
     return label;
 }
 
     return label;
 }
 
@@ -854,7 +907,7 @@ void wxMenuItem::SetText( const wxString& str )
     wxString label1 = wxStripMenuCodes(str.BeforeFirst('\t'));
     if (oldLabel == label1)
         return;
     wxString label1 = wxStripMenuCodes(str.BeforeFirst('\t'));
     if (oldLabel == label1)
         return;
-    
+
     DoSetText(str);
 
     if (m_menuItem)
     DoSetText(str);
 
     if (m_menuItem)
@@ -873,7 +926,7 @@ void wxMenuItem::SetText( const wxString& str )
             if (m_text[n] != wxT('\\'))
                 tmp += m_text[n];
         }
             if (m_text[n] != wxT('\\'))
                 tmp += m_text[n];
         }
-        
+
         gtk_label_set_text_with_mnemonic( GTK_LABEL(label), wxGTK_CONV(tmp) );
 #else
         // set new text
         gtk_label_set_text_with_mnemonic( GTK_LABEL(label), wxGTK_CONV(tmp) );
 #else
         // set new text
@@ -908,6 +961,7 @@ void wxMenuItem::DoSetText( const wxString& str )
         else if ( *pc == wxT('_') )    // escape underscores
         {
             // m_text << wxT("__");    doesn't work
         else if ( *pc == wxT('_') )    // escape underscores
         {
             // m_text << wxT("__");    doesn't work
+            m_text << wxT("__");
         }
         else if (*pc == wxT('/'))      // we have to escape slashes
         {
         }
         else if (*pc == wxT('/'))      // we have to escape slashes
         {
@@ -932,7 +986,9 @@ void wxMenuItem::DoSetText( const wxString& str )
         }
         ++pc;
     }
         }
         ++pc;
     }
-    
+
+    // wxPrintf( L"str %s m_text %s\n", str.c_str(), m_text.c_str() );
+
     m_hotKey = wxT("");
 
     if(*pc == wxT('\t'))
     m_hotKey = wxT("");
 
     if(*pc == wxT('\t'))
@@ -1002,16 +1058,20 @@ bool wxMenuItem::IsChecked() const
 
 wxString wxMenuItem::GetFactoryPath() const
 {
 
 wxString wxMenuItem::GetFactoryPath() const
 {
-    /* in order to get the pointer to the item we need the item text
-       _without_ underscores */
+    // In order to get the pointer to the item we need the item
+    // text _without_ underscores in GTK 1.2
     wxString path( wxT("<main>/") );
 
     for ( const wxChar *pc = m_text.c_str(); *pc; pc++ )
     {
         if ( *pc == wxT('_') )
         {
     wxString path( wxT("<main>/") );
 
     for ( const wxChar *pc = m_text.c_str(); *pc; pc++ )
     {
         if ( *pc == wxT('_') )
         {
+#ifdef __WXGTK20__
+            pc++;
+#else
             // remove '_' unconditionally
             continue;
             // remove '_' unconditionally
             continue;
+#endif
         }
 
         // don't remove ampersands '&' since if we have them in the menu item title
         }
 
         // don't remove ampersands '&' since if we have them in the menu item title
@@ -1037,9 +1097,9 @@ void wxMenu::Init()
 
     m_owner = (GtkWidget*) NULL;
 
 
     m_owner = (GtkWidget*) NULL;
 
-    /* Tearoffs are entries, just like separators. So if we want this
-       menu to be a tear-off one, we just append a tearoff entry
-       immediately. */
+    // Tearoffs are entries, just like separators. So if we want this
+    // menu to be a tear-off one, we just append a tearoff entry
+    // immediately.
     if(m_style & wxMENU_TEAROFF)
     {
        GtkItemFactoryEntry entry;
     if(m_style & wxMENU_TEAROFF)
     {
        GtkItemFactoryEntry entry;
@@ -1048,7 +1108,7 @@ void wxMenu::Init()
        entry.callback_action = 0;
        entry.item_type = (char *)"<Tearoff>";
        entry.accelerator = (gchar*) NULL;
        entry.callback_action = 0;
        entry.item_type = (char *)"<Tearoff>";
        entry.accelerator = (gchar*) NULL;
-       gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 );  /* what is 2 ? */
+       gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 );  // what is 2 ?
        //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "<main>/tearoff" );
     }
 
        //GtkWidget *menuItem = gtk_item_factory_get_widget( m_factory, "<main>/tearoff" );
     }
 
@@ -1089,9 +1149,9 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem)
         entry.item_type = (char *)"<Separator>";
         entry.accelerator = (gchar*) NULL;
 
         entry.item_type = (char *)"<Separator>";
         entry.accelerator = (gchar*) NULL;
 
-        gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 );  /* what is 2 ? */
+        gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 );  // what is 2 ?
 
 
-        /* this will be wrong for more than one separator. do we care? */
+        // this will be wrong for more than one separator. do we care?
         menuItem = gtk_item_factory_get_widget( m_factory, "<main>/sep" );
 
         // we might have a separator inside a radio group
         menuItem = gtk_item_factory_get_widget( m_factory, "<main>/sep" );
 
         // we might have a separator inside a radio group
@@ -1099,10 +1159,10 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem)
     }
     else if ( mitem->IsSubMenu() )
     {
     }
     else if ( mitem->IsSubMenu() )
     {
-        /* text has "_" instead of "&" after mitem->SetText() */
+        // text has "_" instead of "&" after mitem->SetText()
         wxString text( mitem->GetText() );
 
         wxString text( mitem->GetText() );
 
-        /* local buffer in multibyte form */
+        // local buffer in multibyte form
         char buf[200];
         strcpy( buf, "/" );
         strcat( buf, wxGTK_CONV( text ) );
         char buf[200];
         strcpy( buf, "/" );
         strcat( buf, wxGTK_CONV( text ) );
@@ -1114,7 +1174,7 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem)
         entry.item_type = (char *)"<Branch>";
         entry.accelerator = (gchar*) NULL;
 
         entry.item_type = (char *)"<Branch>";
         entry.accelerator = (gchar*) NULL;
 
-        gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 );  /* what is 2 ? */
+        gtk_item_factory_create_item( m_factory, &entry, (gpointer) this, 2 );  // what is 2 ?
 
         wxString path( mitem->GetFactoryPath() );
         menuItem = gtk_item_factory_get_item( m_factory, wxGTK_CONV( path ) );
 
         wxString path( mitem->GetFactoryPath() );
         menuItem = gtk_item_factory_get_item( m_factory, wxGTK_CONV( path ) );
@@ -1158,7 +1218,7 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem)
         gtk_signal_connect( GTK_OBJECT(menuItem), "activate",
                             GTK_SIGNAL_FUNC(gtk_menu_clicked_callback),
                             (gpointer)this );
         gtk_signal_connect( GTK_OBJECT(menuItem), "activate",
                             GTK_SIGNAL_FUNC(gtk_menu_clicked_callback),
                             (gpointer)this );
-                            
+
         gtk_menu_append( GTK_MENU(m_menu), menuItem );
         gtk_widget_show( menuItem );
 
         gtk_menu_append( GTK_MENU(m_menu), menuItem );
         gtk_widget_show( menuItem );
 
@@ -1244,7 +1304,7 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem)
 
         wxString path( mitem->GetFactoryPath() );
         menuItem = gtk_item_factory_get_widget( m_factory, wxGTK_CONV( path ) );
 
         wxString path( mitem->GetFactoryPath() );
         menuItem = gtk_item_factory_get_widget( m_factory, wxGTK_CONV( path ) );
-        
+
         if (!menuItem)
             wxLogError( wxT("Wrong menu path: %s\n"), path.c_str() );
     }
         if (!menuItem)
             wxLogError( wxT("Wrong menu path: %s\n"), path.c_str() );
     }
@@ -1252,7 +1312,7 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem)
     if ( !mitem->IsSeparator() )
     {
         wxASSERT_MSG( menuItem, wxT("invalid menuitem") );
     if ( !mitem->IsSeparator() )
     {
         wxASSERT_MSG( menuItem, wxT("invalid menuitem") );
-    
+
         gtk_signal_connect( GTK_OBJECT(menuItem), "select",
                             GTK_SIGNAL_FUNC(gtk_menu_hilight_callback),
                             (gpointer)this );
         gtk_signal_connect( GTK_OBJECT(menuItem), "select",
                             GTK_SIGNAL_FUNC(gtk_menu_hilight_callback),
                             (gpointer)this );
@@ -1282,7 +1342,6 @@ bool wxMenu::DoInsert(size_t pos, wxMenuItem *item)
     if ( !wxMenuBase::DoInsert(pos, item) )
         return FALSE;
 
     if ( !wxMenuBase::DoInsert(pos, item) )
         return FALSE;
 
-#ifdef __WXGTK12__
     // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as
     // of version 1.2.6), so we first append the item and then change its
     // index
     // GTK+ doesn't have a function to insert a menu using GtkItemFactory (as
     // of version 1.2.6), so we first append the item and then change its
     // index
@@ -1301,12 +1360,6 @@ bool wxMenu::DoInsert(size_t pos, wxMenuItem *item)
     menu_shell->children = g_list_insert(menu_shell->children, data, pos);
 
     return TRUE;
     menu_shell->children = g_list_insert(menu_shell->children, data, pos);
 
     return TRUE;
-#else // GTK < 1.2
-    // this should be easy to do...
-    wxFAIL_MSG( wxT("not implemented") );
-
-    return FALSE;
-#endif // GTK 1.2/1.0
 }
 
 wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
 }
 
 wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
@@ -1323,13 +1376,13 @@ wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
 
 int wxMenu::FindMenuIdByMenuItem( GtkWidget *menuItem ) const
 {
 
 int wxMenu::FindMenuIdByMenuItem( GtkWidget *menuItem ) const
 {
-    wxNode *node = m_items.First();
+    wxMenuItemList::Node    *node = m_items.GetFirst();
     while (node)
     {
     while (node)
     {
-        wxMenuItem *item = (wxMenuItem*)node->Data();
+        wxMenuItem *item = node->GetData();
         if (item->GetMenuItem() == menuItem)
            return item->GetId();
         if (item->GetMenuItem() == menuItem)
            return item->GetId();
-        node = node->Next();
+        node = node->GetNext();
     }
 
     return wxNOT_FOUND;
     }
 
     return wxNOT_FOUND;