Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / unx / gtk / window / gtksalmenu.cxx
blob4a189994ae76d609dc8e86ad1a9ab5915337e261
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <unx/gtk/gtksalmenu.hxx>
12 #ifdef ENABLE_GMENU_INTEGRATION
14 #include <generic/gendata.hxx>
15 #include <unx/saldisp.hxx>
16 #include <unx/gtk/glomenu.h>
17 #include <unx/gtk/gloactiongroup.h>
18 #include <vcl/menu.hxx>
19 #include <unx/gtk/gtkinst.hxx>
21 #if GTK_CHECK_VERSION(3,0,0)
22 # include <gdk/gdkkeysyms-compat.h>
23 #endif
25 #include <sal/log.hxx>
27 // FIXME Copied from framework/inc/framework/menuconfiguration.hxx to
28 // avoid circular dependency between modules. It should be in a common
29 // header (probably in vcl).
30 const sal_uInt16 START_ITEMID_WINDOWLIST = 4600;
31 const sal_uInt16 END_ITEMID_WINDOWLIST = 4699;
33 static bool bMenuVisibility = false;
36 * This function generates the proper command name for all actions, including
37 * duplicated or special ones.
39 static gchar* GetCommandForItem( GtkSalMenuItem* pSalMenuItem, gchar* aCurrentCommand, GActionGroup* pActionGroup )
41 gchar* aCommand = NULL;
43 sal_uInt16 nId = pSalMenuItem->mnId;
44 Menu* pMenu = pSalMenuItem->mpVCLMenu;
46 // If item belongs to window list, generate a command with "window-(id)" format.
47 if ( ( nId >= START_ITEMID_WINDOWLIST ) && ( nId <= END_ITEMID_WINDOWLIST ) )
48 aCommand = g_strdup_printf( "window-%d", nId );
49 else
51 if ( !pMenu )
52 return NULL;
54 OUString aMenuCommand = pMenu->GetItemCommand( nId );
55 gchar* aCommandStr = g_strdup( OUStringToOString( aMenuCommand, RTL_TEXTENCODING_UTF8 ).getStr() );
56 aCommand = g_strdup( aCommandStr );
58 // Some items could have duplicated commands. A new one should be generated.
59 for ( sal_uInt16 i = 2; ; i++ )
61 if ( !g_action_group_has_action( pActionGroup, aCommand )
62 || ( aCurrentCommand && g_strcmp0( aCurrentCommand, aCommand ) == 0 ) )
63 break;
65 g_free( aCommand );
66 aCommand = g_strdup_printf("%s%d", aCommandStr, i);
69 g_free( aCommandStr );
72 return aCommand;
75 bool GtkSalMenu::PrepUpdate()
77 const GtkSalFrame* pFrame = GetFrame();
78 if (pFrame)
80 GtkSalFrame* pNonConstFrame = const_cast<GtkSalFrame*>(pFrame);
81 GtkSalMenu* pSalMenu = this;
83 if ( !pNonConstFrame->GetMenu() )
84 pNonConstFrame->SetMenu( pSalMenu );
86 if ( bMenuVisibility && mpMenuModel && mpActionGroup )
87 return true;
90 return false;
94 * Menu updating methods
97 void RemoveSpareItemsFromNativeMenu( GLOMenu* pMenu, GList** pOldCommandList, unsigned nSection, unsigned nValidItems )
99 sal_Int32 nSectionItems = g_lo_menu_get_n_items_from_section( pMenu, nSection );
101 while ( nSectionItems > (sal_Int32) nValidItems )
103 gchar* aCommand = g_lo_menu_get_command_from_item_in_section( pMenu, nSection, --nSectionItems );
105 if ( aCommand != NULL && pOldCommandList != NULL )
106 *pOldCommandList = g_list_append( *pOldCommandList, g_strdup( aCommand ) );
108 g_free( aCommand );
110 g_lo_menu_remove_from_section( pMenu, nSection, nSectionItems );
114 void RemoveSpareSectionsFromNativeMenu( GLOMenu* pMenu, GList** pOldCommandList, unsigned nLastSection )
116 if ( pMenu == NULL || pOldCommandList == NULL )
117 return;
119 sal_Int32 n = g_menu_model_get_n_items( G_MENU_MODEL( pMenu ) ) - 1;
121 for ( ; n > (sal_Int32) nLastSection; n-- )
123 RemoveSpareItemsFromNativeMenu( pMenu, pOldCommandList, n, 0 );
124 g_lo_menu_remove( pMenu, n );
128 gint CompareStr( gpointer str1, gpointer str2 )
130 return g_strcmp0( static_cast<const gchar*>(str1), static_cast<const gchar*>(str2) );
133 void RemoveUnusedCommands( GLOActionGroup* pActionGroup, GList* pOldCommandList, GList* pNewCommandList )
135 if ( pActionGroup == NULL || pOldCommandList == NULL )
137 g_list_free_full( pOldCommandList, g_free );
138 g_list_free_full( pNewCommandList, g_free );
139 return;
142 while ( pNewCommandList != NULL )
144 GList* pNewCommand = g_list_first( pNewCommandList );
145 pNewCommandList = g_list_remove_link( pNewCommandList, pNewCommand );
147 gpointer aCommand = g_list_nth_data( pNewCommand, 0 );
149 GList* pOldCommand = g_list_find_custom( pOldCommandList, aCommand, reinterpret_cast<GCompareFunc>(CompareStr) );
151 if ( pOldCommand != NULL )
153 pOldCommandList = g_list_remove_link( pOldCommandList, pOldCommand );
154 g_list_free_full( pOldCommand, g_free );
157 g_list_free_full( pNewCommand, g_free );
160 while ( pOldCommandList != NULL )
162 GList* pCommand = g_list_first( pOldCommandList );
163 pOldCommandList = g_list_remove_link( pOldCommandList, pCommand );
165 gchar* aCommand = static_cast<gchar*>(g_list_nth_data( pCommand, 0 ));
167 g_lo_action_group_remove( pActionGroup, aCommand );
169 g_list_free_full( pCommand, g_free );
173 void GtkSalMenu::ImplUpdate( gboolean bRecurse )
175 SolarMutexGuard aGuard;
177 SAL_INFO("vcl.unity", "ImplUpdate pre PrepUpdate");
178 if( !PrepUpdate() )
179 return;
181 Menu* pVCLMenu = mpVCLMenu;
182 GLOMenu* pLOMenu = G_LO_MENU( mpMenuModel );
183 GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( mpActionGroup );
184 SAL_INFO("vcl.unity", "Syncing vcl menu " << pVCLMenu << " to menu model " << pLOMenu << " and action group " << pActionGroup);
185 GList *pOldCommandList = NULL;
186 GList *pNewCommandList = NULL;
188 sal_uInt16 nLOMenuSize = g_menu_model_get_n_items( G_MENU_MODEL( pLOMenu ) );
190 if ( nLOMenuSize == 0 )
191 g_lo_menu_new_section( pLOMenu, 0, NULL );
193 sal_Int32 nSection = 0;
194 sal_Int32 nItemPos = 0;
195 sal_Int32 validItems = 0;
196 sal_Int32 nItem;
198 for ( nItem = 0; nItem < ( sal_Int32 ) GetItemCount(); nItem++ ) {
199 if ( !IsItemVisible( nItem ) )
200 continue;
202 GtkSalMenuItem *pSalMenuItem = GetItemAtPos( nItem );
203 sal_uInt16 nId = pSalMenuItem->mnId;
205 if ( pSalMenuItem->mnType == MenuItemType::SEPARATOR )
207 // Delete extra items from current section.
208 RemoveSpareItemsFromNativeMenu( pLOMenu, &pOldCommandList, nSection, validItems );
210 nSection++;
211 nItemPos = 0;
212 validItems = 0;
214 if ( nLOMenuSize <= nSection )
216 g_lo_menu_new_section( pLOMenu, nSection, NULL );
217 nLOMenuSize++;
220 continue;
223 if ( nItemPos >= g_lo_menu_get_n_items_from_section( pLOMenu, nSection ) )
224 g_lo_menu_insert_in_section( pLOMenu, nSection, nItemPos, "EMPTY STRING" );
226 // Get internal menu item values.
227 OUString aText = pVCLMenu->GetItemText( nId );
228 bool bEnabled = pVCLMenu->IsItemEnabled( nId );
229 vcl::KeyCode nAccelKey = pVCLMenu->GetAccelKey( nId );
230 bool bChecked = pVCLMenu->IsItemChecked( nId );
231 MenuItemBits itemBits = pVCLMenu->GetItemBits( nId );
233 // Store current item command in command list.
234 gchar *aCurrentCommand = g_lo_menu_get_command_from_item_in_section( pLOMenu, nSection, nItemPos );
236 if ( aCurrentCommand != NULL )
237 pOldCommandList = g_list_append( pOldCommandList, aCurrentCommand );
239 // Get the new command for the item.
240 gchar* aNativeCommand = GetCommandForItem( pSalMenuItem, aCurrentCommand, mpActionGroup );
242 // Force updating of native menu labels.
243 NativeSetItemText( nSection, nItemPos, aText );
244 NativeSetAccelerator( nSection, nItemPos, nAccelKey, nAccelKey.GetName( GetFrame()->GetWindow() ) );
246 if ( g_strcmp0( aNativeCommand, "" ) != 0 && pSalMenuItem->mpSubMenu == NULL )
248 NativeSetItemCommand( nSection, nItemPos, nId, aNativeCommand, itemBits, bChecked, FALSE );
249 NativeCheckItem( nSection, nItemPos, itemBits, bChecked );
250 NativeSetEnableItem( aNativeCommand, bEnabled );
252 pNewCommandList = g_list_append( pNewCommandList, g_strdup( aNativeCommand ) );
255 GtkSalMenu* pSubmenu = pSalMenuItem->mpSubMenu;
257 if ( pSubmenu && pSubmenu->GetMenu() )
259 NativeSetItemCommand( nSection, nItemPos, nId, aNativeCommand, itemBits, FALSE, TRUE );
260 pNewCommandList = g_list_append( pNewCommandList, g_strdup( aNativeCommand ) );
262 GLOMenu* pSubMenuModel = g_lo_menu_get_submenu_from_item_in_section( pLOMenu, nSection, nItemPos );
264 if ( pSubMenuModel == NULL )
266 g_lo_menu_new_submenu_in_item_in_section( pLOMenu, nSection, nItemPos );
267 pSubMenuModel = g_lo_menu_get_submenu_from_item_in_section( pLOMenu, nSection, nItemPos );
270 g_object_unref( pSubMenuModel );
272 if ( bRecurse )
274 SAL_INFO("vcl.unity", "preparing submenu " << pSubMenuModel << " to menu model " << G_MENU_MODEL(pSubMenuModel) << " and action group " << G_ACTION_GROUP(pActionGroup));
275 pSubmenu->SetMenuModel( G_MENU_MODEL( pSubMenuModel ) );
276 pSubmenu->SetActionGroup( G_ACTION_GROUP( pActionGroup ) );
277 pSubmenu->ImplUpdate( bRecurse );
281 g_free( aNativeCommand );
283 ++nItemPos;
284 ++validItems;
287 // Delete extra items in last section.
288 RemoveSpareItemsFromNativeMenu( pLOMenu, &pOldCommandList, nSection, validItems );
290 // Delete extra sections.
291 RemoveSpareSectionsFromNativeMenu( pLOMenu, &pOldCommandList, nSection );
293 // Delete unused commands.
294 RemoveUnusedCommands( pActionGroup, pOldCommandList, pNewCommandList );
297 void GtkSalMenu::Update()
299 ImplUpdate( FALSE );
302 void GtkSalMenu::UpdateFull()
304 ImplUpdate( TRUE );
308 * GtkSalMenu
311 GtkSalMenu::GtkSalMenu( bool bMenuBar ) :
312 mbMenuBar( bMenuBar ),
313 mpVCLMenu( NULL ),
314 mpParentSalMenu( NULL ),
315 mpFrame( NULL ),
316 mpMenuModel( NULL ),
317 mpActionGroup( NULL )
321 GtkSalMenu::~GtkSalMenu()
323 SolarMutexGuard aGuard;
325 if ( mbMenuBar )
327 if ( mpMenuModel )
329 // g_lo_menu_remove( G_LO_MENU( mpMenuModel ), 0 );
330 g_object_unref( mpMenuModel );
334 maItems.clear();
337 bool GtkSalMenu::VisibleMenuBar()
339 return bMenuVisibility;
342 void GtkSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos )
344 SolarMutexGuard aGuard;
345 GtkSalMenuItem *pItem = static_cast<GtkSalMenuItem*>( pSalMenuItem );
347 if ( nPos == MENU_APPEND )
348 maItems.push_back( pItem );
349 else
350 maItems.insert( maItems.begin() + nPos, pItem );
352 pItem->mpParentMenu = this;
355 void GtkSalMenu::RemoveItem( unsigned nPos )
357 SolarMutexGuard aGuard;
358 maItems.erase( maItems.begin() + nPos );
361 void GtkSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned )
363 SolarMutexGuard aGuard;
364 GtkSalMenuItem *pItem = static_cast< GtkSalMenuItem* >( pSalMenuItem );
365 GtkSalMenu *pGtkSubMenu = static_cast< GtkSalMenu* >( pSubMenu );
367 if ( pGtkSubMenu == NULL )
368 return;
370 pGtkSubMenu->mpParentSalMenu = this;
371 pItem->mpSubMenu = pGtkSubMenu;
374 static bool bInvalidMenus = false;
375 static gboolean RefreshMenusUnity(gpointer)
377 SolarMutexGuard g;
379 SalDisplay* pSalDisplay = vcl_sal::getSalDisplay(GetGenericData());
380 std::list< SalFrame* >::const_iterator pSalFrame = pSalDisplay->getFrames().begin();
381 std::list< SalFrame* >::const_iterator pEndSalFrame = pSalDisplay->getFrames().end();
382 for(; pSalFrame != pEndSalFrame; ++pSalFrame) {
383 const GtkSalFrame* pGtkSalFrame = static_cast< const GtkSalFrame* >( *pSalFrame );
384 GtkSalFrame* pFrameNonConst = const_cast<GtkSalFrame*>(pGtkSalFrame);
385 GtkSalMenu* pSalMenu = static_cast<GtkSalMenu*>(pFrameNonConst->GetMenu());
386 if(pSalMenu) {
387 pSalMenu->Activate();
388 pSalMenu->UpdateFull();
391 bInvalidMenus = false;
392 return FALSE;
395 static long RefreshMenusUnity(void*, void*)
397 if(!bInvalidMenus) {
398 g_timeout_add(10, &RefreshMenusUnity, NULL);
399 bInvalidMenus = true;
401 return 0;
404 static Link<>* getRefreshLinkInstance()
406 static Link<>* pLink = NULL;
407 if(!pLink) {
408 pLink = new Link<>(NULL, &RefreshMenusUnity);
410 return pLink;
413 void GtkSalMenu::SetFrame( const SalFrame* pFrame )
415 SolarMutexGuard aGuard;
417 vcl::MenuInvalidator::GetMenuInvalidateListeners()->addListener(*getRefreshLinkInstance());
420 assert(mbMenuBar);
421 SAL_INFO("vcl.unity", "GtkSalMenu set to frame");
422 mpFrame = static_cast< const GtkSalFrame* >( pFrame );
423 GtkSalFrame* pFrameNonConst = const_cast<GtkSalFrame*>(mpFrame);
425 // if we had a menu on the GtkSalMenu we have to free it as we generate a
426 // full menu anyway and we might need to reuse an existing model and
427 // actiongroup
428 pFrameNonConst->SetMenu( this );
429 pFrameNonConst->EnsureAppMenuWatch();
431 // Clean menu model and action group if needed.
432 GtkWidget* pWidget = pFrameNonConst->getWindow();
433 GdkWindow* gdkWindow = gtk_widget_get_window( pWidget );
435 GLOMenu* pMenuModel = G_LO_MENU( g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-menubar" ) );
436 GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-action-group" ) );
437 SAL_INFO("vcl.unity", "Found menu model: " << pMenuModel << " and action group: " << pActionGroup);
439 if ( pMenuModel )
441 if ( g_menu_model_get_n_items( G_MENU_MODEL( pMenuModel ) ) > 0 )
442 g_lo_menu_remove( pMenuModel, 0 );
444 mpMenuModel = G_MENU_MODEL( g_lo_menu_new() );
447 if ( pActionGroup )
449 g_lo_action_group_clear( pActionGroup );
450 mpActionGroup = G_ACTION_GROUP( pActionGroup );
453 // Generate the main menu structure.
454 if (bMenuVisibility)
455 UpdateFull();
457 g_lo_menu_insert_section( pMenuModel, 0, NULL, mpMenuModel );
460 const GtkSalFrame* GtkSalMenu::GetFrame() const
462 SolarMutexGuard aGuard;
463 const GtkSalMenu* pMenu = this;
464 while( pMenu && ! pMenu->mpFrame )
465 pMenu = pMenu->mpParentSalMenu;
466 return pMenu ? pMenu->mpFrame : NULL;
469 void GtkSalMenu::NativeCheckItem( unsigned nSection, unsigned nItemPos, MenuItemBits bits, gboolean bCheck )
471 SolarMutexGuard aGuard;
473 if ( mpActionGroup == NULL )
474 return;
476 gchar* aCommand = g_lo_menu_get_command_from_item_in_section( G_LO_MENU( mpMenuModel ), nSection, nItemPos );
478 if ( aCommand != NULL || g_strcmp0( aCommand, "" ) != 0 )
480 GVariant *pCheckValue = NULL;
481 GVariant *pCurrentState = g_action_group_get_action_state( mpActionGroup, aCommand );
483 if ( bits & MenuItemBits::RADIOCHECK )
484 pCheckValue = bCheck ? g_variant_new_string( aCommand ) : g_variant_new_string( "" );
485 else
487 // By default, all checked items are checkmark buttons.
488 if ( bCheck || ( !bCheck && pCurrentState != NULL ) )
489 pCheckValue = g_variant_new_boolean( bCheck );
492 if ( pCheckValue != NULL )
494 if ( pCurrentState == NULL || g_variant_equal( pCurrentState, pCheckValue ) == FALSE )
496 g_action_group_change_action_state( mpActionGroup, aCommand, pCheckValue );
498 else
500 g_variant_unref (pCheckValue);
504 if ( pCurrentState != NULL )
505 g_variant_unref( pCurrentState );
508 if ( aCommand )
509 g_free( aCommand );
512 void GtkSalMenu::NativeSetEnableItem( gchar* aCommand, gboolean bEnable )
514 SolarMutexGuard aGuard;
515 GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( mpActionGroup );
517 if ( g_action_group_get_action_enabled( G_ACTION_GROUP( pActionGroup ), aCommand ) != bEnable )
518 g_lo_action_group_set_action_enabled( pActionGroup, aCommand, bEnable );
521 void GtkSalMenu::NativeSetItemText( unsigned nSection, unsigned nItemPos, const OUString& rText )
523 SolarMutexGuard aGuard;
524 // Escape all underscores so that they don't get interpreted as hotkeys
525 OUString aText = rText.replaceAll( "_", "__" );
526 // Replace the LibreOffice hotkey identifier with an underscore
527 aText = aText.replace( '~', '_' );
528 OString aConvertedText = OUStringToOString( aText, RTL_TEXTENCODING_UTF8 );
530 // Update item text only when necessary.
531 gchar* aLabel = g_lo_menu_get_label_from_item_in_section( G_LO_MENU( mpMenuModel ), nSection, nItemPos );
533 if ( aLabel == NULL || g_strcmp0( aLabel, aConvertedText.getStr() ) != 0 )
534 g_lo_menu_set_label_to_item_in_section( G_LO_MENU( mpMenuModel ), nSection, nItemPos, aConvertedText.getStr() );
536 if ( aLabel )
537 g_free( aLabel );
540 void GtkSalMenu::NativeSetAccelerator( unsigned nSection, unsigned nItemPos, const vcl::KeyCode& rKeyCode, const OUString& rKeyName )
542 SolarMutexGuard aGuard;
544 if ( rKeyName.isEmpty() )
545 return;
547 guint nKeyCode;
548 GdkModifierType nModifiers;
549 GtkSalFrame::KeyCodeToGdkKey(rKeyCode, &nKeyCode, &nModifiers);
551 gchar* aAccelerator = gtk_accelerator_name( nKeyCode, nModifiers );
553 gchar* aCurrentAccel = g_lo_menu_get_accelerator_from_item_in_section( G_LO_MENU( mpMenuModel ), nSection, nItemPos );
555 if ( aCurrentAccel == NULL && g_strcmp0( aCurrentAccel, aAccelerator ) != 0 )
556 g_lo_menu_set_accelerator_to_item_in_section ( G_LO_MENU( mpMenuModel ), nSection, nItemPos, aAccelerator );
558 g_free( aAccelerator );
559 g_free( aCurrentAccel );
562 void GtkSalMenu::NativeSetItemCommand( unsigned nSection,
563 unsigned nItemPos,
564 sal_uInt16 nId,
565 const gchar* aCommand,
566 MenuItemBits nBits,
567 gboolean bChecked,
568 gboolean bIsSubmenu )
570 SolarMutexGuard aGuard;
571 GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( mpActionGroup );
573 GVariant *pTarget = NULL;
575 if ( g_action_group_has_action( mpActionGroup, aCommand ) == FALSE ) {
576 if ( ( nBits & MenuItemBits::CHECKABLE ) || bIsSubmenu )
578 // Item is a checkmark button.
579 GVariantType* pStateType = g_variant_type_new( reinterpret_cast<gchar const *>(G_VARIANT_TYPE_BOOLEAN) );
580 GVariant* pState = g_variant_new_boolean( bChecked );
582 g_lo_action_group_insert_stateful( pActionGroup, aCommand, nId, bIsSubmenu, NULL, pStateType, NULL, pState );
584 else if ( nBits & MenuItemBits::RADIOCHECK )
586 // Item is a radio button.
587 GVariantType* pParameterType = g_variant_type_new( reinterpret_cast<gchar const *>(G_VARIANT_TYPE_STRING) );
588 GVariantType* pStateType = g_variant_type_new( reinterpret_cast<gchar const *>(G_VARIANT_TYPE_STRING) );
589 GVariant* pState = g_variant_new_string( "" );
590 pTarget = g_variant_new_string( aCommand );
592 g_lo_action_group_insert_stateful( pActionGroup, aCommand, nId, FALSE, pParameterType, pStateType, NULL, pState );
594 else
596 // Item is not special, so insert a stateless action.
597 g_lo_action_group_insert( pActionGroup, aCommand, nId, FALSE );
601 GLOMenu* pMenu = G_LO_MENU( mpMenuModel );
603 // Menu item is not updated unless it's necessary.
604 gchar* aCurrentCommand = g_lo_menu_get_command_from_item_in_section( pMenu, nSection, nItemPos );
606 if ( aCurrentCommand == NULL || g_strcmp0( aCurrentCommand, aCommand ) != 0 )
608 g_lo_menu_set_command_to_item_in_section( pMenu, nSection, nItemPos, aCommand );
610 gchar* aItemCommand = g_strconcat("win.", aCommand, NULL );
612 if ( bIsSubmenu )
613 g_lo_menu_set_submenu_action_to_item_in_section( pMenu, nSection, nItemPos, aItemCommand );
614 else
615 g_lo_menu_set_action_and_target_value_to_item_in_section( pMenu, nSection, nItemPos, aItemCommand, pTarget );
617 g_free( aItemCommand );
620 if ( aCurrentCommand )
621 g_free( aCurrentCommand );
624 GtkSalMenu* GtkSalMenu::GetMenuForItemCommand( gchar* aCommand, gboolean bGetSubmenu )
626 SolarMutexGuard aGuard;
627 GtkSalMenu* pMenu = NULL;
628 for ( sal_uInt16 nPos = 0; nPos < maItems.size(); nPos++ )
630 GtkSalMenuItem *pSalItem = maItems[ nPos ];
632 OUString aItemCommand = mpVCLMenu->GetItemCommand( pSalItem->mnId );
633 // Do not join the following two lines, or the OString will be destroyed
634 // immediately, and the gchar* pointed to by aItemCommandStr will be
635 // freed before it can be used - fdo#69090
636 OString aItemCommandOStr = OUStringToOString( aItemCommand, RTL_TEXTENCODING_UTF8 );
637 gchar* aItemCommandStr = const_cast<gchar*>(aItemCommandOStr.getStr());
639 if ( g_strcmp0( aItemCommandStr, aCommand ) == 0 )
641 pMenu = bGetSubmenu ? pSalItem->mpSubMenu : this;
642 break;
644 else
646 if ( pSalItem->mpSubMenu != NULL )
647 pMenu = pSalItem->mpSubMenu->GetMenuForItemCommand( aCommand, bGetSubmenu );
649 if ( pMenu != NULL )
650 break;
654 return pMenu;
657 void GtkSalMenu::DispatchCommand( gint itemId, const gchar *aCommand )
659 SolarMutexGuard aGuard;
660 // Only the menubar is allowed to dispatch commands.
661 if ( !mbMenuBar )
662 return;
664 GtkSalMenu* pSalSubMenu = GetMenuForItemCommand( const_cast<gchar*>(aCommand), FALSE );
665 Menu* pSubMenu = ( pSalSubMenu != NULL ) ? pSalSubMenu->GetMenu() : NULL;
667 MenuBar* pMenuBar = static_cast< MenuBar* >( mpVCLMenu );
668 pMenuBar->HandleMenuCommandEvent( pSubMenu, itemId );
671 void GtkSalMenu::ActivateAllSubmenus(MenuBar* pMenuBar)
673 pMenuBar->HandleMenuActivateEvent(mpVCLMenu);
674 for ( sal_uInt16 nPos = 0; nPos < maItems.size(); nPos++ )
676 GtkSalMenuItem *pSalItem = maItems[ nPos ];
677 if ( pSalItem->mpSubMenu != NULL )
679 pSalItem->mpSubMenu->ActivateAllSubmenus(pMenuBar);
680 pSalItem->mpSubMenu->Update();
685 void GtkSalMenu::Activate()
687 if ( !mbMenuBar )
688 return;
689 ActivateAllSubmenus(static_cast<MenuBar*>(mpVCLMenu));
692 void GtkSalMenu::Deactivate( const gchar* aMenuCommand )
694 if ( !mbMenuBar )
695 return;
697 GtkSalMenu* pSalSubMenu = GetMenuForItemCommand( const_cast<gchar*>(aMenuCommand), TRUE );
699 if ( pSalSubMenu != NULL ) {
700 MenuBar* pMenuBar = static_cast< MenuBar* >( mpVCLMenu );
701 pMenuBar->HandleMenuDeActivateEvent( pSalSubMenu->mpVCLMenu );
705 void GtkSalMenu::Display( bool bVisible )
707 if ( !mbMenuBar || mpVCLMenu == NULL )
708 return;
710 bMenuVisibility = bVisible;
712 bool bVCLMenuVisible = !bVisible;
714 MenuBar* pMenuBar = static_cast< MenuBar* >( mpVCLMenu );
715 pMenuBar->SetDisplayable( bVCLMenuVisible );
718 bool GtkSalMenu::IsItemVisible( unsigned nPos )
720 SolarMutexGuard aGuard;
721 bool bVisible = false;
723 if ( nPos < maItems.size() )
724 bVisible = ( ( GtkSalMenuItem* ) maItems[ nPos ])->mbVisible;
726 return bVisible;
729 void GtkSalMenu::CheckItem( unsigned, bool )
733 void GtkSalMenu::EnableItem( unsigned, bool )
737 void GtkSalMenu::ShowItem( unsigned nPos, bool bShow )
739 SolarMutexGuard aGuard;
740 if ( nPos < maItems.size() )
741 ( ( GtkSalMenuItem* ) maItems[ nPos ] )->mbVisible = bShow;
744 void GtkSalMenu::SetItemText( unsigned, SalMenuItem*, const OUString& )
748 void GtkSalMenu::SetItemImage( unsigned, SalMenuItem*, const Image& )
752 void GtkSalMenu::SetAccelerator( unsigned, SalMenuItem*, const vcl::KeyCode&, const OUString& )
756 void GtkSalMenu::GetSystemMenuData( SystemMenuData* )
761 * GtkSalMenuItem
764 GtkSalMenuItem::GtkSalMenuItem( const SalItemParams* pItemData ) :
765 mnId( pItemData->nId ),
766 mnType( pItemData->eType ),
767 mbVisible( true ),
768 mpVCLMenu( pItemData->pMenu ),
769 mpParentMenu( NULL ),
770 mpSubMenu( NULL )
774 GtkSalMenuItem::~GtkSalMenuItem()
778 #endif
780 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */