LCOV - code coverage report
Current view: top level - vcl/unx/gtk/window - gtksalmenu.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 62 440 14.1 %
Date: 2015-06-13 12:38:46 Functions: 16 46 34.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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             :  */
       9             : 
      10             : #include <unx/gtk/gtksalmenu.hxx>
      11             : 
      12             : #ifdef ENABLE_GMENU_INTEGRATION
      13             : 
      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>
      20             : 
      21             : #if GTK_CHECK_VERSION(3,0,0)
      22             : #  include <gdk/gdkkeysyms-compat.h>
      23             : #endif
      24             : 
      25             : #include <sal/log.hxx>
      26             : 
      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;
      32             : 
      33             : static bool bMenuVisibility = false;
      34             : 
      35             : /*
      36             :  * This function generates the proper command name for all actions, including
      37             :  * duplicated or special ones.
      38             :  */
      39           0 : static gchar* GetCommandForItem( GtkSalMenuItem* pSalMenuItem, gchar* aCurrentCommand, GActionGroup* pActionGroup )
      40             : {
      41           0 :     gchar* aCommand = NULL;
      42             : 
      43           0 :     sal_uInt16 nId = pSalMenuItem->mnId;
      44           0 :     Menu* pMenu = pSalMenuItem->mpVCLMenu;
      45             : 
      46             :     // If item belongs to window list, generate a command with "window-(id)" format.
      47           0 :     if ( ( nId >= START_ITEMID_WINDOWLIST ) && ( nId <= END_ITEMID_WINDOWLIST ) )
      48           0 :         aCommand = g_strdup_printf( "window-%d", nId );
      49             :     else
      50             :     {
      51           0 :         if ( !pMenu )
      52           0 :             return NULL;
      53             : 
      54           0 :         OUString aMenuCommand = pMenu->GetItemCommand( nId );
      55           0 :         gchar* aCommandStr = g_strdup( OUStringToOString( aMenuCommand, RTL_TEXTENCODING_UTF8 ).getStr() );
      56           0 :         aCommand = g_strdup( aCommandStr );
      57             : 
      58             :         // Some items could have duplicated commands. A new one should be generated.
      59           0 :         for ( sal_uInt16 i = 2; ; i++ )
      60             :         {
      61           0 :             if ( !g_action_group_has_action( pActionGroup, aCommand )
      62           0 :                     || ( aCurrentCommand && g_strcmp0( aCurrentCommand, aCommand ) == 0 ) )
      63           0 :                 break;
      64             : 
      65           0 :             g_free( aCommand );
      66           0 :             aCommand = g_strdup_printf("%s%d", aCommandStr, i);
      67           0 :         }
      68             : 
      69           0 :         g_free( aCommandStr );
      70             :     }
      71             : 
      72           0 :     return aCommand;
      73             : }
      74             : 
      75           0 : static void KeyCodeToGdkKey ( const vcl::KeyCode& rKeyCode, guint* pGdkKeyCode, GdkModifierType *pGdkModifiers )
      76             : {
      77           0 :     if ( pGdkKeyCode == NULL || pGdkModifiers == NULL )
      78           0 :         return;
      79             : 
      80             :     // Get GDK key modifiers
      81           0 :     GdkModifierType nModifiers = (GdkModifierType) 0;
      82             : 
      83           0 :     if ( rKeyCode.IsShift() )
      84           0 :         nModifiers = (GdkModifierType) ( nModifiers | GDK_SHIFT_MASK );
      85             : 
      86           0 :     if ( rKeyCode.IsMod1() )
      87           0 :         nModifiers = (GdkModifierType) ( nModifiers | GDK_CONTROL_MASK );
      88             : 
      89           0 :     if ( rKeyCode.IsMod2() )
      90           0 :         nModifiers = (GdkModifierType) ( nModifiers | GDK_MOD1_MASK );
      91             : 
      92           0 :     *pGdkModifiers = nModifiers;
      93             : 
      94             :     // Get GDK keycode.
      95           0 :     guint nKeyCode = 0;
      96             : 
      97           0 :     guint nCode = rKeyCode.GetCode();
      98             : 
      99           0 :     if ( nCode >= KEY_0 && nCode <= KEY_9 )
     100           0 :         nKeyCode = ( nCode - KEY_0 ) + GDK_0;
     101           0 :     else if ( nCode >= KEY_A && nCode <= KEY_Z )
     102           0 :         nKeyCode = ( nCode - KEY_A ) + GDK_A;
     103           0 :     else if ( nCode >= KEY_F1 && nCode <= KEY_F26 )
     104           0 :         nKeyCode = ( nCode - KEY_F1 ) + GDK_F1;
     105             :     else
     106             :     {
     107           0 :         switch( nCode )
     108             :         {
     109           0 :         case KEY_DOWN:          nKeyCode = GDK_Down;            break;
     110           0 :         case KEY_UP:            nKeyCode = GDK_Up;              break;
     111           0 :         case KEY_LEFT:          nKeyCode = GDK_Left;            break;
     112           0 :         case KEY_RIGHT:         nKeyCode = GDK_Right;           break;
     113           0 :         case KEY_HOME:          nKeyCode = GDK_Home;            break;
     114           0 :         case KEY_END:           nKeyCode = GDK_End;             break;
     115           0 :         case KEY_PAGEUP:        nKeyCode = GDK_Page_Up;         break;
     116           0 :         case KEY_PAGEDOWN:      nKeyCode = GDK_Page_Down;       break;
     117           0 :         case KEY_RETURN:        nKeyCode = GDK_Return;          break;
     118           0 :         case KEY_ESCAPE:        nKeyCode = GDK_Escape;          break;
     119           0 :         case KEY_TAB:           nKeyCode = GDK_Tab;             break;
     120           0 :         case KEY_BACKSPACE:     nKeyCode = GDK_BackSpace;       break;
     121           0 :         case KEY_SPACE:         nKeyCode = GDK_space;           break;
     122           0 :         case KEY_INSERT:        nKeyCode = GDK_Insert;          break;
     123           0 :         case KEY_DELETE:        nKeyCode = GDK_Delete;          break;
     124           0 :         case KEY_ADD:           nKeyCode = GDK_plus;            break;
     125           0 :         case KEY_SUBTRACT:      nKeyCode = GDK_minus;           break;
     126           0 :         case KEY_MULTIPLY:      nKeyCode = GDK_asterisk;        break;
     127           0 :         case KEY_DIVIDE:        nKeyCode = GDK_slash;           break;
     128           0 :         case KEY_POINT:         nKeyCode = GDK_period;          break;
     129           0 :         case KEY_COMMA:         nKeyCode = GDK_comma;           break;
     130           0 :         case KEY_LESS:          nKeyCode = GDK_less;            break;
     131           0 :         case KEY_GREATER:       nKeyCode = GDK_greater;         break;
     132           0 :         case KEY_EQUAL:         nKeyCode = GDK_equal;           break;
     133           0 :         case KEY_FIND:          nKeyCode = GDK_Find;            break;
     134           0 :         case KEY_CONTEXTMENU:   nKeyCode = GDK_Menu;            break;
     135           0 :         case KEY_HELP:          nKeyCode = GDK_Help;            break;
     136           0 :         case KEY_UNDO:          nKeyCode = GDK_Undo;            break;
     137           0 :         case KEY_REPEAT:        nKeyCode = GDK_Redo;            break;
     138           0 :         case KEY_DECIMAL:       nKeyCode = GDK_KP_Decimal;      break;
     139           0 :         case KEY_TILDE:         nKeyCode = GDK_asciitilde;      break;
     140           0 :         case KEY_QUOTELEFT:     nKeyCode = GDK_quoteleft;       break;
     141           0 :         case KEY_BRACKETLEFT:   nKeyCode = GDK_bracketleft;     break;
     142           0 :         case KEY_BRACKETRIGHT:  nKeyCode = GDK_bracketright;    break;
     143           0 :         case KEY_SEMICOLON:     nKeyCode = GDK_semicolon;       break;
     144           0 :         case KEY_QUOTERIGHT:    nKeyCode = GDK_quoteright;      break;
     145             : 
     146             :         // Special cases
     147           0 :         case KEY_COPY:          nKeyCode = GDK_Copy;            break;
     148           0 :         case KEY_CUT:           nKeyCode = GDK_Cut;             break;
     149           0 :         case KEY_PASTE:         nKeyCode = GDK_Paste;           break;
     150           0 :         case KEY_OPEN:          nKeyCode = GDK_Open;            break;
     151             :         }
     152             :     }
     153             : 
     154           0 :     *pGdkKeyCode = nKeyCode;
     155             : }
     156             : 
     157           0 : bool GtkSalMenu::PrepUpdate()
     158             : {
     159           0 :     const GtkSalFrame* pFrame = GetFrame();
     160           0 :     if (pFrame)
     161             :     {
     162           0 :         GtkSalFrame* pNonConstFrame = const_cast<GtkSalFrame*>(pFrame);
     163           0 :         GtkSalMenu* pSalMenu = this;
     164             : 
     165           0 :         if ( !pNonConstFrame->GetMenu() )
     166           0 :             pNonConstFrame->SetMenu( pSalMenu );
     167             : 
     168           0 :         if ( bMenuVisibility && mpMenuModel && mpActionGroup )
     169           0 :             return true;
     170             :     }
     171             : 
     172           0 :     return false;
     173             : }
     174             : 
     175             : /*
     176             :  * Menu updating methods
     177             :  */
     178             : 
     179           0 : void RemoveSpareItemsFromNativeMenu( GLOMenu* pMenu, GList** pOldCommandList, unsigned nSection, unsigned nValidItems )
     180             : {
     181           0 :     sal_Int32 nSectionItems = g_lo_menu_get_n_items_from_section( pMenu, nSection );
     182             : 
     183           0 :     while ( nSectionItems > (sal_Int32) nValidItems )
     184             :     {
     185           0 :         gchar* aCommand = g_lo_menu_get_command_from_item_in_section( pMenu, nSection, --nSectionItems );
     186             : 
     187           0 :         if ( aCommand != NULL && pOldCommandList != NULL )
     188           0 :             *pOldCommandList = g_list_append( *pOldCommandList, g_strdup( aCommand ) );
     189             : 
     190           0 :         g_free( aCommand );
     191             : 
     192           0 :         g_lo_menu_remove_from_section( pMenu, nSection, nSectionItems );
     193             :     }
     194           0 : }
     195             : 
     196           0 : void RemoveSpareSectionsFromNativeMenu( GLOMenu* pMenu, GList** pOldCommandList, unsigned nLastSection )
     197             : {
     198           0 :     if ( pMenu == NULL || pOldCommandList == NULL )
     199           0 :         return;
     200             : 
     201           0 :     sal_Int32 n = g_menu_model_get_n_items( G_MENU_MODEL( pMenu ) ) - 1;
     202             : 
     203           0 :     for ( ; n > (sal_Int32) nLastSection; n-- )
     204             :     {
     205           0 :         RemoveSpareItemsFromNativeMenu( pMenu, pOldCommandList, n, 0 );
     206           0 :         g_lo_menu_remove( pMenu, n );
     207             :     }
     208             : }
     209             : 
     210           0 : gint CompareStr( gpointer str1, gpointer str2 )
     211             : {
     212           0 :     return g_strcmp0( static_cast<const gchar*>(str1), static_cast<const gchar*>(str2) );
     213             : }
     214             : 
     215           0 : void RemoveUnusedCommands( GLOActionGroup* pActionGroup, GList* pOldCommandList, GList* pNewCommandList )
     216             : {
     217           0 :     if ( pActionGroup == NULL || pOldCommandList == NULL )
     218             :     {
     219           0 :         g_list_free_full( pOldCommandList, g_free );
     220           0 :         g_list_free_full( pNewCommandList, g_free );
     221           0 :         return;
     222             :     }
     223             : 
     224           0 :     while ( pNewCommandList != NULL )
     225             :     {
     226           0 :         GList* pNewCommand = g_list_first( pNewCommandList );
     227           0 :         pNewCommandList = g_list_remove_link( pNewCommandList, pNewCommand );
     228             : 
     229           0 :         gpointer aCommand = g_list_nth_data( pNewCommand, 0 );
     230             : 
     231           0 :         GList* pOldCommand = g_list_find_custom( pOldCommandList, aCommand, reinterpret_cast<GCompareFunc>(CompareStr) );
     232             : 
     233           0 :         if ( pOldCommand != NULL )
     234             :         {
     235           0 :             pOldCommandList = g_list_remove_link( pOldCommandList, pOldCommand );
     236           0 :             g_list_free_full( pOldCommand, g_free );
     237             :         }
     238             : 
     239           0 :         g_list_free_full( pNewCommand, g_free );
     240             :     }
     241             : 
     242           0 :     while ( pOldCommandList != NULL )
     243             :     {
     244           0 :         GList* pCommand = g_list_first( pOldCommandList );
     245           0 :         pOldCommandList = g_list_remove_link( pOldCommandList, pCommand );
     246             : 
     247           0 :         gchar* aCommand = static_cast<gchar*>(g_list_nth_data( pCommand, 0 ));
     248             : 
     249           0 :         g_lo_action_group_remove( pActionGroup, aCommand );
     250             : 
     251           0 :         g_list_free_full( pCommand, g_free );
     252             :     }
     253             : }
     254             : 
     255           0 : void GtkSalMenu::ImplUpdate( gboolean bRecurse )
     256             : {
     257           0 :     SolarMutexGuard aGuard;
     258             : 
     259             :     SAL_INFO("vcl.unity", "ImplUpdate pre PrepUpdate");
     260           0 :     if( !PrepUpdate() )
     261           0 :         return;
     262             : 
     263           0 :     Menu* pVCLMenu = mpVCLMenu;
     264           0 :     GLOMenu* pLOMenu = G_LO_MENU( mpMenuModel );
     265           0 :     GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( mpActionGroup );
     266             :     SAL_INFO("vcl.unity", "Syncing vcl menu " << pVCLMenu << " to menu model " << pLOMenu << " and action group " << pActionGroup);
     267           0 :     GList *pOldCommandList = NULL;
     268           0 :     GList *pNewCommandList = NULL;
     269             : 
     270           0 :     sal_uInt16 nLOMenuSize = g_menu_model_get_n_items( G_MENU_MODEL( pLOMenu ) );
     271             : 
     272           0 :     if ( nLOMenuSize == 0 )
     273           0 :         g_lo_menu_new_section( pLOMenu, 0, NULL );
     274             : 
     275           0 :     sal_Int32 nSection = 0;
     276           0 :     sal_Int32 nItemPos = 0;
     277           0 :     sal_Int32 validItems = 0;
     278             :     sal_Int32 nItem;
     279             : 
     280           0 :     for ( nItem = 0; nItem < ( sal_Int32 ) GetItemCount(); nItem++ ) {
     281           0 :         if ( !IsItemVisible( nItem ) )
     282           0 :             continue;
     283             : 
     284           0 :         GtkSalMenuItem *pSalMenuItem = GetItemAtPos( nItem );
     285           0 :         sal_uInt16 nId = pSalMenuItem->mnId;
     286             : 
     287           0 :         if ( pSalMenuItem->mnType == MenuItemType::SEPARATOR )
     288             :         {
     289             :             // Delete extra items from current section.
     290           0 :             RemoveSpareItemsFromNativeMenu( pLOMenu, &pOldCommandList, nSection, validItems );
     291             : 
     292           0 :             nSection++;
     293           0 :             nItemPos = 0;
     294           0 :             validItems = 0;
     295             : 
     296           0 :             if ( nLOMenuSize <= nSection )
     297             :             {
     298           0 :                 g_lo_menu_new_section( pLOMenu, nSection, NULL );
     299           0 :                 nLOMenuSize++;
     300             :             }
     301             : 
     302           0 :             continue;
     303             :         }
     304             : 
     305           0 :         if ( nItemPos >= g_lo_menu_get_n_items_from_section( pLOMenu, nSection ) )
     306           0 :             g_lo_menu_insert_in_section( pLOMenu, nSection, nItemPos, "EMPTY STRING" );
     307             : 
     308             :         // Get internal menu item values.
     309           0 :         OUString aText = pVCLMenu->GetItemText( nId );
     310           0 :         bool bEnabled = pVCLMenu->IsItemEnabled( nId );
     311           0 :         vcl::KeyCode nAccelKey = pVCLMenu->GetAccelKey( nId );
     312           0 :         bool bChecked = pVCLMenu->IsItemChecked( nId );
     313           0 :         MenuItemBits itemBits = pVCLMenu->GetItemBits( nId );
     314             : 
     315             :         // Store current item command in command list.
     316           0 :         gchar *aCurrentCommand = g_lo_menu_get_command_from_item_in_section( pLOMenu, nSection, nItemPos );
     317             : 
     318           0 :         if ( aCurrentCommand != NULL )
     319           0 :             pOldCommandList = g_list_append( pOldCommandList, aCurrentCommand );
     320             : 
     321             :         // Get the new command for the item.
     322           0 :         gchar* aNativeCommand = GetCommandForItem( pSalMenuItem, aCurrentCommand, mpActionGroup );
     323             : 
     324             :         // Force updating of native menu labels.
     325           0 :         NativeSetItemText( nSection, nItemPos, aText );
     326           0 :         NativeSetAccelerator( nSection, nItemPos, nAccelKey, nAccelKey.GetName( GetFrame()->GetWindow() ) );
     327             : 
     328           0 :         if ( g_strcmp0( aNativeCommand, "" ) != 0 && pSalMenuItem->mpSubMenu == NULL )
     329             :         {
     330           0 :             NativeSetItemCommand( nSection, nItemPos, nId, aNativeCommand, itemBits, bChecked, FALSE );
     331           0 :             NativeCheckItem( nSection, nItemPos, itemBits, bChecked );
     332           0 :             NativeSetEnableItem( aNativeCommand, bEnabled );
     333             : 
     334           0 :             pNewCommandList = g_list_append( pNewCommandList, g_strdup( aNativeCommand ) );
     335             :         }
     336             : 
     337           0 :         GtkSalMenu* pSubmenu = pSalMenuItem->mpSubMenu;
     338             : 
     339           0 :         if ( pSubmenu && pSubmenu->GetMenu() )
     340             :         {
     341           0 :             NativeSetItemCommand( nSection, nItemPos, nId, aNativeCommand, itemBits, FALSE, TRUE );
     342           0 :             pNewCommandList = g_list_append( pNewCommandList, g_strdup( aNativeCommand ) );
     343             : 
     344           0 :             GLOMenu* pSubMenuModel = g_lo_menu_get_submenu_from_item_in_section( pLOMenu, nSection, nItemPos );
     345             : 
     346           0 :             if ( pSubMenuModel == NULL )
     347             :             {
     348           0 :                 g_lo_menu_new_submenu_in_item_in_section( pLOMenu, nSection, nItemPos );
     349           0 :                 pSubMenuModel = g_lo_menu_get_submenu_from_item_in_section( pLOMenu, nSection, nItemPos );
     350             :             }
     351             : 
     352           0 :             g_object_unref( pSubMenuModel );
     353             : 
     354           0 :             if ( bRecurse )
     355             :             {
     356             :                 SAL_INFO("vcl.unity", "preparing submenu  " << pSubMenuModel << " to menu model " << G_MENU_MODEL(pSubMenuModel) << " and action group " << G_ACTION_GROUP(pActionGroup));
     357           0 :                 pSubmenu->SetMenuModel( G_MENU_MODEL( pSubMenuModel ) );
     358           0 :                 pSubmenu->SetActionGroup( G_ACTION_GROUP( pActionGroup ) );
     359           0 :                 pSubmenu->ImplUpdate( bRecurse );
     360             :             }
     361             :         }
     362             : 
     363           0 :         g_free( aNativeCommand );
     364             : 
     365           0 :         ++nItemPos;
     366           0 :         ++validItems;
     367           0 :     }
     368             : 
     369             :     // Delete extra items in last section.
     370           0 :     RemoveSpareItemsFromNativeMenu( pLOMenu, &pOldCommandList, nSection, validItems );
     371             : 
     372             :     // Delete extra sections.
     373           0 :     RemoveSpareSectionsFromNativeMenu( pLOMenu, &pOldCommandList, nSection );
     374             : 
     375             :     // Delete unused commands.
     376           0 :     RemoveUnusedCommands( pActionGroup, pOldCommandList, pNewCommandList );
     377             : }
     378             : 
     379           0 : void GtkSalMenu::Update()
     380             : {
     381           0 :     ImplUpdate( FALSE );
     382           0 : }
     383             : 
     384           0 : void GtkSalMenu::UpdateFull()
     385             : {
     386           0 :     ImplUpdate( TRUE );
     387           0 : }
     388             : 
     389             : /*
     390             :  * GtkSalMenu
     391             :  */
     392             : 
     393          43 : GtkSalMenu::GtkSalMenu( bool bMenuBar ) :
     394             :     mbMenuBar( bMenuBar ),
     395             :     mpVCLMenu( NULL ),
     396             :     mpParentSalMenu( NULL ),
     397             :     mpFrame( NULL ),
     398             :     mpMenuModel( NULL ),
     399          43 :     mpActionGroup( NULL )
     400             : {
     401          43 : }
     402             : 
     403         126 : GtkSalMenu::~GtkSalMenu()
     404             : {
     405          42 :     SolarMutexGuard aGuard;
     406             : 
     407          42 :     if ( mbMenuBar )
     408             :     {
     409           2 :         if ( mpMenuModel )
     410             :         {
     411             : //            g_lo_menu_remove( G_LO_MENU( mpMenuModel ), 0 );
     412           2 :             g_object_unref( mpMenuModel );
     413             :         }
     414             :     }
     415             : 
     416          42 :     maItems.clear();
     417          84 : }
     418             : 
     419           4 : bool GtkSalMenu::VisibleMenuBar()
     420             : {
     421           4 :     return bMenuVisibility;
     422             : }
     423             : 
     424         136 : void GtkSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos )
     425             : {
     426         136 :     SolarMutexGuard aGuard;
     427         136 :     GtkSalMenuItem *pItem = static_cast<GtkSalMenuItem*>( pSalMenuItem );
     428             : 
     429         136 :     if ( nPos == MENU_APPEND )
     430         136 :         maItems.push_back( pItem );
     431             :     else
     432           0 :         maItems.insert( maItems.begin() + nPos, pItem );
     433             : 
     434         136 :     pItem->mpParentMenu = this;
     435         136 : }
     436             : 
     437           0 : void GtkSalMenu::RemoveItem( unsigned nPos )
     438             : {
     439           0 :     SolarMutexGuard aGuard;
     440           0 :     maItems.erase( maItems.begin() + nPos );
     441           0 : }
     442             : 
     443          24 : void GtkSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned )
     444             : {
     445          24 :     SolarMutexGuard aGuard;
     446          24 :     GtkSalMenuItem *pItem = static_cast< GtkSalMenuItem* >( pSalMenuItem );
     447          24 :     GtkSalMenu *pGtkSubMenu = static_cast< GtkSalMenu* >( pSubMenu );
     448             : 
     449          24 :     if ( pGtkSubMenu == NULL )
     450          29 :         return;
     451             : 
     452          19 :     pGtkSubMenu->mpParentSalMenu = this;
     453          19 :     pItem->mpSubMenu = pGtkSubMenu;
     454             : }
     455             : 
     456             : static bool bInvalidMenus = false;
     457           0 : static gboolean RefreshMenusUnity(gpointer)
     458             : {
     459           0 :     SolarMutexGuard g;
     460             : 
     461           0 :     SalDisplay* pSalDisplay = vcl_sal::getSalDisplay(GetGenericData());
     462           0 :     std::list< SalFrame* >::const_iterator pSalFrame = pSalDisplay->getFrames().begin();
     463           0 :     std::list< SalFrame* >::const_iterator pEndSalFrame = pSalDisplay->getFrames().end();
     464           0 :     for(; pSalFrame != pEndSalFrame; ++pSalFrame) {
     465           0 :         const GtkSalFrame* pGtkSalFrame = static_cast< const GtkSalFrame* >( *pSalFrame );
     466           0 :         GtkSalFrame* pFrameNonConst = const_cast<GtkSalFrame*>(pGtkSalFrame);
     467           0 :         GtkSalMenu* pSalMenu = static_cast<GtkSalMenu*>(pFrameNonConst->GetMenu());
     468           0 :         if(pSalMenu) {
     469           0 :             pSalMenu->Activate();
     470           0 :             pSalMenu->UpdateFull();
     471             :         }
     472             :     }
     473           0 :     bInvalidMenus = false;
     474           0 :     return FALSE;
     475             : }
     476             : 
     477           0 : static long RefreshMenusUnity(void*, void*)
     478             : {
     479           0 :     if(!bInvalidMenus) {
     480           0 :         g_timeout_add(10, &RefreshMenusUnity, NULL);
     481           0 :         bInvalidMenus = true;
     482             :     }
     483           0 :     return 0;
     484             : }
     485             : 
     486           2 : static Link<>* getRefreshLinkInstance()
     487             : {
     488             :     static Link<>* pLink = NULL;
     489           2 :     if(!pLink) {
     490           2 :         pLink = new Link<>(NULL, &RefreshMenusUnity);
     491             :     }
     492           2 :     return pLink;
     493             : }
     494             : 
     495           2 : void GtkSalMenu::SetFrame( const SalFrame* pFrame )
     496             : {
     497           2 :     SolarMutexGuard aGuard;
     498             :     {
     499           2 :         vcl::MenuInvalidator::GetMenuInvalidateListeners()->addListener(*getRefreshLinkInstance());
     500             :     }
     501             : 
     502             :     assert(mbMenuBar);
     503             :     SAL_INFO("vcl.unity", "GtkSalMenu set to frame");
     504           2 :     mpFrame = static_cast< const GtkSalFrame* >( pFrame );
     505           2 :     GtkSalFrame* pFrameNonConst = const_cast<GtkSalFrame*>(mpFrame);
     506             : 
     507             :     // if we had a menu on the GtkSalMenu we have to free it as we generate a
     508             :     // full menu anyway and we might need to reuse an existing model and
     509             :     // actiongroup
     510           2 :     pFrameNonConst->SetMenu( this );
     511           2 :     pFrameNonConst->EnsureAppMenuWatch();
     512             : 
     513             :     // Clean menu model and action group if needed.
     514           2 :     GtkWidget* pWidget = pFrameNonConst->getWindow();
     515           2 :     GdkWindow* gdkWindow = gtk_widget_get_window( pWidget );
     516             : 
     517           2 :     GLOMenu* pMenuModel = G_LO_MENU( g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-menubar" ) );
     518           2 :     GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-action-group" ) );
     519             :     SAL_INFO("vcl.unity", "Found menu model: " << pMenuModel << " and action group: " << pActionGroup);
     520             : 
     521           2 :     if ( pMenuModel )
     522             :     {
     523           2 :         if ( g_menu_model_get_n_items( G_MENU_MODEL( pMenuModel ) ) > 0 )
     524           0 :             g_lo_menu_remove( pMenuModel, 0 );
     525             : 
     526           2 :         mpMenuModel = G_MENU_MODEL( g_lo_menu_new() );
     527             :     }
     528             : 
     529           2 :     if ( pActionGroup )
     530             :     {
     531           2 :         g_lo_action_group_clear( pActionGroup );
     532           2 :         mpActionGroup = G_ACTION_GROUP( pActionGroup );
     533             :     }
     534             : 
     535             :     // Generate the main menu structure.
     536           2 :     if (bMenuVisibility)
     537           0 :         UpdateFull();
     538             : 
     539           2 :     g_lo_menu_insert_section( pMenuModel, 0, NULL, mpMenuModel );
     540           2 : }
     541             : 
     542           0 : const GtkSalFrame* GtkSalMenu::GetFrame() const
     543             : {
     544           0 :     SolarMutexGuard aGuard;
     545           0 :     const GtkSalMenu* pMenu = this;
     546           0 :     while( pMenu && ! pMenu->mpFrame )
     547           0 :         pMenu = pMenu->mpParentSalMenu;
     548           0 :     return pMenu ? pMenu->mpFrame : NULL;
     549             : }
     550             : 
     551           0 : void GtkSalMenu::NativeCheckItem( unsigned nSection, unsigned nItemPos, MenuItemBits bits, gboolean bCheck )
     552             : {
     553           0 :     SolarMutexGuard aGuard;
     554             : 
     555           0 :     if ( mpActionGroup == NULL )
     556           0 :         return;
     557             : 
     558           0 :     gchar* aCommand = g_lo_menu_get_command_from_item_in_section( G_LO_MENU( mpMenuModel ), nSection, nItemPos );
     559             : 
     560           0 :     if ( aCommand != NULL || g_strcmp0( aCommand, "" ) != 0 )
     561             :     {
     562           0 :         GVariant *pCheckValue = NULL;
     563           0 :         GVariant *pCurrentState = g_action_group_get_action_state( mpActionGroup, aCommand );
     564             : 
     565           0 :         if ( bits & MenuItemBits::RADIOCHECK )
     566           0 :             pCheckValue = bCheck ? g_variant_new_string( aCommand ) : g_variant_new_string( "" );
     567             :         else
     568             :         {
     569             :             // By default, all checked items are checkmark buttons.
     570           0 :             if ( bCheck || ( !bCheck && pCurrentState != NULL ) )
     571           0 :                 pCheckValue = g_variant_new_boolean( bCheck );
     572             :         }
     573             : 
     574           0 :         if ( pCheckValue != NULL )
     575             :         {
     576           0 :             if ( pCurrentState == NULL || g_variant_equal( pCurrentState, pCheckValue ) == FALSE )
     577             :             {
     578           0 :                 g_action_group_change_action_state( mpActionGroup, aCommand, pCheckValue );
     579             :             }
     580             :             else
     581             :             {
     582           0 :                 g_variant_unref (pCheckValue);
     583             :             }
     584             :         }
     585             : 
     586           0 :         if ( pCurrentState != NULL )
     587           0 :             g_variant_unref( pCurrentState );
     588             :     }
     589             : 
     590           0 :     if ( aCommand )
     591           0 :         g_free( aCommand );
     592             : }
     593             : 
     594           0 : void GtkSalMenu::NativeSetEnableItem( gchar* aCommand, gboolean bEnable )
     595             : {
     596           0 :     SolarMutexGuard aGuard;
     597           0 :     GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( mpActionGroup );
     598             : 
     599           0 :     if ( g_action_group_get_action_enabled( G_ACTION_GROUP( pActionGroup ), aCommand ) != bEnable )
     600           0 :         g_lo_action_group_set_action_enabled( pActionGroup, aCommand, bEnable );
     601           0 : }
     602             : 
     603           0 : void GtkSalMenu::NativeSetItemText( unsigned nSection, unsigned nItemPos, const OUString& rText )
     604             : {
     605           0 :     SolarMutexGuard aGuard;
     606             :     // Escape all underscores so that they don't get interpreted as hotkeys
     607           0 :     OUString aText = rText.replaceAll( "_", "__" );
     608             :     // Replace the LibreOffice hotkey identifier with an underscore
     609           0 :     aText = aText.replace( '~', '_' );
     610           0 :     OString aConvertedText = OUStringToOString( aText, RTL_TEXTENCODING_UTF8 );
     611             : 
     612             :     // Update item text only when necessary.
     613           0 :     gchar* aLabel = g_lo_menu_get_label_from_item_in_section( G_LO_MENU( mpMenuModel ), nSection, nItemPos );
     614             : 
     615           0 :     if ( aLabel == NULL || g_strcmp0( aLabel, aConvertedText.getStr() ) != 0 )
     616           0 :         g_lo_menu_set_label_to_item_in_section( G_LO_MENU( mpMenuModel ), nSection, nItemPos, aConvertedText.getStr() );
     617             : 
     618           0 :     if ( aLabel )
     619           0 :         g_free( aLabel );
     620           0 : }
     621             : 
     622           0 : void GtkSalMenu::NativeSetAccelerator( unsigned nSection, unsigned nItemPos, const vcl::KeyCode& rKeyCode, const OUString& rKeyName )
     623             : {
     624           0 :     SolarMutexGuard aGuard;
     625             : 
     626           0 :     if ( rKeyName.isEmpty() )
     627           0 :         return;
     628             : 
     629             :     guint nKeyCode;
     630             :     GdkModifierType nModifiers;
     631             : 
     632           0 :     KeyCodeToGdkKey( rKeyCode, &nKeyCode, &nModifiers );
     633             : 
     634           0 :     gchar* aAccelerator = gtk_accelerator_name( nKeyCode, nModifiers );
     635             : 
     636           0 :     gchar* aCurrentAccel = g_lo_menu_get_accelerator_from_item_in_section( G_LO_MENU( mpMenuModel ), nSection, nItemPos );
     637             : 
     638           0 :     if ( aCurrentAccel == NULL && g_strcmp0( aCurrentAccel, aAccelerator ) != 0 )
     639           0 :         g_lo_menu_set_accelerator_to_item_in_section ( G_LO_MENU( mpMenuModel ), nSection, nItemPos, aAccelerator );
     640             : 
     641           0 :     g_free( aAccelerator );
     642           0 :     g_free( aCurrentAccel );
     643             : }
     644             : 
     645           0 : void GtkSalMenu::NativeSetItemCommand( unsigned nSection,
     646             :                                        unsigned nItemPos,
     647             :                                        sal_uInt16 nId,
     648             :                                        const gchar* aCommand,
     649             :                                        MenuItemBits nBits,
     650             :                                        gboolean bChecked,
     651             :                                        gboolean bIsSubmenu )
     652             : {
     653           0 :     SolarMutexGuard aGuard;
     654           0 :     GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( mpActionGroup );
     655             : 
     656           0 :     GVariant *pTarget = NULL;
     657             : 
     658           0 :     if ( g_action_group_has_action( mpActionGroup, aCommand ) == FALSE ) {
     659           0 :         if ( ( nBits & MenuItemBits::CHECKABLE ) || bIsSubmenu )
     660             :         {
     661             :             // Item is a checkmark button.
     662           0 :             GVariantType* pStateType = g_variant_type_new( reinterpret_cast<gchar const *>(G_VARIANT_TYPE_BOOLEAN) );
     663           0 :             GVariant* pState = g_variant_new_boolean( bChecked );
     664             : 
     665           0 :             g_lo_action_group_insert_stateful( pActionGroup, aCommand, nId, bIsSubmenu, NULL, pStateType, NULL, pState );
     666             :         }
     667           0 :         else if ( nBits & MenuItemBits::RADIOCHECK )
     668             :         {
     669             :             // Item is a radio button.
     670           0 :             GVariantType* pParameterType = g_variant_type_new( reinterpret_cast<gchar const *>(G_VARIANT_TYPE_STRING) );
     671           0 :             GVariantType* pStateType = g_variant_type_new( reinterpret_cast<gchar const *>(G_VARIANT_TYPE_STRING) );
     672           0 :             GVariant* pState = g_variant_new_string( "" );
     673           0 :             pTarget = g_variant_new_string( aCommand );
     674             : 
     675           0 :             g_lo_action_group_insert_stateful( pActionGroup, aCommand, nId, FALSE, pParameterType, pStateType, NULL, pState );
     676             :         }
     677             :         else
     678             :         {
     679             :             // Item is not special, so insert a stateless action.
     680           0 :             g_lo_action_group_insert( pActionGroup, aCommand, nId, FALSE );
     681             :         }
     682             :     }
     683             : 
     684           0 :     GLOMenu* pMenu = G_LO_MENU( mpMenuModel );
     685             : 
     686             :     // Menu item is not updated unless it's necessary.
     687           0 :     gchar* aCurrentCommand = g_lo_menu_get_command_from_item_in_section( pMenu, nSection, nItemPos );
     688             : 
     689           0 :     if ( aCurrentCommand == NULL || g_strcmp0( aCurrentCommand, aCommand ) != 0 )
     690             :     {
     691           0 :         g_lo_menu_set_command_to_item_in_section( pMenu, nSection, nItemPos, aCommand );
     692             : 
     693           0 :         gchar* aItemCommand = g_strconcat("win.", aCommand, NULL );
     694             : 
     695           0 :         if ( bIsSubmenu )
     696           0 :             g_lo_menu_set_submenu_action_to_item_in_section( pMenu, nSection, nItemPos, aItemCommand );
     697             :         else
     698           0 :             g_lo_menu_set_action_and_target_value_to_item_in_section( pMenu, nSection, nItemPos, aItemCommand, pTarget );
     699             : 
     700           0 :         g_free( aItemCommand );
     701             :     }
     702             : 
     703           0 :     if ( aCurrentCommand )
     704           0 :         g_free( aCurrentCommand );
     705           0 : }
     706             : 
     707           0 : GtkSalMenu* GtkSalMenu::GetMenuForItemCommand( gchar* aCommand, gboolean bGetSubmenu )
     708             : {
     709           0 :     SolarMutexGuard aGuard;
     710           0 :     GtkSalMenu* pMenu = NULL;
     711           0 :     for ( size_t nPos = 0; nPos < maItems.size(); nPos++ )
     712             :     {
     713           0 :         GtkSalMenuItem *pSalItem = maItems[ nPos ];
     714             : 
     715           0 :         OUString aItemCommand = mpVCLMenu->GetItemCommand( pSalItem->mnId );
     716             :         // Do not join the following two lines, or the OString will be destroyed
     717             :         // immediately, and the gchar* pointed to by aItemCommandStr will be
     718             :         // freed before it can be used - fdo#69090
     719           0 :         OString aItemCommandOStr = OUStringToOString( aItemCommand, RTL_TEXTENCODING_UTF8 );
     720           0 :         gchar* aItemCommandStr = const_cast<gchar*>(aItemCommandOStr.getStr());
     721             : 
     722           0 :         if ( g_strcmp0( aItemCommandStr, aCommand ) == 0 )
     723             :         {
     724           0 :             pMenu = bGetSubmenu ? pSalItem->mpSubMenu : this;
     725           0 :             break;
     726             :         }
     727             :         else
     728             :         {
     729           0 :             if ( pSalItem->mpSubMenu != NULL )
     730           0 :                 pMenu = pSalItem->mpSubMenu->GetMenuForItemCommand( aCommand, bGetSubmenu );
     731             : 
     732           0 :             if ( pMenu != NULL )
     733           0 :                break;
     734             :         }
     735           0 :     }
     736             : 
     737           0 :     return pMenu;
     738             : }
     739             : 
     740           0 : void GtkSalMenu::DispatchCommand( gint itemId, const gchar *aCommand )
     741             : {
     742           0 :     SolarMutexGuard aGuard;
     743             :     // Only the menubar is allowed to dispatch commands.
     744           0 :     if ( !mbMenuBar )
     745           0 :         return;
     746             : 
     747           0 :     GtkSalMenu* pSalSubMenu = GetMenuForItemCommand( const_cast<gchar*>(aCommand), FALSE );
     748           0 :     Menu* pSubMenu = ( pSalSubMenu != NULL ) ? pSalSubMenu->GetMenu() : NULL;
     749             : 
     750           0 :     MenuBar* pMenuBar = static_cast< MenuBar* >( mpVCLMenu );
     751           0 :     pMenuBar->HandleMenuCommandEvent( pSubMenu, itemId );
     752             : }
     753             : 
     754           0 : void GtkSalMenu::ActivateAllSubmenus(MenuBar* pMenuBar)
     755             : {
     756           0 :     pMenuBar->HandleMenuActivateEvent(mpVCLMenu);
     757           0 :     for ( size_t nPos = 0; nPos < maItems.size(); nPos++ )
     758             :     {
     759           0 :         GtkSalMenuItem *pSalItem = maItems[ nPos ];
     760           0 :         if ( pSalItem->mpSubMenu != NULL )
     761             :         {
     762           0 :             pSalItem->mpSubMenu->ActivateAllSubmenus(pMenuBar);
     763           0 :             pSalItem->mpSubMenu->Update();
     764             :         }
     765             :     }
     766           0 : }
     767             : 
     768           0 : void GtkSalMenu::Activate()
     769             : {
     770           0 :     if ( !mbMenuBar )
     771           0 :         return;
     772           0 :     ActivateAllSubmenus(static_cast<MenuBar*>(mpVCLMenu));
     773             : }
     774             : 
     775           0 : void GtkSalMenu::Deactivate( const gchar* aMenuCommand )
     776             : {
     777           0 :     if ( !mbMenuBar )
     778           0 :         return;
     779             : 
     780           0 :     GtkSalMenu* pSalSubMenu = GetMenuForItemCommand( const_cast<gchar*>(aMenuCommand), TRUE );
     781             : 
     782           0 :     if ( pSalSubMenu != NULL ) {
     783           0 :         MenuBar* pMenuBar = static_cast< MenuBar* >( mpVCLMenu );
     784           0 :         pMenuBar->HandleMenuDeActivateEvent( pSalSubMenu->mpVCLMenu );
     785             :     }
     786             : }
     787             : 
     788           0 : void GtkSalMenu::Display( bool bVisible )
     789             : {
     790           0 :     if ( !mbMenuBar || mpVCLMenu == NULL )
     791           0 :         return;
     792             : 
     793           0 :     bMenuVisibility = bVisible;
     794             : 
     795           0 :     bool bVCLMenuVisible = !bVisible;
     796             : 
     797           0 :     MenuBar* pMenuBar = static_cast< MenuBar* >( mpVCLMenu );
     798           0 :     pMenuBar->SetDisplayable( bVCLMenuVisible );
     799             : }
     800             : 
     801           0 : bool GtkSalMenu::IsItemVisible( unsigned nPos )
     802             : {
     803           0 :     SolarMutexGuard aGuard;
     804           0 :     bool bVisible = false;
     805             : 
     806           0 :     if ( nPos < maItems.size() )
     807           0 :         bVisible = maItems[ nPos ]->mbVisible;
     808             : 
     809           0 :     return bVisible;
     810             : }
     811             : 
     812           0 : void GtkSalMenu::CheckItem( unsigned, bool )
     813             : {
     814           0 : }
     815             : 
     816           5 : void GtkSalMenu::EnableItem( unsigned, bool )
     817             : {
     818           5 : }
     819             : 
     820           0 : void GtkSalMenu::ShowItem( unsigned nPos, bool bShow )
     821             : {
     822           0 :     SolarMutexGuard aGuard;
     823           0 :     if ( nPos < maItems.size() )
     824           0 :         maItems[ nPos ]->mbVisible = bShow;
     825           0 : }
     826             : 
     827           7 : void GtkSalMenu::SetItemText( unsigned, SalMenuItem*, const OUString& )
     828             : {
     829           7 : }
     830             : 
     831          36 : void GtkSalMenu::SetItemImage( unsigned, SalMenuItem*, const Image& )
     832             : {
     833          36 : }
     834             : 
     835           0 : void GtkSalMenu::SetAccelerator( unsigned, SalMenuItem*, const vcl::KeyCode&, const OUString& )
     836             : {
     837           0 : }
     838             : 
     839           0 : void GtkSalMenu::GetSystemMenuData( SystemMenuData* )
     840             : {
     841           0 : }
     842             : 
     843             : /*
     844             :  * GtkSalMenuItem
     845             :  */
     846             : 
     847         136 : GtkSalMenuItem::GtkSalMenuItem( const SalItemParams* pItemData ) :
     848             :     mnId( pItemData->nId ),
     849             :     mnType( pItemData->eType ),
     850             :     mbVisible( true ),
     851             :     mpVCLMenu( pItemData->pMenu ),
     852             :     mpParentMenu( NULL ),
     853         136 :     mpSubMenu( NULL )
     854             : {
     855         136 : }
     856             : 
     857         272 : GtkSalMenuItem::~GtkSalMenuItem()
     858             : {
     859         281 : }
     860             : 
     861             : #endif
     862             : 
     863             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11