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  */
19 
20 #include <string>
21 
22 #include <comphelper/fileurl.hxx>
23 #include <rtl/ustrbuf.hxx>
24 #include <sal/log.hxx>
25 #include <tools/long.hxx>
26 #include <o3tl/safeint.hxx>
27 #include <osl/diagnose.h>
28 
29 #include <osl/file.h>
30 
31 #include <vcl/event.hxx>
32 #include <vcl/inputctx.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/window.hxx>
35 #include <vcl/syswin.hxx>
36 #include <vcl/settings.hxx>
37 
38 #include <osx/saldata.hxx>
39 #include <quartz/salgdi.h>
40 #include <osx/salframe.h>
41 #include <osx/salmenu.h>
42 #include <osx/salinst.h>
43 #include <osx/salframeview.h>
44 #include <osx/a11yfactory.h>
45 #include <osx/runinmain.hxx>
46 #include <quartz/utils.h>
47 
48 #include <salwtype.hxx>
49 
50 #include <premac.h>
51 #include <objc/objc-runtime.h>
52 // needed for theming
53 // FIXME: move theming code to salnativewidgets.cxx
54 #include <Carbon/Carbon.h>
55 #include <postmac.h>
56 
57 using namespace std;
58 
59 AquaSalFrame* AquaSalFrame::s_pCaptureFrame = nullptr;
60 
AquaSalFrame(SalFrame * pParent,SalFrameStyleFlags salFrameStyle)61 AquaSalFrame::AquaSalFrame( SalFrame* pParent, SalFrameStyleFlags salFrameStyle ) :
62     mpNSWindow(nil),
63     mpNSView(nil),
64     mpDockMenuEntry(nil),
65     mpGraphics(nullptr),
66     mpParent(nullptr),
67     mnMinWidth(0),
68     mnMinHeight(0),
69     mnMaxWidth(0),
70     mnMaxHeight(0),
71     mbGraphics(false),
72     mbFullScreen( false ),
73     mbShown(false),
74     mbInitShow(true),
75     mbPositioned(false),
76     mbSized(false),
77     mbPresentation( false ),
78     mnStyle( salFrameStyle ),
79     mnStyleMask( 0 ),
80     mnLastEventTime( 0 ),
81     mnLastModifierFlags( 0 ),
82     mpMenu( nullptr ),
83     mnExtStyle( 0 ),
84     mePointerStyle( PointerStyle::Arrow ),
85     mnTrackingRectTag( 0 ),
86     mrClippingPath( nullptr ),
87     mnICOptions( InputContextFlags::NONE ),
88     mnBlinkCursorDelay ( 500 )
89 {
90     mpParent = dynamic_cast<AquaSalFrame*>(pParent);
91 
92     initWindowAndView();
93 
94     SalData* pSalData = GetSalData();
95     pSalData->mpInstance->insertFrame( this );
96     NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
97     if (userDefaults != nil)
98     {
99         id setting = [userDefaults objectForKey: @"NSTextInsertionPointBlinkPeriodOn"];
100         if (setting)
101             mnBlinkCursorDelay = [setting intValue];
102         else
103         {
104             setting = [userDefaults objectForKey: @"NSTextInsertionPointBlinkPeriodOff"];
105             if (setting)
106                 mnBlinkCursorDelay = [setting intValue];
107         }
108     }
109 }
110 
~AquaSalFrame()111 AquaSalFrame::~AquaSalFrame()
112 {
113     if (mbFullScreen)
114         doShowFullScreen(false, maGeometry.nDisplayScreenNumber);
115 
116     assert( GetSalData()->mpInstance->IsMainThread() );
117 
118     // if the frame is destroyed and has the current menubar
119     // set the default menubar
120     if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu )
121         AquaSalMenu::setDefaultMenu();
122 
123     // cleanup clipping stuff
124     doResetClipRegion();
125 
126     [SalFrameView unsetMouseFrame: this];
127 
128     SalData* pSalData = GetSalData();
129     pSalData->mpInstance->eraseFrame( this );
130     pSalData->maPresentationFrames.remove( this );
131 
132     SAL_WARN_IF( this == s_pCaptureFrame, "vcl", "capture frame destroyed" );
133     if( this == s_pCaptureFrame )
134         s_pCaptureFrame = nullptr;
135 
136     delete mpGraphics;
137 
138     if( mpDockMenuEntry )
139     {
140         NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu();
141         // life cycle comment: the menu has ownership of the item, so no release
142         [pDock removeItem: mpDockMenuEntry];
143         if ([pDock numberOfItems] != 0
144             && [[pDock itemAtIndex: 0] isSeparatorItem])
145         {
146             [pDock removeItemAtIndex: 0];
147         }
148     }
149     if ( mpNSView ) {
150         [AquaA11yFactory revokeView: mpNSView];
151         [mpNSView release];
152     }
153     if ( mpNSWindow )
154         [mpNSWindow release];
155 }
156 
initWindowAndView()157 void AquaSalFrame::initWindowAndView()
158 {
159     OSX_SALDATA_RUNINMAIN( initWindowAndView() )
160 
161     // initialize mirroring parameters
162     // FIXME: screens changing
163     NSScreen* pNSScreen = [mpNSWindow screen];
164     if( pNSScreen == nil )
165         pNSScreen = [NSScreen mainScreen];
166     maScreenRect = [pNSScreen frame];
167 
168     // calculate some default geometry
169     NSRect aVisibleRect = [pNSScreen visibleFrame];
170     CocoaToVCL( aVisibleRect );
171 
172     maGeometry.nX = static_cast<int>(aVisibleRect.origin.x + aVisibleRect.size.width / 10);
173     maGeometry.nY = static_cast<int>(aVisibleRect.origin.y + aVisibleRect.size.height / 10);
174     maGeometry.nWidth = static_cast<unsigned int>(aVisibleRect.size.width * 0.8);
175     maGeometry.nHeight = static_cast<unsigned int>(aVisibleRect.size.height * 0.8);
176 
177     // calculate style mask
178 SAL_WNODEPRECATED_DECLARATIONS_PUSH
179         // 'NSBorderlessWindowMask' is deprecated: first deprecated in macOS 10.12
180         // 'NSClosableWindowMask' is deprecated: first deprecated in macOS 10.12
181         // 'NSMiniaturizableWindowMask' is deprecated: first deprecated in macOS 10.12
182         // 'NSResizableWindowMask' is deprecated: first deprecated in macOS 10.12
183         // 'NSTitledWindowMask' is deprecated: first deprecated in macOS 10.12
184     if( (mnStyle & SalFrameStyleFlags::FLOAT) ||
185         (mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION) )
186         mnStyleMask = NSBorderlessWindowMask;
187     else if( mnStyle & SalFrameStyleFlags::DEFAULT )
188     {
189         mnStyleMask = NSTitledWindowMask            |
190                       NSMiniaturizableWindowMask    |
191                       NSResizableWindowMask         |
192                       NSClosableWindowMask;
193         // make default window "maximized"
194         maGeometry.nX = static_cast<int>(aVisibleRect.origin.x);
195         maGeometry.nY = static_cast<int>(aVisibleRect.origin.y);
196         maGeometry.nWidth = static_cast<int>(aVisibleRect.size.width);
197         maGeometry.nHeight = static_cast<int>(aVisibleRect.size.height);
198         mbPositioned = mbSized = true;
199     }
200     else
201     {
202         if( mnStyle & SalFrameStyleFlags::MOVEABLE )
203         {
204             mnStyleMask |= NSTitledWindowMask;
205             if( mpParent == nullptr )
206                 mnStyleMask |= NSMiniaturizableWindowMask;
207         }
208         if( mnStyle & SalFrameStyleFlags::SIZEABLE )
209             mnStyleMask |= NSResizableWindowMask;
210         if( mnStyle & SalFrameStyleFlags::CLOSEABLE )
211             mnStyleMask |= NSClosableWindowMask;
212         // documentation says anything other than NSBorderlessWindowMask (=0)
213         // should also include NSTitledWindowMask;
214         if( mnStyleMask != 0 )
215             mnStyleMask |= NSTitledWindowMask;
216     }
217 SAL_WNODEPRECATED_DECLARATIONS_POP
218 
219     if (Application::IsBitmapRendering())
220         return;
221 
222     // #i91990# support GUI-less (daemon) execution
223     @try
224     {
225         mpNSWindow = [[SalFrameWindow alloc] initWithSalFrame: this];
226         mpNSView = [[SalFrameView alloc] initWithSalFrame: this];
227     }
228     @catch ( id )
229     {
230         std::abort();
231     }
232 
233     if( mnStyle & SalFrameStyleFlags::TOOLTIP )
234         [mpNSWindow setIgnoresMouseEvents: YES];
235     else
236         [mpNSWindow setAcceptsMouseMovedEvents: YES];
237     [mpNSWindow setHasShadow: YES];
238 
239     [mpNSWindow setDelegate: static_cast<id<NSWindowDelegate> >(mpNSWindow)];
240 
241     [mpNSWindow setRestorable:NO];
242     const NSRect aRect = { NSZeroPoint, NSMakeSize( maGeometry.nWidth, maGeometry.nHeight )};
243     mnTrackingRectTag = [mpNSView addTrackingRect: aRect owner: mpNSView userData: nil assumeInside: NO];
244 
245     maSysData.mpNSView = mpNSView;
246 
247     UpdateFrameGeometry();
248 
249     [mpNSWindow setContentView: mpNSView];
250 }
251 
CocoaToVCL(NSRect & io_rRect,bool bRelativeToScreen)252 void AquaSalFrame::CocoaToVCL( NSRect& io_rRect, bool bRelativeToScreen )
253 {
254     if( bRelativeToScreen )
255         io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height);
256     else
257         io_rRect.origin.y = maGeometry.nHeight - (io_rRect.origin.y+io_rRect.size.height);
258 }
259 
VCLToCocoa(NSRect & io_rRect,bool bRelativeToScreen)260 void AquaSalFrame::VCLToCocoa( NSRect& io_rRect, bool bRelativeToScreen )
261 {
262     if( bRelativeToScreen )
263         io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height);
264     else
265         io_rRect.origin.y = maGeometry.nHeight - (io_rRect.origin.y+io_rRect.size.height);
266 }
267 
CocoaToVCL(NSPoint & io_rPoint,bool bRelativeToScreen)268 void AquaSalFrame::CocoaToVCL( NSPoint& io_rPoint, bool bRelativeToScreen )
269 {
270     if( bRelativeToScreen )
271         io_rPoint.y = maScreenRect.size.height - io_rPoint.y;
272     else
273         io_rPoint.y = maGeometry.nHeight - io_rPoint.y;
274 }
275 
VCLToCocoa(NSPoint & io_rPoint,bool bRelativeToScreen)276 void AquaSalFrame::VCLToCocoa( NSPoint& io_rPoint, bool bRelativeToScreen )
277 {
278     if( bRelativeToScreen )
279         io_rPoint.y = maScreenRect.size.height - io_rPoint.y;
280     else
281         io_rPoint.y = maGeometry.nHeight - io_rPoint.y;
282 }
283 
screenParametersChanged()284 void AquaSalFrame::screenParametersChanged()
285 {
286     OSX_SALDATA_RUNINMAIN( screenParametersChanged() )
287 
288     UpdateFrameGeometry();
289 
290     if( mpGraphics )
291         mpGraphics->updateResolution();
292 
293     if (!mbGeometryDidChange)
294         return;
295 
296     CallCallback( SalEvent::DisplayChanged, nullptr );
297 }
298 
AcquireGraphics()299 SalGraphics* AquaSalFrame::AcquireGraphics()
300 {
301     if ( mbGraphics )
302         return nullptr;
303 
304     if ( !mpGraphics )
305     {
306         mpGraphics = new AquaSalGraphics;
307         mpGraphics->SetWindowGraphics( this );
308     }
309 
310     mbGraphics = true;
311     return mpGraphics;
312 }
313 
ReleaseGraphics(SalGraphics * pGraphics)314 void AquaSalFrame::ReleaseGraphics( SalGraphics *pGraphics )
315 {
316     SAL_WARN_IF( pGraphics != mpGraphics, "vcl", "graphics released on wrong frame" );
317     mbGraphics = false;
318 }
319 
PostEvent(std::unique_ptr<ImplSVEvent> pData)320 bool AquaSalFrame::PostEvent(std::unique_ptr<ImplSVEvent> pData)
321 {
322     GetSalData()->mpInstance->PostEvent( this, pData.release(), SalEvent::UserEvent );
323     return true;
324 }
325 
SetTitle(const OUString & rTitle)326 void AquaSalFrame::SetTitle(const OUString& rTitle)
327 {
328     if ( !mpNSWindow )
329         return;
330 
331     OSX_SALDATA_RUNINMAIN( SetTitle(rTitle) )
332 
333     // #i113170# may not be the main thread if called from UNO API
334     SalData::ensureThreadAutoreleasePool();
335 
336     NSString* pTitle = CreateNSString( rTitle );
337     [mpNSWindow setTitle: pTitle];
338 
339     // create an entry in the dock menu
340     const SalFrameStyleFlags nAppWindowStyle = SalFrameStyleFlags::CLOSEABLE | SalFrameStyleFlags::MOVEABLE;
341     if( mpParent == nullptr &&
342         (mnStyle & nAppWindowStyle) == nAppWindowStyle )
343     {
344         if( mpDockMenuEntry == nullptr )
345         {
346             NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu();
347 
348             if ([pDock numberOfItems] != 0) {
349                 NSMenuItem* pTopItem = [pDock itemAtIndex: 0];
350                 if ( [pTopItem hasSubmenu] )
351                     [pDock insertItem: [NSMenuItem separatorItem] atIndex: 0];
352             }
353 
354             mpDockMenuEntry = [pDock insertItemWithTitle: pTitle
355                                      action: @selector(dockMenuItemTriggered:)
356                                      keyEquivalent: @""
357                                      atIndex: 0];
358             [mpDockMenuEntry setTarget: mpNSWindow];
359 
360             // TODO: image (either the generic window image or an icon
361             // check mark (for "main" window ?)
362         }
363         else
364             [mpDockMenuEntry setTitle: pTitle];
365     }
366 
367     if (pTitle)
368         [pTitle release];
369 }
370 
SetIcon(sal_uInt16)371 void AquaSalFrame::SetIcon( sal_uInt16 )
372 {
373 }
374 
SetRepresentedURL(const OUString & i_rDocURL)375 void AquaSalFrame::SetRepresentedURL( const OUString& i_rDocURL )
376 {
377     OSX_SALDATA_RUNINMAIN( SetRepresentedURL( i_rDocURL ) )
378 
379     if( comphelper::isFileUrl(i_rDocURL) )
380     {
381         OUString aSysPath;
382         osl_getSystemPathFromFileURL( i_rDocURL.pData, &aSysPath.pData );
383         NSString* pStr = CreateNSString( aSysPath );
384         if( pStr )
385         {
386             [pStr autorelease];
387             [mpNSWindow setRepresentedFilename: pStr];
388         }
389     }
390 }
391 
initShow()392 void AquaSalFrame::initShow()
393 {
394     OSX_SALDATA_RUNINMAIN( initShow() )
395 
396     mbInitShow = false;
397     if( ! mbPositioned && ! mbFullScreen )
398     {
399         tools::Rectangle aScreenRect;
400         GetWorkArea( aScreenRect );
401         if( mpParent ) // center relative to parent
402         {
403             // center on parent
404             tools::Long nNewX = mpParent->maGeometry.nX + (static_cast<tools::Long>(mpParent->maGeometry.nWidth) - static_cast<tools::Long>(maGeometry.nWidth))/2;
405             if( nNewX < aScreenRect.Left() )
406                 nNewX = aScreenRect.Left();
407             if( tools::Long(nNewX + maGeometry.nWidth) > aScreenRect.Right() )
408                 nNewX = aScreenRect.Right() - maGeometry.nWidth-1;
409             tools::Long nNewY = mpParent->maGeometry.nY + (static_cast<tools::Long>(mpParent->maGeometry.nHeight) - static_cast<tools::Long>(maGeometry.nHeight))/2;
410             if( nNewY < aScreenRect.Top() )
411                 nNewY = aScreenRect.Top();
412             if( nNewY > aScreenRect.Bottom() )
413                 nNewY = aScreenRect.Bottom() - maGeometry.nHeight-1;
414             SetPosSize( nNewX - mpParent->maGeometry.nX,
415                         nNewY - mpParent->maGeometry.nY,
416                         0, 0,  SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
417         }
418         else if( ! (mnStyle & SalFrameStyleFlags::SIZEABLE) )
419         {
420             // center on screen
421             tools::Long nNewX = (aScreenRect.GetWidth() - maGeometry.nWidth)/2;
422             tools::Long nNewY = (aScreenRect.GetHeight() - maGeometry.nHeight)/2;
423             SetPosSize( nNewX, nNewY, 0, 0,  SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
424         }
425     }
426 
427     // make sure the view is present in the wrapper list before any children receive focus
428     [AquaA11yFactory registerView: mpNSView];
429 }
430 
SendPaintEvent(const tools::Rectangle * pRect)431 void AquaSalFrame::SendPaintEvent( const tools::Rectangle* pRect )
432 {
433     OSX_SALDATA_RUNINMAIN( SendPaintEvent( pRect ) )
434 
435     SalPaintEvent aPaintEvt( 0, 0, maGeometry.nWidth, maGeometry.nHeight, true );
436     if( pRect )
437     {
438         aPaintEvt.mnBoundX      = pRect->Left();
439         aPaintEvt.mnBoundY      = pRect->Top();
440         aPaintEvt.mnBoundWidth  = pRect->GetWidth();
441         aPaintEvt.mnBoundHeight = pRect->GetHeight();
442     }
443 
444     CallCallback(SalEvent::Paint, &aPaintEvt);
445 }
446 
Show(bool bVisible,bool bNoActivate)447 void AquaSalFrame::Show(bool bVisible, bool bNoActivate)
448 {
449     if ( !mpNSWindow )
450         return;
451 
452     OSX_SALDATA_RUNINMAIN( Show(bVisible, bNoActivate) )
453 
454     mbShown = bVisible;
455     if(bVisible)
456     {
457         if( mbInitShow )
458             initShow();
459 
460         CallCallback(SalEvent::Resize, nullptr);
461         // trigger filling our backbuffer
462         SendPaintEvent();
463 
464         if( bNoActivate || [mpNSWindow canBecomeKeyWindow] == NO )
465             [mpNSWindow orderFront: NSApp];
466         else
467             [mpNSWindow makeKeyAndOrderFront: NSApp];
468 
469         if( mpParent )
470         {
471             /* #i92674# #i96433# we do not want an invisible parent to show up (which adding a visible
472                child implicitly does). However we also do not want a parentless toolbar.
473 
474                HACK: try to decide when we should not insert a child to its parent
475                floaters and ownerdraw windows have not yet shown up in cases where
476                we don't want the parent to become visible
477             */
478             if( mpParent->mbShown || (mnStyle & (SalFrameStyleFlags::OWNERDRAWDECORATION | SalFrameStyleFlags::FLOAT) ) )
479             {
480                 [mpParent->mpNSWindow addChildWindow: mpNSWindow ordered: NSWindowAbove];
481             }
482         }
483 
484         if( mbPresentation )
485             [mpNSWindow makeMainWindow];
486     }
487     else
488     {
489         // if the frame holding the current menubar gets hidden
490         // show the default menubar
491         if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu )
492             AquaSalMenu::setDefaultMenu();
493 
494         // #i90440# #i94443# work around the focus going back to some other window
495         // if a child gets hidden for a parent window
496         if( mpParent && mpParent->mbShown && [mpNSWindow isKeyWindow] )
497             [mpParent->mpNSWindow makeKeyAndOrderFront: NSApp];
498 
499         [SalFrameView unsetMouseFrame: this];
500         if( mpParent && [mpNSWindow parentWindow] == mpParent->mpNSWindow )
501             [mpParent->mpNSWindow removeChildWindow: mpNSWindow];
502 
503         [mpNSWindow orderOut: NSApp];
504     }
505 }
506 
SetMinClientSize(tools::Long nWidth,tools::Long nHeight)507 void AquaSalFrame::SetMinClientSize( tools::Long nWidth, tools::Long nHeight )
508 {
509     OSX_SALDATA_RUNINMAIN( SetMinClientSize( nWidth, nHeight ) )
510 
511     mnMinWidth = nWidth;
512     mnMinHeight = nHeight;
513 
514     if( mpNSWindow )
515     {
516         // Always add the decoration as the dimension concerns only
517         // the content rectangle
518         nWidth += maGeometry.nLeftDecoration + maGeometry.nRightDecoration;
519         nHeight += maGeometry.nTopDecoration + maGeometry.nBottomDecoration;
520 
521         NSSize aSize = { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) };
522 
523         // Size of full window (content+structure) although we only
524         // have the client size in arguments
525         [mpNSWindow setMinSize: aSize];
526     }
527 }
528 
SetMaxClientSize(tools::Long nWidth,tools::Long nHeight)529 void AquaSalFrame::SetMaxClientSize( tools::Long nWidth, tools::Long nHeight )
530 {
531     OSX_SALDATA_RUNINMAIN( SetMaxClientSize( nWidth, nHeight ) )
532 
533     mnMaxWidth = nWidth;
534     mnMaxHeight = nHeight;
535 
536     if( mpNSWindow )
537     {
538         // Always add the decoration as the dimension concerns only
539         // the content rectangle
540         nWidth += maGeometry.nLeftDecoration + maGeometry.nRightDecoration;
541         nHeight += maGeometry.nTopDecoration + maGeometry.nBottomDecoration;
542 
543         // Carbon windows can't have a size greater than 32767x32767
544         if (nWidth>32767) nWidth=32767;
545         if (nHeight>32767) nHeight=32767;
546 
547         NSSize aSize = { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) };
548 
549         // Size of full window (content+structure) although we only
550         // have the client size in arguments
551         [mpNSWindow setMaxSize: aSize];
552     }
553 }
554 
GetClientSize(tools::Long & rWidth,tools::Long & rHeight)555 void AquaSalFrame::GetClientSize( tools::Long& rWidth, tools::Long& rHeight )
556 {
557     if (mbShown || mbInitShow || Application::IsBitmapRendering())
558     {
559         rWidth  = maGeometry.nWidth;
560         rHeight = maGeometry.nHeight;
561     }
562     else
563     {
564         rWidth  = 0;
565         rHeight = 0;
566     }
567 }
568 
PreparePosSize(tools::Long nX,tools::Long nY,tools::Long nWidth,tools::Long nHeight,sal_uInt16 nFlags)569 SalEvent AquaSalFrame::PreparePosSize(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt16 nFlags)
570 {
571     SalEvent nEvent = SalEvent::NONE;
572     assert(mpNSWindow || Application::IsBitmapRendering());
573 
574     if (nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y))
575     {
576         mbPositioned = true;
577         nEvent = SalEvent::Move;
578     }
579 
580     if (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT))
581     {
582         mbSized = true;
583         nEvent = (nEvent == SalEvent::Move) ? SalEvent::MoveResize : SalEvent::Resize;
584     }
585 
586     if (Application::IsBitmapRendering())
587     {
588         if (nFlags & SAL_FRAME_POSSIZE_X)
589             maGeometry.nX = nX;
590         if (nFlags & SAL_FRAME_POSSIZE_Y)
591             maGeometry.nY = nY;
592         if (nFlags & SAL_FRAME_POSSIZE_WIDTH)
593         {
594             maGeometry.nWidth = nWidth;
595             if (mnMaxWidth > 0 && maGeometry.nWidth > o3tl::make_unsigned(mnMaxWidth))
596                 maGeometry.nWidth = mnMaxWidth;
597             if (mnMinWidth > 0 && maGeometry.nWidth < o3tl::make_unsigned(mnMinWidth))
598                 maGeometry.nWidth = mnMinWidth;
599         }
600         if (nFlags & SAL_FRAME_POSSIZE_HEIGHT)
601         {
602             maGeometry.nHeight = nHeight;
603             if (mnMaxHeight > 0 && maGeometry.nHeight > o3tl::make_unsigned(mnMaxHeight))
604                 maGeometry.nHeight = mnMaxHeight;
605             if (mnMinHeight > 0 && maGeometry.nHeight < o3tl::make_unsigned(mnMinHeight))
606                 maGeometry.nHeight = mnMinHeight;
607         }
608         if (nEvent != SalEvent::NONE)
609             CallCallback(nEvent, nullptr);
610     }
611 
612     return nEvent;
613 }
614 
SetWindowState(const SalFrameState * pState)615 void AquaSalFrame::SetWindowState( const SalFrameState* pState )
616 {
617     if (!mpNSWindow && !Application::IsBitmapRendering())
618         return;
619 
620     OSX_SALDATA_RUNINMAIN( SetWindowState( pState ) )
621 
622     sal_uInt16 nFlags = 0;
623     nFlags |= ((pState->mnMask & WindowStateMask::X) ? SAL_FRAME_POSSIZE_X : 0);
624     nFlags |= ((pState->mnMask & WindowStateMask::Y) ? SAL_FRAME_POSSIZE_Y : 0);
625     nFlags |= ((pState->mnMask & WindowStateMask::Width) ? SAL_FRAME_POSSIZE_WIDTH : 0);
626     nFlags |= ((pState->mnMask & WindowStateMask::Height) ? SAL_FRAME_POSSIZE_HEIGHT : 0);
627 
628     SalEvent nEvent = PreparePosSize(pState->mnX, pState->mnY, pState->mnWidth, pState->mnHeight, nFlags);
629     if (Application::IsBitmapRendering())
630         return;
631 
632     // set normal state
633     NSRect aStateRect = [mpNSWindow frame];
634     aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask];
635     CocoaToVCL(aStateRect);
636     if (pState->mnMask & WindowStateMask::X)
637         aStateRect.origin.x = float(pState->mnX);
638     if (pState->mnMask & WindowStateMask::Y)
639         aStateRect.origin.y = float(pState->mnY);
640     if (pState->mnMask & WindowStateMask::Width)
641         aStateRect.size.width = float(pState->mnWidth);
642     if (pState->mnMask & WindowStateMask::Height)
643         aStateRect.size.height = float(pState->mnHeight);
644     VCLToCocoa(aStateRect);
645     aStateRect = [NSWindow frameRectForContentRect: aStateRect styleMask: mnStyleMask];
646     [mpNSWindow setFrame: aStateRect display: NO];
647 
648     if (pState->mnState == WindowStateState::Minimized)
649         [mpNSWindow miniaturize: NSApp];
650     else if ([mpNSWindow isMiniaturized])
651         [mpNSWindow deminiaturize: NSApp];
652 
653     /* ZOOMED is not really maximized (actually it toggles between a user set size and
654        the program specified one), but comes closest since the default behavior is
655        "maximized" if the user did not intervene
656      */
657     if (pState->mnState == WindowStateState::Maximized)
658     {
659         if (![mpNSWindow isZoomed])
660             [mpNSWindow zoom: NSApp];
661     }
662     else
663     {
664         if ([mpNSWindow isZoomed])
665             [mpNSWindow zoom: NSApp];
666     }
667 
668     // get new geometry
669     UpdateFrameGeometry();
670 
671     // send event that we were moved/sized
672     if( nEvent != SalEvent::NONE )
673         CallCallback( nEvent, nullptr );
674 
675     if (mbShown)
676     {
677         // trigger filling our backbuffer
678         SendPaintEvent();
679 
680         // tell the system the views need to be updated
681         [mpNSWindow display];
682     }
683 }
684 
GetWindowState(SalFrameState * pState)685 bool AquaSalFrame::GetWindowState( SalFrameState* pState )
686 {
687     if (!mpNSWindow)
688     {
689         if (Application::IsBitmapRendering())
690         {
691             pState->mnMask = WindowStateMask::X | WindowStateMask::Y
692                              | WindowStateMask::Width | WindowStateMask::Height
693                              | WindowStateMask::State;
694             pState->mnX = maGeometry.nX;
695             pState->mnY = maGeometry.nY;
696             pState->mnWidth = maGeometry.nWidth;
697             pState->mnHeight = maGeometry.nHeight;
698             pState->mnState = WindowStateState::Normal;
699             return true;
700         }
701         return false;
702     }
703 
704     OSX_SALDATA_RUNINMAIN_UNION( GetWindowState( pState ), boolean )
705 
706     pState->mnMask = WindowStateMask::X                 |
707                      WindowStateMask::Y                 |
708                      WindowStateMask::Width             |
709                      WindowStateMask::Height            |
710                      WindowStateMask::State;
711 
712     NSRect aStateRect = [mpNSWindow frame];
713     aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask];
714     CocoaToVCL( aStateRect );
715     pState->mnX         = tools::Long(aStateRect.origin.x);
716     pState->mnY         = tools::Long(aStateRect.origin.y);
717     pState->mnWidth     = tools::Long(aStateRect.size.width);
718     pState->mnHeight    = tools::Long(aStateRect.size.height);
719 
720     if( [mpNSWindow isMiniaturized] )
721         pState->mnState = WindowStateState::Minimized;
722     else if( ! [mpNSWindow isZoomed] )
723         pState->mnState = WindowStateState::Normal;
724     else
725         pState->mnState = WindowStateState::Maximized;
726 
727     return true;
728 }
729 
SetScreenNumber(unsigned int nScreen)730 void AquaSalFrame::SetScreenNumber(unsigned int nScreen)
731 {
732     if ( !mpNSWindow )
733         return;
734 
735     OSX_SALDATA_RUNINMAIN( SetScreenNumber( nScreen ) )
736 
737     NSArray* pScreens = [NSScreen screens];
738     NSScreen* pScreen = nil;
739     if( pScreens && nScreen < [pScreens count] )
740     {
741         // get new screen frame
742         pScreen = [pScreens objectAtIndex: nScreen];
743         NSRect aNewScreen = [pScreen frame];
744 
745         // get current screen frame
746         pScreen = [mpNSWindow screen];
747         if( pScreen )
748         {
749             NSRect aCurScreen = [pScreen frame];
750             if( aCurScreen.origin.x != aNewScreen.origin.x ||
751                 aCurScreen.origin.y != aNewScreen.origin.y )
752             {
753                 NSRect aFrameRect = [mpNSWindow frame];
754                 aFrameRect.origin.x += aNewScreen.origin.x - aCurScreen.origin.x;
755                 aFrameRect.origin.y += aNewScreen.origin.y - aCurScreen.origin.y;
756                 [mpNSWindow setFrame: aFrameRect display: NO];
757                 UpdateFrameGeometry();
758             }
759         }
760     }
761 }
762 
SetApplicationID(const OUString &)763 void AquaSalFrame::SetApplicationID( const OUString &/*rApplicationID*/ )
764 {
765 }
766 
ShowFullScreen(bool bFullScreen,sal_Int32 nDisplay)767 void AquaSalFrame::ShowFullScreen( bool bFullScreen, sal_Int32 nDisplay )
768 {
769     doShowFullScreen(bFullScreen, nDisplay);
770 }
771 
doShowFullScreen(bool bFullScreen,sal_Int32 nDisplay)772 void AquaSalFrame::doShowFullScreen( bool bFullScreen, sal_Int32 nDisplay )
773 {
774     if (!mpNSWindow)
775     {
776         if (Application::IsBitmapRendering() && bFullScreen)
777             SetPosSize(0, 0, 1024, 768, SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT);
778         return;
779     }
780 
781     SAL_INFO("vcl.osx", __func__ << ": mbFullScreen=" << mbFullScreen << ", bFullScreen=" << bFullScreen);
782 
783     if( mbFullScreen == bFullScreen )
784         return;
785 
786     OSX_SALDATA_RUNINMAIN( ShowFullScreen( bFullScreen, nDisplay ) )
787 
788     mbFullScreen = bFullScreen;
789 
790     if( bFullScreen )
791     {
792         // hide the dock and the menubar if we are on the menu screen
793         // which is always on index 0 according to documentation
794         bool bHideMenu = (nDisplay == 0);
795 
796         NSRect aNewContentRect = NSZeroRect;
797         // get correct screen
798         NSScreen* pScreen = nil;
799         NSArray* pScreens = [NSScreen screens];
800         if( pScreens )
801         {
802             if( nDisplay >= 0 && o3tl::make_unsigned(nDisplay) < [pScreens count] )
803                 pScreen = [pScreens objectAtIndex: nDisplay];
804             else
805             {
806                 // this means span all screens
807                 bHideMenu = true;
808                 NSEnumerator* pEnum = [pScreens objectEnumerator];
809                 while( (pScreen = [pEnum nextObject]) != nil )
810                 {
811                     NSRect aScreenRect = [pScreen frame];
812                     if( aScreenRect.origin.x < aNewContentRect.origin.x )
813                     {
814                         aNewContentRect.size.width += aNewContentRect.origin.x - aScreenRect.origin.x;
815                         aNewContentRect.origin.x = aScreenRect.origin.x;
816                     }
817                     if( aScreenRect.origin.y < aNewContentRect.origin.y )
818                     {
819                         aNewContentRect.size.height += aNewContentRect.origin.y - aScreenRect.origin.y;
820                         aNewContentRect.origin.y = aScreenRect.origin.y;
821                     }
822                     if( aScreenRect.origin.x + aScreenRect.size.width > aNewContentRect.origin.x + aNewContentRect.size.width )
823                         aNewContentRect.size.width = aScreenRect.origin.x + aScreenRect.size.width - aNewContentRect.origin.x;
824                     if( aScreenRect.origin.y + aScreenRect.size.height > aNewContentRect.origin.y + aNewContentRect.size.height )
825                         aNewContentRect.size.height = aScreenRect.origin.y + aScreenRect.size.height - aNewContentRect.origin.y;
826                 }
827             }
828         }
829         if( aNewContentRect.size.width == 0 && aNewContentRect.size.height == 0 )
830         {
831             if( pScreen == nil )
832                 pScreen = [mpNSWindow screen];
833             if( pScreen == nil )
834                 pScreen = [NSScreen mainScreen];
835 
836             aNewContentRect = [pScreen frame];
837         }
838 
839         if( bHideMenu )
840             [NSMenu setMenuBarVisible:NO];
841 
842         maFullScreenRect = [mpNSWindow frame];
843 
844         [mpNSWindow setFrame: [NSWindow frameRectForContentRect: aNewContentRect styleMask: mnStyleMask] display: mbShown ? YES : NO];
845     }
846     else
847     {
848         [mpNSWindow setFrame: maFullScreenRect display: mbShown ? YES : NO];
849 
850         // show the dock and the menubar
851         [NSMenu setMenuBarVisible:YES];
852     }
853 
854     UpdateFrameGeometry();
855     if (mbShown)
856     {
857         CallCallback(SalEvent::MoveResize, nullptr);
858 
859         // trigger filling our backbuffer
860         SendPaintEvent();
861     }
862 }
863 
StartPresentation(bool bStart)864 void AquaSalFrame::StartPresentation( bool bStart )
865 {
866     if ( !mpNSWindow )
867         return;
868 
869     OSX_SALDATA_RUNINMAIN( StartPresentation( bStart ) )
870 
871     if( bStart )
872     {
873         GetSalData()->maPresentationFrames.push_back( this );
874         IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
875                                     kIOPMAssertionLevelOn,
876                                     CFSTR("LibreOffice presentation running"),
877                                     &mnAssertionID);
878         [mpNSWindow setLevel: NSPopUpMenuWindowLevel];
879         if( mbShown )
880             [mpNSWindow makeMainWindow];
881     }
882     else
883     {
884         GetSalData()->maPresentationFrames.remove( this );
885         IOPMAssertionRelease(mnAssertionID);
886         [mpNSWindow setLevel: NSNormalWindowLevel];
887     }
888 }
889 
SetAlwaysOnTop(bool)890 void AquaSalFrame::SetAlwaysOnTop( bool )
891 {
892 }
893 
ToTop(SalFrameToTop nFlags)894 void AquaSalFrame::ToTop(SalFrameToTop nFlags)
895 {
896     if ( !mpNSWindow )
897         return;
898 
899     OSX_SALDATA_RUNINMAIN( ToTop( nFlags ) )
900 
901     if( ! (nFlags & SalFrameToTop::RestoreWhenMin) )
902     {
903         if( ! [mpNSWindow isVisible] || [mpNSWindow isMiniaturized] )
904             return;
905     }
906     if( nFlags & SalFrameToTop::GrabFocus )
907         [mpNSWindow makeKeyAndOrderFront: NSApp];
908     else
909         [mpNSWindow orderFront: NSApp];
910 }
911 
getCurrentCursor()912 NSCursor* AquaSalFrame::getCurrentCursor()
913 {
914     OSX_SALDATA_RUNINMAIN_POINTER( getCurrentCursor(), NSCursor* )
915 
916     NSCursor* pCursor = nil;
917     switch( mePointerStyle )
918     {
919     case PointerStyle::Text:      pCursor = [NSCursor IBeamCursor];           break;
920     case PointerStyle::Cross:     pCursor = [NSCursor crosshairCursor];       break;
921     case PointerStyle::Hand:
922     case PointerStyle::Move:      pCursor = [NSCursor openHandCursor];        break;
923     case PointerStyle::NSize:     pCursor = [NSCursor resizeUpCursor];        break;
924     case PointerStyle::SSize:     pCursor = [NSCursor resizeDownCursor];      break;
925     case PointerStyle::ESize:     pCursor = [NSCursor resizeRightCursor];      break;
926     case PointerStyle::WSize:     pCursor = [NSCursor resizeLeftCursor];     break;
927     case PointerStyle::Arrow:     pCursor = [NSCursor arrowCursor];           break;
928     case PointerStyle::VSplit:
929     case PointerStyle::VSizeBar:
930     case PointerStyle::WindowNSize:
931     case PointerStyle::WindowSSize:
932                             pCursor = [NSCursor resizeUpDownCursor];    break;
933     case PointerStyle::HSplit:
934     case PointerStyle::HSizeBar:
935     case PointerStyle::WindowESize:
936     case PointerStyle::WindowWSize:
937                             pCursor = [NSCursor resizeLeftRightCursor]; break;
938     case PointerStyle::RefHand:   pCursor = [NSCursor pointingHandCursor];    break;
939 
940     default:
941         pCursor = GetSalData()->getCursor( mePointerStyle );
942         if( pCursor == nil )
943         {
944             assert( false && "unmapped cursor" );
945             pCursor = [NSCursor arrowCursor];
946         }
947         break;
948     }
949     return pCursor;
950 }
951 
SetPointer(PointerStyle ePointerStyle)952 void AquaSalFrame::SetPointer( PointerStyle ePointerStyle )
953 {
954     if ( !mpNSWindow )
955         return;
956     if( ePointerStyle == mePointerStyle )
957         return;
958 
959     OSX_SALDATA_RUNINMAIN( SetPointer( ePointerStyle ) )
960 
961     mePointerStyle = ePointerStyle;
962 
963     [mpNSWindow invalidateCursorRectsForView: mpNSView];
964 }
965 
SetPointerPos(tools::Long nX,tools::Long nY)966 void AquaSalFrame::SetPointerPos( tools::Long nX, tools::Long nY )
967 {
968     OSX_SALDATA_RUNINMAIN( SetPointerPos( nX, nY ) )
969 
970     // FIXME: use Cocoa functions
971     // FIXME: multiscreen support
972     CGPoint aPoint = { static_cast<CGFloat>(nX + maGeometry.nX), static_cast<CGFloat>(nY + maGeometry.nY) };
973     CGDirectDisplayID mainDisplayID = CGMainDisplayID();
974     CGDisplayMoveCursorToPoint( mainDisplayID, aPoint );
975 }
976 
Flush()977 void AquaSalFrame::Flush()
978 {
979     if( !(mbGraphics && mpGraphics && mpNSView && mbShown) )
980         return;
981 
982     OSX_SALDATA_RUNINMAIN( Flush() )
983 
984     [mpNSView setNeedsDisplay: YES];
985 
986     // outside of the application's event loop (e.g. IntroWindow)
987     // nothing would trigger paint event handling
988     // => fall back to synchronous painting
989     if( ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
990     {
991         [mpNSView display];
992     }
993 }
994 
Flush(const tools::Rectangle & rRect)995 void AquaSalFrame::Flush( const tools::Rectangle& rRect )
996 {
997     if( !(mbGraphics && mpGraphics && mpNSView && mbShown) )
998         return;
999 
1000     OSX_SALDATA_RUNINMAIN( Flush( rRect ) )
1001 
1002     NSRect aNSRect = { { static_cast<CGFloat>(rRect.Left()), static_cast<CGFloat>(rRect.Top()) }, { static_cast<CGFloat>(rRect.GetWidth()), static_cast<CGFloat>(rRect.GetHeight()) } };
1003     VCLToCocoa( aNSRect, false );
1004     [mpNSView setNeedsDisplayInRect: aNSRect];
1005 
1006     // outside of the application's event loop (e.g. IntroWindow)
1007     // nothing would trigger paint event handling
1008     // => fall back to synchronous painting
1009     if( ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
1010     {
1011         [mpNSView display];
1012     }
1013 }
1014 
SetInputContext(SalInputContext * pContext)1015 void AquaSalFrame::SetInputContext( SalInputContext* pContext )
1016 {
1017     if (!pContext)
1018     {
1019         mnICOptions = InputContextFlags::NONE;
1020         return;
1021     }
1022 
1023     mnICOptions = pContext->mnOptions;
1024 
1025     if(!(pContext->mnOptions & InputContextFlags::Text))
1026         return;
1027 }
1028 
EndExtTextInput(EndExtTextInputFlags)1029 void AquaSalFrame::EndExtTextInput( EndExtTextInputFlags )
1030 {
1031 }
1032 
GetKeyName(sal_uInt16 nKeyCode)1033 OUString AquaSalFrame::GetKeyName( sal_uInt16 nKeyCode )
1034 {
1035     static std::map< sal_uInt16, OUString > aKeyMap;
1036     if( aKeyMap.empty() )
1037     {
1038         sal_uInt16 i;
1039         for( i = KEY_A; i <= KEY_Z; i++ )
1040             aKeyMap[ i ] = OUString( sal_Unicode( 'A' + (i - KEY_A) ) );
1041         for( i = KEY_0; i <= KEY_9; i++ )
1042             aKeyMap[ i ] = OUString( sal_Unicode( '0' + (i - KEY_0) ) );
1043         for( i = KEY_F1; i <= KEY_F26; i++ )
1044         {
1045             aKeyMap[ i ] = "F" + OUString::number(i - KEY_F1 + 1);
1046         }
1047 
1048         aKeyMap[ KEY_DOWN ]     = OUString( u'\x21e3' );
1049         aKeyMap[ KEY_UP ]       = OUString( u'\x21e1' );
1050         aKeyMap[ KEY_LEFT ]     = OUString( u'\x21e0' );
1051         aKeyMap[ KEY_RIGHT ]    = OUString( u'\x21e2' );
1052         aKeyMap[ KEY_HOME ]     = OUString( u'\x2196' );
1053         aKeyMap[ KEY_END ]      = OUString( u'\x2198' );
1054         aKeyMap[ KEY_PAGEUP ]   = OUString( u'\x21de' );
1055         aKeyMap[ KEY_PAGEDOWN ] = OUString( u'\x21df' );
1056         aKeyMap[ KEY_RETURN ]   = OUString( u'\x21a9' );
1057         aKeyMap[ KEY_ESCAPE ]   = "esc";
1058         aKeyMap[ KEY_TAB ]      = OUString( u'\x21e5' );
1059         aKeyMap[ KEY_BACKSPACE ]= OUString( u'\x232b' );
1060         aKeyMap[ KEY_SPACE ]    = OUString( u'\x2423' );
1061         aKeyMap[ KEY_DELETE ]   = OUString( u'\x2326' );
1062         aKeyMap[ KEY_ADD ]      = "+";
1063         aKeyMap[ KEY_SUBTRACT ] = "-";
1064         aKeyMap[ KEY_DIVIDE ]   = "/";
1065         aKeyMap[ KEY_MULTIPLY ] = "*";
1066         aKeyMap[ KEY_POINT ]    = ".";
1067         aKeyMap[ KEY_COMMA ]    = ",";
1068         aKeyMap[ KEY_LESS ]     = "<";
1069         aKeyMap[ KEY_GREATER ]  = ">";
1070         aKeyMap[ KEY_EQUAL ]    = "=";
1071         aKeyMap[ KEY_OPEN ]     = OUString( u'\x23cf' );
1072         aKeyMap[ KEY_TILDE ]    = "~";
1073         aKeyMap[ KEY_BRACKETLEFT ] = "[";
1074         aKeyMap[ KEY_BRACKETRIGHT ] = "]";
1075         aKeyMap[ KEY_SEMICOLON ] = ";";
1076         aKeyMap[ KEY_QUOTERIGHT ] = "'";
1077 
1078         /* yet unmapped KEYCODES:
1079         aKeyMap[ KEY_INSERT ]   = OUString( sal_Unicode( ) );
1080         aKeyMap[ KEY_CUT ]      = OUString( sal_Unicode( ) );
1081         aKeyMap[ KEY_COPY ]     = OUString( sal_Unicode( ) );
1082         aKeyMap[ KEY_PASTE ]    = OUString( sal_Unicode( ) );
1083         aKeyMap[ KEY_UNDO ]     = OUString( sal_Unicode( ) );
1084         aKeyMap[ KEY_REPEAT ]   = OUString( sal_Unicode( ) );
1085         aKeyMap[ KEY_FIND ]     = OUString( sal_Unicode( ) );
1086         aKeyMap[ KEY_PROPERTIES ]     = OUString( sal_Unicode( ) );
1087         aKeyMap[ KEY_FRONT ]    = OUString( sal_Unicode( ) );
1088         aKeyMap[ KEY_CONTEXTMENU ]    = OUString( sal_Unicode( ) );
1089         aKeyMap[ KEY_MENU ]     = OUString( sal_Unicode( ) );
1090         aKeyMap[ KEY_HELP ]     = OUString( sal_Unicode( ) );
1091         aKeyMap[ KEY_HANGUL_HANJA ]   = OUString( sal_Unicode( ) );
1092         aKeyMap[ KEY_DECIMAL ]  = OUString( sal_Unicode( ) );
1093         aKeyMap[ KEY_QUOTELEFT ]= OUString( sal_Unicode( ) );
1094         aKeyMap[ KEY_CAPSLOCK ]= OUString( sal_Unicode( ) );
1095         aKeyMap[ KEY_NUMLOCK ]= OUString( sal_Unicode( ) );
1096         aKeyMap[ KEY_SCROLLLOCK ]= OUString( sal_Unicode( ) );
1097         */
1098 
1099     }
1100 
1101     OUStringBuffer aResult( 16 );
1102 
1103     sal_uInt16 nUnmodifiedCode = (nKeyCode & KEY_CODE_MASK);
1104     std::map< sal_uInt16, OUString >::const_iterator it = aKeyMap.find( nUnmodifiedCode );
1105     if( it != aKeyMap.end() )
1106     {
1107         if( (nKeyCode & KEY_SHIFT) != 0 )
1108             aResult.append( u'\x21e7' ); // shift
1109         if( (nKeyCode & KEY_MOD1) != 0 )
1110             aResult.append( u'\x2318' ); // command
1111         if( (nKeyCode & KEY_MOD2) != 0 )
1112             aResult.append( u'\x2325' ); // alternate
1113         if( (nKeyCode & KEY_MOD3) != 0 )
1114             aResult.append( u'\x2303' ); // control
1115 
1116         aResult.append( it->second );
1117     }
1118 
1119     return aResult.makeStringAndClear();
1120 }
1121 
getAppleScrollBarVariant(StyleSettings & rSettings)1122 static void getAppleScrollBarVariant(StyleSettings &rSettings)
1123 {
1124     bool bIsScrollbarDoubleMax = true; // default is DoubleMax
1125 
1126     CFStringRef AppleScrollBarType = CFSTR("AppleScrollBarVariant");
1127     if( AppleScrollBarType )
1128     {
1129         CFStringRef ScrollBarVariant = static_cast<CFStringRef>(CFPreferencesCopyAppValue( AppleScrollBarType, kCFPreferencesCurrentApplication ));
1130         if( ScrollBarVariant )
1131         {
1132             if( CFGetTypeID( ScrollBarVariant ) == CFStringGetTypeID() )
1133             {
1134                 // TODO: check for the less important variants "DoubleMin" and "DoubleBoth" too
1135                 CFStringRef DoubleMax = CFSTR("DoubleMax");
1136                 if (DoubleMax)
1137                 {
1138                     if ( !CFStringCompare(ScrollBarVariant, DoubleMax, kCFCompareCaseInsensitive) )
1139                         bIsScrollbarDoubleMax = true;
1140                     else
1141                         bIsScrollbarDoubleMax = false;
1142                     CFRelease(DoubleMax);
1143                 }
1144             }
1145             CFRelease( ScrollBarVariant );
1146         }
1147         CFRelease(AppleScrollBarType);
1148     }
1149 
1150     GetSalData()->mbIsScrollbarDoubleMax = bIsScrollbarDoubleMax;
1151 
1152     CFStringRef jumpScroll = CFSTR("AppleScrollerPagingBehavior");
1153     if( jumpScroll )
1154     {
1155         CFBooleanRef jumpStr = static_cast<CFBooleanRef>(CFPreferencesCopyAppValue( jumpScroll, kCFPreferencesCurrentApplication ));
1156         if( jumpStr )
1157         {
1158             if( CFGetTypeID( jumpStr ) == CFBooleanGetTypeID() )
1159                 rSettings.SetPrimaryButtonWarpsSlider(jumpStr == kCFBooleanTrue);
1160             CFRelease( jumpStr );
1161         }
1162         CFRelease( jumpScroll );
1163     }
1164 }
1165 
getColor(NSColor * pSysColor,const Color & rDefault,NSWindow * pWin)1166 static Color getColor( NSColor* pSysColor, const Color& rDefault, NSWindow* pWin )
1167 {
1168     Color aRet( rDefault );
1169     if( pSysColor )
1170     {
1171         // transform to RGB
1172 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1173             // "'colorUsingColorSpaceName:device:' is deprecated: first deprecated in macOS 10.14 -
1174             // Use -colorUsingType: or -colorUsingColorSpace: instead"
1175         NSColor* pRBGColor = [pSysColor colorUsingColorSpaceName: NSDeviceRGBColorSpace device: [pWin deviceDescription]];
1176 SAL_WNODEPRECATED_DECLARATIONS_POP
1177         if( pRBGColor )
1178         {
1179             CGFloat r = 0, g = 0, b = 0, a = 0;
1180             [pRBGColor getRed: &r green: &g blue: &b alpha: &a];
1181             aRet = Color( int(r*255.999), int(g*255.999), int(b*255.999) );
1182             /*
1183             do not release here; leads to duplicate free in yield
1184             it seems the converted color comes out autoreleased, although this
1185             is not documented
1186             [pRBGColor release];
1187             */
1188         }
1189     }
1190     return aRet;
1191 }
1192 
getFont(NSFont * pFont,sal_Int32 nDPIY,const vcl::Font & rDefault)1193 static vcl::Font getFont( NSFont* pFont, sal_Int32 nDPIY, const vcl::Font& rDefault )
1194 {
1195     vcl::Font aResult( rDefault );
1196     if( pFont )
1197     {
1198         aResult.SetFamilyName( GetOUString( [pFont familyName] ) );
1199         aResult.SetFontHeight( static_cast<int>(([pFont pointSize] * 72.0 / static_cast<float>(nDPIY))+0.5) );
1200         aResult.SetItalic( ([pFont italicAngle] != 0.0) ? ITALIC_NORMAL : ITALIC_NONE );
1201         // FIMXE: bold ?
1202     }
1203 
1204     return aResult;
1205 }
1206 
getResolution(sal_Int32 & o_rDPIX,sal_Int32 & o_rDPIY)1207 void AquaSalFrame::getResolution( sal_Int32& o_rDPIX, sal_Int32& o_rDPIY )
1208 {
1209     OSX_SALDATA_RUNINMAIN( getResolution( o_rDPIX, o_rDPIY ) )
1210 
1211     if( ! mpGraphics )
1212     {
1213         AcquireGraphics();
1214         ReleaseGraphics( mpGraphics );
1215     }
1216     mpGraphics->GetResolution( o_rDPIX, o_rDPIY );
1217 }
1218 
1219 // on OSX-Aqua the style settings are independent of the frame, so it does
1220 // not really belong here. Since the connection to the Appearance_Manager
1221 // is currently done in salnativewidgets.cxx this would be a good place.
1222 // On the other hand VCL's platform independent code currently only asks
1223 // SalFrames for system settings anyway, so moving the code somewhere else
1224 // doesn't make the anything cleaner for now
UpdateSettings(AllSettings & rSettings)1225 void AquaSalFrame::UpdateSettings( AllSettings& rSettings )
1226 {
1227     if ( !mpNSWindow )
1228         return;
1229 
1230     OSX_SALDATA_RUNINMAIN( UpdateSettings( rSettings ) )
1231 
1232 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1233         // "'lockFocus' is deprecated: first deprecated in macOS 10.14 - To draw, subclass NSView
1234         // and implement -drawRect:; AppKit's automatic deferred display mechanism will call
1235         // -drawRect: as necessary to display the view."
1236     if (![mpNSView lockFocusIfCanDraw])
1237         return;
1238 SAL_WNODEPRECATED_DECLARATIONS_POP
1239 
1240     StyleSettings aStyleSettings = rSettings.GetStyleSettings();
1241 
1242     // Background Color
1243     Color aBackgroundColor( 0xEC, 0xEC, 0xEC );
1244     aStyleSettings.BatchSetBackgrounds( aBackgroundColor, false );
1245     aStyleSettings.SetLightBorderColor( aBackgroundColor );
1246 
1247     Color aInactiveTabColor( aBackgroundColor );
1248     aInactiveTabColor.DecreaseLuminance( 32 );
1249     aStyleSettings.SetInactiveTabColor( aInactiveTabColor );
1250 
1251     Color aShadowColor( aStyleSettings.GetShadowColor() );
1252     aShadowColor.IncreaseLuminance( 32 );
1253     aStyleSettings.SetShadowColor( aShadowColor );
1254 
1255     // get the system font settings
1256     vcl::Font aAppFont = aStyleSettings.GetAppFont();
1257     sal_Int32 nDPIX = 72, nDPIY = 72;
1258     getResolution( nDPIX, nDPIY );
1259     aAppFont = getFont( [NSFont systemFontOfSize: 0], nDPIY, aAppFont );
1260 
1261     aStyleSettings.SetToolbarIconSize( ToolbarIconSize::Large );
1262 
1263     // TODO: better mapping of macOS<->LibreOffice font settings
1264     vcl::Font aLabelFont( getFont( [NSFont labelFontOfSize: 0], nDPIY, aAppFont ) );
1265     aStyleSettings.BatchSetFonts( aAppFont, aLabelFont );
1266     vcl::Font aMenuFont( getFont( [NSFont menuFontOfSize: 0], nDPIY, aAppFont ) );
1267     aStyleSettings.SetMenuFont( aMenuFont );
1268 
1269     vcl::Font aTitleFont( getFont( [NSFont titleBarFontOfSize: 0], nDPIY, aAppFont ) );
1270     aStyleSettings.SetTitleFont( aTitleFont );
1271     aStyleSettings.SetFloatTitleFont( aTitleFont );
1272 
1273     vcl::Font aTooltipFont(getFont([NSFont toolTipsFontOfSize: 0], nDPIY, aAppFont));
1274     aStyleSettings.SetHelpFont(aTooltipFont);
1275 
1276     Color aHighlightColor( getColor( [NSColor selectedTextBackgroundColor],
1277                                       aStyleSettings.GetHighlightColor(), mpNSWindow ) );
1278     aStyleSettings.SetHighlightColor( aHighlightColor );
1279     Color aHighlightTextColor( getColor( [NSColor selectedTextColor],
1280                                          aStyleSettings.GetHighlightTextColor(), mpNSWindow ) );
1281     aStyleSettings.SetHighlightTextColor( aHighlightTextColor );
1282 
1283 #pragma clang diagnostic push
1284 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1285     Color aMenuHighlightColor( getColor( [NSColor selectedMenuItemColor],
1286                                          aStyleSettings.GetMenuHighlightColor(), mpNSWindow ) );
1287 #pragma clang diagnostic pop
1288     aStyleSettings.SetMenuHighlightColor( aMenuHighlightColor );
1289     Color aMenuHighlightTextColor( getColor( [NSColor selectedMenuItemTextColor],
1290                                              aStyleSettings.GetMenuHighlightTextColor(), mpNSWindow ) );
1291     aStyleSettings.SetMenuHighlightTextColor( aMenuHighlightTextColor );
1292 
1293     aStyleSettings.SetMenuColor( aBackgroundColor );
1294     Color aMenuTextColor( getColor( [NSColor textColor],
1295                                     aStyleSettings.GetMenuTextColor(), mpNSWindow ) );
1296     aStyleSettings.SetMenuTextColor( aMenuTextColor );
1297     aStyleSettings.SetMenuBarTextColor( aMenuTextColor );
1298     aStyleSettings.SetMenuBarRolloverTextColor( aMenuTextColor );
1299     aStyleSettings.SetMenuBarHighlightTextColor(aStyleSettings.GetMenuHighlightTextColor());
1300 
1301     // Set text colors for buttons and their different status according to OS settings, typically white for selected buttons,
1302     // black otherwise
1303 
1304     Color aControlTextColor(getColor([NSColor controlTextColor], COL_BLACK, mpNSWindow));
1305     Color aSelectedControlTextColor(getColor([NSColor selectedControlTextColor], COL_BLACK, mpNSWindow));
1306     Color aAlternateSelectedControlTextColor(getColor([NSColor alternateSelectedControlTextColor], COL_WHITE, mpNSWindow));
1307     aStyleSettings.SetDefaultButtonTextColor(aAlternateSelectedControlTextColor);
1308     aStyleSettings.SetButtonTextColor(aControlTextColor);
1309     aStyleSettings.SetDefaultActionButtonTextColor(aAlternateSelectedControlTextColor);
1310     aStyleSettings.SetActionButtonTextColor(aControlTextColor);
1311     aStyleSettings.SetFlatButtonTextColor(aControlTextColor);
1312     aStyleSettings.SetDefaultButtonRolloverTextColor(aAlternateSelectedControlTextColor);
1313     aStyleSettings.SetButtonRolloverTextColor(aControlTextColor);
1314     aStyleSettings.SetDefaultActionButtonRolloverTextColor(aAlternateSelectedControlTextColor);
1315     aStyleSettings.SetActionButtonRolloverTextColor(aControlTextColor);
1316     aStyleSettings.SetFlatButtonRolloverTextColor(aControlTextColor);
1317     aStyleSettings.SetDefaultButtonPressedRolloverTextColor(aAlternateSelectedControlTextColor);
1318     aStyleSettings.SetButtonPressedRolloverTextColor(aAlternateSelectedControlTextColor);
1319     aStyleSettings.SetDefaultActionButtonPressedRolloverTextColor(aAlternateSelectedControlTextColor);
1320     aStyleSettings.SetActionButtonPressedRolloverTextColor(aAlternateSelectedControlTextColor);
1321     aStyleSettings.SetFlatButtonPressedRolloverTextColor(aControlTextColor);
1322 
1323     // Set text colors for tabs according to OS settings
1324 
1325     aStyleSettings.SetTabTextColor(aControlTextColor);
1326 
1327     // FIXME: Starting with macOS Big Sur, coloring has changed. Currently there is no documentation which system color should be
1328     // used for selected tab text. As a workaround the current OS version has to be considered. This code has to be reviewed once
1329     // issue is covered by documentation.
1330 
1331     NSOperatingSystemVersion aOSVersion = { .majorVersion = 10, .minorVersion = 16, .patchVersion = 0 };
1332     if ([NSProcessInfo.processInfo isOperatingSystemAtLeastVersion: aOSVersion])
1333         aStyleSettings.SetTabHighlightTextColor(aSelectedControlTextColor);
1334     else
1335         aStyleSettings.SetTabHighlightTextColor(aAlternateSelectedControlTextColor);
1336 
1337     aStyleSettings.SetCursorBlinkTime( mnBlinkCursorDelay );
1338 
1339     // no mnemonics on macOS
1340     aStyleSettings.SetOptions( aStyleSettings.GetOptions() | StyleSettingsOptions::NoMnemonics );
1341 
1342     getAppleScrollBarVariant(aStyleSettings);
1343 
1344     // set scrollbar size
1345 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1346         // 'NSRegularControlSize' is deprecated: first deprecated in macOS 10.12
1347     aStyleSettings.SetScrollBarSize( static_cast<tools::Long>([NSScroller scrollerWidthForControlSize:NSRegularControlSize scrollerStyle:NSScrollerStyleLegacy]) );
1348 SAL_WNODEPRECATED_DECLARATIONS_POP
1349     // images in menus false for MacOSX
1350     aStyleSettings.SetPreferredUseImagesInMenus( false );
1351     aStyleSettings.SetHideDisabledMenuItems( true );
1352     aStyleSettings.SetPreferredContextMenuShortcuts( false );
1353 
1354     rSettings.SetStyleSettings( aStyleSettings );
1355 
1356     // don't draw frame around each and every toolbar
1357     ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames = true;
1358 
1359 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1360         // "'unlockFocus' is deprecated: first deprecated in macOS 10.14 - To draw, subclass NSView
1361         // and implement -drawRect:; AppKit's automatic deferred display mechanism will call
1362         // -drawRect: as necessary to display the view."
1363     [mpNSView unlockFocus];
1364 SAL_WNODEPRECATED_DECLARATIONS_POP
1365 }
1366 
GetSystemData() const1367 const SystemEnvData* AquaSalFrame::GetSystemData() const
1368 {
1369     return &maSysData;
1370 }
1371 
Beep()1372 void AquaSalFrame::Beep()
1373 {
1374     OSX_SALDATA_RUNINMAIN( Beep() )
1375     NSBeep();
1376 }
1377 
SetPosSize(tools::Long nX,tools::Long nY,tools::Long nWidth,tools::Long nHeight,sal_uInt16 nFlags)1378 void AquaSalFrame::SetPosSize(
1379     tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt16 nFlags)
1380 {
1381     if (!mpNSWindow && !Application::IsBitmapRendering())
1382         return;
1383 
1384     OSX_SALDATA_RUNINMAIN( SetPosSize( nX, nY, nWidth, nHeight, nFlags ) )
1385 
1386     SalEvent nEvent = PreparePosSize(nX, nY, nWidth, nHeight, nFlags);
1387     if (Application::IsBitmapRendering())
1388         return;
1389 
1390     if( [mpNSWindow isMiniaturized] )
1391         [mpNSWindow deminiaturize: NSApp]; // expand the window
1392 
1393     NSRect aFrameRect = [mpNSWindow frame];
1394     NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask];
1395 
1396     // position is always relative to parent frame
1397     NSRect aParentContentRect;
1398 
1399     if( mpParent )
1400     {
1401         if( AllSettings::GetLayoutRTL() )
1402         {
1403             if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
1404                 nX = mpParent->maGeometry.nWidth - nWidth-1 - nX;
1405             else
1406                 nX = mpParent->maGeometry.nWidth - static_cast<tools::Long>( aContentRect.size.width-1) - nX;
1407         }
1408         NSRect aParentFrameRect = [mpParent->mpNSWindow frame];
1409         aParentContentRect = [NSWindow contentRectForFrameRect: aParentFrameRect styleMask: mpParent->mnStyleMask];
1410     }
1411     else
1412         aParentContentRect = maScreenRect; // use screen if no parent
1413 
1414     CocoaToVCL( aContentRect );
1415     CocoaToVCL( aParentContentRect );
1416 
1417     bool bPaint = false;
1418     if( (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) != 0 )
1419     {
1420         if( nWidth != aContentRect.size.width || nHeight != aContentRect.size.height )
1421             bPaint = true;
1422     }
1423 
1424     // use old window pos if no new pos requested
1425     if( (nFlags & SAL_FRAME_POSSIZE_X) != 0 )
1426         aContentRect.origin.x = nX + aParentContentRect.origin.x;
1427     if( (nFlags & SAL_FRAME_POSSIZE_Y) != 0)
1428         aContentRect.origin.y = nY + aParentContentRect.origin.y;
1429 
1430     // use old size if no new size requested
1431     if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
1432         aContentRect.size.width = nWidth;
1433     if( (nFlags & SAL_FRAME_POSSIZE_HEIGHT) != 0)
1434         aContentRect.size.height = nHeight;
1435 
1436     VCLToCocoa( aContentRect );
1437 
1438     // do not display yet, we need to update our backbuffer
1439     {
1440         [mpNSWindow setFrame: [NSWindow frameRectForContentRect: aContentRect styleMask: mnStyleMask] display: NO];
1441     }
1442 
1443     UpdateFrameGeometry();
1444 
1445     if (nEvent != SalEvent::NONE)
1446         CallCallback(nEvent, nullptr);
1447 
1448     if( mbShown && bPaint )
1449     {
1450         // trigger filling our backbuffer
1451         SendPaintEvent();
1452 
1453         // now inform the system that the views need to be drawn
1454         [mpNSWindow display];
1455     }
1456 }
1457 
GetWorkArea(tools::Rectangle & rRect)1458 void AquaSalFrame::GetWorkArea( tools::Rectangle& rRect )
1459 {
1460     if (!mpNSWindow)
1461     {
1462         if (Application::IsBitmapRendering())
1463             rRect = tools::Rectangle(Point(0, 0), Size(1024, 768));
1464         return;
1465     }
1466 
1467     OSX_SALDATA_RUNINMAIN( GetWorkArea( rRect ) )
1468 
1469     NSScreen* pScreen = [mpNSWindow screen];
1470     if( pScreen ==  nil )
1471         pScreen = [NSScreen mainScreen];
1472     NSRect aRect = [pScreen visibleFrame];
1473     CocoaToVCL( aRect );
1474     rRect.SetLeft( static_cast<tools::Long>(aRect.origin.x) );
1475     rRect.SetTop( static_cast<tools::Long>(aRect.origin.y) );
1476     rRect.SetRight( static_cast<tools::Long>(aRect.origin.x + aRect.size.width - 1) );
1477     rRect.SetBottom( static_cast<tools::Long>(aRect.origin.y + aRect.size.height - 1) );
1478 }
1479 
GetPointerState()1480 SalFrame::SalPointerState AquaSalFrame::GetPointerState()
1481 {
1482     OSX_SALDATA_RUNINMAIN_UNION( GetPointerState(), state )
1483 
1484     SalPointerState state;
1485     state.mnState = 0;
1486 
1487     // get position
1488     NSPoint aPt = [mpNSWindow mouseLocationOutsideOfEventStream];
1489     CocoaToVCL( aPt, false );
1490     state.maPos = Point(static_cast<tools::Long>(aPt.x), static_cast<tools::Long>(aPt.y));
1491 
1492     NSEvent* pCur = [NSApp currentEvent];
1493     bool bMouseEvent = false;
1494     if( pCur )
1495     {
1496         bMouseEvent = true;
1497 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1498     // 'NSLeftMouseDown' is deprecated: first deprecated in macOS 10.12
1499     // 'NSLeftMouseDragged' is deprecated: first deprecated in macOS 10.12
1500     // 'NSLeftMouseUp' is deprecated: first deprecated in macOS 10.12
1501     // 'NSMouseMoved' is deprecated: first deprecated in macOS 10.12
1502     // 'NSOtherMouseDown' is deprecated: first deprecated in macOS 10.12
1503     // 'NSOtherMouseDragged' is deprecated: first deprecated in macOS 10.12
1504     // 'NSOtherMouseUp' is deprecated: first deprecated in macOS 10.12
1505     // 'NSRightMouseDown' is deprecated: first deprecated in macOS 10.12
1506     // 'NSRightMouseDragged' is deprecated: first deprecated in macOS 10.12
1507     // 'NSRightMouseUp' is deprecated: first deprecated in macOS 10.12
1508         switch( [pCur type] )
1509         {
1510         case NSLeftMouseDown:       state.mnState |= MOUSE_LEFT; break;
1511         case NSLeftMouseUp:         break;
1512         case NSRightMouseDown:      state.mnState |= MOUSE_RIGHT; break;
1513         case NSRightMouseUp:        break;
1514         case NSOtherMouseDown:      state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0; break;
1515         case NSOtherMouseUp:        break;
1516         case NSMouseMoved:          break;
1517         case NSLeftMouseDragged:    state.mnState |= MOUSE_LEFT; break;
1518         case NSRightMouseDragged:   state.mnState |= MOUSE_RIGHT; break;
1519         case NSOtherMouseDragged:   state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0; break;
1520             break;
1521         default:
1522             bMouseEvent = false;
1523             break;
1524         }
1525 SAL_WNODEPRECATED_DECLARATIONS_POP
1526     }
1527     if( bMouseEvent )
1528     {
1529         unsigned int nMask = static_cast<unsigned int>([pCur modifierFlags]);
1530 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1531     // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12
1532     // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12
1533     // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12
1534     // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12
1535         if( (nMask & NSShiftKeyMask) != 0 )
1536             state.mnState |= KEY_SHIFT;
1537         if( (nMask & NSControlKeyMask) != 0 )
1538             state.mnState |= KEY_MOD3;
1539         if( (nMask & NSAlternateKeyMask) != 0 )
1540             state.mnState |= KEY_MOD2;
1541         if( (nMask & NSCommandKeyMask) != 0 )
1542             state.mnState |= KEY_MOD1;
1543 SAL_WNODEPRECATED_DECLARATIONS_POP
1544 
1545     }
1546     else
1547     {
1548         // FIXME: replace Carbon by Cocoa
1549         // Cocoa does not have an equivalent for GetCurrentEventButtonState
1550         // and GetCurrentEventKeyModifiers.
1551         // we could try to get away with tracking all events for modifierKeys
1552         // and all mouse events for button state in VCL_NSApplication::sendEvent,
1553         // but it is unclear whether this will get us the same result.
1554         // leave in GetCurrentEventButtonState and GetCurrentEventKeyModifiers for now
1555 
1556         // fill in button state
1557         UInt32 nState = GetCurrentEventButtonState();
1558         state.mnState = 0;
1559         if( nState & 1 )
1560             state.mnState |= MOUSE_LEFT;    // primary button
1561         if( nState & 2 )
1562             state.mnState |= MOUSE_RIGHT;   // secondary button
1563         if( nState & 4 )
1564             state.mnState |= MOUSE_MIDDLE;  // tertiary button
1565 
1566         // fill in modifier state
1567         nState = GetCurrentEventKeyModifiers();
1568         if( nState & shiftKey )
1569             state.mnState |= KEY_SHIFT;
1570         if( nState & controlKey )
1571             state.mnState |= KEY_MOD3;
1572         if( nState & optionKey )
1573             state.mnState |= KEY_MOD2;
1574         if( nState & cmdKey )
1575             state.mnState |= KEY_MOD1;
1576     }
1577 
1578     return state;
1579 }
1580 
GetIndicatorState()1581 KeyIndicatorState AquaSalFrame::GetIndicatorState()
1582 {
1583     return KeyIndicatorState::NONE;
1584 }
1585 
SimulateKeyPress(sal_uInt16)1586 void AquaSalFrame::SimulateKeyPress( sal_uInt16 /*nKeyCode*/ )
1587 {
1588 }
1589 
SetPluginParent(SystemParentData *)1590 void AquaSalFrame::SetPluginParent( SystemParentData* )
1591 {
1592     // plugin parent may be killed unexpectedly by
1593     // plugging process;
1594 
1595     //TODO: implement
1596 }
1597 
MapUnicodeToKeyCode(sal_Unicode,LanguageType,vcl::KeyCode &)1598 bool AquaSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , vcl::KeyCode& )
1599 {
1600     // not supported yet
1601     return false;
1602 }
1603 
GetInputLanguage()1604 LanguageType AquaSalFrame::GetInputLanguage()
1605 {
1606     //TODO: implement
1607     return LANGUAGE_DONTKNOW;
1608 }
1609 
DrawMenuBar()1610 void AquaSalFrame::DrawMenuBar()
1611 {
1612 }
1613 
SetMenu(SalMenu * pSalMenu)1614 void AquaSalFrame::SetMenu( SalMenu* pSalMenu )
1615 {
1616     OSX_SALDATA_RUNINMAIN( SetMenu( pSalMenu ) )
1617 
1618     AquaSalMenu* pMenu = static_cast<AquaSalMenu*>(pSalMenu);
1619     SAL_WARN_IF( pMenu && !pMenu->mbMenuBar, "vcl", "setting non menubar on frame" );
1620     mpMenu = pMenu;
1621     if( mpMenu  )
1622         mpMenu->setMainMenu();
1623 }
1624 
SetExtendedFrameStyle(SalExtStyle nStyle)1625 void AquaSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
1626 {
1627     if ( !mpNSWindow )
1628     {
1629         mnExtStyle = nStyle;
1630         return;
1631     }
1632 
1633     OSX_SALDATA_RUNINMAIN( SetExtendedFrameStyle( nStyle ) )
1634 
1635     if( (mnExtStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) != (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) )
1636         [mpNSWindow setDocumentEdited: (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) ? YES : NO];
1637 
1638     mnExtStyle = nStyle;
1639 }
1640 
GetParent() const1641 SalFrame* AquaSalFrame::GetParent() const
1642 {
1643     return mpParent;
1644 }
1645 
SetParent(SalFrame * pNewParent)1646 void AquaSalFrame::SetParent( SalFrame* pNewParent )
1647 {
1648     bool bShown = mbShown;
1649     // remove from child list
1650     if (bShown)
1651         Show(false);
1652     mpParent = static_cast<AquaSalFrame*>(pNewParent);
1653     // insert to correct parent and paint
1654     Show( bShown );
1655 }
1656 
UpdateFrameGeometry()1657 void AquaSalFrame::UpdateFrameGeometry()
1658 {
1659     bool bFirstTime = (mnTrackingRectTag == 0);
1660     mbGeometryDidChange = false;
1661 
1662     if ( !mpNSWindow )
1663         return;
1664 
1665     OSX_SALDATA_RUNINMAIN( UpdateFrameGeometry() )
1666 
1667     // keep in mind that view and window coordinates are lower left
1668     // whereas vcl's are upper left
1669 
1670     // update screen rect
1671     NSScreen * pScreen = [mpNSWindow screen];
1672     if( pScreen )
1673     {
1674         NSRect aNewScreenRect = [pScreen frame];
1675         if (bFirstTime || !NSEqualRects(maScreenRect, aNewScreenRect))
1676         {
1677             mbGeometryDidChange = true;
1678             maScreenRect = aNewScreenRect;
1679         }
1680         NSArray* pScreens = [NSScreen screens];
1681         if( pScreens )
1682         {
1683             unsigned int nNewDisplayScreenNumber = [pScreens indexOfObject: pScreen];
1684             if (bFirstTime || maGeometry.nDisplayScreenNumber != nNewDisplayScreenNumber)
1685             {
1686                 mbGeometryDidChange = true;
1687                 maGeometry.nDisplayScreenNumber = nNewDisplayScreenNumber;
1688             }
1689         }
1690     }
1691 
1692     NSRect aFrameRect = [mpNSWindow frame];
1693     NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask];
1694 
1695     NSRect aTrackRect = { NSZeroPoint, aContentRect.size };
1696 
1697     if (bFirstTime || !NSEqualRects(maTrackingRect, aTrackRect))
1698     {
1699         mbGeometryDidChange = true;
1700         maTrackingRect = aTrackRect;
1701 
1702         // release old track rect
1703         [mpNSView removeTrackingRect: mnTrackingRectTag];
1704         // install the new track rect
1705         mnTrackingRectTag = [mpNSView addTrackingRect: aTrackRect owner: mpNSView userData: nil assumeInside: NO];
1706     }
1707 
1708     // convert to vcl convention
1709     CocoaToVCL( aFrameRect );
1710     CocoaToVCL( aContentRect );
1711 
1712     if (bFirstTime || !NSEqualRects(maContentRect, aContentRect) || !NSEqualRects(maFrameRect, aFrameRect))
1713     {
1714         mbGeometryDidChange = true;
1715 
1716         maContentRect = aContentRect;
1717         maFrameRect = aFrameRect;
1718 
1719         maGeometry.nX = static_cast<int>(aContentRect.origin.x);
1720         maGeometry.nY = static_cast<int>(aContentRect.origin.y);
1721 
1722         maGeometry.nLeftDecoration = static_cast<unsigned int>(aContentRect.origin.x - aFrameRect.origin.x);
1723         maGeometry.nRightDecoration = static_cast<unsigned int>((aFrameRect.origin.x + aFrameRect.size.width) -
1724                                       (aContentRect.origin.x + aContentRect.size.width));
1725 
1726         maGeometry.nTopDecoration = static_cast<unsigned int>(aContentRect.origin.y - aFrameRect.origin.y);
1727         maGeometry.nBottomDecoration = static_cast<unsigned int>((aFrameRect.origin.y + aFrameRect.size.height) -
1728                                        (aContentRect.origin.y + aContentRect.size.height));
1729 
1730         maGeometry.nWidth = static_cast<unsigned int>(aContentRect.size.width);
1731         maGeometry.nHeight = static_cast<unsigned int>(aContentRect.size.height);
1732     }
1733 }
1734 
CaptureMouse(bool bCapture)1735 void AquaSalFrame::CaptureMouse( bool bCapture )
1736 {
1737     /* Remark:
1738        we'll try to use a pidgin version of capture mouse
1739        on MacOSX (neither carbon nor cocoa) there is a
1740        CaptureMouse equivalent (in Carbon there is TrackMouseLocation
1741        but this is useless to use since it is blocking)
1742 
1743        However on cocoa the active frame seems to get mouse events
1744        also outside the window, so we'll try to forward mouse events
1745        to the capture frame in the hope that one of our frames
1746        gets a mouse event.
1747 
1748        This will break as soon as the user activates another app, but
1749        a mouse click will normally lead to a release of the mouse anyway.
1750 
1751        Let's see how far we get this way. Alternatively we could use one
1752        large overlay window like we did for the carbon implementation,
1753        however that is resource intensive.
1754     */
1755 
1756     if( bCapture )
1757         s_pCaptureFrame = this;
1758     else if( ! bCapture && s_pCaptureFrame == this )
1759         s_pCaptureFrame = nullptr;
1760 }
1761 
ResetClipRegion()1762 void AquaSalFrame::ResetClipRegion()
1763 {
1764     doResetClipRegion();
1765 }
1766 
doResetClipRegion()1767 void AquaSalFrame::doResetClipRegion()
1768 {
1769     if ( !mpNSWindow )
1770         return;
1771 
1772     OSX_SALDATA_RUNINMAIN( ResetClipRegion() )
1773 
1774     // release old path and indicate no clipping
1775     CGPathRelease( mrClippingPath );
1776     mrClippingPath = nullptr;
1777 
1778     if( mpNSView && mbShown )
1779         [mpNSView setNeedsDisplay: YES];
1780     [mpNSWindow setOpaque: YES];
1781     [mpNSWindow invalidateShadow];
1782 }
1783 
BeginSetClipRegion(sal_uInt32 nRects)1784 void AquaSalFrame::BeginSetClipRegion( sal_uInt32 nRects )
1785 {
1786     if ( !mpNSWindow )
1787         return;
1788 
1789     OSX_SALDATA_RUNINMAIN( BeginSetClipRegion( nRects ) )
1790 
1791     // release old path
1792     if( mrClippingPath )
1793     {
1794         CGPathRelease( mrClippingPath );
1795         mrClippingPath = nullptr;
1796     }
1797 
1798     if( maClippingRects.size() > SAL_CLIPRECT_COUNT && nRects < maClippingRects.size() )
1799     {
1800         std::vector<CGRect>().swap(maClippingRects);
1801     }
1802     maClippingRects.clear();
1803     maClippingRects.reserve( nRects );
1804 }
1805 
UnionClipRegion(tools::Long nX,tools::Long nY,tools::Long nWidth,tools::Long nHeight)1806 void AquaSalFrame::UnionClipRegion(
1807     tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
1808 {
1809     // #i113170# may not be the main thread if called from UNO API
1810     SalData::ensureThreadAutoreleasePool();
1811 
1812     if( nWidth && nHeight )
1813     {
1814         NSRect aRect = { { static_cast<CGFloat>(nX), static_cast<CGFloat>(nY) }, { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) } };
1815         VCLToCocoa( aRect, false );
1816         maClippingRects.push_back( CGRectMake(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height) );
1817     }
1818 }
1819 
EndSetClipRegion()1820 void AquaSalFrame::EndSetClipRegion()
1821 {
1822     if ( !mpNSWindow )
1823         return;
1824 
1825     OSX_SALDATA_RUNINMAIN( EndSetClipRegion() )
1826 
1827     if( ! maClippingRects.empty() )
1828     {
1829         mrClippingPath = CGPathCreateMutable();
1830         CGPathAddRects( mrClippingPath, nullptr, maClippingRects.data(), maClippingRects.size() );
1831     }
1832     if( mpNSView && mbShown )
1833         [mpNSView setNeedsDisplay: YES];
1834     [mpNSWindow setOpaque: (mrClippingPath != nullptr) ? NO : YES];
1835     [mpNSWindow setBackgroundColor: [NSColor clearColor]];
1836     // shadow is invalidated when view gets drawn again
1837 }
1838 
1839 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1840