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