Related: tdf#137748 "Update" should have use-underline
[LibreOffice.git] / vcl / osx / salframe.cxx
bloba5356fcf19be4032e78e9ef9f0601b0959b72cf5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <string>
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>
29 #include <osl/file.h>
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>
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>
48 #include <salwtype.hxx>
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>
58 AquaSalFrame* AquaSalFrame::s_pCaptureFrame = nullptr;
60 AquaSalFrame::AquaSalFrame( SalFrame* pParent, SalFrameStyleFlags salFrameStyle ) :
61 mpNSWindow(nil),
62 mpNSView(nil),
63 mpDockMenuEntry(nil),
64 mpGraphics(nullptr),
65 mpParent(nullptr),
66 mnMinWidth(0),
67 mnMinHeight(0),
68 mnMaxWidth(0),
69 mnMaxHeight(0),
70 mbGraphics(false),
71 mbFullScreen( false ),
72 mbShown(false),
73 mbInitShow(true),
74 mbPositioned(false),
75 mbSized(false),
76 mbPresentation( false ),
77 mnStyle( salFrameStyle ),
78 mnStyleMask( 0 ),
79 mnLastEventTime( 0 ),
80 mnLastModifierFlags( 0 ),
81 mpMenu( nullptr ),
82 mnExtStyle( 0 ),
83 mePointerStyle( PointerStyle::Arrow ),
84 mnTrackingRectTag( 0 ),
85 mrClippingPath( nullptr ),
86 mnICOptions( InputContextFlags::NONE ),
87 mnBlinkCursorDelay ( 500 )
89 mpParent = dynamic_cast<AquaSalFrame*>(pParent);
91 initWindowAndView();
93 SalData* pSalData = GetSalData();
94 pSalData->mpInstance->insertFrame( this );
95 NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
96 if (userDefaults != nil)
98 id setting = [userDefaults objectForKey: @"NSTextInsertionPointBlinkPeriodOn"];
99 if (setting)
100 mnBlinkCursorDelay = [setting intValue];
101 else
103 setting = [userDefaults objectForKey: @"NSTextInsertionPointBlinkPeriodOff"];
104 if (setting)
105 mnBlinkCursorDelay = [setting intValue];
110 AquaSalFrame::~AquaSalFrame()
112 if (mbFullScreen)
113 doShowFullScreen(false, maGeometry.nDisplayScreenNumber);
115 assert( GetSalData()->mpInstance->IsMainThread() );
117 // if the frame is destroyed and has the current menubar
118 // set the default menubar
119 if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu )
120 AquaSalMenu::setDefaultMenu();
122 // cleanup clipping stuff
123 doResetClipRegion();
125 [SalFrameView unsetMouseFrame: this];
127 SalData* pSalData = GetSalData();
128 pSalData->mpInstance->eraseFrame( this );
129 pSalData->maPresentationFrames.remove( this );
131 SAL_WARN_IF( this == s_pCaptureFrame, "vcl", "capture frame destroyed" );
132 if( this == s_pCaptureFrame )
133 s_pCaptureFrame = nullptr;
135 delete mpGraphics;
137 if( mpDockMenuEntry )
139 NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu();
140 // life cycle comment: the menu has ownership of the item, so no release
141 [pDock removeItem: mpDockMenuEntry];
142 if ([pDock numberOfItems] != 0
143 && [[pDock itemAtIndex: 0] isSeparatorItem])
145 [pDock removeItemAtIndex: 0];
148 if ( mpNSView ) {
149 [AquaA11yFactory revokeView: mpNSView];
150 [mpNSView release];
152 if ( mpNSWindow )
153 [mpNSWindow release];
156 void AquaSalFrame::initWindowAndView()
158 OSX_SALDATA_RUNINMAIN( initWindowAndView() )
160 // initialize mirroring parameters
161 // FIXME: screens changing
162 NSScreen* pNSScreen = [mpNSWindow screen];
163 if( pNSScreen == nil )
164 pNSScreen = [NSScreen mainScreen];
165 maScreenRect = [pNSScreen frame];
167 // calculate some default geometry
168 NSRect aVisibleRect = [pNSScreen visibleFrame];
169 CocoaToVCL( aVisibleRect );
171 maGeometry.nX = static_cast<int>(aVisibleRect.origin.x + aVisibleRect.size.width / 10);
172 maGeometry.nY = static_cast<int>(aVisibleRect.origin.y + aVisibleRect.size.height / 10);
173 maGeometry.nWidth = static_cast<unsigned int>(aVisibleRect.size.width * 0.8);
174 maGeometry.nHeight = static_cast<unsigned int>(aVisibleRect.size.height * 0.8);
176 // calculate style mask
177 if( (mnStyle & SalFrameStyleFlags::FLOAT) ||
178 (mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION) )
179 mnStyleMask = NSWindowStyleMaskBorderless;
180 else if( mnStyle & SalFrameStyleFlags::DEFAULT )
182 mnStyleMask = NSWindowStyleMaskTitled |
183 NSWindowStyleMaskMiniaturizable |
184 NSWindowStyleMaskResizable |
185 NSWindowStyleMaskClosable;
186 // make default window "maximized"
187 maGeometry.nX = static_cast<int>(aVisibleRect.origin.x);
188 maGeometry.nY = static_cast<int>(aVisibleRect.origin.y);
189 maGeometry.nWidth = static_cast<int>(aVisibleRect.size.width);
190 maGeometry.nHeight = static_cast<int>(aVisibleRect.size.height);
191 mbPositioned = mbSized = true;
193 else
195 if( mnStyle & SalFrameStyleFlags::MOVEABLE )
197 mnStyleMask |= NSWindowStyleMaskTitled;
198 if( mpParent == nullptr )
199 mnStyleMask |= NSWindowStyleMaskMiniaturizable;
201 if( mnStyle & SalFrameStyleFlags::SIZEABLE )
202 mnStyleMask |= NSWindowStyleMaskResizable;
203 if( mnStyle & SalFrameStyleFlags::CLOSEABLE )
204 mnStyleMask |= NSWindowStyleMaskClosable;
205 // documentation says anything other than NSWindowStyleMaskBorderless (=0)
206 // should also include NSWindowStyleMaskTitled;
207 if( mnStyleMask != 0 )
208 mnStyleMask |= NSWindowStyleMaskTitled;
211 if (Application::IsBitmapRendering())
212 return;
214 // #i91990# support GUI-less (daemon) execution
215 @try
217 mpNSWindow = [[SalFrameWindow alloc] initWithSalFrame: this];
218 mpNSView = [[SalFrameView alloc] initWithSalFrame: this];
220 @catch ( id )
222 std::abort();
225 if( mnStyle & SalFrameStyleFlags::TOOLTIP )
226 [mpNSWindow setIgnoresMouseEvents: YES];
227 else
228 [mpNSWindow setAcceptsMouseMovedEvents: YES];
229 [mpNSWindow setHasShadow: YES];
231 [mpNSWindow setDelegate: static_cast<id<NSWindowDelegate> >(mpNSWindow)];
233 [mpNSWindow setRestorable:NO];
234 const NSRect aRect = { NSZeroPoint, NSMakeSize( maGeometry.nWidth, maGeometry.nHeight )};
235 mnTrackingRectTag = [mpNSView addTrackingRect: aRect owner: mpNSView userData: nil assumeInside: NO];
237 maSysData.mpNSView = mpNSView;
239 UpdateFrameGeometry();
241 [mpNSWindow setContentView: mpNSView];
244 void AquaSalFrame::CocoaToVCL( NSRect& io_rRect, bool bRelativeToScreen )
246 if( bRelativeToScreen )
247 io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height);
248 else
249 io_rRect.origin.y = maGeometry.nHeight - (io_rRect.origin.y+io_rRect.size.height);
252 void AquaSalFrame::VCLToCocoa( NSRect& io_rRect, bool bRelativeToScreen )
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);
260 void AquaSalFrame::CocoaToVCL( NSPoint& io_rPoint, bool bRelativeToScreen )
262 if( bRelativeToScreen )
263 io_rPoint.y = maScreenRect.size.height - io_rPoint.y;
264 else
265 io_rPoint.y = maGeometry.nHeight - io_rPoint.y;
268 void AquaSalFrame::VCLToCocoa( NSPoint& io_rPoint, bool bRelativeToScreen )
270 if( bRelativeToScreen )
271 io_rPoint.y = maScreenRect.size.height - io_rPoint.y;
272 else
273 io_rPoint.y = maGeometry.nHeight - io_rPoint.y;
276 void AquaSalFrame::screenParametersChanged()
278 OSX_SALDATA_RUNINMAIN( screenParametersChanged() )
280 UpdateFrameGeometry();
282 if( mpGraphics )
283 mpGraphics->updateResolution();
285 if (!mbGeometryDidChange)
286 return;
288 CallCallback( SalEvent::DisplayChanged, nullptr );
291 SalGraphics* AquaSalFrame::AcquireGraphics()
293 if ( mbGraphics )
294 return nullptr;
296 if ( !mpGraphics )
298 mpGraphics = new AquaSalGraphics;
299 mpGraphics->SetWindowGraphics( this );
302 mbGraphics = true;
303 return mpGraphics;
306 void AquaSalFrame::ReleaseGraphics( SalGraphics *pGraphics )
308 SAL_WARN_IF( pGraphics != mpGraphics, "vcl", "graphics released on wrong frame" );
309 mbGraphics = false;
312 bool AquaSalFrame::PostEvent(std::unique_ptr<ImplSVEvent> pData)
314 GetSalData()->mpInstance->PostEvent( this, pData.release(), SalEvent::UserEvent );
315 return true;
318 void AquaSalFrame::SetTitle(const OUString& rTitle)
320 if ( !mpNSWindow )
321 return;
323 OSX_SALDATA_RUNINMAIN( SetTitle(rTitle) )
325 // #i113170# may not be the main thread if called from UNO API
326 SalData::ensureThreadAutoreleasePool();
328 NSString* pTitle = CreateNSString( rTitle );
329 [mpNSWindow setTitle: pTitle];
331 // create an entry in the dock menu
332 const SalFrameStyleFlags nAppWindowStyle = SalFrameStyleFlags::CLOSEABLE | SalFrameStyleFlags::MOVEABLE;
333 if( mpParent == nullptr &&
334 (mnStyle & nAppWindowStyle) == nAppWindowStyle )
336 if( mpDockMenuEntry == nullptr )
338 NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu();
340 if ([pDock numberOfItems] != 0) {
341 NSMenuItem* pTopItem = [pDock itemAtIndex: 0];
342 if ( [pTopItem hasSubmenu] )
343 [pDock insertItem: [NSMenuItem separatorItem] atIndex: 0];
346 mpDockMenuEntry = [pDock insertItemWithTitle: pTitle
347 action: @selector(dockMenuItemTriggered:)
348 keyEquivalent: @""
349 atIndex: 0];
350 [mpDockMenuEntry setTarget: mpNSWindow];
352 // TODO: image (either the generic window image or an icon
353 // check mark (for "main" window ?)
355 else
356 [mpDockMenuEntry setTitle: pTitle];
359 if (pTitle)
360 [pTitle release];
363 void AquaSalFrame::SetIcon( sal_uInt16 )
367 void AquaSalFrame::SetRepresentedURL( const OUString& i_rDocURL )
369 OSX_SALDATA_RUNINMAIN( SetRepresentedURL( i_rDocURL ) )
371 if( comphelper::isFileUrl(i_rDocURL) )
373 OUString aSysPath;
374 osl_getSystemPathFromFileURL( i_rDocURL.pData, &aSysPath.pData );
375 NSString* pStr = CreateNSString( aSysPath );
376 if( pStr )
378 [pStr autorelease];
379 [mpNSWindow setRepresentedFilename: pStr];
384 void AquaSalFrame::initShow()
386 OSX_SALDATA_RUNINMAIN( initShow() )
388 mbInitShow = false;
389 if( ! mbPositioned && ! mbFullScreen )
391 tools::Rectangle aScreenRect;
392 GetWorkArea( aScreenRect );
393 if( mpParent ) // center relative to parent
395 // center on parent
396 tools::Long nNewX = mpParent->maGeometry.nX + (static_cast<tools::Long>(mpParent->maGeometry.nWidth) - static_cast<tools::Long>(maGeometry.nWidth))/2;
397 if( nNewX < aScreenRect.Left() )
398 nNewX = aScreenRect.Left();
399 if( tools::Long(nNewX + maGeometry.nWidth) > aScreenRect.Right() )
400 nNewX = aScreenRect.Right() - maGeometry.nWidth-1;
401 tools::Long nNewY = mpParent->maGeometry.nY + (static_cast<tools::Long>(mpParent->maGeometry.nHeight) - static_cast<tools::Long>(maGeometry.nHeight))/2;
402 if( nNewY < aScreenRect.Top() )
403 nNewY = aScreenRect.Top();
404 if( nNewY > aScreenRect.Bottom() )
405 nNewY = aScreenRect.Bottom() - maGeometry.nHeight-1;
406 SetPosSize( nNewX - mpParent->maGeometry.nX,
407 nNewY - mpParent->maGeometry.nY,
408 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
410 else if( ! (mnStyle & SalFrameStyleFlags::SIZEABLE) )
412 // center on screen
413 tools::Long nNewX = (aScreenRect.GetWidth() - maGeometry.nWidth)/2;
414 tools::Long nNewY = (aScreenRect.GetHeight() - maGeometry.nHeight)/2;
415 SetPosSize( nNewX, nNewY, 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
419 // make sure the view is present in the wrapper list before any children receive focus
420 [AquaA11yFactory registerView: mpNSView];
423 void AquaSalFrame::SendPaintEvent( const tools::Rectangle* pRect )
425 OSX_SALDATA_RUNINMAIN( SendPaintEvent( pRect ) )
427 SalPaintEvent aPaintEvt( 0, 0, maGeometry.nWidth, maGeometry.nHeight, true );
428 if( pRect )
430 aPaintEvt.mnBoundX = pRect->Left();
431 aPaintEvt.mnBoundY = pRect->Top();
432 aPaintEvt.mnBoundWidth = pRect->GetWidth();
433 aPaintEvt.mnBoundHeight = pRect->GetHeight();
436 CallCallback(SalEvent::Paint, &aPaintEvt);
439 void AquaSalFrame::Show(bool bVisible, bool bNoActivate)
441 if ( !mpNSWindow )
442 return;
444 OSX_SALDATA_RUNINMAIN( Show(bVisible, bNoActivate) )
446 mbShown = bVisible;
447 if(bVisible)
449 if( mbInitShow )
450 initShow();
452 CallCallback(SalEvent::Resize, nullptr);
453 // trigger filling our backbuffer
454 SendPaintEvent();
456 if( bNoActivate || [mpNSWindow canBecomeKeyWindow] == NO )
457 [mpNSWindow orderFront: NSApp];
458 else
459 [mpNSWindow makeKeyAndOrderFront: NSApp];
461 if( mpParent )
463 /* #i92674# #i96433# we do not want an invisible parent to show up (which adding a visible
464 child implicitly does). However we also do not want a parentless toolbar.
466 HACK: try to decide when we should not insert a child to its parent
467 floaters and ownerdraw windows have not yet shown up in cases where
468 we don't want the parent to become visible
470 if( mpParent->mbShown || (mnStyle & (SalFrameStyleFlags::OWNERDRAWDECORATION | SalFrameStyleFlags::FLOAT) ) )
472 [mpParent->mpNSWindow addChildWindow: mpNSWindow ordered: NSWindowAbove];
476 if( mbPresentation )
477 [mpNSWindow makeMainWindow];
479 else
481 // if the frame holding the current menubar gets hidden
482 // show the default menubar
483 if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu )
484 AquaSalMenu::setDefaultMenu();
486 // #i90440# #i94443# work around the focus going back to some other window
487 // if a child gets hidden for a parent window
488 if( mpParent && mpParent->mbShown && [mpNSWindow isKeyWindow] )
489 [mpParent->mpNSWindow makeKeyAndOrderFront: NSApp];
491 [SalFrameView unsetMouseFrame: this];
492 if( mpParent && [mpNSWindow parentWindow] == mpParent->mpNSWindow )
493 [mpParent->mpNSWindow removeChildWindow: mpNSWindow];
495 [mpNSWindow orderOut: NSApp];
499 void AquaSalFrame::SetMinClientSize( tools::Long nWidth, tools::Long nHeight )
501 OSX_SALDATA_RUNINMAIN( SetMinClientSize( nWidth, nHeight ) )
503 mnMinWidth = nWidth;
504 mnMinHeight = nHeight;
506 if( mpNSWindow )
508 // Always add the decoration as the dimension concerns only
509 // the content rectangle
510 nWidth += maGeometry.nLeftDecoration + maGeometry.nRightDecoration;
511 nHeight += maGeometry.nTopDecoration + maGeometry.nBottomDecoration;
513 NSSize aSize = { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) };
515 // Size of full window (content+structure) although we only
516 // have the client size in arguments
517 [mpNSWindow setMinSize: aSize];
521 void AquaSalFrame::SetMaxClientSize( tools::Long nWidth, tools::Long nHeight )
523 OSX_SALDATA_RUNINMAIN( SetMaxClientSize( nWidth, nHeight ) )
525 mnMaxWidth = nWidth;
526 mnMaxHeight = nHeight;
528 if( mpNSWindow )
530 // Always add the decoration as the dimension concerns only
531 // the content rectangle
532 nWidth += maGeometry.nLeftDecoration + maGeometry.nRightDecoration;
533 nHeight += maGeometry.nTopDecoration + maGeometry.nBottomDecoration;
535 // Carbon windows can't have a size greater than 32767x32767
536 if (nWidth>32767) nWidth=32767;
537 if (nHeight>32767) nHeight=32767;
539 NSSize aSize = { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) };
541 // Size of full window (content+structure) although we only
542 // have the client size in arguments
543 [mpNSWindow setMaxSize: aSize];
547 void AquaSalFrame::GetClientSize( tools::Long& rWidth, tools::Long& rHeight )
549 if (mbShown || mbInitShow || Application::IsBitmapRendering())
551 rWidth = maGeometry.nWidth;
552 rHeight = maGeometry.nHeight;
554 else
556 rWidth = 0;
557 rHeight = 0;
561 SalEvent AquaSalFrame::PreparePosSize(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt16 nFlags)
563 SalEvent nEvent = SalEvent::NONE;
564 assert(mpNSWindow || Application::IsBitmapRendering());
566 if (nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y))
568 mbPositioned = true;
569 nEvent = SalEvent::Move;
572 if (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT))
574 mbSized = true;
575 nEvent = (nEvent == SalEvent::Move) ? SalEvent::MoveResize : SalEvent::Resize;
578 if (Application::IsBitmapRendering())
580 if (nFlags & SAL_FRAME_POSSIZE_X)
581 maGeometry.nX = nX;
582 if (nFlags & SAL_FRAME_POSSIZE_Y)
583 maGeometry.nY = nY;
584 if (nFlags & SAL_FRAME_POSSIZE_WIDTH)
586 maGeometry.nWidth = nWidth;
587 if (mnMaxWidth > 0 && maGeometry.nWidth > o3tl::make_unsigned(mnMaxWidth))
588 maGeometry.nWidth = mnMaxWidth;
589 if (mnMinWidth > 0 && maGeometry.nWidth < o3tl::make_unsigned(mnMinWidth))
590 maGeometry.nWidth = mnMinWidth;
592 if (nFlags & SAL_FRAME_POSSIZE_HEIGHT)
594 maGeometry.nHeight = nHeight;
595 if (mnMaxHeight > 0 && maGeometry.nHeight > o3tl::make_unsigned(mnMaxHeight))
596 maGeometry.nHeight = mnMaxHeight;
597 if (mnMinHeight > 0 && maGeometry.nHeight < o3tl::make_unsigned(mnMinHeight))
598 maGeometry.nHeight = mnMinHeight;
600 if (nEvent != SalEvent::NONE)
601 CallCallback(nEvent, nullptr);
604 return nEvent;
607 void AquaSalFrame::SetWindowState( const SalFrameState* pState )
609 if (!mpNSWindow && !Application::IsBitmapRendering())
610 return;
612 OSX_SALDATA_RUNINMAIN( SetWindowState( pState ) )
614 sal_uInt16 nFlags = 0;
615 nFlags |= ((pState->mnMask & WindowStateMask::X) ? SAL_FRAME_POSSIZE_X : 0);
616 nFlags |= ((pState->mnMask & WindowStateMask::Y) ? SAL_FRAME_POSSIZE_Y : 0);
617 nFlags |= ((pState->mnMask & WindowStateMask::Width) ? SAL_FRAME_POSSIZE_WIDTH : 0);
618 nFlags |= ((pState->mnMask & WindowStateMask::Height) ? SAL_FRAME_POSSIZE_HEIGHT : 0);
620 SalEvent nEvent = PreparePosSize(pState->mnX, pState->mnY, pState->mnWidth, pState->mnHeight, nFlags);
621 if (Application::IsBitmapRendering())
622 return;
624 // set normal state
625 NSRect aStateRect = [mpNSWindow frame];
626 aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask];
627 CocoaToVCL(aStateRect);
628 if (pState->mnMask & WindowStateMask::X)
629 aStateRect.origin.x = float(pState->mnX);
630 if (pState->mnMask & WindowStateMask::Y)
631 aStateRect.origin.y = float(pState->mnY);
632 if (pState->mnMask & WindowStateMask::Width)
633 aStateRect.size.width = float(pState->mnWidth);
634 if (pState->mnMask & WindowStateMask::Height)
635 aStateRect.size.height = float(pState->mnHeight);
636 VCLToCocoa(aStateRect);
637 aStateRect = [NSWindow frameRectForContentRect: aStateRect styleMask: mnStyleMask];
638 [mpNSWindow setFrame: aStateRect display: NO];
640 if (pState->mnState == WindowStateState::Minimized)
641 [mpNSWindow miniaturize: NSApp];
642 else if ([mpNSWindow isMiniaturized])
643 [mpNSWindow deminiaturize: NSApp];
645 /* ZOOMED is not really maximized (actually it toggles between a user set size and
646 the program specified one), but comes closest since the default behavior is
647 "maximized" if the user did not intervene
649 if (pState->mnState == WindowStateState::Maximized)
651 if (![mpNSWindow isZoomed])
652 [mpNSWindow zoom: NSApp];
654 else
656 if ([mpNSWindow isZoomed])
657 [mpNSWindow zoom: NSApp];
660 // get new geometry
661 UpdateFrameGeometry();
663 // send event that we were moved/sized
664 if( nEvent != SalEvent::NONE )
665 CallCallback( nEvent, nullptr );
667 if (mbShown)
669 // trigger filling our backbuffer
670 SendPaintEvent();
672 // tell the system the views need to be updated
673 [mpNSWindow display];
677 bool AquaSalFrame::GetWindowState( SalFrameState* pState )
679 if (!mpNSWindow)
681 if (Application::IsBitmapRendering())
683 pState->mnMask = WindowStateMask::X | WindowStateMask::Y
684 | WindowStateMask::Width | WindowStateMask::Height
685 | WindowStateMask::State;
686 pState->mnX = maGeometry.nX;
687 pState->mnY = maGeometry.nY;
688 pState->mnWidth = maGeometry.nWidth;
689 pState->mnHeight = maGeometry.nHeight;
690 pState->mnState = WindowStateState::Normal;
691 return true;
693 return false;
696 OSX_SALDATA_RUNINMAIN_UNION( GetWindowState( pState ), boolean )
698 pState->mnMask = WindowStateMask::X |
699 WindowStateMask::Y |
700 WindowStateMask::Width |
701 WindowStateMask::Height |
702 WindowStateMask::State;
704 NSRect aStateRect = [mpNSWindow frame];
705 aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask];
706 CocoaToVCL( aStateRect );
707 pState->mnX = tools::Long(aStateRect.origin.x);
708 pState->mnY = tools::Long(aStateRect.origin.y);
709 pState->mnWidth = tools::Long(aStateRect.size.width);
710 pState->mnHeight = tools::Long(aStateRect.size.height);
712 if( [mpNSWindow isMiniaturized] )
713 pState->mnState = WindowStateState::Minimized;
714 else if( ! [mpNSWindow isZoomed] )
715 pState->mnState = WindowStateState::Normal;
716 else
717 pState->mnState = WindowStateState::Maximized;
719 return true;
722 void AquaSalFrame::SetScreenNumber(unsigned int nScreen)
724 if ( !mpNSWindow )
725 return;
727 OSX_SALDATA_RUNINMAIN( SetScreenNumber( nScreen ) )
729 NSArray* pScreens = [NSScreen screens];
730 NSScreen* pScreen = nil;
731 if( pScreens && nScreen < [pScreens count] )
733 // get new screen frame
734 pScreen = [pScreens objectAtIndex: nScreen];
735 NSRect aNewScreen = [pScreen frame];
737 // get current screen frame
738 pScreen = [mpNSWindow screen];
739 if( pScreen )
741 NSRect aCurScreen = [pScreen frame];
742 if( aCurScreen.origin.x != aNewScreen.origin.x ||
743 aCurScreen.origin.y != aNewScreen.origin.y )
745 NSRect aFrameRect = [mpNSWindow frame];
746 aFrameRect.origin.x += aNewScreen.origin.x - aCurScreen.origin.x;
747 aFrameRect.origin.y += aNewScreen.origin.y - aCurScreen.origin.y;
748 [mpNSWindow setFrame: aFrameRect display: NO];
749 UpdateFrameGeometry();
755 void AquaSalFrame::SetApplicationID( const OUString &/*rApplicationID*/ )
759 void AquaSalFrame::ShowFullScreen( bool bFullScreen, sal_Int32 nDisplay )
761 doShowFullScreen(bFullScreen, nDisplay);
764 void AquaSalFrame::doShowFullScreen( bool bFullScreen, sal_Int32 nDisplay )
766 if (!mpNSWindow)
768 if (Application::IsBitmapRendering() && bFullScreen)
769 SetPosSize(0, 0, 1024, 768, SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT);
770 return;
773 SAL_INFO("vcl.osx", __func__ << ": mbFullScreen=" << mbFullScreen << ", bFullScreen=" << bFullScreen);
775 if( mbFullScreen == bFullScreen )
776 return;
778 OSX_SALDATA_RUNINMAIN( ShowFullScreen( bFullScreen, nDisplay ) )
780 mbFullScreen = bFullScreen;
782 if( bFullScreen )
784 // hide the dock and the menubar if we are on the menu screen
785 // which is always on index 0 according to documentation
786 bool bHideMenu = (nDisplay == 0);
788 NSRect aNewContentRect = NSZeroRect;
789 // get correct screen
790 NSScreen* pScreen = nil;
791 NSArray* pScreens = [NSScreen screens];
792 if( pScreens )
794 if( nDisplay >= 0 && o3tl::make_unsigned(nDisplay) < [pScreens count] )
795 pScreen = [pScreens objectAtIndex: nDisplay];
796 else
798 // this means span all screens
799 bHideMenu = true;
800 NSEnumerator* pEnum = [pScreens objectEnumerator];
801 while( (pScreen = [pEnum nextObject]) != nil )
803 NSRect aScreenRect = [pScreen frame];
804 if( aScreenRect.origin.x < aNewContentRect.origin.x )
806 aNewContentRect.size.width += aNewContentRect.origin.x - aScreenRect.origin.x;
807 aNewContentRect.origin.x = aScreenRect.origin.x;
809 if( aScreenRect.origin.y < aNewContentRect.origin.y )
811 aNewContentRect.size.height += aNewContentRect.origin.y - aScreenRect.origin.y;
812 aNewContentRect.origin.y = aScreenRect.origin.y;
814 if( aScreenRect.origin.x + aScreenRect.size.width > aNewContentRect.origin.x + aNewContentRect.size.width )
815 aNewContentRect.size.width = aScreenRect.origin.x + aScreenRect.size.width - aNewContentRect.origin.x;
816 if( aScreenRect.origin.y + aScreenRect.size.height > aNewContentRect.origin.y + aNewContentRect.size.height )
817 aNewContentRect.size.height = aScreenRect.origin.y + aScreenRect.size.height - aNewContentRect.origin.y;
821 if( aNewContentRect.size.width == 0 && aNewContentRect.size.height == 0 )
823 if( pScreen == nil )
824 pScreen = [mpNSWindow screen];
825 if( pScreen == nil )
826 pScreen = [NSScreen mainScreen];
828 aNewContentRect = [pScreen frame];
831 if( bHideMenu )
832 [NSMenu setMenuBarVisible:NO];
834 maFullScreenRect = [mpNSWindow frame];
836 [mpNSWindow setFrame: [NSWindow frameRectForContentRect: aNewContentRect styleMask: mnStyleMask] display: mbShown ? YES : NO];
838 else
840 [mpNSWindow setFrame: maFullScreenRect display: mbShown ? YES : NO];
842 // show the dock and the menubar
843 [NSMenu setMenuBarVisible:YES];
846 UpdateFrameGeometry();
847 if (mbShown)
849 CallCallback(SalEvent::MoveResize, nullptr);
851 // trigger filling our backbuffer
852 SendPaintEvent();
856 void AquaSalFrame::StartPresentation( bool bStart )
858 if ( !mpNSWindow )
859 return;
861 OSX_SALDATA_RUNINMAIN( StartPresentation( bStart ) )
863 if( bStart )
865 GetSalData()->maPresentationFrames.push_back( this );
866 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
867 kIOPMAssertionLevelOn,
868 CFSTR("LibreOffice presentation running"),
869 &mnAssertionID);
870 [mpNSWindow setLevel: NSPopUpMenuWindowLevel];
871 if( mbShown )
872 [mpNSWindow makeMainWindow];
874 else
876 GetSalData()->maPresentationFrames.remove( this );
877 IOPMAssertionRelease(mnAssertionID);
878 [mpNSWindow setLevel: NSNormalWindowLevel];
882 void AquaSalFrame::SetAlwaysOnTop( bool )
886 void AquaSalFrame::ToTop(SalFrameToTop nFlags)
888 if ( !mpNSWindow )
889 return;
891 OSX_SALDATA_RUNINMAIN( ToTop( nFlags ) )
893 if( ! (nFlags & SalFrameToTop::RestoreWhenMin) )
895 if( ! [mpNSWindow isVisible] || [mpNSWindow isMiniaturized] )
896 return;
898 if( nFlags & SalFrameToTop::GrabFocus )
899 [mpNSWindow makeKeyAndOrderFront: NSApp];
900 else
901 [mpNSWindow orderFront: NSApp];
904 NSCursor* AquaSalFrame::getCurrentCursor()
906 OSX_SALDATA_RUNINMAIN_POINTER( getCurrentCursor(), NSCursor* )
908 NSCursor* pCursor = nil;
909 switch( mePointerStyle )
911 case PointerStyle::Text: pCursor = [NSCursor IBeamCursor]; break;
912 case PointerStyle::Cross: pCursor = [NSCursor crosshairCursor]; break;
913 case PointerStyle::Hand:
914 case PointerStyle::Move: pCursor = [NSCursor openHandCursor]; break;
915 case PointerStyle::NSize: pCursor = [NSCursor resizeUpCursor]; break;
916 case PointerStyle::SSize: pCursor = [NSCursor resizeDownCursor]; break;
917 case PointerStyle::ESize: pCursor = [NSCursor resizeRightCursor]; break;
918 case PointerStyle::WSize: pCursor = [NSCursor resizeLeftCursor]; break;
919 case PointerStyle::Arrow: pCursor = [NSCursor arrowCursor]; break;
920 case PointerStyle::VSplit:
921 case PointerStyle::VSizeBar:
922 case PointerStyle::WindowNSize:
923 case PointerStyle::WindowSSize:
924 pCursor = [NSCursor resizeUpDownCursor]; break;
925 case PointerStyle::HSplit:
926 case PointerStyle::HSizeBar:
927 case PointerStyle::WindowESize:
928 case PointerStyle::WindowWSize:
929 pCursor = [NSCursor resizeLeftRightCursor]; break;
930 case PointerStyle::RefHand: pCursor = [NSCursor pointingHandCursor]; break;
932 default:
933 pCursor = GetSalData()->getCursor( mePointerStyle );
934 if( pCursor == nil )
936 assert( false && "unmapped cursor" );
937 pCursor = [NSCursor arrowCursor];
939 break;
941 return pCursor;
944 void AquaSalFrame::SetPointer( PointerStyle ePointerStyle )
946 if ( !mpNSWindow )
947 return;
948 if( ePointerStyle == mePointerStyle )
949 return;
951 OSX_SALDATA_RUNINMAIN( SetPointer( ePointerStyle ) )
953 mePointerStyle = ePointerStyle;
955 [mpNSWindow invalidateCursorRectsForView: mpNSView];
958 void AquaSalFrame::SetPointerPos( tools::Long nX, tools::Long nY )
960 OSX_SALDATA_RUNINMAIN( SetPointerPos( nX, nY ) )
962 // FIXME: use Cocoa functions
963 // FIXME: multiscreen support
964 CGPoint aPoint = { static_cast<CGFloat>(nX + maGeometry.nX), static_cast<CGFloat>(nY + maGeometry.nY) };
965 CGDirectDisplayID mainDisplayID = CGMainDisplayID();
966 CGDisplayMoveCursorToPoint( mainDisplayID, aPoint );
969 void AquaSalFrame::Flush()
971 if( !(mbGraphics && mpGraphics && mpNSView && mbShown) )
972 return;
974 OSX_SALDATA_RUNINMAIN( Flush() )
976 [mpNSView setNeedsDisplay: YES];
978 // outside of the application's event loop (e.g. IntroWindow)
979 // nothing would trigger paint event handling
980 // => fall back to synchronous painting
981 if( ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
983 mpGraphics->Flush();
984 [mpNSView display];
988 void AquaSalFrame::Flush( const tools::Rectangle& rRect )
990 if( !(mbGraphics && mpGraphics && mpNSView && mbShown) )
991 return;
993 OSX_SALDATA_RUNINMAIN( Flush( rRect ) )
995 NSRect aNSRect = { { static_cast<CGFloat>(rRect.Left()), static_cast<CGFloat>(rRect.Top()) }, { static_cast<CGFloat>(rRect.GetWidth()), static_cast<CGFloat>(rRect.GetHeight()) } };
996 VCLToCocoa( aNSRect, false );
997 [mpNSView setNeedsDisplayInRect: aNSRect];
999 // outside of the application's event loop (e.g. IntroWindow)
1000 // nothing would trigger paint event handling
1001 // => fall back to synchronous painting
1002 if( ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
1004 mpGraphics->Flush( rRect );
1005 [mpNSView display];
1009 void AquaSalFrame::SetInputContext( SalInputContext* pContext )
1011 if (!pContext)
1013 mnICOptions = InputContextFlags::NONE;
1014 return;
1017 mnICOptions = pContext->mnOptions;
1019 if(!(pContext->mnOptions & InputContextFlags::Text))
1020 return;
1023 void AquaSalFrame::EndExtTextInput( EndExtTextInputFlags )
1027 OUString AquaSalFrame::GetKeyName( sal_uInt16 nKeyCode )
1029 static std::map< sal_uInt16, OUString > aKeyMap;
1030 if( aKeyMap.empty() )
1032 sal_uInt16 i;
1033 for( i = KEY_A; i <= KEY_Z; i++ )
1034 aKeyMap[ i ] = OUString( sal_Unicode( 'A' + (i - KEY_A) ) );
1035 for( i = KEY_0; i <= KEY_9; i++ )
1036 aKeyMap[ i ] = OUString( sal_Unicode( '0' + (i - KEY_0) ) );
1037 for( i = KEY_F1; i <= KEY_F26; i++ )
1039 aKeyMap[ i ] = "F" + OUString::number(i - KEY_F1 + 1);
1042 aKeyMap[ KEY_DOWN ] = OUString( u'\x21e3' );
1043 aKeyMap[ KEY_UP ] = OUString( u'\x21e1' );
1044 aKeyMap[ KEY_LEFT ] = OUString( u'\x21e0' );
1045 aKeyMap[ KEY_RIGHT ] = OUString( u'\x21e2' );
1046 aKeyMap[ KEY_HOME ] = OUString( u'\x2196' );
1047 aKeyMap[ KEY_END ] = OUString( u'\x2198' );
1048 aKeyMap[ KEY_PAGEUP ] = OUString( u'\x21de' );
1049 aKeyMap[ KEY_PAGEDOWN ] = OUString( u'\x21df' );
1050 aKeyMap[ KEY_RETURN ] = OUString( u'\x21a9' );
1051 aKeyMap[ KEY_ESCAPE ] = "esc";
1052 aKeyMap[ KEY_TAB ] = OUString( u'\x21e5' );
1053 aKeyMap[ KEY_BACKSPACE ]= OUString( u'\x232b' );
1054 aKeyMap[ KEY_SPACE ] = OUString( u'\x2423' );
1055 aKeyMap[ KEY_DELETE ] = OUString( u'\x2326' );
1056 aKeyMap[ KEY_ADD ] = "+";
1057 aKeyMap[ KEY_SUBTRACT ] = "-";
1058 aKeyMap[ KEY_DIVIDE ] = "/";
1059 aKeyMap[ KEY_MULTIPLY ] = "*";
1060 aKeyMap[ KEY_POINT ] = ".";
1061 aKeyMap[ KEY_COMMA ] = ",";
1062 aKeyMap[ KEY_LESS ] = "<";
1063 aKeyMap[ KEY_GREATER ] = ">";
1064 aKeyMap[ KEY_EQUAL ] = "=";
1065 aKeyMap[ KEY_OPEN ] = OUString( u'\x23cf' );
1066 aKeyMap[ KEY_TILDE ] = "~";
1067 aKeyMap[ KEY_BRACKETLEFT ] = "[";
1068 aKeyMap[ KEY_BRACKETRIGHT ] = "]";
1069 aKeyMap[ KEY_SEMICOLON ] = ";";
1070 aKeyMap[ KEY_QUOTERIGHT ] = "'";
1072 /* yet unmapped KEYCODES:
1073 aKeyMap[ KEY_INSERT ] = OUString( sal_Unicode( ) );
1074 aKeyMap[ KEY_CUT ] = OUString( sal_Unicode( ) );
1075 aKeyMap[ KEY_COPY ] = OUString( sal_Unicode( ) );
1076 aKeyMap[ KEY_PASTE ] = OUString( sal_Unicode( ) );
1077 aKeyMap[ KEY_UNDO ] = OUString( sal_Unicode( ) );
1078 aKeyMap[ KEY_REPEAT ] = OUString( sal_Unicode( ) );
1079 aKeyMap[ KEY_FIND ] = OUString( sal_Unicode( ) );
1080 aKeyMap[ KEY_PROPERTIES ] = OUString( sal_Unicode( ) );
1081 aKeyMap[ KEY_FRONT ] = OUString( sal_Unicode( ) );
1082 aKeyMap[ KEY_CONTEXTMENU ] = OUString( sal_Unicode( ) );
1083 aKeyMap[ KEY_MENU ] = OUString( sal_Unicode( ) );
1084 aKeyMap[ KEY_HELP ] = OUString( sal_Unicode( ) );
1085 aKeyMap[ KEY_HANGUL_HANJA ] = OUString( sal_Unicode( ) );
1086 aKeyMap[ KEY_DECIMAL ] = OUString( sal_Unicode( ) );
1087 aKeyMap[ KEY_QUOTELEFT ]= OUString( sal_Unicode( ) );
1088 aKeyMap[ KEY_CAPSLOCK ]= OUString( sal_Unicode( ) );
1089 aKeyMap[ KEY_NUMLOCK ]= OUString( sal_Unicode( ) );
1090 aKeyMap[ KEY_SCROLLLOCK ]= OUString( sal_Unicode( ) );
1095 OUStringBuffer aResult( 16 );
1097 sal_uInt16 nUnmodifiedCode = (nKeyCode & KEY_CODE_MASK);
1098 std::map< sal_uInt16, OUString >::const_iterator it = aKeyMap.find( nUnmodifiedCode );
1099 if( it != aKeyMap.end() )
1101 if( (nKeyCode & KEY_SHIFT) != 0 )
1102 aResult.append( u'\x21e7' ); // shift
1103 if( (nKeyCode & KEY_MOD1) != 0 )
1104 aResult.append( u'\x2318' ); // command
1105 if( (nKeyCode & KEY_MOD2) != 0 )
1106 aResult.append( u'\x2325' ); // alternate
1107 if( (nKeyCode & KEY_MOD3) != 0 )
1108 aResult.append( u'\x2303' ); // control
1110 aResult.append( it->second );
1113 return aResult.makeStringAndClear();
1116 static void getAppleScrollBarVariant(StyleSettings &rSettings)
1118 bool bIsScrollbarDoubleMax = true; // default is DoubleMax
1120 CFStringRef AppleScrollBarType = CFSTR("AppleScrollBarVariant");
1121 if( AppleScrollBarType )
1123 CFStringRef ScrollBarVariant = static_cast<CFStringRef>(CFPreferencesCopyAppValue( AppleScrollBarType, kCFPreferencesCurrentApplication ));
1124 if( ScrollBarVariant )
1126 if( CFGetTypeID( ScrollBarVariant ) == CFStringGetTypeID() )
1128 // TODO: check for the less important variants "DoubleMin" and "DoubleBoth" too
1129 CFStringRef DoubleMax = CFSTR("DoubleMax");
1130 if (DoubleMax)
1132 if ( !CFStringCompare(ScrollBarVariant, DoubleMax, kCFCompareCaseInsensitive) )
1133 bIsScrollbarDoubleMax = true;
1134 else
1135 bIsScrollbarDoubleMax = false;
1136 CFRelease(DoubleMax);
1139 CFRelease( ScrollBarVariant );
1141 CFRelease(AppleScrollBarType);
1144 GetSalData()->mbIsScrollbarDoubleMax = bIsScrollbarDoubleMax;
1146 CFStringRef jumpScroll = CFSTR("AppleScrollerPagingBehavior");
1147 if( jumpScroll )
1149 CFBooleanRef jumpStr = static_cast<CFBooleanRef>(CFPreferencesCopyAppValue( jumpScroll, kCFPreferencesCurrentApplication ));
1150 if( jumpStr )
1152 if( CFGetTypeID( jumpStr ) == CFBooleanGetTypeID() )
1153 rSettings.SetPrimaryButtonWarpsSlider(jumpStr == kCFBooleanTrue);
1154 CFRelease( jumpStr );
1156 CFRelease( jumpScroll );
1160 static Color getColor( NSColor* pSysColor, const Color& rDefault, NSWindow* pWin )
1162 Color aRet( rDefault );
1163 if( pSysColor )
1165 // transform to RGB
1166 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1167 // "'colorUsingColorSpaceName:device:' is deprecated: first deprecated in macOS 10.14 -
1168 // Use -colorUsingType: or -colorUsingColorSpace: instead"
1169 NSColor* pRBGColor = [pSysColor colorUsingColorSpaceName: NSDeviceRGBColorSpace device: [pWin deviceDescription]];
1170 SAL_WNODEPRECATED_DECLARATIONS_POP
1171 if( pRBGColor )
1173 CGFloat r = 0, g = 0, b = 0, a = 0;
1174 [pRBGColor getRed: &r green: &g blue: &b alpha: &a];
1175 aRet = Color( int(r*255.999), int(g*255.999), int(b*255.999) );
1177 do not release here; leads to duplicate free in yield
1178 it seems the converted color comes out autoreleased, although this
1179 is not documented
1180 [pRBGColor release];
1184 return aRet;
1187 static vcl::Font getFont( NSFont* pFont, sal_Int32 nDPIY, const vcl::Font& rDefault )
1189 vcl::Font aResult( rDefault );
1190 if( pFont )
1192 aResult.SetFamilyName( GetOUString( [pFont familyName] ) );
1193 aResult.SetFontHeight( static_cast<int>(([pFont pointSize] * 72.0 / static_cast<float>(nDPIY))+0.5) );
1194 aResult.SetItalic( ([pFont italicAngle] != 0.0) ? ITALIC_NORMAL : ITALIC_NONE );
1195 // FIMXE: bold ?
1198 return aResult;
1201 void AquaSalFrame::getResolution( sal_Int32& o_rDPIX, sal_Int32& o_rDPIY )
1203 OSX_SALDATA_RUNINMAIN( getResolution( o_rDPIX, o_rDPIY ) )
1205 if( ! mpGraphics )
1207 AcquireGraphics();
1208 ReleaseGraphics( mpGraphics );
1210 mpGraphics->GetResolution( o_rDPIX, o_rDPIY );
1213 // on OSX-Aqua the style settings are independent of the frame, so it does
1214 // not really belong here. Since the connection to the Appearance_Manager
1215 // is currently done in salnativewidgets.cxx this would be a good place.
1216 // On the other hand VCL's platform independent code currently only asks
1217 // SalFrames for system settings anyway, so moving the code somewhere else
1218 // doesn't make the anything cleaner for now
1219 void AquaSalFrame::UpdateSettings( AllSettings& rSettings )
1221 if ( !mpNSWindow )
1222 return;
1224 OSX_SALDATA_RUNINMAIN( UpdateSettings( rSettings ) )
1226 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1227 // "'lockFocus' is deprecated: first deprecated in macOS 10.14 - To draw, subclass NSView
1228 // and implement -drawRect:; AppKit's automatic deferred display mechanism will call
1229 // -drawRect: as necessary to display the view."
1230 if (![mpNSView lockFocusIfCanDraw])
1231 return;
1232 SAL_WNODEPRECATED_DECLARATIONS_POP
1234 StyleSettings aStyleSettings = rSettings.GetStyleSettings();
1236 // Background Color
1237 Color aBackgroundColor( 0xEC, 0xEC, 0xEC );
1238 aStyleSettings.BatchSetBackgrounds( aBackgroundColor, false );
1239 aStyleSettings.SetLightBorderColor( aBackgroundColor );
1241 Color aInactiveTabColor( aBackgroundColor );
1242 aInactiveTabColor.DecreaseLuminance( 32 );
1243 aStyleSettings.SetInactiveTabColor( aInactiveTabColor );
1245 Color aShadowColor( aStyleSettings.GetShadowColor() );
1246 aShadowColor.IncreaseLuminance( 32 );
1247 aStyleSettings.SetShadowColor( aShadowColor );
1249 // get the system font settings
1250 vcl::Font aAppFont = aStyleSettings.GetAppFont();
1251 sal_Int32 nDPIX = 72, nDPIY = 72;
1252 getResolution( nDPIX, nDPIY );
1253 aAppFont = getFont( [NSFont systemFontOfSize: 0], nDPIY, aAppFont );
1255 aStyleSettings.SetToolbarIconSize( ToolbarIconSize::Large );
1257 // TODO: better mapping of macOS<->LibreOffice font settings
1258 vcl::Font aLabelFont( getFont( [NSFont labelFontOfSize: 0], nDPIY, aAppFont ) );
1259 aStyleSettings.BatchSetFonts( aAppFont, aLabelFont );
1260 vcl::Font aMenuFont( getFont( [NSFont menuFontOfSize: 0], nDPIY, aAppFont ) );
1261 aStyleSettings.SetMenuFont( aMenuFont );
1263 vcl::Font aTitleFont( getFont( [NSFont titleBarFontOfSize: 0], nDPIY, aAppFont ) );
1264 aStyleSettings.SetTitleFont( aTitleFont );
1265 aStyleSettings.SetFloatTitleFont( aTitleFont );
1267 vcl::Font aTooltipFont(getFont([NSFont toolTipsFontOfSize: 0], nDPIY, aAppFont));
1268 aStyleSettings.SetHelpFont(aTooltipFont);
1270 Color aHighlightColor( getColor( [NSColor selectedTextBackgroundColor],
1271 aStyleSettings.GetHighlightColor(), mpNSWindow ) );
1272 aStyleSettings.SetHighlightColor( aHighlightColor );
1273 Color aHighlightTextColor( getColor( [NSColor selectedTextColor],
1274 aStyleSettings.GetHighlightTextColor(), mpNSWindow ) );
1275 aStyleSettings.SetHighlightTextColor( aHighlightTextColor );
1277 #pragma clang diagnostic push
1278 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1279 Color aMenuHighlightColor( getColor( [NSColor selectedMenuItemColor],
1280 aStyleSettings.GetMenuHighlightColor(), mpNSWindow ) );
1281 #pragma clang diagnostic pop
1282 aStyleSettings.SetMenuHighlightColor( aMenuHighlightColor );
1283 Color aMenuHighlightTextColor( getColor( [NSColor selectedMenuItemTextColor],
1284 aStyleSettings.GetMenuHighlightTextColor(), mpNSWindow ) );
1285 aStyleSettings.SetMenuHighlightTextColor( aMenuHighlightTextColor );
1287 aStyleSettings.SetMenuColor( aBackgroundColor );
1288 Color aMenuTextColor( getColor( [NSColor textColor],
1289 aStyleSettings.GetMenuTextColor(), mpNSWindow ) );
1290 aStyleSettings.SetMenuTextColor( aMenuTextColor );
1291 aStyleSettings.SetMenuBarTextColor( aMenuTextColor );
1292 aStyleSettings.SetMenuBarRolloverTextColor( aMenuTextColor );
1293 aStyleSettings.SetMenuBarHighlightTextColor(aStyleSettings.GetMenuHighlightTextColor());
1295 // Set text colors for buttons and their different status according to OS settings, typically white for selected buttons,
1296 // black otherwise
1298 Color aControlTextColor(getColor([NSColor controlTextColor], COL_BLACK, mpNSWindow));
1299 Color aSelectedControlTextColor(getColor([NSColor selectedControlTextColor], COL_BLACK, mpNSWindow));
1300 Color aAlternateSelectedControlTextColor(getColor([NSColor alternateSelectedControlTextColor], COL_WHITE, mpNSWindow));
1301 aStyleSettings.SetDefaultButtonTextColor(aAlternateSelectedControlTextColor);
1302 aStyleSettings.SetButtonTextColor(aControlTextColor);
1303 aStyleSettings.SetDefaultActionButtonTextColor(aAlternateSelectedControlTextColor);
1304 aStyleSettings.SetActionButtonTextColor(aControlTextColor);
1305 aStyleSettings.SetFlatButtonTextColor(aControlTextColor);
1306 aStyleSettings.SetDefaultButtonRolloverTextColor(aAlternateSelectedControlTextColor);
1307 aStyleSettings.SetButtonRolloverTextColor(aControlTextColor);
1308 aStyleSettings.SetDefaultActionButtonRolloverTextColor(aAlternateSelectedControlTextColor);
1309 aStyleSettings.SetActionButtonRolloverTextColor(aControlTextColor);
1310 aStyleSettings.SetFlatButtonRolloverTextColor(aControlTextColor);
1311 aStyleSettings.SetDefaultButtonPressedRolloverTextColor(aAlternateSelectedControlTextColor);
1312 aStyleSettings.SetButtonPressedRolloverTextColor(aAlternateSelectedControlTextColor);
1313 aStyleSettings.SetDefaultActionButtonPressedRolloverTextColor(aAlternateSelectedControlTextColor);
1314 aStyleSettings.SetActionButtonPressedRolloverTextColor(aAlternateSelectedControlTextColor);
1315 aStyleSettings.SetFlatButtonPressedRolloverTextColor(aControlTextColor);
1317 // Set text colors for tabs according to OS settings
1319 aStyleSettings.SetTabTextColor(aControlTextColor);
1321 // FIXME: Starting with macOS Big Sur, coloring has changed. Currently there is no documentation which system color should be
1322 // used for selected tab text. As a workaround the current OS version has to be considered. This code has to be reviewed once
1323 // issue is covered by documentation.
1325 NSOperatingSystemVersion aOSVersion = { .majorVersion = 10, .minorVersion = 16, .patchVersion = 0 };
1326 if ([NSProcessInfo.processInfo isOperatingSystemAtLeastVersion: aOSVersion])
1327 aStyleSettings.SetTabHighlightTextColor(aSelectedControlTextColor);
1328 else
1329 aStyleSettings.SetTabHighlightTextColor(aAlternateSelectedControlTextColor);
1331 aStyleSettings.SetCursorBlinkTime( mnBlinkCursorDelay );
1333 // no mnemonics on macOS
1334 aStyleSettings.SetOptions( aStyleSettings.GetOptions() | StyleSettingsOptions::NoMnemonics );
1336 getAppleScrollBarVariant(aStyleSettings);
1338 // set scrollbar size
1339 aStyleSettings.SetScrollBarSize( static_cast<tools::Long>([NSScroller scrollerWidthForControlSize:NSControlSizeRegular scrollerStyle:NSScrollerStyleLegacy]) );
1340 // images in menus false for MacOSX
1341 aStyleSettings.SetPreferredUseImagesInMenus( false );
1342 aStyleSettings.SetHideDisabledMenuItems( true );
1343 aStyleSettings.SetPreferredContextMenuShortcuts( false );
1345 rSettings.SetStyleSettings( aStyleSettings );
1347 // don't draw frame around each and every toolbar
1348 ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames = true;
1350 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1351 // "'unlockFocus' is deprecated: first deprecated in macOS 10.14 - To draw, subclass NSView
1352 // and implement -drawRect:; AppKit's automatic deferred display mechanism will call
1353 // -drawRect: as necessary to display the view."
1354 [mpNSView unlockFocus];
1355 SAL_WNODEPRECATED_DECLARATIONS_POP
1358 const SystemEnvData* AquaSalFrame::GetSystemData() const
1360 return &maSysData;
1363 void AquaSalFrame::Beep()
1365 OSX_SALDATA_RUNINMAIN( Beep() )
1366 NSBeep();
1369 void AquaSalFrame::SetPosSize(
1370 tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt16 nFlags)
1372 if (!mpNSWindow && !Application::IsBitmapRendering())
1373 return;
1375 OSX_SALDATA_RUNINMAIN( SetPosSize( nX, nY, nWidth, nHeight, nFlags ) )
1377 SalEvent nEvent = PreparePosSize(nX, nY, nWidth, nHeight, nFlags);
1378 if (Application::IsBitmapRendering())
1379 return;
1381 if( [mpNSWindow isMiniaturized] )
1382 [mpNSWindow deminiaturize: NSApp]; // expand the window
1384 NSRect aFrameRect = [mpNSWindow frame];
1385 NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask];
1387 // position is always relative to parent frame
1388 NSRect aParentContentRect;
1390 if( mpParent )
1392 if( AllSettings::GetLayoutRTL() )
1394 if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
1395 nX = mpParent->maGeometry.nWidth - nWidth-1 - nX;
1396 else
1397 nX = mpParent->maGeometry.nWidth - static_cast<tools::Long>( aContentRect.size.width-1) - nX;
1399 NSRect aParentFrameRect = [mpParent->mpNSWindow frame];
1400 aParentContentRect = [NSWindow contentRectForFrameRect: aParentFrameRect styleMask: mpParent->mnStyleMask];
1402 else
1403 aParentContentRect = maScreenRect; // use screen if no parent
1405 CocoaToVCL( aContentRect );
1406 CocoaToVCL( aParentContentRect );
1408 bool bPaint = false;
1409 if( (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) != 0 )
1411 if( nWidth != aContentRect.size.width || nHeight != aContentRect.size.height )
1412 bPaint = true;
1415 // use old window pos if no new pos requested
1416 if( (nFlags & SAL_FRAME_POSSIZE_X) != 0 )
1417 aContentRect.origin.x = nX + aParentContentRect.origin.x;
1418 if( (nFlags & SAL_FRAME_POSSIZE_Y) != 0)
1419 aContentRect.origin.y = nY + aParentContentRect.origin.y;
1421 // use old size if no new size requested
1422 if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
1423 aContentRect.size.width = nWidth;
1424 if( (nFlags & SAL_FRAME_POSSIZE_HEIGHT) != 0)
1425 aContentRect.size.height = nHeight;
1427 VCLToCocoa( aContentRect );
1429 // do not display yet, we need to update our backbuffer
1431 [mpNSWindow setFrame: [NSWindow frameRectForContentRect: aContentRect styleMask: mnStyleMask] display: NO];
1434 UpdateFrameGeometry();
1436 if (nEvent != SalEvent::NONE)
1437 CallCallback(nEvent, nullptr);
1439 if( mbShown && bPaint )
1441 // trigger filling our backbuffer
1442 SendPaintEvent();
1444 // now inform the system that the views need to be drawn
1445 [mpNSWindow display];
1449 void AquaSalFrame::GetWorkArea( tools::Rectangle& rRect )
1451 if (!mpNSWindow)
1453 if (Application::IsBitmapRendering())
1454 rRect = tools::Rectangle(Point(0, 0), Size(1024, 768));
1455 return;
1458 OSX_SALDATA_RUNINMAIN( GetWorkArea( rRect ) )
1460 NSScreen* pScreen = [mpNSWindow screen];
1461 if( pScreen == nil )
1462 pScreen = [NSScreen mainScreen];
1463 NSRect aRect = [pScreen visibleFrame];
1464 CocoaToVCL( aRect );
1465 rRect.SetLeft( static_cast<tools::Long>(aRect.origin.x) );
1466 rRect.SetTop( static_cast<tools::Long>(aRect.origin.y) );
1467 rRect.SetRight( static_cast<tools::Long>(aRect.origin.x + aRect.size.width - 1) );
1468 rRect.SetBottom( static_cast<tools::Long>(aRect.origin.y + aRect.size.height - 1) );
1471 SalFrame::SalPointerState AquaSalFrame::GetPointerState()
1473 OSX_SALDATA_RUNINMAIN_UNION( GetPointerState(), state )
1475 SalPointerState state;
1476 state.mnState = 0;
1478 // get position
1479 NSPoint aPt = [mpNSWindow mouseLocationOutsideOfEventStream];
1480 CocoaToVCL( aPt, false );
1481 state.maPos = Point(static_cast<tools::Long>(aPt.x), static_cast<tools::Long>(aPt.y));
1483 NSEvent* pCur = [NSApp currentEvent];
1484 bool bMouseEvent = false;
1485 if( pCur )
1487 bMouseEvent = true;
1488 switch( [pCur type] )
1490 case NSEventTypeLeftMouseDown:
1491 state.mnState |= MOUSE_LEFT;
1492 break;
1493 case NSEventTypeLeftMouseUp:
1494 break;
1495 case NSEventTypeRightMouseDown:
1496 state.mnState |= MOUSE_RIGHT;
1497 break;
1498 case NSEventTypeRightMouseUp:
1499 break;
1500 case NSEventTypeOtherMouseDown:
1501 state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0;
1502 break;
1503 case NSEventTypeOtherMouseUp:
1504 break;
1505 case NSEventTypeMouseMoved:
1506 break;
1507 case NSEventTypeLeftMouseDragged:
1508 state.mnState |= MOUSE_LEFT;
1509 break;
1510 case NSEventTypeRightMouseDragged:
1511 state.mnState |= MOUSE_RIGHT;
1512 break;
1513 case NSEventTypeOtherMouseDragged:
1514 state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0;
1515 break;
1516 default:
1517 bMouseEvent = false;
1518 break;
1521 if( bMouseEvent )
1523 unsigned int nMask = static_cast<unsigned int>([pCur modifierFlags]);
1524 if( (nMask & NSEventModifierFlagShift) != 0 )
1525 state.mnState |= KEY_SHIFT;
1526 if( (nMask & NSEventModifierFlagControl) != 0 )
1527 state.mnState |= KEY_MOD3;
1528 if( (nMask & NSEventModifierFlagOption) != 0 )
1529 state.mnState |= KEY_MOD2;
1530 if( (nMask & NSEventModifierFlagCommand) != 0 )
1531 state.mnState |= KEY_MOD1;
1534 else
1536 // FIXME: replace Carbon by Cocoa
1537 // Cocoa does not have an equivalent for GetCurrentEventButtonState
1538 // and GetCurrentEventKeyModifiers.
1539 // we could try to get away with tracking all events for modifierKeys
1540 // and all mouse events for button state in VCL_NSApplication::sendEvent,
1541 // but it is unclear whether this will get us the same result.
1542 // leave in GetCurrentEventButtonState and GetCurrentEventKeyModifiers for now
1544 // fill in button state
1545 UInt32 nState = GetCurrentEventButtonState();
1546 state.mnState = 0;
1547 if( nState & 1 )
1548 state.mnState |= MOUSE_LEFT; // primary button
1549 if( nState & 2 )
1550 state.mnState |= MOUSE_RIGHT; // secondary button
1551 if( nState & 4 )
1552 state.mnState |= MOUSE_MIDDLE; // tertiary button
1554 // fill in modifier state
1555 nState = GetCurrentEventKeyModifiers();
1556 if( nState & shiftKey )
1557 state.mnState |= KEY_SHIFT;
1558 if( nState & controlKey )
1559 state.mnState |= KEY_MOD3;
1560 if( nState & optionKey )
1561 state.mnState |= KEY_MOD2;
1562 if( nState & cmdKey )
1563 state.mnState |= KEY_MOD1;
1566 return state;
1569 KeyIndicatorState AquaSalFrame::GetIndicatorState()
1571 return KeyIndicatorState::NONE;
1574 void AquaSalFrame::SimulateKeyPress( sal_uInt16 /*nKeyCode*/ )
1578 void AquaSalFrame::SetPluginParent( SystemParentData* )
1580 // plugin parent may be killed unexpectedly by
1581 // plugging process;
1583 //TODO: implement
1586 bool AquaSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , vcl::KeyCode& )
1588 // not supported yet
1589 return false;
1592 LanguageType AquaSalFrame::GetInputLanguage()
1594 //TODO: implement
1595 return LANGUAGE_DONTKNOW;
1598 void AquaSalFrame::DrawMenuBar()
1602 void AquaSalFrame::SetMenu( SalMenu* pSalMenu )
1604 OSX_SALDATA_RUNINMAIN( SetMenu( pSalMenu ) )
1606 AquaSalMenu* pMenu = static_cast<AquaSalMenu*>(pSalMenu);
1607 SAL_WARN_IF( pMenu && !pMenu->mbMenuBar, "vcl", "setting non menubar on frame" );
1608 mpMenu = pMenu;
1609 if( mpMenu )
1610 mpMenu->setMainMenu();
1613 void AquaSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
1615 if ( !mpNSWindow )
1617 mnExtStyle = nStyle;
1618 return;
1621 OSX_SALDATA_RUNINMAIN( SetExtendedFrameStyle( nStyle ) )
1623 if( (mnExtStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) != (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) )
1624 [mpNSWindow setDocumentEdited: (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) ? YES : NO];
1626 mnExtStyle = nStyle;
1629 SalFrame* AquaSalFrame::GetParent() const
1631 return mpParent;
1634 void AquaSalFrame::SetParent( SalFrame* pNewParent )
1636 bool bShown = mbShown;
1637 // remove from child list
1638 if (bShown)
1639 Show(false);
1640 mpParent = static_cast<AquaSalFrame*>(pNewParent);
1641 // insert to correct parent and paint
1642 Show( bShown );
1645 void AquaSalFrame::UpdateFrameGeometry()
1647 bool bFirstTime = (mnTrackingRectTag == 0);
1648 mbGeometryDidChange = false;
1650 if ( !mpNSWindow )
1651 return;
1653 OSX_SALDATA_RUNINMAIN( UpdateFrameGeometry() )
1655 // keep in mind that view and window coordinates are lower left
1656 // whereas vcl's are upper left
1658 // update screen rect
1659 NSScreen * pScreen = [mpNSWindow screen];
1660 if( pScreen )
1662 NSRect aNewScreenRect = [pScreen frame];
1663 if (bFirstTime || !NSEqualRects(maScreenRect, aNewScreenRect))
1665 mbGeometryDidChange = true;
1666 maScreenRect = aNewScreenRect;
1668 NSArray* pScreens = [NSScreen screens];
1669 if( pScreens )
1671 unsigned int nNewDisplayScreenNumber = [pScreens indexOfObject: pScreen];
1672 if (bFirstTime || maGeometry.nDisplayScreenNumber != nNewDisplayScreenNumber)
1674 mbGeometryDidChange = true;
1675 maGeometry.nDisplayScreenNumber = nNewDisplayScreenNumber;
1680 NSRect aFrameRect = [mpNSWindow frame];
1681 NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask];
1683 NSRect aTrackRect = { NSZeroPoint, aContentRect.size };
1685 if (bFirstTime || !NSEqualRects(maTrackingRect, aTrackRect))
1687 mbGeometryDidChange = true;
1688 maTrackingRect = aTrackRect;
1690 // release old track rect
1691 [mpNSView removeTrackingRect: mnTrackingRectTag];
1692 // install the new track rect
1693 mnTrackingRectTag = [mpNSView addTrackingRect: aTrackRect owner: mpNSView userData: nil assumeInside: NO];
1696 // convert to vcl convention
1697 CocoaToVCL( aFrameRect );
1698 CocoaToVCL( aContentRect );
1700 if (bFirstTime || !NSEqualRects(maContentRect, aContentRect) || !NSEqualRects(maFrameRect, aFrameRect))
1702 mbGeometryDidChange = true;
1704 maContentRect = aContentRect;
1705 maFrameRect = aFrameRect;
1707 maGeometry.nX = static_cast<int>(aContentRect.origin.x);
1708 maGeometry.nY = static_cast<int>(aContentRect.origin.y);
1710 maGeometry.nLeftDecoration = static_cast<unsigned int>(aContentRect.origin.x - aFrameRect.origin.x);
1711 maGeometry.nRightDecoration = static_cast<unsigned int>((aFrameRect.origin.x + aFrameRect.size.width) -
1712 (aContentRect.origin.x + aContentRect.size.width));
1714 maGeometry.nTopDecoration = static_cast<unsigned int>(aContentRect.origin.y - aFrameRect.origin.y);
1715 maGeometry.nBottomDecoration = static_cast<unsigned int>((aFrameRect.origin.y + aFrameRect.size.height) -
1716 (aContentRect.origin.y + aContentRect.size.height));
1718 maGeometry.nWidth = static_cast<unsigned int>(aContentRect.size.width);
1719 maGeometry.nHeight = static_cast<unsigned int>(aContentRect.size.height);
1723 void AquaSalFrame::CaptureMouse( bool bCapture )
1725 /* Remark:
1726 we'll try to use a pidgin version of capture mouse
1727 on MacOSX (neither carbon nor cocoa) there is a
1728 CaptureMouse equivalent (in Carbon there is TrackMouseLocation
1729 but this is useless to use since it is blocking)
1731 However on cocoa the active frame seems to get mouse events
1732 also outside the window, so we'll try to forward mouse events
1733 to the capture frame in the hope that one of our frames
1734 gets a mouse event.
1736 This will break as soon as the user activates another app, but
1737 a mouse click will normally lead to a release of the mouse anyway.
1739 Let's see how far we get this way. Alternatively we could use one
1740 large overlay window like we did for the carbon implementation,
1741 however that is resource intensive.
1744 if( bCapture )
1745 s_pCaptureFrame = this;
1746 else if( ! bCapture && s_pCaptureFrame == this )
1747 s_pCaptureFrame = nullptr;
1750 void AquaSalFrame::ResetClipRegion()
1752 doResetClipRegion();
1755 void AquaSalFrame::doResetClipRegion()
1757 if ( !mpNSWindow )
1758 return;
1760 OSX_SALDATA_RUNINMAIN( ResetClipRegion() )
1762 // release old path and indicate no clipping
1763 CGPathRelease( mrClippingPath );
1764 mrClippingPath = nullptr;
1766 if( mpNSView && mbShown )
1767 [mpNSView setNeedsDisplay: YES];
1768 [mpNSWindow setOpaque: YES];
1769 [mpNSWindow invalidateShadow];
1772 void AquaSalFrame::BeginSetClipRegion( sal_uInt32 nRects )
1774 if ( !mpNSWindow )
1775 return;
1777 OSX_SALDATA_RUNINMAIN( BeginSetClipRegion( nRects ) )
1779 // release old path
1780 if( mrClippingPath )
1782 CGPathRelease( mrClippingPath );
1783 mrClippingPath = nullptr;
1786 if( maClippingRects.size() > SAL_CLIPRECT_COUNT && nRects < maClippingRects.size() )
1788 std::vector<CGRect>().swap(maClippingRects);
1790 maClippingRects.clear();
1791 maClippingRects.reserve( nRects );
1794 void AquaSalFrame::UnionClipRegion(
1795 tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
1797 // #i113170# may not be the main thread if called from UNO API
1798 SalData::ensureThreadAutoreleasePool();
1800 if( nWidth && nHeight )
1802 NSRect aRect = { { static_cast<CGFloat>(nX), static_cast<CGFloat>(nY) }, { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) } };
1803 VCLToCocoa( aRect, false );
1804 maClippingRects.push_back( CGRectMake(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height) );
1808 void AquaSalFrame::EndSetClipRegion()
1810 if ( !mpNSWindow )
1811 return;
1813 OSX_SALDATA_RUNINMAIN( EndSetClipRegion() )
1815 if( ! maClippingRects.empty() )
1817 mrClippingPath = CGPathCreateMutable();
1818 CGPathAddRects( mrClippingPath, nullptr, maClippingRects.data(), maClippingRects.size() );
1820 if( mpNSView && mbShown )
1821 [mpNSView setNeedsDisplay: YES];
1822 [mpNSWindow setOpaque: (mrClippingPath != nullptr) ? NO : YES];
1823 [mpNSWindow setBackgroundColor: [NSColor clearColor]];
1824 // shadow is invalidated when view gets drawn again
1827 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */