1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <osl/diagnose.h>
23 #include <vcl/window.hxx>
25 #include <osx/salinst.h>
26 #include <osx/saldata.hxx>
27 #include <osx/salframe.h>
28 #include <osx/salmenu.h>
29 #include <osx/salnsmenu.h>
31 @implementation SalNSMenu
32 -(id)initWithMenu: (AquaSalMenu*)pMenu
35 return [super initWithTitle: [NSString string]];
38 -(void)menuNeedsUpdate: (NSMenu*)pMenu
40 SolarMutexGuard aGuard;
44 const AquaSalFrame* pFrame = mpMenu->getFrame();
45 if( pFrame && AquaSalFrame::isAlive( pFrame ) )
47 SalMenuEvent aMenuEvt;
49 aMenuEvt.mpMenu = mpMenu->mpVCLMenu;
52 pFrame->CallCallback(SalEvent::MenuActivate, &aMenuEvt);
53 pFrame->CallCallback(SalEvent::MenuDeactivate, &aMenuEvt);
56 OSL_FAIL( "unconnected menu" );
58 else if( mpMenu->mpVCLMenu )
60 mpMenu->mpVCLMenu->Activate();
61 mpMenu->mpVCLMenu->Deactivate();
63 // Hide disabled items
64 NSArray* elements = [pMenu itemArray];
65 NSEnumerator* it = [elements objectEnumerator];
67 while ( ( element = [it nextObject] ) != nil )
69 NSMenuItem* item = static_cast< NSMenuItem* >( element );
70 if( ![item isSeparatorItem] )
71 [item setHidden: ![item isEnabled]];
77 -(void)setSalMenu: (AquaSalMenu*)pMenu
83 @implementation SalNSMenuItem
84 -(id)initWithMenuItem: (AquaSalMenuItem*)pMenuItem
86 mpMenuItem = pMenuItem;
87 id ret = [super initWithTitle: [NSString string]
88 action: @selector(menuItemTriggered:)
89 keyEquivalent: [NSString string]];
90 [ret setTarget: self];
93 -(void)menuItemTriggered: (id)aSender
96 SolarMutexGuard aGuard;
98 // tdf#49853 Keyboard shortcuts are also handled by the menu bar, but at least some of them
99 // must still end up in the view. This is necessary to handle common edit actions in docked
100 // windows (e.g. in toolbar fields).
101 NSEvent* pEvent = [NSApp currentEvent];
102 SAL_WNODEPRECATED_DECLARATIONS_PUSH
103 // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12
104 // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12
105 // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12
106 // 'NSKeyDown' is deprecated: first deprecated in macOS 10.12
107 // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12
108 if( pEvent && [pEvent type] == NSKeyDown )
110 unsigned int nModMask = ([pEvent modifierFlags] & (NSShiftKeyMask|NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask));
111 NSString* charactersIgnoringModifiers = [pEvent charactersIgnoringModifiers];
112 if( nModMask == NSCommandKeyMask &&
113 ( [charactersIgnoringModifiers isEqualToString: @"v"] ||
114 [charactersIgnoringModifiers isEqualToString: @"c"] ||
115 [charactersIgnoringModifiers isEqualToString: @"x"] ||
116 [charactersIgnoringModifiers isEqualToString: @"a"] ||
117 [charactersIgnoringModifiers isEqualToString: @"z"] ) )
119 [[[NSApp keyWindow] contentView] keyDown: pEvent];
123 SAL_WNODEPRECATED_DECLARATIONS_POP
125 const AquaSalFrame* pFrame = mpMenuItem->mpParentMenu ? mpMenuItem->mpParentMenu->getFrame() : nullptr;
126 if( pFrame && AquaSalFrame::isAlive( pFrame ) && ! pFrame->GetWindow()->IsInModalMode() )
128 SalMenuEvent aMenuEvt( mpMenuItem->mnId, mpMenuItem->mpVCLMenu );
129 pFrame->CallCallback(SalEvent::MenuCommand, &aMenuEvt);
131 else if( mpMenuItem->mpVCLMenu )
133 // if an item from submenu was selected. the corresponding Window does not exist because
134 // we use native popup menus, so we have to set the selected menuitem directly
135 // incidentally this of course works for top level popup menus, too
136 PopupMenu * pPopupMenu = dynamic_cast<PopupMenu *>(mpMenuItem->mpVCLMenu.get());
139 // FIXME: revise this ugly code
141 // select handlers in vcl are dispatch on the original menu
142 // if not consumed by the select handler of the current menu
143 // however since only the starting menu ever came into Execute
144 // the hierarchy is not build up. Workaround this by getting
145 // the menu it should have been
147 // get started from hierarchy in vcl menus
148 AquaSalMenu* pParentMenu = mpMenuItem->mpParentMenu;
149 Menu* pCurMenu = mpMenuItem->mpVCLMenu;
150 while( pParentMenu && pParentMenu->mpVCLMenu )
152 pCurMenu = pParentMenu->mpVCLMenu;
153 pParentMenu = pParentMenu->mpParentSalMenu;
156 pPopupMenu->SetSelectedEntry( mpMenuItem->mnId );
157 pPopupMenu->ImplSelectWithStart( pCurMenu );
160 OSL_FAIL( "menubar item without frame !" );
165 @implementation OOStatusItemView
166 -(void)drawRect: (NSRect)aRect
168 NSGraphicsContext* pContext = [NSGraphicsContext currentContext];
169 [pContext saveGraphicsState];
170 SAL_WNODEPRECATED_DECLARATIONS_PUSH
171 // "'drawStatusBarBackgroundInRect:withHighlight:' is deprecated: first deprecated in macOS
172 // 10.14 - Use the standard button instead which handles highlight drawing, making this
174 [SalData::getStatusItem() drawStatusBarBackgroundInRect: aRect withHighlight: NO];
175 SAL_WNODEPRECATED_DECLARATIONS_POP
176 if( AquaSalMenu::pCurrentMenuBar )
178 const std::vector< AquaSalMenu::MenuBarButtonEntry >& rButtons( AquaSalMenu::pCurrentMenuBar->getButtons() );
179 NSRect aFrame = [self frame];
180 NSRect aImgRect = { { 2, 0 }, { 0, 0 } };
181 for( size_t i = 0; i < rButtons.size(); ++i )
183 const Size aPixSize = rButtons[i].maButton.maImage.GetSizePixel();
184 const NSRect aFromRect = { NSZeroPoint, NSMakeSize( aPixSize.Width(), aPixSize.Height()) };
185 aImgRect.origin.y = floor((aFrame.size.height - aFromRect.size.height)/2);
186 aImgRect.size = aFromRect.size;
187 if( rButtons[i].mpNSImage )
188 SAL_WNODEPRECATED_DECLARATIONS_PUSH
189 // 'NSCompositeSourceOver' is deprecated: first deprecated in macOS 10.12
190 [rButtons[i].mpNSImage drawInRect: aImgRect fromRect: aFromRect operation: NSCompositeSourceOver fraction: 1.0];
191 SAL_WNODEPRECATED_DECLARATIONS_POP
192 aImgRect.origin.x += aFromRect.size.width + 2;
195 [pContext restoreGraphicsState];
198 -(void)mouseUp: (NSEvent *)pEvent
200 /* check if button goes up inside one of our status buttons */
201 if( AquaSalMenu::pCurrentMenuBar )
203 const std::vector< AquaSalMenu::MenuBarButtonEntry >& rButtons( AquaSalMenu::pCurrentMenuBar->getButtons() );
204 NSRect aFrame = [self frame];
205 NSRect aImgRect = { { 2, 0 }, { 0, 0 } };
206 NSPoint aMousePt = [pEvent locationInWindow];
207 for( size_t i = 0; i < rButtons.size(); ++i )
209 const Size aPixSize = rButtons[i].maButton.maImage.GetSizePixel();
210 const NSRect aFromRect = { NSZeroPoint, NSMakeSize( aPixSize.Width(), aPixSize.Height()) };
211 aImgRect.origin.y = (aFrame.size.height - aFromRect.size.height)/2;
212 aImgRect.size = aFromRect.size;
213 if( aMousePt.x >= aImgRect.origin.x && aMousePt.x <= (aImgRect.origin.x+aImgRect.size.width) &&
214 aMousePt.y >= aImgRect.origin.y && aMousePt.y <= (aImgRect.origin.y+aImgRect.size.height) )
216 if( AquaSalMenu::pCurrentMenuBar->mpFrame && AquaSalFrame::isAlive( AquaSalMenu::pCurrentMenuBar->mpFrame ) )
218 SalMenuEvent aMenuEvt( rButtons[i].maButton.mnId, AquaSalMenu::pCurrentMenuBar->mpVCLMenu );
219 AquaSalMenu::pCurrentMenuBar->mpFrame->CallCallback(SalEvent::MenuButtonCommand, &aMenuEvt);
224 aImgRect.origin.x += aFromRect.size.width + 2;
231 NSStatusBar* pStatBar = [NSStatusBar systemStatusBar];
232 NSSize aSize = { 0, [pStatBar thickness] };
233 [self removeAllToolTips];
234 if( AquaSalMenu::pCurrentMenuBar )
236 const std::vector< AquaSalMenu::MenuBarButtonEntry >& rButtons( AquaSalMenu::pCurrentMenuBar->getButtons() );
237 if( ! rButtons.empty() )
240 for( size_t i = 0; i < rButtons.size(); ++i )
242 NSRect aImgRect = { { aSize.width,
243 static_cast<CGFloat>(floor((aSize.height-rButtons[i].maButton.maImage.GetSizePixel().Height())/2)) },
244 { static_cast<CGFloat>(rButtons[i].maButton.maImage.GetSizePixel().Width()),
245 static_cast<CGFloat>(rButtons[i].maButton.maImage.GetSizePixel().Height()) } };
246 if( rButtons[i].mpToolTipString )
247 [self addToolTipRect: aImgRect owner: rButtons[i].mpToolTipString userData: nullptr];
248 aSize.width += 2 + aImgRect.size.width;
252 [self setFrameSize: aSize];
257 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */