LCOV - code coverage report
Current view: top level - vcl/unx/gtk/window - gtksalmenu.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 0 442 0.0 %
Date: 2014-11-03 Functions: 0 46 0.0 %
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 = ( GtkSalFrame* ) pFrame;
     163           0 :         GtkSalMenu* pSalMenu = ((GtkSalMenu*) 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( (const gchar*) str1, (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, (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 = (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           0 : GtkSalMenu::GtkSalMenu( bool bMenuBar ) :
     394             :     mbMenuBar( bMenuBar ),
     395             :     mpVCLMenu( NULL ),
     396             :     mpOldSalMenu( NULL ),
     397             :     mpParentSalMenu( NULL ),
     398             :     mpFrame( NULL ),
     399             :     mpMenuModel( NULL ),
     400           0 :     mpActionGroup( NULL )
     401             : {
     402           0 : }
     403             : 
     404           0 : GtkSalMenu::~GtkSalMenu()
     405             : {
     406           0 :     SolarMutexGuard aGuard;
     407             : 
     408           0 :     if ( mbMenuBar )
     409             :     {
     410           0 :         if ( mpMenuModel )
     411             :         {
     412             : //            g_lo_menu_remove( G_LO_MENU( mpMenuModel ), 0 );
     413           0 :             g_object_unref( mpMenuModel );
     414             :         }
     415             :     }
     416             : 
     417           0 :     maItems.clear();
     418           0 : }
     419             : 
     420           0 : bool GtkSalMenu::VisibleMenuBar()
     421             : {
     422           0 :     return bMenuVisibility;
     423             : }
     424             : 
     425           0 : void GtkSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos )
     426             : {
     427           0 :     SolarMutexGuard aGuard;
     428           0 :     GtkSalMenuItem *pItem = static_cast<GtkSalMenuItem*>( pSalMenuItem );
     429             : 
     430           0 :     if ( nPos == MENU_APPEND )
     431           0 :         maItems.push_back( pItem );
     432             :     else
     433           0 :         maItems.insert( maItems.begin() + nPos, pItem );
     434             : 
     435           0 :     pItem->mpParentMenu = this;
     436           0 : }
     437             : 
     438           0 : void GtkSalMenu::RemoveItem( unsigned nPos )
     439             : {
     440           0 :     SolarMutexGuard aGuard;
     441           0 :     maItems.erase( maItems.begin() + nPos );
     442           0 : }
     443             : 
     444           0 : void GtkSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned )
     445             : {
     446           0 :     SolarMutexGuard aGuard;
     447           0 :     GtkSalMenuItem *pItem = static_cast< GtkSalMenuItem* >( pSalMenuItem );
     448           0 :     GtkSalMenu *pGtkSubMenu = static_cast< GtkSalMenu* >( pSubMenu );
     449             : 
     450           0 :     if ( pGtkSubMenu == NULL )
     451           0 :         return;
     452             : 
     453           0 :     pGtkSubMenu->mpParentSalMenu = this;
     454           0 :     pItem->mpSubMenu = pGtkSubMenu;
     455             : }
     456             : 
     457             : static bool bInvalidMenus = false;
     458           0 : static gboolean RefreshMenusUnity(gpointer)
     459             : {
     460           0 :     SolarMutexGuard g;
     461             : 
     462           0 :     SalDisplay* pSalDisplay = GetGenericData()->GetSalDisplay();
     463           0 :     std::list< SalFrame* >::const_iterator pSalFrame = pSalDisplay->getFrames().begin();
     464           0 :     std::list< SalFrame* >::const_iterator pEndSalFrame = pSalDisplay->getFrames().end();
     465           0 :     for(; pSalFrame != pEndSalFrame; ++pSalFrame) {
     466           0 :         const GtkSalFrame* pGtkSalFrame = static_cast< const GtkSalFrame* >( *pSalFrame );
     467           0 :         GtkSalFrame* pFrameNonConst = const_cast<GtkSalFrame*>(pGtkSalFrame);
     468           0 :         GtkSalMenu* pSalMenu = static_cast<GtkSalMenu*>(pFrameNonConst->GetMenu());
     469           0 :         if(pSalMenu) {
     470           0 :             pSalMenu->Activate();
     471           0 :             pSalMenu->UpdateFull();
     472             :         }
     473             :     }
     474           0 :     bInvalidMenus = false;
     475           0 :     return FALSE;
     476             : }
     477             : 
     478           0 : static long RefreshMenusUnity(void*, void*)
     479             : {
     480           0 :     if(!bInvalidMenus) {
     481           0 :         g_timeout_add(10, &RefreshMenusUnity, NULL);
     482           0 :         bInvalidMenus = true;
     483             :     }
     484           0 :     return 0;
     485             : }
     486             : 
     487           0 : static Link* getRefreshLinkInstance()
     488             : {
     489             :     static Link* pLink = NULL;
     490           0 :     if(!pLink) {
     491           0 :         pLink = new Link(NULL, &RefreshMenusUnity);
     492             :     }
     493           0 :     return pLink;
     494             : }
     495             : 
     496           0 : void GtkSalMenu::SetFrame( const SalFrame* pFrame )
     497             : {
     498           0 :     SolarMutexGuard aGuard;
     499             :     {
     500           0 :         vcl::MenuInvalidator aInvalidator;
     501           0 :         aInvalidator.GetMenuInvalidateListeners()->addListener(*getRefreshLinkInstance());
     502             :     }
     503             : 
     504             :     assert(mbMenuBar);
     505             :     SAL_INFO("vcl.unity", "GtkSalMenu set to frame");
     506           0 :     mpFrame = static_cast< const GtkSalFrame* >( pFrame );
     507           0 :     GtkSalFrame* pFrameNonConst = const_cast<GtkSalFrame*>(mpFrame);
     508             : 
     509             :     // if we had a menu on the GtkSalMenu we have to free it as we generate a
     510             :     // full menu anyway and we might need to reuse an existing model and
     511             :     // actiongroup
     512           0 :     mpOldSalMenu = static_cast< GtkSalMenu* >( pFrameNonConst->GetMenu() );
     513           0 :     pFrameNonConst->SetMenu( this );
     514           0 :     pFrameNonConst->EnsureAppMenuWatch();
     515             : 
     516             :     // Clean menu model and action group if needed.
     517           0 :     GtkWidget* pWidget = pFrameNonConst->getWindow();
     518           0 :     GdkWindow* gdkWindow = gtk_widget_get_window( pWidget );
     519             : 
     520           0 :     GLOMenu* pMenuModel = G_LO_MENU( g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-menubar" ) );
     521           0 :     GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-action-group" ) );
     522             :     SAL_INFO("vcl.unity", "Found menu model: " << pMenuModel << " and action group: " << pActionGroup);
     523             : 
     524           0 :     if ( pMenuModel )
     525             :     {
     526           0 :         if ( g_menu_model_get_n_items( G_MENU_MODEL( pMenuModel ) ) > 0 )
     527           0 :             g_lo_menu_remove( pMenuModel, 0 );
     528             : 
     529           0 :         mpMenuModel = G_MENU_MODEL( g_lo_menu_new() );
     530             :     }
     531             : 
     532           0 :     if ( pActionGroup )
     533             :     {
     534           0 :         g_lo_action_group_clear( pActionGroup );
     535           0 :         mpActionGroup = G_ACTION_GROUP( pActionGroup );
     536             :     }
     537             : 
     538             :     // Generate the main menu structure.
     539           0 :     if (bMenuVisibility)
     540           0 :         UpdateFull();
     541             : 
     542           0 :     g_lo_menu_insert_section( pMenuModel, 0, NULL, mpMenuModel );
     543           0 : }
     544             : 
     545           0 : const GtkSalFrame* GtkSalMenu::GetFrame() const
     546             : {
     547           0 :     SolarMutexGuard aGuard;
     548           0 :     const GtkSalMenu* pMenu = this;
     549           0 :     while( pMenu && ! pMenu->mpFrame )
     550           0 :         pMenu = pMenu->mpParentSalMenu;
     551           0 :     return pMenu ? pMenu->mpFrame : NULL;
     552             : }
     553             : 
     554           0 : void GtkSalMenu::NativeCheckItem( unsigned nSection, unsigned nItemPos, MenuItemBits bits, gboolean bCheck )
     555             : {
     556           0 :     SolarMutexGuard aGuard;
     557             : 
     558           0 :     if ( mpActionGroup == NULL )
     559           0 :         return;
     560             : 
     561           0 :     gchar* aCommand = g_lo_menu_get_command_from_item_in_section( G_LO_MENU( mpMenuModel ), nSection, nItemPos );
     562             : 
     563           0 :     if ( aCommand != NULL || g_strcmp0( aCommand, "" ) != 0 )
     564             :     {
     565           0 :         GVariant *pCheckValue = NULL;
     566           0 :         GVariant *pCurrentState = g_action_group_get_action_state( mpActionGroup, aCommand );
     567             : 
     568           0 :         if ( bits & MenuItemBits::RADIOCHECK )
     569           0 :             pCheckValue = bCheck ? g_variant_new_string( aCommand ) : g_variant_new_string( "" );
     570             :         else
     571             :         {
     572             :             // By default, all checked items are checkmark buttons.
     573           0 :             if ( bCheck || ( !bCheck && pCurrentState != NULL ) )
     574           0 :                 pCheckValue = g_variant_new_boolean( bCheck );
     575             :         }
     576             : 
     577           0 :         if ( pCheckValue != NULL )
     578             :         {
     579           0 :             if ( pCurrentState == NULL || g_variant_equal( pCurrentState, pCheckValue ) == FALSE )
     580             :             {
     581           0 :                 g_action_group_change_action_state( mpActionGroup, aCommand, pCheckValue );
     582             :             }
     583             :             else
     584             :             {
     585           0 :                 g_variant_unref (pCheckValue);
     586             :             }
     587             :         }
     588             : 
     589           0 :         if ( pCurrentState != NULL )
     590           0 :             g_variant_unref( pCurrentState );
     591             :     }
     592             : 
     593           0 :     if ( aCommand )
     594           0 :         g_free( aCommand );
     595             : }
     596             : 
     597           0 : void GtkSalMenu::NativeSetEnableItem( gchar* aCommand, gboolean bEnable )
     598             : {
     599           0 :     SolarMutexGuard aGuard;
     600           0 :     GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( mpActionGroup );
     601             : 
     602           0 :     if ( g_action_group_get_action_enabled( G_ACTION_GROUP( pActionGroup ), aCommand ) != bEnable )
     603           0 :         g_lo_action_group_set_action_enabled( pActionGroup, aCommand, bEnable );
     604           0 : }
     605             : 
     606           0 : void GtkSalMenu::NativeSetItemText( unsigned nSection, unsigned nItemPos, const OUString& rText )
     607             : {
     608           0 :     SolarMutexGuard aGuard;
     609             :     // Escape all underscores so that they don't get interpreted as hotkeys
     610           0 :     OUString aText = rText.replaceAll( "_", "__" );
     611             :     // Replace the LibreOffice hotkey identifier with an underscore
     612           0 :     aText = aText.replace( '~', '_' );
     613           0 :     OString aConvertedText = OUStringToOString( aText, RTL_TEXTENCODING_UTF8 );
     614             : 
     615             :     // Update item text only when necessary.
     616           0 :     gchar* aLabel = g_lo_menu_get_label_from_item_in_section( G_LO_MENU( mpMenuModel ), nSection, nItemPos );
     617             : 
     618           0 :     if ( aLabel == NULL || g_strcmp0( aLabel, aConvertedText.getStr() ) != 0 )
     619           0 :         g_lo_menu_set_label_to_item_in_section( G_LO_MENU( mpMenuModel ), nSection, nItemPos, aConvertedText.getStr() );
     620             : 
     621           0 :     if ( aLabel )
     622           0 :         g_free( aLabel );
     623           0 : }
     624             : 
     625           0 : void GtkSalMenu::NativeSetAccelerator( unsigned nSection, unsigned nItemPos, const vcl::KeyCode& rKeyCode, const OUString& rKeyName )
     626             : {
     627           0 :     SolarMutexGuard aGuard;
     628             : 
     629           0 :     if ( rKeyName.isEmpty() )
     630           0 :         return;
     631             : 
     632             :     guint nKeyCode;
     633             :     GdkModifierType nModifiers;
     634             : 
     635           0 :     KeyCodeToGdkKey( rKeyCode, &nKeyCode, &nModifiers );
     636             : 
     637           0 :     gchar* aAccelerator = gtk_accelerator_name( nKeyCode, nModifiers );
     638             : 
     639           0 :     gchar* aCurrentAccel = g_lo_menu_get_accelerator_from_item_in_section( G_LO_MENU( mpMenuModel ), nSection, nItemPos );
     640             : 
     641           0 :     if ( aCurrentAccel == NULL && g_strcmp0( aCurrentAccel, aAccelerator ) != 0 )
     642           0 :         g_lo_menu_set_accelerator_to_item_in_section ( G_LO_MENU( mpMenuModel ), nSection, nItemPos, aAccelerator );
     643             : 
     644           0 :     g_free( aAccelerator );
     645           0 :     g_free( aCurrentAccel );
     646             : }
     647             : 
     648           0 : void GtkSalMenu::NativeSetItemCommand( unsigned nSection,
     649             :                                        unsigned nItemPos,
     650             :                                        sal_uInt16 nId,
     651             :                                        const gchar* aCommand,
     652             :                                        MenuItemBits nBits,
     653             :                                        gboolean bChecked,
     654             :                                        gboolean bIsSubmenu )
     655             : {
     656           0 :     SolarMutexGuard aGuard;
     657           0 :     GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( mpActionGroup );
     658             : 
     659           0 :     GVariant *pTarget = NULL;
     660             : 
     661           0 :     if ( g_action_group_has_action( mpActionGroup, aCommand ) == FALSE ) {
     662           0 :         if ( ( nBits & MenuItemBits::CHECKABLE ) || bIsSubmenu )
     663             :         {
     664             :             // Item is a checkmark button.
     665           0 :             GVariantType* pStateType = g_variant_type_new( (gchar*) G_VARIANT_TYPE_BOOLEAN );
     666           0 :             GVariant* pState = g_variant_new_boolean( bChecked );
     667             : 
     668           0 :             g_lo_action_group_insert_stateful( pActionGroup, aCommand, nId, bIsSubmenu, NULL, pStateType, NULL, pState );
     669             :         }
     670           0 :         else if ( nBits & MenuItemBits::RADIOCHECK )
     671             :         {
     672             :             // Item is a radio button.
     673           0 :             GVariantType* pParameterType = g_variant_type_new( (gchar*) G_VARIANT_TYPE_STRING );
     674           0 :             GVariantType* pStateType = g_variant_type_new( (gchar*) G_VARIANT_TYPE_STRING );
     675           0 :             GVariant* pState = g_variant_new_string( "" );
     676           0 :             pTarget = g_variant_new_string( aCommand );
     677             : 
     678           0 :             g_lo_action_group_insert_stateful( pActionGroup, aCommand, nId, FALSE, pParameterType, pStateType, NULL, pState );
     679             :         }
     680             :         else
     681             :         {
     682             :             // Item is not special, so insert a stateless action.
     683           0 :             g_lo_action_group_insert( pActionGroup, aCommand, nId, FALSE );
     684             :         }
     685             :     }
     686             : 
     687           0 :     GLOMenu* pMenu = G_LO_MENU( mpMenuModel );
     688             : 
     689             :     // Menu item is not updated unless it's necessary.
     690           0 :     gchar* aCurrentCommand = g_lo_menu_get_command_from_item_in_section( pMenu, nSection, nItemPos );
     691             : 
     692           0 :     if ( aCurrentCommand == NULL || g_strcmp0( aCurrentCommand, aCommand ) != 0 )
     693             :     {
     694           0 :         g_lo_menu_set_command_to_item_in_section( pMenu, nSection, nItemPos, aCommand );
     695             : 
     696           0 :         gchar* aItemCommand = g_strconcat("win.", aCommand, NULL );
     697             : 
     698           0 :         if ( bIsSubmenu )
     699           0 :             g_lo_menu_set_submenu_action_to_item_in_section( pMenu, nSection, nItemPos, aItemCommand );
     700             :         else
     701           0 :             g_lo_menu_set_action_and_target_value_to_item_in_section( pMenu, nSection, nItemPos, aItemCommand, pTarget );
     702             : 
     703           0 :         g_free( aItemCommand );
     704             :     }
     705             : 
     706           0 :     if ( aCurrentCommand )
     707           0 :         g_free( aCurrentCommand );
     708           0 : }
     709             : 
     710           0 : GtkSalMenu* GtkSalMenu::GetMenuForItemCommand( gchar* aCommand, gboolean bGetSubmenu )
     711             : {
     712           0 :     SolarMutexGuard aGuard;
     713           0 :     GtkSalMenu* pMenu = NULL;
     714           0 :     for ( sal_uInt16 nPos = 0; nPos < maItems.size(); nPos++ )
     715             :     {
     716           0 :         GtkSalMenuItem *pSalItem = maItems[ nPos ];
     717             : 
     718           0 :         OUString aItemCommand = mpVCLMenu->GetItemCommand( pSalItem->mnId );
     719             :         // Do not join the following two lines, or the OString will be destroyed
     720             :         // immediately, and the gchar* pointed to by aItemCommandStr will be
     721             :         // freed before it can be used - fdo#69090
     722           0 :         OString aItemCommandOStr = OUStringToOString( aItemCommand, RTL_TEXTENCODING_UTF8 );
     723           0 :         gchar* aItemCommandStr = (gchar*) aItemCommandOStr.getStr();
     724             : 
     725           0 :         if ( g_strcmp0( aItemCommandStr, aCommand ) == 0 )
     726             :         {
     727           0 :             pMenu = bGetSubmenu ? pSalItem->mpSubMenu : this;
     728           0 :             break;
     729             :         }
     730             :         else
     731             :         {
     732           0 :             if ( pSalItem->mpSubMenu != NULL )
     733           0 :                 pMenu = pSalItem->mpSubMenu->GetMenuForItemCommand( aCommand, bGetSubmenu );
     734             : 
     735           0 :             if ( pMenu != NULL )
     736           0 :                break;
     737             :         }
     738           0 :     }
     739             : 
     740           0 :     return pMenu;
     741             : }
     742             : 
     743           0 : void GtkSalMenu::DispatchCommand( gint itemId, const gchar *aCommand )
     744             : {
     745           0 :     SolarMutexGuard aGuard;
     746             :     // Only the menubar is allowed to dispatch commands.
     747           0 :     if ( !mbMenuBar )
     748           0 :         return;
     749             : 
     750           0 :     GtkSalMenu* pSalSubMenu = GetMenuForItemCommand( (gchar*) aCommand, FALSE );
     751           0 :     Menu* pSubMenu = ( pSalSubMenu != NULL ) ? pSalSubMenu->GetMenu() : NULL;
     752             : 
     753           0 :     MenuBar* pMenuBar = static_cast< MenuBar* >( mpVCLMenu );
     754           0 :     pMenuBar->HandleMenuCommandEvent( pSubMenu, itemId );
     755             : }
     756             : 
     757           0 : void GtkSalMenu::ActivateAllSubmenus(MenuBar* pMenuBar)
     758             : {
     759           0 :     pMenuBar->HandleMenuActivateEvent(mpVCLMenu);
     760           0 :     for ( sal_uInt16 nPos = 0; nPos < maItems.size(); nPos++ )
     761             :     {
     762           0 :         GtkSalMenuItem *pSalItem = maItems[ nPos ];
     763           0 :         if ( pSalItem->mpSubMenu != NULL )
     764             :         {
     765           0 :             pSalItem->mpSubMenu->ActivateAllSubmenus(pMenuBar);
     766           0 :             pSalItem->mpSubMenu->Update();
     767             :         }
     768             :     }
     769           0 : }
     770             : 
     771           0 : void GtkSalMenu::Activate()
     772             : {
     773           0 :     if ( !mbMenuBar )
     774           0 :         return;
     775           0 :     ActivateAllSubmenus(static_cast<MenuBar*>(mpVCLMenu));
     776             : }
     777             : 
     778           0 : void GtkSalMenu::Deactivate( const gchar* aMenuCommand )
     779             : {
     780           0 :     if ( !mbMenuBar )
     781           0 :         return;
     782             : 
     783           0 :     GtkSalMenu* pSalSubMenu = GetMenuForItemCommand( (gchar*) aMenuCommand, TRUE );
     784             : 
     785           0 :     if ( pSalSubMenu != NULL ) {
     786           0 :         MenuBar* pMenuBar = static_cast< MenuBar* >( mpVCLMenu );
     787           0 :         pMenuBar->HandleMenuDeActivateEvent( pSalSubMenu->mpVCLMenu );
     788             :     }
     789             : }
     790             : 
     791           0 : void GtkSalMenu::Display( bool bVisible )
     792             : {
     793           0 :     if ( !mbMenuBar || mpVCLMenu == NULL )
     794           0 :         return;
     795             : 
     796           0 :     bMenuVisibility = bVisible;
     797             : 
     798           0 :     bool bVCLMenuVisible = ( bVisible ) ? false : true;
     799             : 
     800           0 :     MenuBar* pMenuBar = static_cast< MenuBar* >( mpVCLMenu );
     801           0 :     pMenuBar->SetDisplayable( bVCLMenuVisible );
     802             : }
     803             : 
     804           0 : bool GtkSalMenu::IsItemVisible( unsigned nPos )
     805             : {
     806           0 :     SolarMutexGuard aGuard;
     807           0 :     bool bVisible = false;
     808             : 
     809           0 :     if ( nPos < maItems.size() )
     810           0 :         bVisible = ( ( GtkSalMenuItem* ) maItems[ nPos ])->mbVisible;
     811             : 
     812           0 :     return bVisible;
     813             : }
     814             : 
     815           0 : void GtkSalMenu::CheckItem( unsigned, bool )
     816             : {
     817           0 : }
     818             : 
     819           0 : void GtkSalMenu::EnableItem( unsigned, bool )
     820             : {
     821           0 : }
     822             : 
     823           0 : void GtkSalMenu::ShowItem( unsigned nPos, bool bShow )
     824             : {
     825           0 :     SolarMutexGuard aGuard;
     826           0 :     if ( nPos < maItems.size() )
     827           0 :         ( ( GtkSalMenuItem* ) maItems[ nPos ] )->mbVisible = bShow;
     828           0 : }
     829             : 
     830           0 : void GtkSalMenu::SetItemText( unsigned, SalMenuItem*, const OUString& )
     831             : {
     832           0 : }
     833             : 
     834           0 : void GtkSalMenu::SetItemImage( unsigned, SalMenuItem*, const Image& )
     835             : {
     836           0 : }
     837             : 
     838           0 : void GtkSalMenu::SetAccelerator( unsigned, SalMenuItem*, const vcl::KeyCode&, const OUString& )
     839             : {
     840           0 : }
     841             : 
     842           0 : void GtkSalMenu::GetSystemMenuData( SystemMenuData* )
     843             : {
     844           0 : }
     845             : 
     846             : /*
     847             :  * GtkSalMenuItem
     848             :  */
     849             : 
     850           0 : GtkSalMenuItem::GtkSalMenuItem( const SalItemParams* pItemData ) :
     851             :     mnId( pItemData->nId ),
     852             :     mnType( pItemData->eType ),
     853             :     mbVisible( true ),
     854             :     mpVCLMenu( pItemData->pMenu ),
     855             :     mpParentMenu( NULL ),
     856           0 :     mpSubMenu( NULL )
     857             : {
     858           0 : }
     859             : 
     860           0 : GtkSalMenuItem::~GtkSalMenuItem()
     861             : {
     862           0 : }
     863             : 
     864             : #endif
     865             : 
     866             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10