xref: /aoo41x/main/vcl/aqua/source/window/salmenu.cxx (revision 245318c3)
19f62ea84SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
39f62ea84SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
49f62ea84SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
59f62ea84SAndrew Rist  * distributed with this work for additional information
69f62ea84SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
79f62ea84SAndrew Rist  * to you under the Apache License, Version 2.0 (the
89f62ea84SAndrew Rist  * "License"); you may not use this file except in compliance
99f62ea84SAndrew Rist  * with the License.  You may obtain a copy of the License at
109f62ea84SAndrew Rist  *
119f62ea84SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
129f62ea84SAndrew Rist  *
139f62ea84SAndrew Rist  * Unless required by applicable law or agreed to in writing,
149f62ea84SAndrew Rist  * software distributed under the License is distributed on an
159f62ea84SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
169f62ea84SAndrew Rist  * KIND, either express or implied.  See the License for the
179f62ea84SAndrew Rist  * specific language governing permissions and limitations
189f62ea84SAndrew Rist  * under the License.
199f62ea84SAndrew Rist  *
209f62ea84SAndrew Rist  *************************************************************/
219f62ea84SAndrew Rist 
229f62ea84SAndrew 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 
initAppMenu()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 
CreateMenu(sal_Bool bMenuBar,Menu * pVCLMenu)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 
DestroyMenu(SalMenu * pSalMenu)220cdf0e10cSrcweir void AquaSalInstance::DestroyMenu( SalMenu* pSalMenu )
221cdf0e10cSrcweir {
222cdf0e10cSrcweir     delete pSalMenu;
223cdf0e10cSrcweir }
224cdf0e10cSrcweir 
CreateMenuItem(const SalItemParams * pItemData)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 
DestroyMenuItem(SalMenuItem * pSalMenuItem)235cdf0e10cSrcweir void AquaSalInstance::DestroyMenuItem( SalMenuItem* pSalMenuItem )
236cdf0e10cSrcweir {
237cdf0e10cSrcweir     delete pSalMenuItem;
238cdf0e10cSrcweir }
239cdf0e10cSrcweir 
240cdf0e10cSrcweir 
241cdf0e10cSrcweir // =======================================================================
242cdf0e10cSrcweir 
243cdf0e10cSrcweir 
244cdf0e10cSrcweir /*
245cdf0e10cSrcweir  * AquaSalMenu
246cdf0e10cSrcweir  */
247cdf0e10cSrcweir 
AquaSalMenu(bool bMenuBar)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];
2582dae3561SHerbert Dürr         [mpMenu setDelegate: (id<NSMenuDelegate>)mpMenu];
259cdf0e10cSrcweir     }
260cdf0e10cSrcweir     else
261cdf0e10cSrcweir     {
262cdf0e10cSrcweir         mpMenu = [NSApp mainMenu];
263cdf0e10cSrcweir     }
264cdf0e10cSrcweir     [mpMenu setAutoenablesItems: NO];
265cdf0e10cSrcweir }
266cdf0e10cSrcweir 
~AquaSalMenu()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 
removeUnusedItemsRunner(NSMenu * pMenu)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 
ShowNativePopupMenu(FloatingWindow * pWin,const Rectangle & rRect,sal_uLong nFlags)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();
354bde8a4bdSHerbert Dürr     NSWindow* pParentNSWindow = pParentAquaSalFrame->mpNSWindow;
355bde8a4bdSHerbert Dürr     NSView* pParentNSView = [pParentNSWindow contentView];
356bde8a4bdSHerbert Dürr     NSView* pPopupNSView = ((AquaSalFrame *) pWin->ImplGetWindow()->ImplGetFrame())->mpNSView;
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 
getItemIndexByPos(sal_uInt16 nPos) const396cdf0e10cSrcweir 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 
getFrame() const406cdf0e10cSrcweir 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 
unsetMainMenu()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 
setMainMenu()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 
setDefaultMenu()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 
enableMainMenu(bool bEnable)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 
addFallbackMenuItem(NSMenuItem * pNewItem)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 
removeFallbackMenuItem(NSMenuItem * pOldItem)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 
VisibleMenuBar()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 
SetFrame(const SalFrame * pFrame)538cdf0e10cSrcweir void AquaSalMenu::SetFrame( const SalFrame *pFrame )
539cdf0e10cSrcweir {
540cdf0e10cSrcweir     mpFrame = static_cast<const AquaSalFrame*>(pFrame);
541cdf0e10cSrcweir }
542cdf0e10cSrcweir 
InsertItem(SalMenuItem * pSalMenuItem,unsigned nPos)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 
RemoveItem(unsigned nPos)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 
SetSubMenu(SalMenuItem * pSalMenuItem,SalMenu * pSubMenu,unsigned)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 
CheckItem(unsigned nPos,sal_Bool bCheck)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 
EnableItem(unsigned nPos,sal_Bool bEnable)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 
SetItemImage(unsigned,SalMenuItem * pSMI,const Image & rImage)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 
SetItemText(unsigned,SalMenuItem * i_pSalMenuItem,const XubString & i_rText)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 
SetAccelerator(unsigned,SalMenuItem * pSalMenuItem,const KeyCode & rKeyCode,const XubString &)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 
GetSystemMenuData(SystemMenuData *)785cdf0e10cSrcweir void AquaSalMenu::GetSystemMenuData( SystemMenuData* )
786cdf0e10cSrcweir {
787cdf0e10cSrcweir }
788cdf0e10cSrcweir 
findButtonItem(sal_uInt16 i_nItemId)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 
statusLayout()799cdf0e10cSrcweir void AquaSalMenu::statusLayout()
800cdf0e10cSrcweir {
801cdf0e10cSrcweir     if( GetSalData()->mpStatusItem )
802cdf0e10cSrcweir     {
803bde8a4bdSHerbert Dürr         NSView* pNSView = [GetSalData()->mpStatusItem view];
804bde8a4bdSHerbert Dürr         if( [pNSView isMemberOfClass: [OOStatusItemView class]] ) // well of course it is
805bde8a4bdSHerbert Dürr             [(OOStatusItemView*)pNSView layout];
806cdf0e10cSrcweir         else
807cdf0e10cSrcweir             DBG_ERROR( "someone stole our status view" );
808cdf0e10cSrcweir     }
809cdf0e10cSrcweir }
810cdf0e10cSrcweir 
releaseButtonEntry(MenuBarButtonEntry & i_rEntry)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 
AddMenuBarButton(const SalMenuButtonItem & i_rNewItem)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 
RemoveMenuBarButton(sal_uInt16 i_nId)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 
GetMenuBarButtonRectPixel(sal_uInt16 i_nItemId,SalFrame * i_pReferenceFrame)869cdf0e10cSrcweir Rectangle AquaSalMenu::GetMenuBarButtonRectPixel( sal_uInt16 i_nItemId, SalFrame* i_pReferenceFrame )
870cdf0e10cSrcweir {
871*245318c3SHerbert Dürr     if( GetSalData()->mnSystemVersion < OSX_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 
886bde8a4bdSHerbert Dürr     NSView* pNSView = [pItem view];
887bde8a4bdSHerbert Dürr     if( ! pNSView )
888cdf0e10cSrcweir         return Rectangle();
889bde8a4bdSHerbert Dürr     NSWindow* pNSWin = [pNSView window];
890bde8a4bdSHerbert Dürr     if( ! pNSWin )
891cdf0e10cSrcweir         return Rectangle();
892cdf0e10cSrcweir 
893bde8a4bdSHerbert Dürr     NSRect aRect = [pNSWin frame];
894bde8a4bdSHerbert Dürr     aRect.origin = [pNSWin 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 
AquaSalMenuItem(const SalItemParams * pItemData)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 
~AquaSalMenuItem()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