bump product version to 7.2.5.1
[LibreOffice.git] / vcl / osx / salnsmenu.mm
blob1dba47f031db37e600d436b05fd44ab6df7f4772
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
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
34     mpMenu = pMenu;
35     return [super initWithTitle: [NSString string]];
38 -(void)menuNeedsUpdate: (NSMenu*)pMenu
40     SolarMutexGuard aGuard;
42     if( mpMenu )
43     {
44         const AquaSalFrame* pFrame = mpMenu->getFrame();
45         if( pFrame && AquaSalFrame::isAlive( pFrame ) )
46         {
47             SalMenuEvent aMenuEvt;
48             aMenuEvt.mnId   = 0;
49             aMenuEvt.mpMenu = mpMenu->mpVCLMenu;
50             if( aMenuEvt.mpMenu )
51             {
52                 pFrame->CallCallback(SalEvent::MenuActivate, &aMenuEvt);
53                 pFrame->CallCallback(SalEvent::MenuDeactivate, &aMenuEvt);
54             }
55             else
56                 OSL_FAIL( "unconnected menu" );
57         }
58         else if( mpMenu->mpVCLMenu )
59         {
60             mpMenu->mpVCLMenu->Activate();
61             mpMenu->mpVCLMenu->Deactivate();
63             // Hide disabled items
64             NSArray* elements = [pMenu itemArray];
65             NSEnumerator* it = [elements objectEnumerator];
66             id element;
67             while ( ( element = [it nextObject] ) != nil )
68             {
69                 NSMenuItem* item = static_cast< NSMenuItem* >( element );
70                 if( ![item isSeparatorItem] )
71                     [item setHidden: ![item isEnabled]];
72             }
73         }
74     }
77 -(void)setSalMenu: (AquaSalMenu*)pMenu
79     mpMenu = pMenu;
81 @end
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];
91     return ret;
93 -(void)menuItemTriggered: (id)aSender
95     (void)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 )
109     {
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"] ) )
118         {
119             [[[NSApp keyWindow] contentView] keyDown: pEvent];
120             return;
121         }
122     }
123 SAL_WNODEPRECATED_DECLARATIONS_POP
125     const AquaSalFrame* pFrame = mpMenuItem->mpParentMenu ? mpMenuItem->mpParentMenu->getFrame() : nullptr;
126     if( pFrame && AquaSalFrame::isAlive( pFrame ) && ! pFrame->GetWindow()->IsInModalMode() )
127     {
128         SalMenuEvent aMenuEvt( mpMenuItem->mnId, mpMenuItem->mpVCLMenu );
129         pFrame->CallCallback(SalEvent::MenuCommand, &aMenuEvt);
130     }
131     else if( mpMenuItem->mpVCLMenu )
132     {
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());
137         if( pPopupMenu )
138         {
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 )
151             {
152                 pCurMenu = pParentMenu->mpVCLMenu;
153                 pParentMenu = pParentMenu->mpParentSalMenu;
154             }
156             pPopupMenu->SetSelectedEntry( mpMenuItem->mnId );
157             pPopupMenu->ImplSelectWithStart( pCurMenu );
158         }
159         else
160             OSL_FAIL( "menubar item without frame !" );
161     }
163 @end
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
173         // method obsolete"
174     [SalData::getStatusItem() drawStatusBarBackgroundInRect: aRect withHighlight: NO];
175 SAL_WNODEPRECATED_DECLARATIONS_POP
176     if( AquaSalMenu::pCurrentMenuBar )
177     {
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 )
182         {
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;
193         }
194     }
195     [pContext restoreGraphicsState];
198 -(void)mouseUp: (NSEvent *)pEvent
200     /* check if button goes up inside one of our status buttons */
201     if( AquaSalMenu::pCurrentMenuBar )
202     {
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 )
208         {
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) )
215             {
216                 if( AquaSalMenu::pCurrentMenuBar->mpFrame && AquaSalFrame::isAlive( AquaSalMenu::pCurrentMenuBar->mpFrame ) )
217                 {
218                     SalMenuEvent aMenuEvt( rButtons[i].maButton.mnId, AquaSalMenu::pCurrentMenuBar->mpVCLMenu );
219                     AquaSalMenu::pCurrentMenuBar->mpFrame->CallCallback(SalEvent::MenuButtonCommand, &aMenuEvt);
220                 }
221                 return;
222             }
224             aImgRect.origin.x += aFromRect.size.width + 2;
225         }
226     }
229 -(void)layout
231     NSStatusBar* pStatBar = [NSStatusBar systemStatusBar];
232     NSSize aSize = { 0, [pStatBar thickness] };
233     [self removeAllToolTips];
234     if( AquaSalMenu::pCurrentMenuBar )
235     {
236         const std::vector< AquaSalMenu::MenuBarButtonEntry >& rButtons( AquaSalMenu::pCurrentMenuBar->getButtons() );
237         if( ! rButtons.empty() )
238         {
239             aSize.width = 2;
240             for( size_t i = 0; i < rButtons.size(); ++i )
241             {
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;
249             }
250         }
251     }
252     [self setFrameSize: aSize];
254 @end
257 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */