1*9f62ea84SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*9f62ea84SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*9f62ea84SAndrew Rist * or more contributor license agreements. See the NOTICE file 5*9f62ea84SAndrew Rist * distributed with this work for additional information 6*9f62ea84SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*9f62ea84SAndrew Rist * to you under the Apache License, Version 2.0 (the 8*9f62ea84SAndrew Rist * "License"); you may not use this file except in compliance 9*9f62ea84SAndrew Rist * with the License. You may obtain a copy of the License at 10*9f62ea84SAndrew Rist * 11*9f62ea84SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12*9f62ea84SAndrew Rist * 13*9f62ea84SAndrew Rist * Unless required by applicable law or agreed to in writing, 14*9f62ea84SAndrew Rist * software distributed under the License is distributed on an 15*9f62ea84SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*9f62ea84SAndrew Rist * KIND, either express or implied. See the License for the 17*9f62ea84SAndrew Rist * specific language governing permissions and limitations 18*9f62ea84SAndrew Rist * under the License. 19*9f62ea84SAndrew Rist * 20*9f62ea84SAndrew Rist *************************************************************/ 21*9f62ea84SAndrew Rist 22*9f62ea84SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir #include "rtl/ustrbuf.hxx" 25cdf0e10cSrcweir 26cdf0e10cSrcweir #include "vcl/cmdevt.hxx" 27cdf0e10cSrcweir #include "vcl/floatwin.hxx" 28cdf0e10cSrcweir #include "vcl/window.hxx" 29cdf0e10cSrcweir #include "vcl/svapp.hxx" 30cdf0e10cSrcweir 31cdf0e10cSrcweir #include "aqua/saldata.hxx" 32cdf0e10cSrcweir #include "aqua/salinst.h" 33cdf0e10cSrcweir #include "aqua/salmenu.h" 34cdf0e10cSrcweir #include "aqua/salnsmenu.h" 35cdf0e10cSrcweir #include "aqua/salframe.h" 36cdf0e10cSrcweir #include "aqua/salbmp.h" 37cdf0e10cSrcweir #include "aqua/aqua11ywrapper.h" 38cdf0e10cSrcweir 39cdf0e10cSrcweir #include "svids.hrc" 40cdf0e10cSrcweir #include "window.h" 41cdf0e10cSrcweir 42cdf0e10cSrcweir const AquaSalMenu* AquaSalMenu::pCurrentMenuBar = NULL; 43cdf0e10cSrcweir 44cdf0e10cSrcweir @interface MainMenuSelector : NSObject 45cdf0e10cSrcweir { 46cdf0e10cSrcweir } 47cdf0e10cSrcweir -(void)showDialog: (int)nDialog; 48cdf0e10cSrcweir -(void)showPreferences: (id)sender; 49cdf0e10cSrcweir -(void)showAbout: (id)sender; 50cdf0e10cSrcweir @end 51cdf0e10cSrcweir 52cdf0e10cSrcweir @implementation MainMenuSelector 53cdf0e10cSrcweir -(void)showDialog: (int)nDialog 54cdf0e10cSrcweir { 55cdf0e10cSrcweir if( AquaSalMenu::pCurrentMenuBar ) 56cdf0e10cSrcweir { 57cdf0e10cSrcweir const AquaSalFrame* pFrame = AquaSalMenu::pCurrentMenuBar->mpFrame; 58cdf0e10cSrcweir if( pFrame && AquaSalFrame::isAlive( pFrame ) ) 59cdf0e10cSrcweir { 60cdf0e10cSrcweir pFrame->CallCallback( SALEVENT_SHOWDIALOG, reinterpret_cast<void*>(nDialog) ); 61cdf0e10cSrcweir } 62cdf0e10cSrcweir } 63cdf0e10cSrcweir else 64cdf0e10cSrcweir { 65cdf0e10cSrcweir String aDialog; 66cdf0e10cSrcweir if( nDialog == SHOWDIALOG_ID_ABOUT ) 67cdf0e10cSrcweir aDialog = String( RTL_CONSTASCII_USTRINGPARAM( "ABOUT" ) ); 68cdf0e10cSrcweir else if( nDialog == SHOWDIALOG_ID_PREFERENCES ) 69cdf0e10cSrcweir aDialog = String( RTL_CONSTASCII_USTRINGPARAM( "PREFERENCES" ) ); 70cdf0e10cSrcweir const ApplicationEvent* pAppEvent = new ApplicationEvent( String(), 71cdf0e10cSrcweir ApplicationAddress(), 72cdf0e10cSrcweir ByteString( "SHOWDIALOG" ), 73cdf0e10cSrcweir aDialog ); 74cdf0e10cSrcweir AquaSalInstance::aAppEventList.push_back( pAppEvent ); 75cdf0e10cSrcweir } 76cdf0e10cSrcweir } 77cdf0e10cSrcweir 78cdf0e10cSrcweir -(void)showPreferences: (id) sender 79cdf0e10cSrcweir { 80cdf0e10cSrcweir (void)sender; 81cdf0e10cSrcweir YIELD_GUARD; 82cdf0e10cSrcweir 83cdf0e10cSrcweir [self showDialog: SHOWDIALOG_ID_PREFERENCES]; 84cdf0e10cSrcweir } 85cdf0e10cSrcweir -(void)showAbout: (id) sender 86cdf0e10cSrcweir { 87cdf0e10cSrcweir (void)sender; 88cdf0e10cSrcweir YIELD_GUARD; 89cdf0e10cSrcweir 90cdf0e10cSrcweir [self showDialog: SHOWDIALOG_ID_ABOUT]; 91cdf0e10cSrcweir } 92cdf0e10cSrcweir @end 93cdf0e10cSrcweir 94cdf0e10cSrcweir 95cdf0e10cSrcweir // FIXME: currently this is leaked 96cdf0e10cSrcweir static MainMenuSelector* pMainMenuSelector = nil; 97cdf0e10cSrcweir 98cdf0e10cSrcweir static void initAppMenu() 99cdf0e10cSrcweir { 100cdf0e10cSrcweir static bool bOnce = true; 101cdf0e10cSrcweir if( bOnce ) 102cdf0e10cSrcweir { 103cdf0e10cSrcweir bOnce = false; 104cdf0e10cSrcweir 105cdf0e10cSrcweir ResMgr* pMgr = ImplGetResMgr(); 106cdf0e10cSrcweir if( pMgr ) 107cdf0e10cSrcweir { 108cdf0e10cSrcweir // get the main menu 109cdf0e10cSrcweir NSMenu* pMainMenu = [NSApp mainMenu]; 110cdf0e10cSrcweir if( pMainMenu != nil ) 111cdf0e10cSrcweir { 112cdf0e10cSrcweir // create the action selector 113cdf0e10cSrcweir pMainMenuSelector = [[MainMenuSelector alloc] init]; 114cdf0e10cSrcweir 115cdf0e10cSrcweir // get the proper submenu 116cdf0e10cSrcweir NSMenu* pAppMenu = [[pMainMenu itemAtIndex: 0] submenu]; 117cdf0e10cSrcweir if( pAppMenu ) 118cdf0e10cSrcweir { 119cdf0e10cSrcweir // insert about entry 120cdf0e10cSrcweir String aAbout( ResId( SV_STDTEXT_ABOUT, *pMgr ) ); 121cdf0e10cSrcweir NSString* pString = CreateNSString( aAbout ); 122cdf0e10cSrcweir NSMenuItem* pNewItem = [pAppMenu insertItemWithTitle: pString 123cdf0e10cSrcweir action: @selector(showAbout:) 124cdf0e10cSrcweir keyEquivalent: @"" 125cdf0e10cSrcweir atIndex: 0]; 126cdf0e10cSrcweir if (pString) 127cdf0e10cSrcweir [pString release]; 128cdf0e10cSrcweir if( pNewItem ) 129cdf0e10cSrcweir { 130cdf0e10cSrcweir [pNewItem setTarget: pMainMenuSelector]; 131cdf0e10cSrcweir [pAppMenu insertItem: [NSMenuItem separatorItem] atIndex: 1]; 132cdf0e10cSrcweir } 133cdf0e10cSrcweir 134cdf0e10cSrcweir // insert preferences entry 135cdf0e10cSrcweir String aPref( ResId( SV_STDTEXT_PREFERENCES, *pMgr ) ); 136cdf0e10cSrcweir pString = CreateNSString( aPref ); 137cdf0e10cSrcweir pNewItem = [pAppMenu insertItemWithTitle: pString 138cdf0e10cSrcweir action: @selector(showPreferences:) 139cdf0e10cSrcweir keyEquivalent: @"," 140cdf0e10cSrcweir atIndex: 2]; 141cdf0e10cSrcweir if (pString) 142cdf0e10cSrcweir [pString release]; 143cdf0e10cSrcweir if( pNewItem ) 144cdf0e10cSrcweir { 145cdf0e10cSrcweir [pNewItem setKeyEquivalentModifierMask: NSCommandKeyMask]; 146cdf0e10cSrcweir [pNewItem setTarget: pMainMenuSelector]; 147cdf0e10cSrcweir [pAppMenu insertItem: [NSMenuItem separatorItem] atIndex: 3]; 148cdf0e10cSrcweir } 149cdf0e10cSrcweir 150cdf0e10cSrcweir // WARNING: ultra ugly code ahead 151cdf0e10cSrcweir 152cdf0e10cSrcweir // rename standard entries 153cdf0e10cSrcweir // rename "Services" 154cdf0e10cSrcweir pNewItem = [pAppMenu itemAtIndex: 4]; 155cdf0e10cSrcweir if( pNewItem ) 156cdf0e10cSrcweir { 157cdf0e10cSrcweir pString = CreateNSString( String( ResId( SV_MENU_MAC_SERVICES, *pMgr ) ) ); 158cdf0e10cSrcweir [pNewItem setTitle: pString]; 159cdf0e10cSrcweir if( pString ) 160cdf0e10cSrcweir [pString release]; 161cdf0e10cSrcweir } 162cdf0e10cSrcweir 163cdf0e10cSrcweir // rename "Hide NewApplication" 164cdf0e10cSrcweir pNewItem = [pAppMenu itemAtIndex: 6]; 165cdf0e10cSrcweir if( pNewItem ) 166cdf0e10cSrcweir { 167cdf0e10cSrcweir pString = CreateNSString( String( ResId( SV_MENU_MAC_HIDEAPP, *pMgr ) ) ); 168cdf0e10cSrcweir [pNewItem setTitle: pString]; 169cdf0e10cSrcweir if( pString ) 170cdf0e10cSrcweir [pString release]; 171cdf0e10cSrcweir } 172cdf0e10cSrcweir 173cdf0e10cSrcweir // rename "Hide Others" 174cdf0e10cSrcweir pNewItem = [pAppMenu itemAtIndex: 7]; 175cdf0e10cSrcweir if( pNewItem ) 176cdf0e10cSrcweir { 177cdf0e10cSrcweir pString = CreateNSString( String( ResId( SV_MENU_MAC_HIDEALL, *pMgr ) ) ); 178cdf0e10cSrcweir [pNewItem setTitle: pString]; 179cdf0e10cSrcweir if( pString ) 180cdf0e10cSrcweir [pString release]; 181cdf0e10cSrcweir } 182cdf0e10cSrcweir 183cdf0e10cSrcweir // rename "Show all" 184cdf0e10cSrcweir pNewItem = [pAppMenu itemAtIndex: 8]; 185cdf0e10cSrcweir if( pNewItem ) 186cdf0e10cSrcweir { 187cdf0e10cSrcweir pString = CreateNSString( String( ResId( SV_MENU_MAC_SHOWALL, *pMgr ) ) ); 188cdf0e10cSrcweir [pNewItem setTitle: pString]; 189cdf0e10cSrcweir if( pString ) 190cdf0e10cSrcweir [pString release]; 191cdf0e10cSrcweir } 192cdf0e10cSrcweir 193cdf0e10cSrcweir // rename "Quit NewApplication" 194cdf0e10cSrcweir pNewItem = [pAppMenu itemAtIndex: 10]; 195cdf0e10cSrcweir if( pNewItem ) 196cdf0e10cSrcweir { 197cdf0e10cSrcweir pString = CreateNSString( String( ResId( SV_MENU_MAC_QUITAPP, *pMgr ) ) ); 198cdf0e10cSrcweir [pNewItem setTitle: pString]; 199cdf0e10cSrcweir if( pString ) 200cdf0e10cSrcweir [pString release]; 201cdf0e10cSrcweir } 202cdf0e10cSrcweir } 203cdf0e10cSrcweir } 204cdf0e10cSrcweir } 205cdf0e10cSrcweir } 206cdf0e10cSrcweir } 207cdf0e10cSrcweir 208cdf0e10cSrcweir // ======================================================================= 209cdf0e10cSrcweir 210cdf0e10cSrcweir SalMenu* AquaSalInstance::CreateMenu( sal_Bool bMenuBar, Menu* pVCLMenu ) 211cdf0e10cSrcweir { 212cdf0e10cSrcweir initAppMenu(); 213cdf0e10cSrcweir 214cdf0e10cSrcweir AquaSalMenu *pAquaSalMenu = new AquaSalMenu( bMenuBar ); 215cdf0e10cSrcweir pAquaSalMenu->mpVCLMenu = pVCLMenu; 216cdf0e10cSrcweir 217cdf0e10cSrcweir return pAquaSalMenu; 218cdf0e10cSrcweir } 219cdf0e10cSrcweir 220cdf0e10cSrcweir void AquaSalInstance::DestroyMenu( SalMenu* pSalMenu ) 221cdf0e10cSrcweir { 222cdf0e10cSrcweir delete pSalMenu; 223cdf0e10cSrcweir } 224cdf0e10cSrcweir 225cdf0e10cSrcweir SalMenuItem* AquaSalInstance::CreateMenuItem( const SalItemParams* pItemData ) 226cdf0e10cSrcweir { 227cdf0e10cSrcweir if( !pItemData ) 228cdf0e10cSrcweir return NULL; 229cdf0e10cSrcweir 230cdf0e10cSrcweir AquaSalMenuItem *pSalMenuItem = new AquaSalMenuItem( pItemData ); 231cdf0e10cSrcweir 232cdf0e10cSrcweir return pSalMenuItem; 233cdf0e10cSrcweir } 234cdf0e10cSrcweir 235cdf0e10cSrcweir void AquaSalInstance::DestroyMenuItem( SalMenuItem* pSalMenuItem ) 236cdf0e10cSrcweir { 237cdf0e10cSrcweir delete pSalMenuItem; 238cdf0e10cSrcweir } 239cdf0e10cSrcweir 240cdf0e10cSrcweir 241cdf0e10cSrcweir // ======================================================================= 242cdf0e10cSrcweir 243cdf0e10cSrcweir 244cdf0e10cSrcweir /* 245cdf0e10cSrcweir * AquaSalMenu 246cdf0e10cSrcweir */ 247cdf0e10cSrcweir 248cdf0e10cSrcweir AquaSalMenu::AquaSalMenu( bool bMenuBar ) : 249cdf0e10cSrcweir mbMenuBar( bMenuBar ), 250cdf0e10cSrcweir mpMenu( nil ), 251cdf0e10cSrcweir mpVCLMenu( NULL ), 252cdf0e10cSrcweir mpFrame( NULL ), 253cdf0e10cSrcweir mpParentSalMenu( NULL ) 254cdf0e10cSrcweir { 255cdf0e10cSrcweir if( ! mbMenuBar ) 256cdf0e10cSrcweir { 257cdf0e10cSrcweir mpMenu = [[SalNSMenu alloc] initWithMenu: this]; 258cdf0e10cSrcweir [mpMenu setDelegate: mpMenu]; 259cdf0e10cSrcweir } 260cdf0e10cSrcweir else 261cdf0e10cSrcweir { 262cdf0e10cSrcweir mpMenu = [NSApp mainMenu]; 263cdf0e10cSrcweir } 264cdf0e10cSrcweir [mpMenu setAutoenablesItems: NO]; 265cdf0e10cSrcweir } 266cdf0e10cSrcweir 267cdf0e10cSrcweir AquaSalMenu::~AquaSalMenu() 268cdf0e10cSrcweir { 269cdf0e10cSrcweir // actually someone should have done AquaSalFrame::SetMenu( NULL ) 270cdf0e10cSrcweir // on our frame, alas it is not so 271cdf0e10cSrcweir if( mpFrame && AquaSalFrame::isAlive( mpFrame ) && mpFrame->mpMenu == this ) 272cdf0e10cSrcweir const_cast<AquaSalFrame*>(mpFrame)->mpMenu = NULL; 273cdf0e10cSrcweir 274cdf0e10cSrcweir // this should normally be empty already, but be careful... 275cdf0e10cSrcweir for( size_t i = 0; i < maButtons.size(); i++ ) 276cdf0e10cSrcweir releaseButtonEntry( maButtons[i] ); 277cdf0e10cSrcweir maButtons.clear(); 278cdf0e10cSrcweir 279cdf0e10cSrcweir // is this leaking in some cases ? the release often leads to a duplicate release 280cdf0e10cSrcweir // it seems the parent item gets ownership of the menu 281cdf0e10cSrcweir if( mpMenu ) 282cdf0e10cSrcweir { 283cdf0e10cSrcweir if( mbMenuBar ) 284cdf0e10cSrcweir { 285cdf0e10cSrcweir if( pCurrentMenuBar == this ) 286cdf0e10cSrcweir { 287cdf0e10cSrcweir // if the current menubar gets destroyed, set the default menubar 288cdf0e10cSrcweir setDefaultMenu(); 289cdf0e10cSrcweir } 290cdf0e10cSrcweir } 291cdf0e10cSrcweir else 292cdf0e10cSrcweir // the system may still hold a reference on mpMenu 293cdf0e10cSrcweir { 294cdf0e10cSrcweir // so set the pointer to this AquaSalMenu to NULL 295cdf0e10cSrcweir // to protect from calling a dead object 296cdf0e10cSrcweir 297cdf0e10cSrcweir // in ! mbMenuBar case our mpMenu is actually a SalNSMenu* 298cdf0e10cSrcweir // so we can safely cast here 299cdf0e10cSrcweir [static_cast<SalNSMenu*>(mpMenu) setSalMenu: NULL]; 300cdf0e10cSrcweir /* #i89860# FIXME: 301cdf0e10cSrcweir using [autorelease] here (and in AquaSalMenuItem::~AquaSalMenuItem) 302cdf0e10cSrcweir instead of [release] fixes an occasional crash. That should 303cdf0e10cSrcweir indicate that we release menus / menu items in the wrong order 304cdf0e10cSrcweir somewhere, but I could not find that case. 305cdf0e10cSrcweir */ 306cdf0e10cSrcweir [mpMenu autorelease]; 307cdf0e10cSrcweir } 308cdf0e10cSrcweir } 309cdf0e10cSrcweir } 310cdf0e10cSrcweir 311cdf0e10cSrcweir sal_Int32 removeUnusedItemsRunner(NSMenu * pMenu) 312cdf0e10cSrcweir { 313cdf0e10cSrcweir NSArray * elements = [pMenu itemArray]; 314cdf0e10cSrcweir NSEnumerator * it = [elements objectEnumerator]; 315cdf0e10cSrcweir id elem; 316cdf0e10cSrcweir NSMenuItem * lastDisplayedMenuItem = nil; 317cdf0e10cSrcweir sal_Int32 drawnItems = 0; 318cdf0e10cSrcweir bool firstEnabledItemIsNoSeparator = false; 319cdf0e10cSrcweir while((elem=[it nextObject]) != nil) { 320cdf0e10cSrcweir NSMenuItem * item = static_cast<NSMenuItem *>(elem); 321cdf0e10cSrcweir if( (![item isEnabled] && ![item isSeparatorItem]) || ([item isSeparatorItem] && (lastDisplayedMenuItem != nil && [lastDisplayedMenuItem isSeparatorItem])) ) { 322cdf0e10cSrcweir [[item menu]removeItem:item]; 323cdf0e10cSrcweir } else { 324cdf0e10cSrcweir if( ! firstEnabledItemIsNoSeparator && [item isSeparatorItem] ) { 325cdf0e10cSrcweir [[item menu]removeItem:item]; 326cdf0e10cSrcweir } else { 327cdf0e10cSrcweir firstEnabledItemIsNoSeparator = true; 328cdf0e10cSrcweir lastDisplayedMenuItem = item; 329cdf0e10cSrcweir drawnItems++; 330cdf0e10cSrcweir if( [item hasSubmenu] ) { 331cdf0e10cSrcweir removeUnusedItemsRunner( [item submenu] ); 332cdf0e10cSrcweir } 333cdf0e10cSrcweir } 334cdf0e10cSrcweir } 335cdf0e10cSrcweir } 336cdf0e10cSrcweir if( lastDisplayedMenuItem != nil && [lastDisplayedMenuItem isSeparatorItem]) { 337cdf0e10cSrcweir [[lastDisplayedMenuItem menu]removeItem:lastDisplayedMenuItem]; 338cdf0e10cSrcweir } 339cdf0e10cSrcweir return drawnItems; 340cdf0e10cSrcweir } 341cdf0e10cSrcweir 342cdf0e10cSrcweir bool AquaSalMenu::ShowNativePopupMenu(FloatingWindow * pWin, const Rectangle& rRect, sal_uLong nFlags) 343cdf0e10cSrcweir { 344cdf0e10cSrcweir // do not use native popup menu when AQUA_NATIVE_MENUS is set to sal_False 345cdf0e10cSrcweir if( ! VisibleMenuBar() ) { 346cdf0e10cSrcweir return false; 347cdf0e10cSrcweir } 348cdf0e10cSrcweir 349cdf0e10cSrcweir // set offsets for positioning 350cdf0e10cSrcweir const float offset = 9.0; 351cdf0e10cSrcweir 352cdf0e10cSrcweir // get the pointers 353cdf0e10cSrcweir AquaSalFrame * pParentAquaSalFrame = (AquaSalFrame *) pWin->ImplGetWindowImpl()->mpRealParent->ImplGetFrame(); 354cdf0e10cSrcweir NSWindow * pParentNSWindow = pParentAquaSalFrame->mpWindow; 355cdf0e10cSrcweir NSView * pParentNSView = [pParentNSWindow contentView]; 356cdf0e10cSrcweir NSView * pPopupNSView = ((AquaSalFrame *) pWin->ImplGetWindow()->ImplGetFrame())->mpView; 357cdf0e10cSrcweir NSRect popupFrame = [pPopupNSView frame]; 358cdf0e10cSrcweir 359cdf0e10cSrcweir // since we manipulate the menu below (removing entries) 360cdf0e10cSrcweir // let's rather make a copy here and work with that 361cdf0e10cSrcweir NSMenu* pCopyMenu = [mpMenu copy]; 362cdf0e10cSrcweir 363cdf0e10cSrcweir // filter disabled elements 364cdf0e10cSrcweir removeUnusedItemsRunner( pCopyMenu ); 365cdf0e10cSrcweir 366cdf0e10cSrcweir // create frame rect 367cdf0e10cSrcweir NSRect displayPopupFrame = NSMakeRect( rRect.nLeft+(offset-1), rRect.nTop+(offset+1), popupFrame.size.width, 0 ); 368cdf0e10cSrcweir pParentAquaSalFrame->VCLToCocoa(displayPopupFrame, false); 369cdf0e10cSrcweir 370cdf0e10cSrcweir // do the same strange semantics as vcl popup windows to arrive at a frame geometry 371cdf0e10cSrcweir // in mirrored UI case; best done by actually executing the same code 372cdf0e10cSrcweir sal_uInt16 nArrangeIndex; 373cdf0e10cSrcweir pWin->SetPosPixel( pWin->ImplCalcPos( pWin, rRect, nFlags, nArrangeIndex ) ); 374cdf0e10cSrcweir displayPopupFrame.origin.x = pWin->ImplGetFrame()->maGeometry.nX - pParentAquaSalFrame->maGeometry.nX + offset; 375cdf0e10cSrcweir displayPopupFrame.origin.y = pWin->ImplGetFrame()->maGeometry.nY - pParentAquaSalFrame->maGeometry.nY + offset; 376cdf0e10cSrcweir pParentAquaSalFrame->VCLToCocoa(displayPopupFrame, false); 377cdf0e10cSrcweir 378cdf0e10cSrcweir // #i111992# if this menu was opened due to a key event, prevent dispatching that yet again 379cdf0e10cSrcweir if( [pParentNSView respondsToSelector: @selector(clearLastEvent)] ) 380cdf0e10cSrcweir [pParentNSView performSelector:@selector(clearLastEvent)]; 381cdf0e10cSrcweir 382cdf0e10cSrcweir // open popup menu 383cdf0e10cSrcweir NSPopUpButtonCell * pPopUpButtonCell = [[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]; 384cdf0e10cSrcweir [pPopUpButtonCell setMenu: pCopyMenu]; 385cdf0e10cSrcweir [pPopUpButtonCell selectItem:nil]; 386cdf0e10cSrcweir [AquaA11yWrapper setPopupMenuOpen: YES]; 387cdf0e10cSrcweir [pPopUpButtonCell performClickWithFrame:displayPopupFrame inView:pParentNSView]; 388cdf0e10cSrcweir [pPopUpButtonCell release]; 389cdf0e10cSrcweir [AquaA11yWrapper setPopupMenuOpen: NO]; 390cdf0e10cSrcweir 391cdf0e10cSrcweir // clean up the copy 392cdf0e10cSrcweir [pCopyMenu release]; 393cdf0e10cSrcweir return true; 394cdf0e10cSrcweir } 395cdf0e10cSrcweir 396cdf0e10cSrcweir int AquaSalMenu::getItemIndexByPos( sal_uInt16 nPos ) const 397cdf0e10cSrcweir { 398cdf0e10cSrcweir int nIndex = 0; 399cdf0e10cSrcweir if( nPos == MENU_APPEND ) 400cdf0e10cSrcweir nIndex = [mpMenu numberOfItems]; 401cdf0e10cSrcweir else 402cdf0e10cSrcweir nIndex = sal::static_int_cast<int>( mbMenuBar ? nPos+1 : nPos ); 403cdf0e10cSrcweir return nIndex; 404cdf0e10cSrcweir } 405cdf0e10cSrcweir 406cdf0e10cSrcweir const AquaSalFrame* AquaSalMenu::getFrame() const 407cdf0e10cSrcweir { 408cdf0e10cSrcweir const AquaSalMenu* pMenu = this; 409cdf0e10cSrcweir while( pMenu && ! pMenu->mpFrame ) 410cdf0e10cSrcweir pMenu = pMenu->mpParentSalMenu; 411cdf0e10cSrcweir return pMenu ? pMenu->mpFrame : NULL; 412cdf0e10cSrcweir } 413cdf0e10cSrcweir 414cdf0e10cSrcweir void AquaSalMenu::unsetMainMenu() 415cdf0e10cSrcweir { 416cdf0e10cSrcweir pCurrentMenuBar = NULL; 417cdf0e10cSrcweir 418cdf0e10cSrcweir // remove items from main menu 419cdf0e10cSrcweir NSMenu* pMenu = [NSApp mainMenu]; 420cdf0e10cSrcweir for( int nItems = [pMenu numberOfItems]; nItems > 1; nItems-- ) 421cdf0e10cSrcweir [pMenu removeItemAtIndex: 1]; 422cdf0e10cSrcweir } 423cdf0e10cSrcweir 424cdf0e10cSrcweir void AquaSalMenu::setMainMenu() 425cdf0e10cSrcweir { 426cdf0e10cSrcweir DBG_ASSERT( mbMenuBar, "setMainMenu on non menubar" ); 427cdf0e10cSrcweir if( mbMenuBar ) 428cdf0e10cSrcweir { 429cdf0e10cSrcweir if( pCurrentMenuBar != this ) 430cdf0e10cSrcweir { 431cdf0e10cSrcweir unsetMainMenu(); 432cdf0e10cSrcweir // insert our items 433cdf0e10cSrcweir for( unsigned int i = 0; i < maItems.size(); i++ ) 434cdf0e10cSrcweir { 435cdf0e10cSrcweir NSMenuItem* pItem = maItems[i]->mpMenuItem; 436cdf0e10cSrcweir [mpMenu insertItem: pItem atIndex: i+1]; 437cdf0e10cSrcweir } 438cdf0e10cSrcweir pCurrentMenuBar = this; 439cdf0e10cSrcweir 440cdf0e10cSrcweir // change status item 441cdf0e10cSrcweir statusLayout(); 442cdf0e10cSrcweir } 443cdf0e10cSrcweir enableMainMenu( true ); 444cdf0e10cSrcweir } 445cdf0e10cSrcweir } 446cdf0e10cSrcweir 447cdf0e10cSrcweir void AquaSalMenu::setDefaultMenu() 448cdf0e10cSrcweir { 449cdf0e10cSrcweir NSMenu* pMenu = [NSApp mainMenu]; 450cdf0e10cSrcweir 451cdf0e10cSrcweir unsetMainMenu(); 452cdf0e10cSrcweir 453cdf0e10cSrcweir // insert default items 454cdf0e10cSrcweir std::vector< NSMenuItem* >& rFallbackMenu( GetSalData()->maFallbackMenu ); 455cdf0e10cSrcweir for( unsigned int i = 0, nAddItems = rFallbackMenu.size(); i < nAddItems; i++ ) 456cdf0e10cSrcweir { 457cdf0e10cSrcweir NSMenuItem* pItem = rFallbackMenu[i]; 458cdf0e10cSrcweir if( [pItem menu] == nil ) 459cdf0e10cSrcweir [pMenu insertItem: pItem atIndex: i+1]; 460cdf0e10cSrcweir } 461cdf0e10cSrcweir } 462cdf0e10cSrcweir 463cdf0e10cSrcweir void AquaSalMenu::enableMainMenu( bool bEnable ) 464cdf0e10cSrcweir { 465cdf0e10cSrcweir NSMenu* pMainMenu = [NSApp mainMenu]; 466cdf0e10cSrcweir if( pMainMenu ) 467cdf0e10cSrcweir { 468cdf0e10cSrcweir // enable/disable items from main menu 469cdf0e10cSrcweir int nItems = [pMainMenu numberOfItems]; 470cdf0e10cSrcweir for( int n = 1; n < nItems; n++ ) 471cdf0e10cSrcweir { 472cdf0e10cSrcweir NSMenuItem* pItem = [pMainMenu itemAtIndex: n]; 473cdf0e10cSrcweir [pItem setEnabled: bEnable ? YES : NO]; 474cdf0e10cSrcweir } 475cdf0e10cSrcweir } 476cdf0e10cSrcweir } 477cdf0e10cSrcweir 478cdf0e10cSrcweir void AquaSalMenu::addFallbackMenuItem( NSMenuItem* pNewItem ) 479cdf0e10cSrcweir { 480cdf0e10cSrcweir initAppMenu(); 481cdf0e10cSrcweir 482cdf0e10cSrcweir std::vector< NSMenuItem* >& rFallbackMenu( GetSalData()->maFallbackMenu ); 483cdf0e10cSrcweir 484cdf0e10cSrcweir // prevent duplicate insertion 485cdf0e10cSrcweir int nItems = rFallbackMenu.size(); 486cdf0e10cSrcweir for( int i = 0; i < nItems; i++ ) 487cdf0e10cSrcweir { 488cdf0e10cSrcweir if( rFallbackMenu[i] == pNewItem ) 489cdf0e10cSrcweir return; 490cdf0e10cSrcweir } 491cdf0e10cSrcweir 492cdf0e10cSrcweir // push the item to the back and retain it 493cdf0e10cSrcweir [pNewItem retain]; 494cdf0e10cSrcweir rFallbackMenu.push_back( pNewItem ); 495cdf0e10cSrcweir 496cdf0e10cSrcweir if( pCurrentMenuBar == NULL ) 497cdf0e10cSrcweir setDefaultMenu(); 498cdf0e10cSrcweir } 499cdf0e10cSrcweir 500cdf0e10cSrcweir void AquaSalMenu::removeFallbackMenuItem( NSMenuItem* pOldItem ) 501cdf0e10cSrcweir { 502cdf0e10cSrcweir std::vector< NSMenuItem* >& rFallbackMenu( GetSalData()->maFallbackMenu ); 503cdf0e10cSrcweir 504cdf0e10cSrcweir // find item 505cdf0e10cSrcweir unsigned int nItems = rFallbackMenu.size(); 506cdf0e10cSrcweir for( unsigned int i = 0; i < nItems; i++ ) 507cdf0e10cSrcweir { 508cdf0e10cSrcweir if( rFallbackMenu[i] == pOldItem ) 509cdf0e10cSrcweir { 510cdf0e10cSrcweir // remove item and release 511cdf0e10cSrcweir rFallbackMenu.erase( rFallbackMenu.begin() + i ); 512cdf0e10cSrcweir [pOldItem release]; 513cdf0e10cSrcweir 514cdf0e10cSrcweir if( pCurrentMenuBar == NULL ) 515cdf0e10cSrcweir setDefaultMenu(); 516cdf0e10cSrcweir 517cdf0e10cSrcweir return; 518cdf0e10cSrcweir } 519cdf0e10cSrcweir } 520cdf0e10cSrcweir } 521cdf0e10cSrcweir 522cdf0e10cSrcweir sal_Bool AquaSalMenu::VisibleMenuBar() 523cdf0e10cSrcweir { 524cdf0e10cSrcweir // Enable/disable experimental native menus code? 525cdf0e10cSrcweir // 526cdf0e10cSrcweir // To disable native menus, set the environment variable AQUA_NATIVE_MENUS to FALSE 527cdf0e10cSrcweir 528cdf0e10cSrcweir static const char *pExperimental = getenv ("AQUA_NATIVE_MENUS"); 529cdf0e10cSrcweir 530cdf0e10cSrcweir if ( ImplGetSVData()->mbIsTestTool || (pExperimental && !strcasecmp(pExperimental, "FALSE")) ) 531cdf0e10cSrcweir return sal_False; 532cdf0e10cSrcweir 533cdf0e10cSrcweir // End of experimental code enable/disable part 534cdf0e10cSrcweir 535cdf0e10cSrcweir return sal_True; 536cdf0e10cSrcweir } 537cdf0e10cSrcweir 538cdf0e10cSrcweir void AquaSalMenu::SetFrame( const SalFrame *pFrame ) 539cdf0e10cSrcweir { 540cdf0e10cSrcweir mpFrame = static_cast<const AquaSalFrame*>(pFrame); 541cdf0e10cSrcweir } 542cdf0e10cSrcweir 543cdf0e10cSrcweir void AquaSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos ) 544cdf0e10cSrcweir { 545cdf0e10cSrcweir AquaSalMenuItem *pAquaSalMenuItem = static_cast<AquaSalMenuItem*>(pSalMenuItem); 546cdf0e10cSrcweir 547cdf0e10cSrcweir pAquaSalMenuItem->mpParentMenu = this; 548cdf0e10cSrcweir DBG_ASSERT( pAquaSalMenuItem->mpVCLMenu == NULL || 549cdf0e10cSrcweir pAquaSalMenuItem->mpVCLMenu == mpVCLMenu || 550cdf0e10cSrcweir mpVCLMenu == NULL, 551cdf0e10cSrcweir "resetting menu ?" ); 552cdf0e10cSrcweir if( pAquaSalMenuItem->mpVCLMenu ) 553cdf0e10cSrcweir mpVCLMenu = pAquaSalMenuItem->mpVCLMenu; 554cdf0e10cSrcweir 555cdf0e10cSrcweir if( nPos == MENU_APPEND || nPos == maItems.size() ) 556cdf0e10cSrcweir maItems.push_back( pAquaSalMenuItem ); 557cdf0e10cSrcweir else if( nPos < maItems.size() ) 558cdf0e10cSrcweir maItems.insert( maItems.begin() + nPos, pAquaSalMenuItem ); 559cdf0e10cSrcweir else 560cdf0e10cSrcweir { 561cdf0e10cSrcweir DBG_ERROR( "invalid item index in insert" ); 562cdf0e10cSrcweir return; 563cdf0e10cSrcweir } 564cdf0e10cSrcweir 565cdf0e10cSrcweir if( ! mbMenuBar || pCurrentMenuBar == this ) 566cdf0e10cSrcweir [mpMenu insertItem: pAquaSalMenuItem->mpMenuItem atIndex: getItemIndexByPos(nPos)]; 567cdf0e10cSrcweir } 568cdf0e10cSrcweir 569cdf0e10cSrcweir void AquaSalMenu::RemoveItem( unsigned nPos ) 570cdf0e10cSrcweir { 571cdf0e10cSrcweir AquaSalMenuItem* pRemoveItem = NULL; 572cdf0e10cSrcweir if( nPos == MENU_APPEND || nPos == (maItems.size()-1) ) 573cdf0e10cSrcweir { 574cdf0e10cSrcweir pRemoveItem = maItems.back(); 575cdf0e10cSrcweir maItems.pop_back(); 576cdf0e10cSrcweir } 577cdf0e10cSrcweir else if( nPos < maItems.size() ) 578cdf0e10cSrcweir { 579cdf0e10cSrcweir pRemoveItem = maItems[ nPos ]; 580cdf0e10cSrcweir maItems.erase( maItems.begin()+nPos ); 581cdf0e10cSrcweir } 582cdf0e10cSrcweir else 583cdf0e10cSrcweir { 584cdf0e10cSrcweir DBG_ERROR( "invalid item index in remove" ); 585cdf0e10cSrcweir return; 586cdf0e10cSrcweir } 587cdf0e10cSrcweir 588cdf0e10cSrcweir pRemoveItem->mpParentMenu = NULL; 589cdf0e10cSrcweir 590cdf0e10cSrcweir if( ! mbMenuBar || pCurrentMenuBar == this ) 591cdf0e10cSrcweir [mpMenu removeItemAtIndex: getItemIndexByPos(nPos)]; 592cdf0e10cSrcweir } 593cdf0e10cSrcweir 594cdf0e10cSrcweir void AquaSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned /*nPos*/ ) 595cdf0e10cSrcweir { 596cdf0e10cSrcweir AquaSalMenuItem *pAquaSalMenuItem = static_cast<AquaSalMenuItem*>(pSalMenuItem); 597cdf0e10cSrcweir AquaSalMenu *subAquaSalMenu = static_cast<AquaSalMenu*>(pSubMenu); 598cdf0e10cSrcweir 599cdf0e10cSrcweir if (subAquaSalMenu) 600cdf0e10cSrcweir { 601cdf0e10cSrcweir pAquaSalMenuItem->mpSubMenu = subAquaSalMenu; 602cdf0e10cSrcweir if( subAquaSalMenu->mpParentSalMenu == NULL ) 603cdf0e10cSrcweir { 604cdf0e10cSrcweir subAquaSalMenu->mpParentSalMenu = this; 605cdf0e10cSrcweir [pAquaSalMenuItem->mpMenuItem setSubmenu: subAquaSalMenu->mpMenu]; 606cdf0e10cSrcweir 607cdf0e10cSrcweir // set title of submenu 608cdf0e10cSrcweir [subAquaSalMenu->mpMenu setTitle: [pAquaSalMenuItem->mpMenuItem title]]; 609cdf0e10cSrcweir } 610cdf0e10cSrcweir else if( subAquaSalMenu->mpParentSalMenu != this ) 611cdf0e10cSrcweir { 612cdf0e10cSrcweir // cocoa doesn't allow menus to be submenus of multiple 613cdf0e10cSrcweir // menu items, so place a copy in the menu item instead ? 614cdf0e10cSrcweir // let's hope that NSMenu copy does the right thing 615cdf0e10cSrcweir NSMenu* pCopy = [subAquaSalMenu->mpMenu copy]; 616cdf0e10cSrcweir [pAquaSalMenuItem->mpMenuItem setSubmenu: pCopy]; 617cdf0e10cSrcweir 618cdf0e10cSrcweir // set title of submenu 619cdf0e10cSrcweir [pCopy setTitle: [pAquaSalMenuItem->mpMenuItem title]]; 620cdf0e10cSrcweir } 621cdf0e10cSrcweir } 622cdf0e10cSrcweir else 623cdf0e10cSrcweir { 624cdf0e10cSrcweir if( pAquaSalMenuItem->mpSubMenu ) 625cdf0e10cSrcweir { 626cdf0e10cSrcweir if( pAquaSalMenuItem->mpSubMenu->mpParentSalMenu == this ) 627cdf0e10cSrcweir pAquaSalMenuItem->mpSubMenu->mpParentSalMenu = NULL; 628cdf0e10cSrcweir } 629cdf0e10cSrcweir pAquaSalMenuItem->mpSubMenu = NULL; 630cdf0e10cSrcweir [pAquaSalMenuItem->mpMenuItem setSubmenu: nil]; 631cdf0e10cSrcweir } 632cdf0e10cSrcweir } 633cdf0e10cSrcweir 634cdf0e10cSrcweir void AquaSalMenu::CheckItem( unsigned nPos, sal_Bool bCheck ) 635cdf0e10cSrcweir { 636cdf0e10cSrcweir if( nPos < maItems.size() ) 637cdf0e10cSrcweir { 638cdf0e10cSrcweir NSMenuItem* pItem = maItems[nPos]->mpMenuItem; 639cdf0e10cSrcweir [pItem setState: bCheck ? NSOnState : NSOffState]; 640cdf0e10cSrcweir } 641cdf0e10cSrcweir } 642cdf0e10cSrcweir 643cdf0e10cSrcweir void AquaSalMenu::EnableItem( unsigned nPos, sal_Bool bEnable ) 644cdf0e10cSrcweir { 645cdf0e10cSrcweir if( nPos < maItems.size() ) 646cdf0e10cSrcweir { 647cdf0e10cSrcweir NSMenuItem* pItem = maItems[nPos]->mpMenuItem; 648cdf0e10cSrcweir [pItem setEnabled: bEnable ? YES : NO]; 649cdf0e10cSrcweir } 650cdf0e10cSrcweir } 651cdf0e10cSrcweir 652cdf0e10cSrcweir void AquaSalMenu::SetItemImage( unsigned /*nPos*/, SalMenuItem* pSMI, const Image& rImage ) 653cdf0e10cSrcweir { 654cdf0e10cSrcweir AquaSalMenuItem* pSalMenuItem = static_cast<AquaSalMenuItem*>( pSMI ); 655cdf0e10cSrcweir if( ! pSalMenuItem || ! pSalMenuItem->mpMenuItem ) 656cdf0e10cSrcweir return; 657cdf0e10cSrcweir 658cdf0e10cSrcweir NSImage* pImage = CreateNSImage( rImage ); 659cdf0e10cSrcweir 660cdf0e10cSrcweir [pSalMenuItem->mpMenuItem setImage: pImage]; 661cdf0e10cSrcweir if( pImage ) 662cdf0e10cSrcweir [pImage release]; 663cdf0e10cSrcweir } 664cdf0e10cSrcweir 665cdf0e10cSrcweir void AquaSalMenu::SetItemText( unsigned /*i_nPos*/, SalMenuItem* i_pSalMenuItem, const XubString& i_rText ) 666cdf0e10cSrcweir { 667cdf0e10cSrcweir if (!i_pSalMenuItem) 668cdf0e10cSrcweir return; 669cdf0e10cSrcweir 670cdf0e10cSrcweir AquaSalMenuItem *pAquaSalMenuItem = (AquaSalMenuItem *) i_pSalMenuItem; 671cdf0e10cSrcweir 672cdf0e10cSrcweir String aText( i_rText ); 673cdf0e10cSrcweir 674cdf0e10cSrcweir // Delete mnemonics 675cdf0e10cSrcweir aText.EraseAllChars( '~' ); 676cdf0e10cSrcweir 677cdf0e10cSrcweir /* #i90015# until there is a correct solution 678cdf0e10cSrcweir strip out any appended (.*) in menubar entries 679cdf0e10cSrcweir */ 680cdf0e10cSrcweir if( mbMenuBar ) 681cdf0e10cSrcweir { 682cdf0e10cSrcweir xub_StrLen nPos = aText.SearchBackward( sal_Unicode( '(' ) ); 683cdf0e10cSrcweir if( nPos != STRING_NOTFOUND ) 684cdf0e10cSrcweir { 685cdf0e10cSrcweir xub_StrLen nPos2 = aText.Search( sal_Unicode( ')' ) ); 686cdf0e10cSrcweir if( nPos2 != STRING_NOTFOUND ) 687cdf0e10cSrcweir aText.Erase( nPos, nPos2-nPos+1 ); 688cdf0e10cSrcweir } 689cdf0e10cSrcweir } 690cdf0e10cSrcweir 691cdf0e10cSrcweir NSString* pString = CreateNSString( aText ); 692cdf0e10cSrcweir if (pString) 693cdf0e10cSrcweir { 694cdf0e10cSrcweir [pAquaSalMenuItem->mpMenuItem setTitle: pString]; 695cdf0e10cSrcweir // if the menu item has a submenu, change its title as well 696cdf0e10cSrcweir if (pAquaSalMenuItem->mpSubMenu) 697cdf0e10cSrcweir [pAquaSalMenuItem->mpSubMenu->mpMenu setTitle: pString]; 698cdf0e10cSrcweir [pString release]; 699cdf0e10cSrcweir } 700cdf0e10cSrcweir } 701cdf0e10cSrcweir 702cdf0e10cSrcweir void AquaSalMenu::SetAccelerator( unsigned /*nPos*/, SalMenuItem* pSalMenuItem, const KeyCode& rKeyCode, const XubString& /*rKeyName*/ ) 703cdf0e10cSrcweir { 704cdf0e10cSrcweir sal_uInt16 nModifier; 705cdf0e10cSrcweir sal_Unicode nCommandKey = 0; 706cdf0e10cSrcweir 707cdf0e10cSrcweir sal_uInt16 nKeyCode=rKeyCode.GetCode(); 708cdf0e10cSrcweir if( nKeyCode ) 709cdf0e10cSrcweir { 710cdf0e10cSrcweir if ((nKeyCode>=KEY_A) && (nKeyCode<=KEY_Z)) // letter A..Z 711cdf0e10cSrcweir nCommandKey = nKeyCode-KEY_A + 'a'; 712cdf0e10cSrcweir else if ((nKeyCode>=KEY_0) && (nKeyCode<=KEY_9)) // numbers 0..9 713cdf0e10cSrcweir nCommandKey = nKeyCode-KEY_0 + '0'; 714cdf0e10cSrcweir else if ((nKeyCode>=KEY_F1) && (nKeyCode<=KEY_F26)) // function keys F1..F26 715cdf0e10cSrcweir nCommandKey = nKeyCode-KEY_F1 + NSF1FunctionKey; 716cdf0e10cSrcweir else if( nKeyCode == KEY_REPEAT ) 717cdf0e10cSrcweir nCommandKey = NSRedoFunctionKey; 718cdf0e10cSrcweir else if( nKeyCode == KEY_SPACE ) 719cdf0e10cSrcweir nCommandKey = ' '; 720cdf0e10cSrcweir else 721cdf0e10cSrcweir { 722cdf0e10cSrcweir switch (nKeyCode) 723cdf0e10cSrcweir { 724cdf0e10cSrcweir case KEY_ADD: 725cdf0e10cSrcweir nCommandKey='+'; 726cdf0e10cSrcweir break; 727cdf0e10cSrcweir case KEY_SUBTRACT: 728cdf0e10cSrcweir nCommandKey='-'; 729cdf0e10cSrcweir break; 730cdf0e10cSrcweir case KEY_MULTIPLY: 731cdf0e10cSrcweir nCommandKey='*'; 732cdf0e10cSrcweir break; 733cdf0e10cSrcweir case KEY_DIVIDE: 734cdf0e10cSrcweir nCommandKey='/'; 735cdf0e10cSrcweir break; 736cdf0e10cSrcweir case KEY_POINT: 737cdf0e10cSrcweir nCommandKey='.'; 738cdf0e10cSrcweir break; 739cdf0e10cSrcweir case KEY_LESS: 740cdf0e10cSrcweir nCommandKey='<'; 741cdf0e10cSrcweir break; 742cdf0e10cSrcweir case KEY_GREATER: 743cdf0e10cSrcweir nCommandKey='>'; 744cdf0e10cSrcweir break; 745cdf0e10cSrcweir case KEY_EQUAL: 746cdf0e10cSrcweir nCommandKey='='; 747cdf0e10cSrcweir break; 748cdf0e10cSrcweir } 749cdf0e10cSrcweir } 750cdf0e10cSrcweir } 751cdf0e10cSrcweir else // not even a code ? nonsense -> ignore 752cdf0e10cSrcweir return; 753cdf0e10cSrcweir 754cdf0e10cSrcweir DBG_ASSERT( nCommandKey, "unmapped accelerator key" ); 755cdf0e10cSrcweir 756cdf0e10cSrcweir nModifier=rKeyCode.GetAllModifier(); 757cdf0e10cSrcweir 758cdf0e10cSrcweir // should always use the command key 759cdf0e10cSrcweir int nItemModifier = 0; 760cdf0e10cSrcweir 761cdf0e10cSrcweir if (nModifier & KEY_SHIFT) 762cdf0e10cSrcweir { 763cdf0e10cSrcweir nItemModifier |= NSShiftKeyMask; // actually useful only for function keys 764cdf0e10cSrcweir if( nKeyCode >= KEY_A && nKeyCode <= KEY_Z ) 765cdf0e10cSrcweir nCommandKey = nKeyCode - KEY_A + 'A'; 766cdf0e10cSrcweir } 767cdf0e10cSrcweir 768cdf0e10cSrcweir if (nModifier & KEY_MOD1) 769cdf0e10cSrcweir nItemModifier |= NSCommandKeyMask; 770cdf0e10cSrcweir 771cdf0e10cSrcweir if(nModifier & KEY_MOD2) 772cdf0e10cSrcweir nItemModifier |= NSAlternateKeyMask; 773cdf0e10cSrcweir 774cdf0e10cSrcweir if(nModifier & KEY_MOD3) 775cdf0e10cSrcweir nItemModifier |= NSControlKeyMask; 776cdf0e10cSrcweir 777cdf0e10cSrcweir AquaSalMenuItem *pAquaSalMenuItem = (AquaSalMenuItem *) pSalMenuItem; 778cdf0e10cSrcweir NSString* pString = CreateNSString( rtl::OUString( &nCommandKey, 1 ) ); 779cdf0e10cSrcweir [pAquaSalMenuItem->mpMenuItem setKeyEquivalent: pString]; 780cdf0e10cSrcweir [pAquaSalMenuItem->mpMenuItem setKeyEquivalentModifierMask: nItemModifier]; 781cdf0e10cSrcweir if (pString) 782cdf0e10cSrcweir [pString release]; 783cdf0e10cSrcweir } 784cdf0e10cSrcweir 785cdf0e10cSrcweir void AquaSalMenu::GetSystemMenuData( SystemMenuData* ) 786cdf0e10cSrcweir { 787cdf0e10cSrcweir } 788cdf0e10cSrcweir 789cdf0e10cSrcweir AquaSalMenu::MenuBarButtonEntry* AquaSalMenu::findButtonItem( sal_uInt16 i_nItemId ) 790cdf0e10cSrcweir { 791cdf0e10cSrcweir for( size_t i = 0; i < maButtons.size(); ++i ) 792cdf0e10cSrcweir { 793cdf0e10cSrcweir if( maButtons[i].maButton.mnId == i_nItemId ) 794cdf0e10cSrcweir return &maButtons[i]; 795cdf0e10cSrcweir } 796cdf0e10cSrcweir return NULL; 797cdf0e10cSrcweir } 798cdf0e10cSrcweir 799cdf0e10cSrcweir void AquaSalMenu::statusLayout() 800cdf0e10cSrcweir { 801cdf0e10cSrcweir if( GetSalData()->mpStatusItem ) 802cdf0e10cSrcweir { 803cdf0e10cSrcweir NSView* pView = [GetSalData()->mpStatusItem view]; 804cdf0e10cSrcweir if( [pView isMemberOfClass: [OOStatusItemView class]] ) // well of course it is 805cdf0e10cSrcweir [(OOStatusItemView*)pView layout]; 806cdf0e10cSrcweir else 807cdf0e10cSrcweir DBG_ERROR( "someone stole our status view" ); 808cdf0e10cSrcweir } 809cdf0e10cSrcweir } 810cdf0e10cSrcweir 811cdf0e10cSrcweir void AquaSalMenu::releaseButtonEntry( MenuBarButtonEntry& i_rEntry ) 812cdf0e10cSrcweir { 813cdf0e10cSrcweir if( i_rEntry.mpNSImage ) 814cdf0e10cSrcweir { 815cdf0e10cSrcweir [i_rEntry.mpNSImage release]; 816cdf0e10cSrcweir i_rEntry.mpNSImage = nil; 817cdf0e10cSrcweir } 818cdf0e10cSrcweir if( i_rEntry.mpToolTipString ) 819cdf0e10cSrcweir { 820cdf0e10cSrcweir [i_rEntry.mpToolTipString release]; 821cdf0e10cSrcweir i_rEntry.mpToolTipString = nil; 822cdf0e10cSrcweir } 823cdf0e10cSrcweir } 824cdf0e10cSrcweir 825cdf0e10cSrcweir bool AquaSalMenu::AddMenuBarButton( const SalMenuButtonItem& i_rNewItem ) 826cdf0e10cSrcweir { 827cdf0e10cSrcweir if( ! mbMenuBar || ! VisibleMenuBar() ) 828cdf0e10cSrcweir return false; 829cdf0e10cSrcweir 830cdf0e10cSrcweir MenuBarButtonEntry* pEntry = findButtonItem( i_rNewItem.mnId ); 831cdf0e10cSrcweir if( pEntry ) 832cdf0e10cSrcweir { 833cdf0e10cSrcweir releaseButtonEntry( *pEntry ); 834cdf0e10cSrcweir pEntry->maButton = i_rNewItem; 835cdf0e10cSrcweir pEntry->mpNSImage = CreateNSImage( i_rNewItem.maImage ); 836cdf0e10cSrcweir if( i_rNewItem.maToolTipText.getLength() ) 837cdf0e10cSrcweir pEntry->mpToolTipString = CreateNSString( i_rNewItem.maToolTipText ); 838cdf0e10cSrcweir } 839cdf0e10cSrcweir else 840cdf0e10cSrcweir { 841cdf0e10cSrcweir maButtons.push_back( MenuBarButtonEntry( i_rNewItem ) ); 842cdf0e10cSrcweir maButtons.back().mpNSImage = CreateNSImage( i_rNewItem.maImage ); 843cdf0e10cSrcweir maButtons.back().mpToolTipString = CreateNSString( i_rNewItem.maToolTipText ); 844cdf0e10cSrcweir } 845cdf0e10cSrcweir 846cdf0e10cSrcweir // lazy create status item 847cdf0e10cSrcweir SalData::getStatusItem(); 848cdf0e10cSrcweir 849cdf0e10cSrcweir if( pCurrentMenuBar == this ) 850cdf0e10cSrcweir statusLayout(); 851cdf0e10cSrcweir 852cdf0e10cSrcweir return true; 853cdf0e10cSrcweir } 854cdf0e10cSrcweir 855cdf0e10cSrcweir void AquaSalMenu::RemoveMenuBarButton( sal_uInt16 i_nId ) 856cdf0e10cSrcweir { 857cdf0e10cSrcweir MenuBarButtonEntry* pEntry = findButtonItem( i_nId ); 858cdf0e10cSrcweir if( pEntry ) 859cdf0e10cSrcweir { 860cdf0e10cSrcweir releaseButtonEntry( *pEntry ); 861cdf0e10cSrcweir // note: vector guarantees that its contents are in a plain array 862cdf0e10cSrcweir maButtons.erase( maButtons.begin() + (pEntry - &maButtons[0]) ); 863cdf0e10cSrcweir } 864cdf0e10cSrcweir 865cdf0e10cSrcweir if( pCurrentMenuBar == this ) 866cdf0e10cSrcweir statusLayout(); 867cdf0e10cSrcweir } 868cdf0e10cSrcweir 869cdf0e10cSrcweir Rectangle AquaSalMenu::GetMenuBarButtonRectPixel( sal_uInt16 i_nItemId, SalFrame* i_pReferenceFrame ) 870cdf0e10cSrcweir { 871cdf0e10cSrcweir if( GetSalData()->mnSystemVersion < VER_LEOPARD ) 872cdf0e10cSrcweir return Rectangle( Point( -1, -1 ), Size( 1, 1 ) ); 873cdf0e10cSrcweir 874cdf0e10cSrcweir if( ! i_pReferenceFrame || ! AquaSalFrame::isAlive( static_cast<AquaSalFrame*>(i_pReferenceFrame) ) ) 875cdf0e10cSrcweir return Rectangle(); 876cdf0e10cSrcweir 877cdf0e10cSrcweir MenuBarButtonEntry* pEntry = findButtonItem( i_nItemId ); 878cdf0e10cSrcweir 879cdf0e10cSrcweir if( ! pEntry ) 880cdf0e10cSrcweir return Rectangle(); 881cdf0e10cSrcweir 882cdf0e10cSrcweir NSStatusItem* pItem = SalData::getStatusItem(); 883cdf0e10cSrcweir if( ! pItem ) 884cdf0e10cSrcweir return Rectangle(); 885cdf0e10cSrcweir 886cdf0e10cSrcweir NSView* pView = [pItem view]; 887cdf0e10cSrcweir if( ! pView ) 888cdf0e10cSrcweir return Rectangle(); 889cdf0e10cSrcweir NSWindow* pWin = [pView window]; 890cdf0e10cSrcweir if( ! pWin ) 891cdf0e10cSrcweir return Rectangle(); 892cdf0e10cSrcweir 893cdf0e10cSrcweir NSRect aRect = [pWin frame]; 894cdf0e10cSrcweir aRect.origin = [pWin convertBaseToScreen: NSMakePoint( 0, 0 )]; 895cdf0e10cSrcweir 896cdf0e10cSrcweir // make coordinates relative to reference frame 897cdf0e10cSrcweir static_cast<AquaSalFrame*>(i_pReferenceFrame)->CocoaToVCL( aRect.origin ); 898cdf0e10cSrcweir aRect.origin.x -= i_pReferenceFrame->maGeometry.nX; 899cdf0e10cSrcweir aRect.origin.y -= i_pReferenceFrame->maGeometry.nY + aRect.size.height; 900cdf0e10cSrcweir 901cdf0e10cSrcweir return Rectangle( Point(static_cast<long int>(aRect.origin.x), 902cdf0e10cSrcweir static_cast<long int>(aRect.origin.y) 903cdf0e10cSrcweir ), 904cdf0e10cSrcweir Size( static_cast<long int>(aRect.size.width), 905cdf0e10cSrcweir static_cast<long int>(aRect.size.height) 906cdf0e10cSrcweir ) 907cdf0e10cSrcweir ); 908cdf0e10cSrcweir } 909cdf0e10cSrcweir 910cdf0e10cSrcweir // ======================================================================= 911cdf0e10cSrcweir 912cdf0e10cSrcweir /* 913cdf0e10cSrcweir * SalMenuItem 914cdf0e10cSrcweir */ 915cdf0e10cSrcweir 916cdf0e10cSrcweir AquaSalMenuItem::AquaSalMenuItem( const SalItemParams* pItemData ) : 917cdf0e10cSrcweir mnId( pItemData->nId ), 918cdf0e10cSrcweir mpVCLMenu( pItemData->pMenu ), 919cdf0e10cSrcweir mpParentMenu( NULL ), 920cdf0e10cSrcweir mpSubMenu( NULL ), 921cdf0e10cSrcweir mpMenuItem( nil ) 922cdf0e10cSrcweir { 923cdf0e10cSrcweir String aText( pItemData->aText ); 924cdf0e10cSrcweir 925cdf0e10cSrcweir // Delete mnemonics 926cdf0e10cSrcweir aText.EraseAllChars( '~' ); 927cdf0e10cSrcweir 928cdf0e10cSrcweir if (pItemData->eType == MENUITEM_SEPARATOR) 929cdf0e10cSrcweir { 930cdf0e10cSrcweir mpMenuItem = [NSMenuItem separatorItem]; 931cdf0e10cSrcweir // these can go occasionally go in and out of a menu, ensure their lifecycle 932cdf0e10cSrcweir // also for the release in AquaSalMenuItem destructor 933cdf0e10cSrcweir [mpMenuItem retain]; 934cdf0e10cSrcweir } 935cdf0e10cSrcweir else 936cdf0e10cSrcweir { 937cdf0e10cSrcweir mpMenuItem = [[SalNSMenuItem alloc] initWithMenuItem: this]; 938cdf0e10cSrcweir [mpMenuItem setEnabled: YES]; 939cdf0e10cSrcweir NSString* pString = CreateNSString( aText ); 940cdf0e10cSrcweir if (pString) 941cdf0e10cSrcweir { 942cdf0e10cSrcweir [mpMenuItem setTitle: pString]; 943cdf0e10cSrcweir [pString release]; 944cdf0e10cSrcweir } 945cdf0e10cSrcweir // anything but a separator should set a menu to dispatch to 946cdf0e10cSrcweir DBG_ASSERT( mpVCLMenu, "no menu" ); 947cdf0e10cSrcweir } 948cdf0e10cSrcweir } 949cdf0e10cSrcweir 950cdf0e10cSrcweir AquaSalMenuItem::~AquaSalMenuItem() 951cdf0e10cSrcweir { 952cdf0e10cSrcweir /* #i89860# FIXME: 953cdf0e10cSrcweir using [autorelease] here (and in AquaSalMenu:::~AquaSalMenu) instead of 954cdf0e10cSrcweir [release] fixes an occasional crash. That should indicate that we release 955cdf0e10cSrcweir menus / menu items in the wrong order somewhere, but I 956cdf0e10cSrcweir could not find that case. 957cdf0e10cSrcweir */ 958cdf0e10cSrcweir if( mpMenuItem ) 959cdf0e10cSrcweir [mpMenuItem autorelease]; 960cdf0e10cSrcweir } 961cdf0e10cSrcweir 962cdf0e10cSrcweir // ------------------------------------------------------------------- 963cdf0e10cSrcweir 964