1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
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>
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
);
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 ) )
66 aCommand
= g_strdup_printf("%s%d", aCommandStr
, i
);
69 g_free( aCommandStr
);
75 bool GtkSalMenu::PrepUpdate()
77 const GtkSalFrame
* pFrame
= GetFrame();
80 GtkSalFrame
* pNonConstFrame
= const_cast<GtkSalFrame
*>(pFrame
);
81 GtkSalMenu
* pSalMenu
= this;
83 if ( !pNonConstFrame
->GetMenu() )
84 pNonConstFrame
->SetMenu( pSalMenu
);
86 if ( bMenuVisibility
&& mpMenuModel
&& mpActionGroup
)
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
) );
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
)
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
);
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");
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;
198 for ( nItem
= 0; nItem
< ( sal_Int32
) GetItemCount(); nItem
++ ) {
199 if ( !IsItemVisible( nItem
) )
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
);
214 if ( nLOMenuSize
<= nSection
)
216 g_lo_menu_new_section( pLOMenu
, nSection
, NULL
);
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
);
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
);
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()
302 void GtkSalMenu::UpdateFull()
311 GtkSalMenu::GtkSalMenu( bool bMenuBar
) :
312 mbMenuBar( bMenuBar
),
314 mpParentSalMenu( NULL
),
317 mpActionGroup( NULL
)
321 GtkSalMenu::~GtkSalMenu()
323 SolarMutexGuard aGuard
;
329 // g_lo_menu_remove( G_LO_MENU( mpMenuModel ), 0 );
330 g_object_unref( mpMenuModel
);
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
);
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
)
370 pGtkSubMenu
->mpParentSalMenu
= this;
371 pItem
->mpSubMenu
= pGtkSubMenu
;
374 static bool bInvalidMenus
= false;
375 static gboolean
RefreshMenusUnity(gpointer
)
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());
387 pSalMenu
->Activate();
388 pSalMenu
->UpdateFull();
391 bInvalidMenus
= false;
395 static long RefreshMenusUnity(void*, void*)
398 g_timeout_add(10, &RefreshMenusUnity
, NULL
);
399 bInvalidMenus
= true;
404 static Link
<>* getRefreshLinkInstance()
406 static Link
<>* pLink
= NULL
;
408 pLink
= new Link
<>(NULL
, &RefreshMenusUnity
);
413 void GtkSalMenu::SetFrame( const SalFrame
* pFrame
)
415 SolarMutexGuard aGuard
;
417 vcl::MenuInvalidator::GetMenuInvalidateListeners()->addListener(*getRefreshLinkInstance());
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
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
);
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() );
449 g_lo_action_group_clear( pActionGroup
);
450 mpActionGroup
= G_ACTION_GROUP( pActionGroup
);
453 // Generate the main menu structure.
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
)
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( "" );
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
);
500 g_variant_unref (pCheckValue
);
504 if ( pCurrentState
!= NULL
)
505 g_variant_unref( pCurrentState
);
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() );
540 void GtkSalMenu::NativeSetAccelerator( unsigned nSection
, unsigned nItemPos
, const vcl::KeyCode
& rKeyCode
, const OUString
& rKeyName
)
542 SolarMutexGuard aGuard
;
544 if ( rKeyName
.isEmpty() )
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
,
565 const gchar
* aCommand
,
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
);
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
);
613 g_lo_menu_set_submenu_action_to_item_in_section( pMenu
, nSection
, nItemPos
, aItemCommand
);
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;
646 if ( pSalItem
->mpSubMenu
!= NULL
)
647 pMenu
= pSalItem
->mpSubMenu
->GetMenuForItemCommand( aCommand
, bGetSubmenu
);
657 void GtkSalMenu::DispatchCommand( gint itemId
, const gchar
*aCommand
)
659 SolarMutexGuard aGuard
;
660 // Only the menubar is allowed to dispatch commands.
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()
689 ActivateAllSubmenus(static_cast<MenuBar
*>(mpVCLMenu
));
692 void GtkSalMenu::Deactivate( const gchar
* aMenuCommand
)
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
)
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
;
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
* )
764 GtkSalMenuItem::GtkSalMenuItem( const SalItemParams
* pItemData
) :
765 mnId( pItemData
->nId
),
766 mnType( pItemData
->eType
),
768 mpVCLMenu( pItemData
->pMenu
),
769 mpParentMenu( NULL
),
774 GtkSalMenuItem::~GtkSalMenuItem()
780 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */