/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// Related: tdf#126638 enable the menu's "autoenabledItems" property // Enable the menu's "autoenabledItems" property so that // -[SalNSMenuItem validateMenuItem:] will be called before handling // a key shortcut and the menu item can be temporarily disabled if a // modal window is displayed.
[mpMenu setAutoenablesItems: YES];
} else
{
mpMenu = [NSApp mainMenu];
[mpMenu setAutoenablesItems: NO];
}
}
AquaSalMenu::~AquaSalMenu()
{ // actually someone should have done AquaSalFrame::SetMenu( NULL ) // on our frame, alas it is not so if( mpFrame && AquaSalFrame::isAlive( mpFrame ) && mpFrame->mpMenu == this ) const_cast<AquaSalFrame*>(mpFrame)->mpMenu = nullptr;
// this should normally be empty already, but be careful... for( size_t i = 0; i < maButtons.size(); i++ )
releaseButtonEntry( maButtons[i] );
maButtons.clear();
// is this leaking in some cases ? the release often leads to a duplicate release // it seems the parent item gets ownership of the menu if( mpMenu )
{ if( mbMenuBar )
{ if( pCurrentMenuBar == this )
{ // if the current menubar gets destroyed, set the default menubar
setDefaultMenu();
}
} else // the system may still hold a reference on mpMenu
{ // so set the pointer to this AquaSalMenu to NULL // to protect from calling a dead object
// in ! mbMenuBar case our mpMenu is actually a SalNSMenu* // so we can safely cast here
[static_cast<SalNSMenu*>(mpMenu) setSalMenu: nullptr]; /* #i89860# FIXME: using [autorelease] here (and in AquaSalMenuItem::~AquaSalMenuItem) instead of [release] fixes an occasional crash. That should indicate that we release menus / menu items in the wrong order somewhere, but I could not find that case.
*/
[mpMenu autorelease];
}
}
}
bool AquaSalMenu::ShowNativePopupMenu(FloatingWindow * pWin, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags)
{ // set offsets for positioning constfloat offset = 9.0;
// do the same strange semantics as vcl popup windows to arrive at a frame geometry // in mirrored UI case; best done by actually executing the same code
sal_uInt16 nArrangeIndex;
pWin->SetPosPixel( FloatingWindow::ImplCalcPos( pWin, rRect, nFlags, nArrangeIndex ) );
displayPopupFrame.origin.x = pWin->ImplGetFrame()->GetUnmirroredGeometry().x() - pParentAquaSalFrame->GetUnmirroredGeometry().x() + offset;
displayPopupFrame.origin.y = pWin->ImplGetFrame()->GetUnmirroredGeometry().y() - pParentAquaSalFrame->GetUnmirroredGeometry().y() + offset;
pParentAquaSalFrame->VCLToCocoa(displayPopupFrame, false);
// #i111992# if this menu was opened due to a key event, prevent dispatching that yet again if( [pParentNSView respondsToSelector: @selector(clearLastEvent)] )
[pParentNSView performSelector:@selector(clearLastEvent)];
// remove items from main menu
NSMenu* pMenu = [NSApp mainMenu]; for( int nItems = [pMenu numberOfItems]; nItems > 1; nItems-- )
[pMenu removeItemAtIndex: 1];
}
void AquaSalMenu::setMainMenu()
{
SAL_WARN_IF( !mbMenuBar, "vcl", "setMainMenu on non menubar" ); if( mbMenuBar )
{ if( pCurrentMenuBar != this )
{
unsetMainMenu(); // insert our items for( std::vector<AquaSalMenuItem *>::size_type i = 0; i < maItems.size(); i++ )
{
NSMenuItem* pItem = maItems[i]->mpMenuItem;
[mpMenu insertItem: pItem atIndex: i+1];
// tdf#165448 Allow macOS to add menu items in LibreOffice windows menu // macOS will automatically insert menu items in NSApp's // windows menu so set that menu to LibreOffice's windows menu. if( maItems[i]->mpVCLMenu && maItems[i]->mpVCLMenu->GetItemCommand( maItems[i]->mnId ) == u".uno:WindowList"_ustr )
{ // Avoid macOS inserting duplicate menu items in the // windows menu
NSMenu *pWindowsMenu = [pItem submenu]; if( [NSApp windowsMenu] != pWindowsMenu )
[NSApp setWindowsMenu: pWindowsMenu];
}
}
pCurrentMenuBar = this;
void AquaSalMenu::setDefaultMenu()
{ // tdf#160427 native menu changes can only be done on the main thread
OSX_SALDATA_RUNINMAIN(AquaSalMenu::setDefaultMenu())
// Related: tdf#128186 force key window to a native full screen window // AquaSalMenu::setDefaultMenu() is generally called when the key // window has been closed. When not in native full screen mode, // macOS appears to automatically set the key window. // However, closing a native full screen window sometimes causes // the application to drop out of full screen mode even if there // are still native full screen windows open. So, if the application // is active, activate all windows to force macOS to set the key // to a window rather than leaving the application in a state where // the key window is nil. if( [NSApp isActive] )
[[NSRunningApplication currentApplication] activateWithOptions: NSApplicationActivateAllWindows];
}
void AquaSalMenu::enableMainMenu( bool bEnable )
{
NSMenu* pMainMenu = [NSApp mainMenu]; if( pMainMenu )
{ // enable/disable items from main menu int nItems = [pMainMenu numberOfItems]; for( int n = 1; n < nItems; n++ )
{
NSMenuItem* pItem = [pMainMenu itemAtIndex: n]; if( [pItem isKindOfClass: [SalNSMenuItem class]])
[static_cast<SalNSMenuItem*>(pItem) setReallyEnabled: bEnable]; else
[pItem setEnabled: bEnable];
}
}
}
void AquaSalMenu::RemoveItem( unsigned nPos )
{ // tdf#160427 native menu changes can only be done on the main thread
OSX_SALDATA_RUNINMAIN(RemoveItem(nPos))
// set title of submenu
[subAquaSalMenu->mpMenu setTitle: [pAquaSalMenuItem->mpMenuItem title]];
} elseif( subAquaSalMenu->mpParentSalMenu != this )
{ // cocoa doesn't allow menus to be submenus of multiple // menu items, so place a copy in the menu item instead ? // let's hope that NSMenu copy does the right thing
NSMenu* pCopy = [subAquaSalMenu->mpMenu copy];
[pAquaSalMenuItem->mpMenuItem setSubmenu: pCopy];
// set title of submenu
[pCopy setTitle: [pAquaSalMenuItem->mpMenuItem title]];
}
} else
{ if( pAquaSalMenuItem->mpSubMenu )
{ if( pAquaSalMenuItem->mpSubMenu->mpParentSalMenu == this )
pAquaSalMenuItem->mpSubMenu->mpParentSalMenu = nullptr;
}
pAquaSalMenuItem->mpSubMenu = nullptr;
[pAquaSalMenuItem->mpMenuItem setSubmenu: nil];
}
}
// Delete all mnemonics of mbMenuBar and CJK-style mnemonic
OUString aText = MnemonicGenerator::EraseAllMnemonicChars(i_rText);
if (aText.endsWith("...", &aText))
aText += u"\u2026";
NSString* pString = CreateNSString( aText ); if (pString)
{
[pAquaSalMenuItem->mpMenuItem setTitle: pString]; // if the menu item has a submenu, change its title as well if (pAquaSalMenuItem->mpSubMenu)
[pAquaSalMenuItem->mpSubMenu->mpMenu setTitle: pString];
[pString release];
}
}
void AquaSalMenu::statusLayout()
{ if( GetSalData()->mpStatusItem )
{
SAL_WNODEPRECATED_DECLARATIONS_PUSH // "'view' is deprecated: first deprecated in macOS 10.14 - Use the standard button // property instead"
NSView* pNSView = [GetSalData()->mpStatusItem view];
SAL_WNODEPRECATED_DECLARATIONS_POP if( [pNSView isMemberOfClass: [OOStatusItemView class]] ) // well of course it is
[static_cast<OOStatusItemView*>(pNSView) layout]; else
OSL_FAIL( "someone stole our status view" );
}
}
AquaSalMenuItem::AquaSalMenuItem( const SalItemParams* pItemData ) :
mnId( pItemData->nId ),
mpVCLMenu( pItemData->pMenu ),
mpParentMenu( nullptr ),
mpSubMenu( nullptr ),
mpMenuItem( nil )
{ if (pItemData->eType == MenuItemType::SEPARATOR)
{
mpMenuItem = [NSMenuItem separatorItem]; // these can go occasionally go in and out of a menu, ensure their lifecycle // also for the release in AquaSalMenuItem destructor
[mpMenuItem retain];
} else
{
mpMenuItem = [[SalNSMenuItem alloc] initWithMenuItem: this];
[static_cast<SalNSMenuItem*>(mpMenuItem) setReallyEnabled: YES];
// peel mnemonics because on mac there are no such things for menu items // Delete CJK-style mnemonics for the dropdown menu of the 'New button' and lower menu of 'File > New'
NSString* pString = CreateNSString(MnemonicGenerator::EraseAllMnemonicChars(pItemData->aText)); if (pString)
{
[mpMenuItem setTitle: pString];
[pString release];
} // anything but a separator should set a menu to dispatch to
SAL_WARN_IF( !mpVCLMenu, "vcl", "no menu" );
}
}
AquaSalMenuItem::~AquaSalMenuItem()
{ /* #i89860# FIXME: using [autorelease] here (and in AquaSalMenu:::~AquaSalMenu) instead of [release] fixes an occasional crash. That should indicate that we release menus / menu items in the wrong order somewhere, but I could not find that case.
*/ if( mpMenuItem )
[mpMenuItem autorelease];
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.