tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / vcl / osx / salframe.cxx
blob9d85969363b651503fe395ea5b824a4ded053abe
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 <IconThemeSelector.hxx>
21 #include <string>
23 #include <comphelper/fileurl.hxx>
24 #include <rtl/ustrbuf.hxx>
25 #include <sal/log.hxx>
26 #include <tools/long.hxx>
27 #include <o3tl/safeint.hxx>
28 #include <osl/diagnose.h>
30 #include <osl/file.h>
32 #include <vcl/event.hxx>
33 #include <vcl/inputctx.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/window.hxx>
36 #include <vcl/syswin.hxx>
37 #include <vcl/settings.hxx>
38 #include <vcl/themecolors.hxx>
40 #include <osx/saldata.hxx>
41 #include <quartz/salgdi.h>
42 #include <osx/salframe.h>
43 #include <osx/salmenu.h>
44 #include <osx/salinst.h>
45 #include <osx/salframeview.h>
46 #include <osx/a11yfactory.h>
47 #include <osx/runinmain.hxx>
48 #include <quartz/utils.h>
50 #include <salwtype.hxx>
52 #include <premac.h>
53 #include <objc/objc-runtime.h>
54 // needed for theming
55 // FIXME: move theming code to salnativewidgets.cxx
56 #include <Carbon/Carbon.h>
57 #include <quartz/CGHelpers.hxx>
58 #include <postmac.h>
60 #if HAVE_FEATURE_SKIA
61 #include <vcl/skia/SkiaHelper.hxx>
62 #endif
64 const int nMinBlinkCursorDelay = 500;
66 AquaSalFrame* AquaSalFrame::s_pCaptureFrame = nullptr;
68 AquaSalFrame::AquaSalFrame( SalFrame* pParent, SalFrameStyleFlags salFrameStyle ) :
69 mpNSWindow(nil),
70 mpNSView(nil),
71 mpDockMenuEntry(nil),
72 mpGraphics(nullptr),
73 mpParent(nullptr),
74 mnMinWidth(0),
75 mnMinHeight(0),
76 mnMaxWidth(0),
77 mnMaxHeight(0),
78 mbGraphics(false),
79 mbFullScreen( false ),
80 mbShown(false),
81 mbInitShow(true),
82 mbPositioned(false),
83 mbSized(false),
84 mbPresentation( false ),
85 mnStyle( salFrameStyle ),
86 mnStyleMask( 0 ),
87 mnLastEventTime( 0 ),
88 mnLastModifierFlags( 0 ),
89 mpMenu( nullptr ),
90 mnExtStyle( 0 ),
91 mePointerStyle( PointerStyle::Arrow ),
92 mrClippingPath( nullptr ),
93 mnICOptions( InputContextFlags::NONE ),
94 mnBlinkCursorDelay( nMinBlinkCursorDelay ),
95 mbForceFlush( false )
97 mpParent = dynamic_cast<AquaSalFrame*>(pParent);
99 initWindowAndView();
101 SalData* pSalData = GetSalData();
102 pSalData->mpInstance->insertFrame( this );
103 NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
105 // tdf#150177 Limit minimum blink cursor rate
106 // This bug occurs when the values for NSTextInsertionPointBlinkPeriodOn or
107 // NSTextInsertionPointBlinkPeriodOff are set to zero or close to zero.
108 // LibreOffice becomes very sluggish opening documents when either is set
109 // at 100 milliseconds or less so set the blink rate to the maximum of
110 // nMinBlinkCursorDelay, NSTextInsertionPointBlinkPeriodOn, and
111 // NSTextInsertionPointBlinkPeriodOff.
112 mnBlinkCursorDelay = nMinBlinkCursorDelay;
113 if (userDefaults != nil)
115 id setting = [userDefaults objectForKey: @"NSTextInsertionPointBlinkPeriodOn"];
116 if (setting && [setting isKindOfClass:[NSNumber class]])
117 mnBlinkCursorDelay = std::max(mnBlinkCursorDelay, [setting intValue]);
119 setting = [userDefaults objectForKey: @"NSTextInsertionPointBlinkPeriodOff"];
120 if (setting && [setting isKindOfClass:[NSNumber class]])
121 mnBlinkCursorDelay = std::max(mnBlinkCursorDelay, [setting intValue]);
125 AquaSalFrame::~AquaSalFrame()
127 if (mbFullScreen)
128 doShowFullScreen(false, maGeometry.screen());
130 assert( GetSalData()->mpInstance->IsMainThread() );
132 // if the frame is destroyed and has the current menubar
133 // set the default menubar
134 if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu )
135 AquaSalMenu::setDefaultMenu();
137 // cleanup clipping stuff
138 doResetClipRegion();
140 [SalFrameView unsetMouseFrame: this];
142 SalData* pSalData = GetSalData();
143 pSalData->mpInstance->eraseFrame( this );
144 pSalData->maPresentationFrames.remove( this );
146 SAL_WARN_IF( this == s_pCaptureFrame, "vcl", "capture frame destroyed" );
147 if( this == s_pCaptureFrame )
148 s_pCaptureFrame = nullptr;
150 delete mpGraphics;
152 if( mpDockMenuEntry )
154 NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu();
155 // life cycle comment: the menu has ownership of the item, so no release
156 [pDock removeItem: mpDockMenuEntry];
157 if ([pDock numberOfItems] != 0
158 && [[pDock itemAtIndex: 0] isSeparatorItem])
160 [pDock removeItemAtIndex: 0];
163 if ( mpNSView ) {
164 if ([mpNSView isKindOfClass:[SalFrameView class]])
165 [static_cast<SalFrameView*>(mpNSView) revokeWrapper];
166 [mpNSView release];
168 if ( mpNSWindow )
169 [mpNSWindow release];
172 void AquaSalFrame::initWindowAndView()
174 OSX_SALDATA_RUNINMAIN( initWindowAndView() )
176 // initialize mirroring parameters
177 // FIXME: screens changing
178 NSScreen* pNSScreen = [mpNSWindow screen];
179 if( pNSScreen == nil )
180 pNSScreen = [NSScreen mainScreen];
181 maScreenRect = [pNSScreen frame];
183 // calculate some default geometry
184 NSRect aVisibleRect = [pNSScreen visibleFrame];
185 CocoaToVCL( aVisibleRect );
187 maGeometry.setX(static_cast<sal_Int32>(aVisibleRect.origin.x + aVisibleRect.size.width / 10));
188 maGeometry.setY(static_cast<sal_Int32>(aVisibleRect.origin.y + aVisibleRect.size.height / 10));
189 maGeometry.setWidth(static_cast<sal_uInt32>(aVisibleRect.size.width * 0.8));
190 maGeometry.setHeight(static_cast<sal_uInt32>(aVisibleRect.size.height * 0.8));
192 // calculate style mask
193 if( (mnStyle & SalFrameStyleFlags::FLOAT) ||
194 (mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION) )
195 mnStyleMask = NSWindowStyleMaskBorderless;
196 else if( mnStyle & SalFrameStyleFlags::DEFAULT )
198 mnStyleMask = NSWindowStyleMaskTitled |
199 NSWindowStyleMaskMiniaturizable |
200 NSWindowStyleMaskResizable |
201 NSWindowStyleMaskClosable;
202 // make default window "maximized"
203 maGeometry.setX(static_cast<sal_Int32>(aVisibleRect.origin.x));
204 maGeometry.setY(static_cast<sal_Int32>(aVisibleRect.origin.y));
205 maGeometry.setWidth(static_cast<sal_uInt32>(aVisibleRect.size.width));
206 maGeometry.setHeight(static_cast<sal_uInt32>(aVisibleRect.size.height));
207 mbPositioned = mbSized = true;
209 else
211 if( mnStyle & SalFrameStyleFlags::MOVEABLE )
213 mnStyleMask |= NSWindowStyleMaskTitled;
214 if( mpParent == nullptr )
215 mnStyleMask |= NSWindowStyleMaskMiniaturizable;
217 if( mnStyle & SalFrameStyleFlags::SIZEABLE )
218 mnStyleMask |= NSWindowStyleMaskResizable;
219 if( mnStyle & SalFrameStyleFlags::CLOSEABLE )
220 mnStyleMask |= NSWindowStyleMaskClosable;
221 // documentation says anything other than NSWindowStyleMaskBorderless (=0)
222 // should also include NSWindowStyleMaskTitled;
223 if( mnStyleMask != 0 )
224 mnStyleMask |= NSWindowStyleMaskTitled;
227 if (Application::IsBitmapRendering())
228 return;
230 // #i91990# support GUI-less (daemon) execution
231 @try
233 mpNSWindow = [[SalFrameWindow alloc] initWithSalFrame: this];
234 mpNSView = [[SalFrameView alloc] initWithSalFrame: this];
236 @catch ( id )
238 std::abort();
241 if( mnStyle & SalFrameStyleFlags::TOOLTIP )
242 [mpNSWindow setIgnoresMouseEvents: YES];
243 else
244 // Related: tdf#155092 mouse events are now handled by tracking areas
245 [mpNSWindow setAcceptsMouseMovedEvents: NO];
246 [mpNSWindow setHasShadow: YES];
248 [mpNSWindow setDelegate: static_cast<id<NSWindowDelegate> >(mpNSWindow)];
250 [mpNSWindow setRestorable:NO];
252 maSysData.mpNSView = mpNSView;
254 UpdateFrameGeometry();
256 [mpNSWindow setContentView: mpNSView];
259 void AquaSalFrame::CocoaToVCL( NSRect& io_rRect, bool bRelativeToScreen )
261 if( bRelativeToScreen )
262 io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height);
263 else
264 io_rRect.origin.y = maGeometry.height() - (io_rRect.origin.y+io_rRect.size.height);
267 void AquaSalFrame::VCLToCocoa( NSRect& io_rRect, bool bRelativeToScreen )
269 if( bRelativeToScreen )
270 io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height);
271 else
272 io_rRect.origin.y = maGeometry.height() - (io_rRect.origin.y+io_rRect.size.height);
275 void AquaSalFrame::CocoaToVCL( NSPoint& io_rPoint, bool bRelativeToScreen )
277 if( bRelativeToScreen )
278 io_rPoint.y = maScreenRect.size.height - io_rPoint.y;
279 else
280 io_rPoint.y = maGeometry.height() - io_rPoint.y;
283 void AquaSalFrame::VCLToCocoa( NSPoint& io_rPoint, bool bRelativeToScreen )
285 if( bRelativeToScreen )
286 io_rPoint.y = maScreenRect.size.height - io_rPoint.y;
287 else
288 io_rPoint.y = maGeometry.height() - io_rPoint.y;
291 void AquaSalFrame::screenParametersChanged()
293 OSX_SALDATA_RUNINMAIN( screenParametersChanged() )
295 sal::aqua::resetTotalScreenBounds();
296 sal::aqua::resetWindowScaling();
298 UpdateFrameGeometry();
300 if( mpGraphics )
301 mpGraphics->updateResolution();
303 if (!mbGeometryDidChange)
304 return;
306 CallCallback( SalEvent::DisplayChanged, nullptr );
309 SalGraphics* AquaSalFrame::AcquireGraphics()
311 if ( mbGraphics )
312 return nullptr;
314 if ( !mpGraphics )
316 mpGraphics = new AquaSalGraphics;
317 mpGraphics->SetWindowGraphics( this );
320 mbGraphics = true;
321 return mpGraphics;
324 void AquaSalFrame::ReleaseGraphics( SalGraphics *pGraphics )
326 SAL_WARN_IF( pGraphics != mpGraphics, "vcl", "graphics released on wrong frame" );
327 mbGraphics = false;
330 bool AquaSalFrame::PostEvent(std::unique_ptr<ImplSVEvent> pData)
332 GetSalData()->mpInstance->PostEvent( this, pData.release(), SalEvent::UserEvent );
333 return true;
336 void AquaSalFrame::SetTitle(const OUString& rTitle)
338 if ( !mpNSWindow )
339 return;
341 OSX_SALDATA_RUNINMAIN( SetTitle(rTitle) )
343 // #i113170# may not be the main thread if called from UNO API
344 SalData::ensureThreadAutoreleasePool();
346 NSString* pTitle = CreateNSString( rTitle );
347 [mpNSWindow setTitle: pTitle];
349 // create an entry in the dock menu
350 const SalFrameStyleFlags nAppWindowStyle = SalFrameStyleFlags::CLOSEABLE | SalFrameStyleFlags::MOVEABLE;
351 if( mpParent == nullptr &&
352 (mnStyle & nAppWindowStyle) == nAppWindowStyle )
354 if( mpDockMenuEntry == nullptr )
356 NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu();
358 if ([pDock numberOfItems] != 0) {
359 NSMenuItem* pTopItem = [pDock itemAtIndex: 0];
360 if ( [pTopItem hasSubmenu] )
361 [pDock insertItem: [NSMenuItem separatorItem] atIndex: 0];
364 mpDockMenuEntry = [pDock insertItemWithTitle: pTitle
365 action: @selector(dockMenuItemTriggered:)
366 keyEquivalent: @""
367 atIndex: 0];
368 [mpDockMenuEntry setTarget: mpNSWindow];
370 // TODO: image (either the generic window image or an icon
371 // check mark (for "main" window ?)
373 else
374 [mpDockMenuEntry setTitle: pTitle];
377 if (pTitle)
378 [pTitle release];
381 void AquaSalFrame::SetIcon( sal_uInt16 )
385 void AquaSalFrame::SetRepresentedURL( const OUString& i_rDocURL )
387 OSX_SALDATA_RUNINMAIN( SetRepresentedURL( i_rDocURL ) )
389 if( comphelper::isFileUrl(i_rDocURL) )
391 OUString aSysPath;
392 osl_getSystemPathFromFileURL( i_rDocURL.pData, &aSysPath.pData );
393 NSString* pStr = CreateNSString( aSysPath );
394 if( pStr )
396 [pStr autorelease];
397 [mpNSWindow setRepresentedFilename: pStr];
402 void AquaSalFrame::initShow()
404 OSX_SALDATA_RUNINMAIN( initShow() )
406 mbInitShow = false;
407 if( ! mbPositioned && ! mbFullScreen )
409 AbsoluteScreenPixelRectangle aScreenRect;
410 GetWorkArea( aScreenRect );
411 if( mpParent ) // center relative to parent
413 // center on parent
414 tools::Long nNewX = mpParent->maGeometry.x() + (static_cast<tools::Long>(mpParent->maGeometry.width()) - static_cast<tools::Long>(maGeometry.width())) / 2;
415 if( nNewX < aScreenRect.Left() )
416 nNewX = aScreenRect.Left();
417 if (static_cast<tools::Long>(nNewX + maGeometry.width()) > aScreenRect.Right())
418 nNewX = aScreenRect.Right() - maGeometry.width() - 1;
419 tools::Long nNewY = mpParent->maGeometry.y() + (static_cast<tools::Long>(mpParent->maGeometry.height()) - static_cast<tools::Long>(maGeometry.height())) / 2;
420 if( nNewY < aScreenRect.Top() )
421 nNewY = aScreenRect.Top();
422 if( nNewY > aScreenRect.Bottom() )
423 nNewY = aScreenRect.Bottom() - maGeometry.height() - 1;
424 SetPosSize( nNewX - mpParent->maGeometry.x(),
425 nNewY - mpParent->maGeometry.y(),
426 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
428 else if( ! (mnStyle & SalFrameStyleFlags::SIZEABLE) )
430 // center on screen
431 tools::Long nNewX = (aScreenRect.GetWidth() - maGeometry.width()) / 2;
432 tools::Long nNewY = (aScreenRect.GetHeight() - maGeometry.height()) / 2;
433 SetPosSize( nNewX, nNewY, 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
437 // make sure the view is present in the wrapper list before any children receive focus
438 if (mpNSView && [mpNSView isKindOfClass:[SalFrameView class]])
439 [static_cast<SalFrameView*>(mpNSView) registerWrapper];
442 void AquaSalFrame::SendPaintEvent( const tools::Rectangle* pRect )
444 OSX_SALDATA_RUNINMAIN( SendPaintEvent( pRect ) )
446 SalPaintEvent aPaintEvt(0, 0, maGeometry.width(), maGeometry.height(), true);
447 if( pRect )
449 aPaintEvt.mnBoundX = pRect->Left();
450 aPaintEvt.mnBoundY = pRect->Top();
451 aPaintEvt.mnBoundWidth = pRect->GetWidth();
452 aPaintEvt.mnBoundHeight = pRect->GetHeight();
455 CallCallback(SalEvent::Paint, &aPaintEvt);
458 void AquaSalFrame::Show(bool bVisible, bool bNoActivate)
460 if ( !mpNSWindow )
461 return;
463 OSX_SALDATA_RUNINMAIN( Show(bVisible, bNoActivate) )
465 // tdf#152173 Don't display tooltip windows when application is inactive
466 // Starting with macOS 13 Ventura, inactive applications receive mouse
467 // move events so when LibreOffice is inactive, a mouse move event causes
468 // a tooltip to be displayed. Since the tooltip window is attached to its
469 // parent window (to ensure that the tooltip is above the parent window),
470 // displaying a tooltip pulls the parent window in front of the windows
471 // of all other inactive applications.
472 // Also, don't display tooltips when mousing over non-key windows even if
473 // the application is active as the tooltip window will pull the non-key
474 // window in front of the key window.
475 if (bVisible && (mnStyle & SalFrameStyleFlags::TOOLTIP))
477 if (![NSApp isActive])
478 return;
480 if (mpParent)
482 // tdf#157565 show tooltip if any parent window is the key window
483 bool bKeyWindowFound = false;
484 NSWindow *pParent = mpParent->mpNSWindow;
485 while (pParent)
487 if ([pParent isKeyWindow])
489 bKeyWindowFound = true;
490 break;
492 pParent = [pParent parentWindow];
494 if (!bKeyWindowFound)
495 return;
499 mbShown = bVisible;
500 if(bVisible)
502 if( mbInitShow )
503 initShow();
505 CallCallback(SalEvent::Resize, nullptr);
506 // trigger filling our backbuffer
507 SendPaintEvent();
509 if( bNoActivate || [mpNSWindow canBecomeKeyWindow] == NO )
510 [mpNSWindow orderFront: NSApp];
511 else
512 [mpNSWindow makeKeyAndOrderFront: NSApp];
514 if( mpParent )
516 /* #i92674# #i96433# we do not want an invisible parent to show up (which adding a visible
517 child implicitly does). However we also do not want a parentless toolbar.
519 HACK: try to decide when we should not insert a child to its parent
520 floaters and ownerdraw windows have not yet shown up in cases where
521 we don't want the parent to become visible
523 if( mpParent->mbShown || (mnStyle & (SalFrameStyleFlags::OWNERDRAWDECORATION | SalFrameStyleFlags::FLOAT) ) )
525 [mpParent->mpNSWindow addChildWindow: mpNSWindow ordered: NSWindowAbove];
529 if( mbPresentation )
530 [mpNSWindow makeMainWindow];
532 else
534 // if the frame holding the current menubar gets hidden
535 // show the default menubar
536 if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu )
537 AquaSalMenu::setDefaultMenu();
539 // #i90440# #i94443# work around the focus going back to some other window
540 // if a child gets hidden for a parent window
541 if( mpParent && mpParent->mbShown && [mpNSWindow isKeyWindow] )
542 [mpParent->mpNSWindow makeKeyAndOrderFront: NSApp];
544 [SalFrameView unsetMouseFrame: this];
545 if( mpParent && [mpNSWindow parentWindow] == mpParent->mpNSWindow )
546 [mpParent->mpNSWindow removeChildWindow: mpNSWindow];
548 [mpNSWindow orderOut: NSApp];
552 void AquaSalFrame::SetMinClientSize( tools::Long nWidth, tools::Long nHeight )
554 OSX_SALDATA_RUNINMAIN( SetMinClientSize( nWidth, nHeight ) )
556 mnMinWidth = nWidth;
557 mnMinHeight = nHeight;
559 if( mpNSWindow )
561 // Always add the decoration as the dimension concerns only
562 // the content rectangle
563 nWidth += maGeometry.leftDecoration() + maGeometry.rightDecoration();
564 nHeight += maGeometry.topDecoration() + maGeometry.bottomDecoration();
566 NSSize aSize = { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) };
568 // Size of full window (content+structure) although we only
569 // have the client size in arguments
570 [mpNSWindow setMinSize: aSize];
574 void AquaSalFrame::SetMaxClientSize( tools::Long nWidth, tools::Long nHeight )
576 OSX_SALDATA_RUNINMAIN( SetMaxClientSize( nWidth, nHeight ) )
578 mnMaxWidth = nWidth;
579 mnMaxHeight = nHeight;
581 if( mpNSWindow )
583 // Always add the decoration as the dimension concerns only
584 // the content rectangle
585 nWidth += maGeometry.leftDecoration() + maGeometry.rightDecoration();
586 nHeight += maGeometry.topDecoration() + maGeometry.bottomDecoration();
588 // Carbon windows can't have a size greater than 32767x32767
589 if (nWidth>32767) nWidth=32767;
590 if (nHeight>32767) nHeight=32767;
592 NSSize aSize = { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) };
594 // Size of full window (content+structure) although we only
595 // have the client size in arguments
596 [mpNSWindow setMaxSize: aSize];
600 void AquaSalFrame::GetClientSize( tools::Long& rWidth, tools::Long& rHeight )
602 if (mbShown || mbInitShow || Application::IsBitmapRendering())
604 rWidth = maGeometry.width();
605 rHeight = maGeometry.height();
607 else
609 rWidth = 0;
610 rHeight = 0;
614 SalEvent AquaSalFrame::PreparePosSize(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt16 nFlags)
616 SalEvent nEvent = SalEvent::NONE;
617 assert(mpNSWindow || Application::IsBitmapRendering());
619 if (nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y))
621 mbPositioned = true;
622 nEvent = SalEvent::Move;
625 if (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT))
627 mbSized = true;
628 nEvent = (nEvent == SalEvent::Move) ? SalEvent::MoveResize : SalEvent::Resize;
631 if (Application::IsBitmapRendering())
633 if (nFlags & SAL_FRAME_POSSIZE_X)
634 maGeometry.setX(nX);
635 if (nFlags & SAL_FRAME_POSSIZE_Y)
636 maGeometry.setY(nY);
637 if (nFlags & SAL_FRAME_POSSIZE_WIDTH)
639 maGeometry.setWidth(nWidth);
640 if (mnMaxWidth > 0 && maGeometry.width() > mnMaxWidth)
641 maGeometry.setWidth(mnMaxWidth);
642 if (mnMinWidth > 0 && maGeometry.width() < mnMinWidth)
643 maGeometry.setWidth(mnMinWidth);
645 if (nFlags & SAL_FRAME_POSSIZE_HEIGHT)
647 maGeometry.setHeight(nHeight);
648 if (mnMaxHeight > 0 && maGeometry.height() > mnMaxHeight)
649 maGeometry.setHeight(mnMaxHeight);
650 if (mnMinHeight > 0 && maGeometry.height() < mnMinHeight)
651 maGeometry.setHeight(mnMinHeight);
653 if (nEvent != SalEvent::NONE)
654 CallCallback(nEvent, nullptr);
657 return nEvent;
660 void AquaSalFrame::SetWindowState(const vcl::WindowData* pState)
662 if (!mpNSWindow && !Application::IsBitmapRendering())
663 return;
665 OSX_SALDATA_RUNINMAIN( SetWindowState( pState ) )
667 sal_uInt16 nFlags = 0;
668 nFlags |= ((pState->mask() & vcl::WindowDataMask::X) ? SAL_FRAME_POSSIZE_X : 0);
669 nFlags |= ((pState->mask() & vcl::WindowDataMask::Y) ? SAL_FRAME_POSSIZE_Y : 0);
670 nFlags |= ((pState->mask() & vcl::WindowDataMask::Width) ? SAL_FRAME_POSSIZE_WIDTH : 0);
671 nFlags |= ((pState->mask() & vcl::WindowDataMask::Height) ? SAL_FRAME_POSSIZE_HEIGHT : 0);
673 SalEvent nEvent = PreparePosSize(pState->x(), pState->y(), pState->width(), pState->height(), nFlags);
674 if (Application::IsBitmapRendering())
675 return;
677 // set normal state
678 NSRect aStateRect = [mpNSWindow frame];
679 aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask];
680 CocoaToVCL(aStateRect);
681 if (pState->mask() & vcl::WindowDataMask::X)
682 aStateRect.origin.x = float(pState->x());
683 if (pState->mask() & vcl::WindowDataMask::Y)
684 aStateRect.origin.y = float(pState->y());
685 if (pState->mask() & vcl::WindowDataMask::Width)
686 aStateRect.size.width = float(pState->width());
687 if (pState->mask() & vcl::WindowDataMask::Height)
688 aStateRect.size.height = float(pState->height());
689 VCLToCocoa(aStateRect);
690 aStateRect = [NSWindow frameRectForContentRect: aStateRect styleMask: mnStyleMask];
691 [mpNSWindow setFrame: aStateRect display: NO];
693 if (pState->state() == vcl::WindowState::Minimized)
694 [mpNSWindow miniaturize: NSApp];
695 else if ([mpNSWindow isMiniaturized])
696 [mpNSWindow deminiaturize: NSApp];
698 /* ZOOMED is not really maximized (actually it toggles between a user set size and
699 the program specified one), but comes closest since the default behavior is
700 "maximized" if the user did not intervene
702 if (pState->state() == vcl::WindowState::Maximized)
704 if (![mpNSWindow isZoomed])
705 [mpNSWindow zoom: NSApp];
707 else
709 if ([mpNSWindow isZoomed])
710 [mpNSWindow zoom: NSApp];
713 // get new geometry
714 UpdateFrameGeometry();
716 // send event that we were moved/sized
717 if( nEvent != SalEvent::NONE )
718 CallCallback( nEvent, nullptr );
720 if (mbShown)
722 // trigger filling our backbuffer
723 SendPaintEvent();
725 // tell the system the views need to be updated
726 [mpNSWindow display];
730 bool AquaSalFrame::GetWindowState(vcl::WindowData* pState)
732 if (!mpNSWindow)
734 if (Application::IsBitmapRendering())
736 pState->setMask(vcl::WindowDataMask::PosSizeState);
737 pState->setPosSize(maGeometry.posSize());
738 pState->setState(vcl::WindowState::Normal);
739 return true;
741 return false;
744 OSX_SALDATA_RUNINMAIN_UNION( GetWindowState( pState ), boolean )
746 pState->setMask(vcl::WindowDataMask::PosSizeState);
748 NSRect aStateRect = [mpNSWindow frame];
749 aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask];
750 CocoaToVCL( aStateRect );
751 pState->setX(static_cast<sal_Int32>(aStateRect.origin.x));
752 pState->setY(static_cast<sal_Int32>(aStateRect.origin.y));
753 pState->setWidth(static_cast<sal_uInt32>(aStateRect.size.width));
754 pState->setHeight(static_cast<sal_uInt32>(aStateRect.size.height));
756 if( [mpNSWindow isMiniaturized] )
757 pState->setState(vcl::WindowState::Minimized);
758 else if( ! [mpNSWindow isZoomed] )
759 pState->setState(vcl::WindowState::Normal);
760 else
761 pState->setState(vcl::WindowState::Maximized);
763 return true;
766 void AquaSalFrame::SetScreenNumber(unsigned int nScreen)
768 if ( !mpNSWindow )
769 return;
771 OSX_SALDATA_RUNINMAIN( SetScreenNumber( nScreen ) )
773 NSArray* pScreens = [NSScreen screens];
774 NSScreen* pScreen = nil;
775 if( pScreens && nScreen < [pScreens count] )
777 // get new screen frame
778 pScreen = [pScreens objectAtIndex: nScreen];
779 NSRect aNewScreen = [pScreen frame];
781 // get current screen frame
782 pScreen = [mpNSWindow screen];
783 if( pScreen )
785 NSRect aCurScreen = [pScreen frame];
786 if( aCurScreen.origin.x != aNewScreen.origin.x ||
787 aCurScreen.origin.y != aNewScreen.origin.y )
789 NSRect aFrameRect = [mpNSWindow frame];
790 aFrameRect.origin.x += aNewScreen.origin.x - aCurScreen.origin.x;
791 aFrameRect.origin.y += aNewScreen.origin.y - aCurScreen.origin.y;
792 [mpNSWindow setFrame: aFrameRect display: NO];
793 UpdateFrameGeometry();
799 void AquaSalFrame::SetApplicationID( const OUString &/*rApplicationID*/ )
803 void AquaSalFrame::ShowFullScreen( bool bFullScreen, sal_Int32 nDisplay )
805 doShowFullScreen(bFullScreen, nDisplay);
808 void AquaSalFrame::doShowFullScreen( bool bFullScreen, sal_Int32 nDisplay )
810 if (!mpNSWindow)
812 if (Application::IsBitmapRendering() && bFullScreen)
813 SetPosSize(0, 0, 1024, 768, SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT);
814 return;
817 SAL_INFO("vcl.osx", __func__ << ": mbFullScreen=" << mbFullScreen << ", bFullScreen=" << bFullScreen);
819 if( mbFullScreen == bFullScreen )
820 return;
822 OSX_SALDATA_RUNINMAIN( ShowFullScreen( bFullScreen, nDisplay ) )
824 mbFullScreen = bFullScreen;
826 if( bFullScreen )
828 // hide the dock and the menubar if we are on the menu screen
829 // which is always on index 0 according to documentation
830 bool bHideMenu = (nDisplay == 0);
832 NSRect aNewContentRect = NSZeroRect;
833 // get correct screen
834 NSScreen* pScreen = nil;
835 NSArray* pScreens = [NSScreen screens];
836 if( pScreens )
838 if( nDisplay >= 0 && o3tl::make_unsigned(nDisplay) < [pScreens count] )
839 pScreen = [pScreens objectAtIndex: nDisplay];
840 else
842 // this means span all screens
843 bHideMenu = true;
844 NSEnumerator* pEnum = [pScreens objectEnumerator];
845 while( (pScreen = [pEnum nextObject]) != nil )
847 NSRect aScreenRect = [pScreen frame];
848 if( aScreenRect.origin.x < aNewContentRect.origin.x )
850 aNewContentRect.size.width += aNewContentRect.origin.x - aScreenRect.origin.x;
851 aNewContentRect.origin.x = aScreenRect.origin.x;
853 if( aScreenRect.origin.y < aNewContentRect.origin.y )
855 aNewContentRect.size.height += aNewContentRect.origin.y - aScreenRect.origin.y;
856 aNewContentRect.origin.y = aScreenRect.origin.y;
858 if( aScreenRect.origin.x + aScreenRect.size.width > aNewContentRect.origin.x + aNewContentRect.size.width )
859 aNewContentRect.size.width = aScreenRect.origin.x + aScreenRect.size.width - aNewContentRect.origin.x;
860 if( aScreenRect.origin.y + aScreenRect.size.height > aNewContentRect.origin.y + aNewContentRect.size.height )
861 aNewContentRect.size.height = aScreenRect.origin.y + aScreenRect.size.height - aNewContentRect.origin.y;
865 if( aNewContentRect.size.width == 0 && aNewContentRect.size.height == 0 )
867 if( pScreen == nil )
868 pScreen = [mpNSWindow screen];
869 if( pScreen == nil )
870 pScreen = [NSScreen mainScreen];
872 aNewContentRect = [pScreen frame];
875 if( bHideMenu )
876 [NSMenu setMenuBarVisible:NO];
878 maFullScreenRect = [mpNSWindow frame];
880 [mpNSWindow setFrame: [NSWindow frameRectForContentRect: aNewContentRect styleMask: mnStyleMask] display: mbShown ? YES : NO];
882 else
884 [mpNSWindow setFrame: maFullScreenRect display: mbShown ? YES : NO];
886 // show the dock and the menubar
887 [NSMenu setMenuBarVisible:YES];
890 UpdateFrameGeometry();
891 if (mbShown)
893 CallCallback(SalEvent::MoveResize, nullptr);
895 // trigger filling our backbuffer
896 SendPaintEvent();
900 void AquaSalFrame::StartPresentation( bool bStart )
902 if ( !mpNSWindow )
903 return;
905 OSX_SALDATA_RUNINMAIN( StartPresentation( bStart ) )
907 if( bStart )
909 GetSalData()->maPresentationFrames.push_back( this );
910 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
911 kIOPMAssertionLevelOn,
912 CFSTR("LibreOffice presentation running"),
913 &mnAssertionID);
914 [mpNSWindow setLevel: NSPopUpMenuWindowLevel];
915 if( mbShown )
916 [mpNSWindow makeMainWindow];
918 else
920 GetSalData()->maPresentationFrames.remove( this );
921 IOPMAssertionRelease(mnAssertionID);
922 [mpNSWindow setLevel: NSNormalWindowLevel];
926 void AquaSalFrame::SetAlwaysOnTop( bool )
930 void AquaSalFrame::ToTop(SalFrameToTop nFlags)
932 if ( !mpNSWindow )
933 return;
935 OSX_SALDATA_RUNINMAIN( ToTop( nFlags ) )
937 if( ! (nFlags & SalFrameToTop::RestoreWhenMin) )
939 if( ! [mpNSWindow isVisible] || [mpNSWindow isMiniaturized] )
940 return;
942 if( nFlags & SalFrameToTop::GrabFocus )
943 [mpNSWindow makeKeyAndOrderFront: NSApp];
944 else
945 [mpNSWindow orderFront: NSApp];
948 NSCursor* AquaSalFrame::getCurrentCursor()
950 OSX_SALDATA_RUNINMAIN_POINTER( getCurrentCursor(), NSCursor* )
952 NSCursor* pCursor = nil;
953 switch( mePointerStyle )
955 case PointerStyle::Text: pCursor = [NSCursor IBeamCursor]; break;
956 case PointerStyle::Cross: pCursor = [NSCursor crosshairCursor]; break;
957 case PointerStyle::Hand:
958 case PointerStyle::Move: pCursor = [NSCursor openHandCursor]; break;
959 case PointerStyle::NSize: pCursor = [NSCursor resizeUpCursor]; break;
960 case PointerStyle::SSize: pCursor = [NSCursor resizeDownCursor]; break;
961 case PointerStyle::ESize: pCursor = [NSCursor resizeRightCursor]; break;
962 case PointerStyle::WSize: pCursor = [NSCursor resizeLeftCursor]; break;
963 case PointerStyle::Arrow: pCursor = [NSCursor arrowCursor]; break;
964 case PointerStyle::VSplit:
965 case PointerStyle::VSizeBar:
966 case PointerStyle::WindowNSize:
967 case PointerStyle::WindowSSize:
968 pCursor = [NSCursor resizeUpDownCursor]; break;
969 case PointerStyle::HSplit:
970 case PointerStyle::HSizeBar:
971 case PointerStyle::WindowESize:
972 case PointerStyle::WindowWSize:
973 pCursor = [NSCursor resizeLeftRightCursor]; break;
974 case PointerStyle::RefHand: pCursor = [NSCursor pointingHandCursor]; break;
976 default:
977 pCursor = GetSalData()->getCursor( mePointerStyle );
978 if( pCursor == nil )
980 assert( false && "unmapped cursor" );
981 pCursor = [NSCursor arrowCursor];
983 break;
985 return pCursor;
988 void AquaSalFrame::SetPointer( PointerStyle ePointerStyle )
990 if ( !mpNSWindow )
991 return;
992 if( ePointerStyle == mePointerStyle )
993 return;
995 OSX_SALDATA_RUNINMAIN( SetPointer( ePointerStyle ) )
997 mePointerStyle = ePointerStyle;
999 [mpNSWindow invalidateCursorRectsForView: mpNSView];
1002 void AquaSalFrame::SetPointerPos( tools::Long nX, tools::Long nY )
1004 OSX_SALDATA_RUNINMAIN( SetPointerPos( nX, nY ) )
1006 // FIXME: use Cocoa functions
1007 // FIXME: multiscreen support
1008 CGPoint aPoint = { static_cast<CGFloat>(nX + maGeometry.x()), static_cast<CGFloat>(nY + maGeometry.y()) };
1009 CGDirectDisplayID mainDisplayID = CGMainDisplayID();
1010 CGDisplayMoveCursorToPoint( mainDisplayID, aPoint );
1013 static bool lcl_ShouldDisplayInsteadOFFlush()
1015 bool bRet = false;
1016 #if HAVE_FEATURE_SKIA
1017 bRet = SkiaHelper::isVCLSkiaEnabled() && SkiaHelper::renderMethodToUse() != SkiaHelper::RenderRaster;
1018 #endif
1019 return bRet;
1022 void AquaSalFrame::Flush()
1024 if( !(mbGraphics && mpGraphics && mpNSView && mbShown) )
1025 return;
1027 OSX_SALDATA_RUNINMAIN( Flush() )
1029 [mpNSView setNeedsDisplay: YES];
1031 // outside of the application's event loop (e.g. IntroWindow)
1032 // nothing would trigger paint event handling
1033 // => fall back to synchronous painting
1034 if( mbForceFlush || ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
1036 mbForceFlush = false;
1038 // Related: tdf#163945 don't directly flush graphics with Skia/Metal
1039 // When dragging a selection box on an empty background in
1040 // Impress and only with Skia/Metal, the selection box
1041 // would not keep up with the pointer. The selection box
1042 // would repaint sporadically or not at all if the pointer
1043 // was dragged rapidly and the status bar was visible.
1044 // Apparently, flushing a graphics doesn't actually do much
1045 // of anything with Skia/Raster and Skia disabled so the
1046 // selection box repaints without any noticeable delay.
1047 // However, with Skia/Metal every flush of a graphics
1048 // creates and queues a new CAMetalLayer drawable. During
1049 // rapid dragging, this can lead to creating and queueing
1050 // up to 200 drawables per second leaving no spare time for
1051 // the Impress selection box painting timer to fire.
1052 // So with Skia/Metal, throttle the rate of flushing by
1053 // calling display on the view.
1054 bool bDisplay = lcl_ShouldDisplayInsteadOFFlush();
1055 if (!bDisplay)
1056 mpGraphics->Flush();
1058 // Related: tdf#155266 skip redisplay of the view when forcing flush
1059 // It appears that calling -[NSView display] overwhelms some Intel Macs
1060 // so only flush the graphics and skip immediate redisplay of the view.
1061 if( bDisplay || ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
1062 [mpNSView display];
1066 void AquaSalFrame::Flush( const tools::Rectangle& rRect )
1068 if( !(mbGraphics && mpGraphics && mpNSView && mbShown) )
1069 return;
1071 OSX_SALDATA_RUNINMAIN( Flush( rRect ) )
1073 NSRect aNSRect = { { static_cast<CGFloat>(rRect.Left()), static_cast<CGFloat>(rRect.Top()) }, { static_cast<CGFloat>(rRect.GetWidth()), static_cast<CGFloat>(rRect.GetHeight()) } };
1074 VCLToCocoa( aNSRect, false );
1075 [mpNSView setNeedsDisplayInRect: aNSRect];
1077 // outside of the application's event loop (e.g. IntroWindow)
1078 // nothing would trigger paint event handling
1079 // => fall back to synchronous painting
1080 if( mbForceFlush || ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
1082 mbForceFlush = false;
1084 // Related: tdf#163945 don't directly flush graphics with Skia/Metal
1085 // When dragging a selection box on an empty background in
1086 // Impress and only with Skia/Metal, the selection box
1087 // would not keep up with the pointer. The selection box
1088 // would repaint sporadically or not at all if the pointer
1089 // was dragged rapidly and the status bar was visible.
1090 // Apparently, flushing a graphics doesn't actually do much
1091 // of anything with Skia/Raster and Skia disabled so the
1092 // selection box repaints without any noticeable delay.
1093 // However, with Skia/Metal every flush of a graphics
1094 // creates and queues a new CAMetalLayer drawable. During
1095 // rapid dragging, this can lead to creating and queueing
1096 // up to 200 drawables per second leaving no spare time for
1097 // the Impress selection box painting timer to fire.
1098 // So with Skia/Metal, throttle the rate of flushing by
1099 // calling display on the view.
1100 bool bDisplay = lcl_ShouldDisplayInsteadOFFlush();
1101 if (!bDisplay)
1102 mpGraphics->Flush();
1104 // Related: tdf#155266 skip redisplay of the view when forcing flush
1105 // It appears that calling -[NSView display] overwhelms some Intel Macs
1106 // so only flush the graphics and skip immediate redisplay of the view.
1107 if( bDisplay || ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
1108 [mpNSView displayRect: aNSRect];
1112 void AquaSalFrame::SetInputContext( SalInputContext* pContext )
1114 if (!pContext)
1116 mnICOptions = InputContextFlags::NONE;
1117 return;
1120 mnICOptions = pContext->mnOptions;
1122 if(!(pContext->mnOptions & InputContextFlags::Text))
1123 return;
1126 void AquaSalFrame::EndExtTextInput( EndExtTextInputFlags nFlags )
1128 // tdf#82115 Commit uncommitted text when a popup menu is opened
1129 // The Windows implementation of this method commits or discards the native
1130 // input method session. It appears that very few, if any, macOS
1131 // applications discard the uncommitted text when cancelling a session so
1132 // always commit the uncommitted text.
1133 SalFrameWindow *pWindow = static_cast<SalFrameWindow*>(mpNSWindow);
1134 if (pWindow && [pWindow isKindOfClass:[SalFrameWindow class]])
1135 [pWindow endExtTextInput:nFlags];
1138 OUString AquaSalFrame::GetKeyName( sal_uInt16 nKeyCode )
1140 static std::map< sal_uInt16, OUString > aKeyMap;
1141 if( aKeyMap.empty() )
1143 sal_uInt16 i;
1144 for( i = KEY_A; i <= KEY_Z; i++ )
1145 aKeyMap[ i ] = OUString( sal_Unicode( 'A' + (i - KEY_A) ) );
1146 for( i = KEY_0; i <= KEY_9; i++ )
1147 aKeyMap[ i ] = OUString( sal_Unicode( '0' + (i - KEY_0) ) );
1148 for( i = KEY_F1; i <= KEY_F26; i++ )
1150 aKeyMap[ i ] = "F" + OUString::number(i - KEY_F1 + 1);
1153 aKeyMap[ KEY_DOWN ] = OUString( u'\x21e3' );
1154 aKeyMap[ KEY_UP ] = OUString( u'\x21e1' );
1155 aKeyMap[ KEY_LEFT ] = OUString( u'\x21e0' );
1156 aKeyMap[ KEY_RIGHT ] = OUString( u'\x21e2' );
1157 aKeyMap[ KEY_HOME ] = OUString( u'\x2196' );
1158 aKeyMap[ KEY_END ] = OUString( u'\x2198' );
1159 aKeyMap[ KEY_PAGEUP ] = OUString( u'\x21de' );
1160 aKeyMap[ KEY_PAGEDOWN ] = OUString( u'\x21df' );
1161 aKeyMap[ KEY_RETURN ] = OUString( u'\x21a9' );
1162 aKeyMap[ KEY_ESCAPE ] = "esc";
1163 aKeyMap[ KEY_TAB ] = OUString( u'\x21e5' );
1164 aKeyMap[ KEY_BACKSPACE ]= OUString( u'\x232b' );
1165 aKeyMap[ KEY_SPACE ] = OUString( u'\x2423' );
1166 aKeyMap[ KEY_DELETE ] = OUString( u'\x2326' );
1167 aKeyMap[ KEY_ADD ] = "+";
1168 aKeyMap[ KEY_SUBTRACT ] = "-";
1169 aKeyMap[ KEY_DIVIDE ] = "/";
1170 aKeyMap[ KEY_MULTIPLY ] = "*";
1171 aKeyMap[ KEY_POINT ] = ".";
1172 aKeyMap[ KEY_COMMA ] = ",";
1173 aKeyMap[ KEY_LESS ] = "<";
1174 aKeyMap[ KEY_GREATER ] = ">";
1175 aKeyMap[ KEY_EQUAL ] = "=";
1176 aKeyMap[ KEY_OPEN ] = OUString( u'\x23cf' );
1177 aKeyMap[ KEY_TILDE ] = "~";
1178 aKeyMap[ KEY_BRACKETLEFT ] = "[";
1179 aKeyMap[ KEY_BRACKETRIGHT ] = "]";
1180 aKeyMap[ KEY_SEMICOLON ] = ";";
1181 aKeyMap[ KEY_QUOTERIGHT ] = "'";
1182 aKeyMap[ KEY_RIGHTCURLYBRACKET ] = "}";
1183 aKeyMap[ KEY_NUMBERSIGN ] = "#";
1184 aKeyMap[ KEY_COLON ] = ":";
1186 /* yet unmapped KEYCODES:
1187 aKeyMap[ KEY_INSERT ] = OUString( sal_Unicode( ) );
1188 aKeyMap[ KEY_CUT ] = OUString( sal_Unicode( ) );
1189 aKeyMap[ KEY_COPY ] = OUString( sal_Unicode( ) );
1190 aKeyMap[ KEY_PASTE ] = OUString( sal_Unicode( ) );
1191 aKeyMap[ KEY_UNDO ] = OUString( sal_Unicode( ) );
1192 aKeyMap[ KEY_REPEAT ] = OUString( sal_Unicode( ) );
1193 aKeyMap[ KEY_FIND ] = OUString( sal_Unicode( ) );
1194 aKeyMap[ KEY_PROPERTIES ] = OUString( sal_Unicode( ) );
1195 aKeyMap[ KEY_FRONT ] = OUString( sal_Unicode( ) );
1196 aKeyMap[ KEY_CONTEXTMENU ] = OUString( sal_Unicode( ) );
1197 aKeyMap[ KEY_MENU ] = OUString( sal_Unicode( ) );
1198 aKeyMap[ KEY_HELP ] = OUString( sal_Unicode( ) );
1199 aKeyMap[ KEY_HANGUL_HANJA ] = OUString( sal_Unicode( ) );
1200 aKeyMap[ KEY_DECIMAL ] = OUString( sal_Unicode( ) );
1201 aKeyMap[ KEY_QUOTELEFT ]= OUString( sal_Unicode( ) );
1202 aKeyMap[ KEY_CAPSLOCK ]= OUString( sal_Unicode( ) );
1203 aKeyMap[ KEY_NUMLOCK ]= OUString( sal_Unicode( ) );
1204 aKeyMap[ KEY_SCROLLLOCK ]= OUString( sal_Unicode( ) );
1209 OUStringBuffer aResult( 16 );
1211 sal_uInt16 nUnmodifiedCode = (nKeyCode & KEY_CODE_MASK);
1212 std::map< sal_uInt16, OUString >::const_iterator it = aKeyMap.find( nUnmodifiedCode );
1213 if( it != aKeyMap.end() )
1215 if( (nKeyCode & KEY_SHIFT) != 0 )
1216 aResult.append( u'\x21e7' ); // shift
1217 if( (nKeyCode & KEY_MOD1) != 0 )
1218 aResult.append( u'\x2318' ); // command
1219 if( (nKeyCode & KEY_MOD2) != 0 )
1220 aResult.append( u'\x2325' ); // alternate
1221 if( (nKeyCode & KEY_MOD3) != 0 )
1222 aResult.append( u'\x2303' ); // control
1224 aResult.append( it->second );
1227 return aResult.makeStringAndClear();
1230 static void getAppleScrollBarVariant(StyleSettings &rSettings)
1232 bool bIsScrollbarDoubleMax = true; // default is DoubleMax
1234 CFStringRef AppleScrollBarType = CFSTR("AppleScrollBarVariant");
1235 if( AppleScrollBarType )
1237 CFStringRef ScrollBarVariant = static_cast<CFStringRef>(CFPreferencesCopyAppValue( AppleScrollBarType, kCFPreferencesCurrentApplication ));
1238 if( ScrollBarVariant )
1240 if( CFGetTypeID( ScrollBarVariant ) == CFStringGetTypeID() )
1242 // TODO: check for the less important variants "DoubleMin" and "DoubleBoth" too
1243 CFStringRef DoubleMax = CFSTR("DoubleMax");
1244 if (DoubleMax)
1246 if ( !CFStringCompare(ScrollBarVariant, DoubleMax, kCFCompareCaseInsensitive) )
1247 bIsScrollbarDoubleMax = true;
1248 else
1249 bIsScrollbarDoubleMax = false;
1250 CFRelease(DoubleMax);
1253 CFRelease( ScrollBarVariant );
1255 CFRelease(AppleScrollBarType);
1258 GetSalData()->mbIsScrollbarDoubleMax = bIsScrollbarDoubleMax;
1260 CFStringRef jumpScroll = CFSTR("AppleScrollerPagingBehavior");
1261 if( jumpScroll )
1263 CFBooleanRef jumpStr = static_cast<CFBooleanRef>(CFPreferencesCopyAppValue( jumpScroll, kCFPreferencesCurrentApplication ));
1264 if( jumpStr )
1266 if( CFGetTypeID( jumpStr ) == CFBooleanGetTypeID() )
1267 rSettings.SetPrimaryButtonWarpsSlider(jumpStr == kCFBooleanTrue);
1268 CFRelease( jumpStr );
1270 CFRelease( jumpScroll );
1274 static Color getNSBoxBackgroundColor(NSColor* pSysColor)
1276 // Figuring out what a NSBox will draw for windowBackground, etc. seems very difficult.
1277 // So just draw to a 1x1 surface and read what actually gets drawn
1278 // This is similar to getPixel
1279 #if defined OSL_BIGENDIAN
1280 struct
1282 unsigned char b, g, r, a;
1283 } aPixel;
1284 #else
1285 struct
1287 unsigned char a, r, g, b;
1288 } aPixel;
1289 #endif
1291 // create a one-pixel bitmap context
1292 CGContextRef xOnePixelContext = CGBitmapContextCreate(
1293 &aPixel, 1, 1, 8, 32, GetSalData()->mxRGBSpace,
1294 uint32_t(kCGImageAlphaNoneSkipFirst) | uint32_t(kCGBitmapByteOrder32Big));
1296 NSGraphicsContext* graphicsContext = [NSGraphicsContext graphicsContextWithCGContext:xOnePixelContext flipped:NO];
1298 NSRect rect = { NSZeroPoint, NSMakeSize(1, 1) };
1299 NSBox* pBox = [[NSBox alloc] initWithFrame: rect];
1301 [pBox setBoxType: NSBoxCustom];
1302 [pBox setFillColor: pSysColor];
1303 SAL_WNODEPRECATED_DECLARATIONS_PUSH // setBorderType first deprecated in macOS 10.15
1304 [pBox setBorderType: NSNoBorder];
1305 SAL_WNODEPRECATED_DECLARATIONS_POP
1307 [pBox displayRectIgnoringOpacity: rect inContext: graphicsContext];
1309 [pBox release];
1311 CGContextRelease(xOnePixelContext);
1313 return Color(aPixel.r, aPixel.g, aPixel.b);
1316 static Color getColor( NSColor* pSysColor, const Color& rDefault, NSWindow* pWin )
1318 Color aRet( rDefault );
1319 if( pSysColor )
1321 // transform to RGB
1322 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1323 // "'colorUsingColorSpaceName:device:' is deprecated: first deprecated in macOS 10.14 -
1324 // Use -colorUsingType: or -colorUsingColorSpace: instead"
1325 NSColor* pRBGColor = [pSysColor colorUsingColorSpaceName: NSDeviceRGBColorSpace device: [pWin deviceDescription]];
1326 SAL_WNODEPRECATED_DECLARATIONS_POP
1327 if( pRBGColor )
1329 CGFloat r = 0, g = 0, b = 0, a = 0;
1330 [pRBGColor getRed: &r green: &g blue: &b alpha: &a];
1331 aRet = Color( int(r*255.999), int(g*255.999), int(b*255.999) );
1334 return aRet;
1337 static vcl::Font getFont( NSFont* pFont, sal_Int32 nDPIY, const vcl::Font& rDefault )
1339 vcl::Font aResult( rDefault );
1340 if( pFont )
1342 aResult.SetFamilyName( GetOUString( [pFont familyName] ) );
1343 aResult.SetFontHeight( static_cast<int>(ceil([pFont pointSize] * 72.0 / static_cast<float>(nDPIY))) );
1344 aResult.SetItalic( ([pFont italicAngle] != 0.0) ? ITALIC_NORMAL : ITALIC_NONE );
1345 // FIMXE: bold ?
1348 return aResult;
1351 void AquaSalFrame::getResolution( sal_Int32& o_rDPIX, sal_Int32& o_rDPIY )
1353 OSX_SALDATA_RUNINMAIN( getResolution( o_rDPIX, o_rDPIY ) )
1355 if( ! mpGraphics )
1357 AcquireGraphics();
1358 ReleaseGraphics( mpGraphics );
1360 mpGraphics->GetResolution( o_rDPIX, o_rDPIY );
1363 void AquaSalFrame::UpdateDarkMode()
1365 if (@available(macOS 10.14, iOS 13, *))
1367 switch (MiscSettings::GetDarkMode())
1369 case 0: // auto
1370 default:
1371 [NSApp setAppearance: nil];
1372 break;
1373 case 1: // light
1374 [NSApp setAppearance: [NSAppearance appearanceNamed: NSAppearanceNameAqua]];
1375 break;
1376 case 2: // dark
1377 [NSApp setAppearance: [NSAppearance appearanceNamed: NSAppearanceNameDarkAqua]];
1378 break;
1383 bool AquaSalFrame::GetUseDarkMode() const
1385 if (!mpNSView)
1386 return false;
1387 bool bUseDarkMode(false);
1388 if (@available(macOS 10.14, iOS 13, *))
1390 NSAppearanceName match = [mpNSView.effectiveAppearance bestMatchFromAppearancesWithNames: @[
1391 NSAppearanceNameAqua, NSAppearanceNameDarkAqua]];
1392 bUseDarkMode = [match isEqualToString: NSAppearanceNameDarkAqua];
1394 return bUseDarkMode;
1397 bool AquaSalFrame::GetUseReducedAnimation() const
1399 return [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldReduceMotion];
1402 static void lcl_LoadColorsFromTheme(StyleSettings& rStyleSet)
1404 const ThemeColors& rThemeColors = ThemeColors::GetThemeColors();
1405 rStyleSet.SetWindowColor(rThemeColors.GetWindowColor());
1406 rStyleSet.BatchSetBackgrounds(rThemeColors.GetWindowColor());
1407 rStyleSet.SetActiveTabColor(rThemeColors.GetWindowColor());
1408 rStyleSet.SetInactiveTabColor(rThemeColors.GetBaseColor());
1409 rStyleSet.SetDisableColor(rThemeColors.GetDisabledColor()); // tab outline
1410 // Highlight related colors
1411 rStyleSet.SetAccentColor(rThemeColors.GetAccentColor());
1412 rStyleSet.SetHighlightColor(rThemeColors.GetAccentColor());
1413 rStyleSet.SetListBoxWindowHighlightColor(rThemeColors.GetAccentColor());
1414 rStyleSet.SetListBoxWindowTextColor(rThemeColors.GetWindowTextColor());
1415 rStyleSet.SetListBoxWindowBackgroundColor(rThemeColors.GetBaseColor());
1416 rStyleSet.SetListBoxWindowHighlightTextColor(rThemeColors.GetMenuHighlightTextColor());
1417 rStyleSet.SetWindowTextColor(rThemeColors.GetWindowTextColor()); // Treeview Lists
1418 rStyleSet.SetRadioCheckTextColor(rThemeColors.GetWindowTextColor());
1419 rStyleSet.SetLabelTextColor(rThemeColors.GetWindowTextColor());
1420 rStyleSet.SetFieldTextColor(rThemeColors.GetWindowTextColor());
1421 rStyleSet.SetFieldColor(rThemeColors.GetBaseColor());
1422 rStyleSet.SetMenuBarTextColor(rThemeColors.GetMenuBarTextColor());
1423 rStyleSet.SetMenuTextColor(rThemeColors.GetMenuTextColor());
1424 rStyleSet.SetDefaultActionButtonTextColor(rThemeColors.GetButtonTextColor());
1425 rStyleSet.SetActionButtonTextColor(rThemeColors.GetButtonTextColor());
1426 rStyleSet.SetShadowColor(rThemeColors.GetShadeColor());
1427 rStyleSet.SetDefaultButtonTextColor(rThemeColors.GetButtonTextColor());
1428 rStyleSet.SetDefaultButtonRolloverTextColor(rThemeColors.GetButtonTextColor());
1429 rStyleSet.SetDefaultButtonPressedRolloverTextColor(rThemeColors.GetButtonTextColor());
1430 rStyleSet.SetFlatButtonTextColor(rThemeColors.GetButtonTextColor());
1431 rStyleSet.SetFlatButtonPressedRolloverTextColor(rThemeColors.GetButtonTextColor());
1432 rStyleSet.SetFlatButtonRolloverTextColor(rThemeColors.GetButtonTextColor());
1433 rStyleSet.SetButtonRolloverTextColor(rThemeColors.GetButtonTextColor());
1434 rStyleSet.SetDefaultActionButtonRolloverTextColor(rThemeColors.GetButtonTextColor());
1435 rStyleSet.SetDefaultActionButtonPressedRolloverTextColor(rThemeColors.GetButtonTextColor());
1436 rStyleSet.SetActionButtonRolloverTextColor(rThemeColors.GetButtonTextColor());
1437 rStyleSet.SetActionButtonPressedRolloverTextColor(rThemeColors.GetButtonTextColor());
1438 rStyleSet.SetFieldRolloverTextColor(rThemeColors.GetButtonTextColor());
1439 rStyleSet.SetButtonRolloverTextColor(rThemeColors.GetButtonTextColor());
1440 rStyleSet.SetButtonPressedRolloverTextColor(rThemeColors.GetButtonTextColor());
1441 rStyleSet.SetHelpColor(rThemeColors.GetWindowColor());
1442 rStyleSet.SetHelpTextColor(rThemeColors.GetWindowTextColor());
1443 // rStyleSet.SetHighlightTextColor(rThemeColors.GetActiveTextColor());
1444 // rStyleSet.SetActiveColor(rThemeColors.GetActiveColor());
1445 // rStyleSet.SetActiveTextColor(rThemeColors.GetActiveTextColor());
1446 // rStyleSet.SetLinkColor(rThemeColors.GetAccentColor());
1447 // Color aVisitedLinkColor = rThemeColors.GetActiveColor();
1448 // aVisitedLinkColor.Merge(rThemeColors.GetWindowColor(), 100);
1449 // rStyleSet.SetVisitedLinkColor(aVisitedLinkColor);
1450 // rStyleSet.SetToolTextColor(Color(255, 0, 0));
1451 rStyleSet.SetTabRolloverTextColor(rThemeColors.GetMenuBarHighlightTextColor());
1454 // on OSX-Aqua the style settings are independent of the frame, so it does
1455 // not really belong here. Since the connection to the Appearance_Manager
1456 // is currently done in salnativewidgets.cxx this would be a good place.
1457 // On the other hand VCL's platform independent code currently only asks
1458 // SalFrames for system settings anyway, so moving the code somewhere else
1459 // doesn't make the anything cleaner for now
1460 void AquaSalFrame::UpdateSettings( AllSettings& rSettings )
1462 if ( !mpNSWindow )
1463 return;
1465 OSX_SALDATA_RUNINMAIN( UpdateSettings( rSettings ) )
1467 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1468 // "'lockFocus' is deprecated: first deprecated in macOS 10.14 - To draw, subclass NSView
1469 // and implement -drawRect:; AppKit's automatic deferred display mechanism will call
1470 // -drawRect: as necessary to display the view."
1471 if (![mpNSView lockFocusIfCanDraw])
1472 return;
1473 SAL_WNODEPRECATED_DECLARATIONS_POP
1475 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1476 // "'setCurrentAppearance:' is deprecated: first deprecated in macOS 12.0 - Use
1477 // -performAsCurrentDrawingAppearance: to temporarily set the drawing appearance, or
1478 // +currentDrawingAppearance to access the currently drawing appearance."
1479 [NSAppearance setCurrentAppearance: mpNSView.effectiveAppearance];
1480 SAL_WNODEPRECATED_DECLARATIONS_POP
1482 StyleSettings aStyleSettings = rSettings.GetStyleSettings();
1484 bool bUseDarkMode(GetUseDarkMode());
1485 if (!ThemeColors::IsThemeLoaded())
1487 OUString sThemeName(!bUseDarkMode ? u"sukapura_svg" : u"sukapura_dark_svg");
1488 aStyleSettings.SetPreferredIconTheme(sThemeName, bUseDarkMode);
1490 else
1492 aStyleSettings.SetPreferredIconTheme(
1493 vcl::IconThemeSelector::GetIconThemeForDesktopEnvironment(
1494 Application::GetDesktopEnvironment(),
1495 ThemeColors::GetThemeColors().GetWindowColor().IsDark()));
1498 Color aControlBackgroundColor(getNSBoxBackgroundColor([NSColor controlBackgroundColor]));
1499 Color aWindowBackgroundColor(getNSBoxBackgroundColor([NSColor windowBackgroundColor]));
1500 Color aUnderPageBackgroundColor(getNSBoxBackgroundColor([NSColor underPageBackgroundColor]));
1502 // Background Color
1503 aStyleSettings.BatchSetBackgrounds( aWindowBackgroundColor, false );
1504 aStyleSettings.SetLightBorderColor( aWindowBackgroundColor );
1506 aStyleSettings.SetActiveTabColor(aWindowBackgroundColor);
1507 Color aInactiveTabColor( aWindowBackgroundColor );
1508 aInactiveTabColor.DecreaseLuminance( 32 );
1509 aStyleSettings.SetInactiveTabColor( aInactiveTabColor );
1511 Color aShadowColor = getColor( [NSColor systemGrayColor ],
1512 aStyleSettings.GetShadowColor(), mpNSWindow );
1513 aStyleSettings.SetShadowColor( aShadowColor );
1515 // tdf#152284 for DarkMode brighten it, while darken for BrightMode
1516 NSColor* pDarkColor = bUseDarkMode ? [[NSColor systemGrayColor] highlightWithLevel: 0.5]
1517 : [[NSColor systemGrayColor] shadowWithLevel: 0.5];
1518 Color aDarkShadowColor = getColor( pDarkColor, aStyleSettings.GetDarkShadowColor(), mpNSWindow );
1519 aStyleSettings.SetDarkShadowColor(aDarkShadowColor);
1521 // get the system font settings
1522 vcl::Font aAppFont = aStyleSettings.GetAppFont();
1523 sal_Int32 nDPIX = 72, nDPIY = 72;
1524 getResolution( nDPIX, nDPIY );
1525 aAppFont = getFont( [NSFont systemFontOfSize: 0], nDPIY, aAppFont );
1527 aStyleSettings.SetToolbarIconSize( ToolbarIconSize::Large );
1529 // TODO: better mapping of macOS<->LibreOffice font settings
1530 vcl::Font aLabelFont( getFont( [NSFont labelFontOfSize: 0], nDPIY, aAppFont ) );
1531 aStyleSettings.BatchSetFonts( aAppFont, aLabelFont );
1532 vcl::Font aMenuFont( getFont( [NSFont menuFontOfSize: 0], nDPIY, aAppFont ) );
1533 aStyleSettings.SetMenuFont( aMenuFont );
1535 vcl::Font aTitleFont( getFont( [NSFont titleBarFontOfSize: 0], nDPIY, aAppFont ) );
1536 aStyleSettings.SetTitleFont( aTitleFont );
1537 aStyleSettings.SetFloatTitleFont( aTitleFont );
1539 vcl::Font aTooltipFont(getFont([NSFont toolTipsFontOfSize: 0], nDPIY, aAppFont));
1540 aStyleSettings.SetHelpFont(aTooltipFont);
1542 Color aAccentColor( getColor( [NSColor controlAccentColor],
1543 aStyleSettings.GetAccentColor(), mpNSWindow ) );
1544 aStyleSettings.SetAccentColor( aAccentColor );
1546 Color aHighlightColor( getColor( [NSColor selectedTextBackgroundColor],
1547 aStyleSettings.GetHighlightColor(), mpNSWindow ) );
1548 aStyleSettings.SetHighlightColor( aHighlightColor );
1549 Color aHighlightTextColor( getColor( [NSColor selectedTextColor],
1550 aStyleSettings.GetHighlightTextColor(), mpNSWindow ) );
1551 aStyleSettings.SetHighlightTextColor( aHighlightTextColor );
1553 aStyleSettings.SetLinkColor(getColor( [NSColor linkColor],
1554 aStyleSettings.GetLinkColor(), mpNSWindow ) );
1555 aStyleSettings.SetVisitedLinkColor(getColor( [NSColor purpleColor],
1556 aStyleSettings.GetVisitedLinkColor(), mpNSWindow ) );
1558 #pragma clang diagnostic push
1559 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1560 Color aMenuHighlightColor( getColor( [NSColor selectedMenuItemColor],
1561 aStyleSettings.GetMenuHighlightColor(), mpNSWindow ) );
1562 #pragma clang diagnostic pop
1563 aStyleSettings.SetMenuHighlightColor( aMenuHighlightColor );
1564 Color aMenuHighlightTextColor( getColor( [NSColor selectedMenuItemTextColor],
1565 aStyleSettings.GetMenuHighlightTextColor(), mpNSWindow ) );
1566 aStyleSettings.SetMenuHighlightTextColor( aMenuHighlightTextColor );
1568 aStyleSettings.SetMenuColor( aWindowBackgroundColor );
1569 Color aMenuTextColor( getColor( [NSColor textColor],
1570 aStyleSettings.GetMenuTextColor(), mpNSWindow ) );
1571 aStyleSettings.SetMenuTextColor( aMenuTextColor );
1572 aStyleSettings.SetMenuBarTextColor( aMenuTextColor );
1573 aStyleSettings.SetMenuBarRolloverTextColor( aMenuTextColor );
1574 aStyleSettings.SetMenuBarHighlightTextColor(aStyleSettings.GetMenuHighlightTextColor());
1576 aStyleSettings.SetListBoxWindowBackgroundColor( aWindowBackgroundColor );
1577 aStyleSettings.SetListBoxWindowTextColor( aMenuTextColor );
1578 aStyleSettings.SetListBoxWindowHighlightColor( aMenuHighlightColor );
1579 aStyleSettings.SetListBoxWindowHighlightTextColor( aMenuHighlightTextColor );
1581 // FIXME: Starting with macOS Big Sur, coloring has changed. Currently there is no documentation which system color should be
1582 // used for some button states and for selected tab text. As a workaround the current OS version has to be considered. This code
1583 // has to be reviewed once issue is covered by documentation.
1585 // Set text colors for buttons and their different status according to OS settings, typically white for selected buttons,
1586 // black otherwise
1588 NSOperatingSystemVersion aOSVersion = { .majorVersion = 10, .minorVersion = 16, .patchVersion = 0 };
1589 Color aControlTextColor(getColor([NSColor controlTextColor], COL_BLACK, mpNSWindow ));
1590 Color aSelectedControlTextColor(getColor([NSColor selectedControlTextColor], COL_BLACK, mpNSWindow ));
1591 Color aAlternateSelectedControlTextColor(getColor([NSColor alternateSelectedControlTextColor], COL_WHITE, mpNSWindow ));
1592 aStyleSettings.SetWindowColor(aWindowBackgroundColor);
1593 aStyleSettings.SetListBoxWindowBackgroundColor(aWindowBackgroundColor);
1595 aStyleSettings.SetDialogTextColor(aControlTextColor);
1596 aStyleSettings.SetButtonTextColor(aControlTextColor);
1597 aStyleSettings.SetActionButtonTextColor(aControlTextColor);
1598 aStyleSettings.SetRadioCheckTextColor(aControlTextColor);
1599 aStyleSettings.SetGroupTextColor(aControlTextColor);
1600 aStyleSettings.SetLabelTextColor(aControlTextColor);
1601 aStyleSettings.SetWindowTextColor(aControlTextColor);
1602 aStyleSettings.SetFieldTextColor(aControlTextColor);
1604 aStyleSettings.SetFieldRolloverTextColor(aControlTextColor);
1605 aStyleSettings.SetFieldColor(aControlBackgroundColor);
1606 aStyleSettings.SetDefaultActionButtonTextColor(aAlternateSelectedControlTextColor);
1607 aStyleSettings.SetFlatButtonTextColor(aControlTextColor);
1608 aStyleSettings.SetDefaultButtonRolloverTextColor(aAlternateSelectedControlTextColor);
1609 aStyleSettings.SetButtonRolloverTextColor(aControlTextColor);
1610 aStyleSettings.SetDefaultActionButtonRolloverTextColor(aAlternateSelectedControlTextColor);
1611 aStyleSettings.SetActionButtonRolloverTextColor(aControlTextColor);
1612 aStyleSettings.SetFlatButtonRolloverTextColor(aControlTextColor);
1613 aStyleSettings.SetDefaultButtonPressedRolloverTextColor(aAlternateSelectedControlTextColor);
1614 aStyleSettings.SetDefaultActionButtonPressedRolloverTextColor(aAlternateSelectedControlTextColor);
1615 aStyleSettings.SetFlatButtonPressedRolloverTextColor(aControlTextColor);
1616 if ([NSProcessInfo.processInfo isOperatingSystemAtLeastVersion: aOSVersion])
1618 aStyleSettings.SetDefaultButtonTextColor(aAlternateSelectedControlTextColor);
1619 aStyleSettings.SetButtonPressedRolloverTextColor(aSelectedControlTextColor);
1620 aStyleSettings.SetActionButtonPressedRolloverTextColor(aSelectedControlTextColor);
1622 else
1624 aStyleSettings.SetButtonPressedRolloverTextColor(aAlternateSelectedControlTextColor);
1625 aStyleSettings.SetActionButtonPressedRolloverTextColor(aAlternateSelectedControlTextColor);
1626 aStyleSettings.SetDefaultButtonTextColor(aSelectedControlTextColor);
1629 aStyleSettings.SetWorkspaceColor(aUnderPageBackgroundColor);
1631 aStyleSettings.SetHelpColor(aControlBackgroundColor);
1632 aStyleSettings.SetHelpTextColor(aControlTextColor);
1633 aStyleSettings.SetToolTextColor(aControlTextColor);
1635 // Set text colors for tabs according to OS settings
1637 aStyleSettings.SetTabTextColor(aControlTextColor);
1638 aStyleSettings.SetTabRolloverTextColor(aControlTextColor);
1639 if ([NSProcessInfo.processInfo isOperatingSystemAtLeastVersion: aOSVersion])
1640 aStyleSettings.SetTabHighlightTextColor(aSelectedControlTextColor);
1641 else
1642 aStyleSettings.SetTabHighlightTextColor(aAlternateSelectedControlTextColor);
1644 aStyleSettings.SetCursorBlinkTime( mnBlinkCursorDelay );
1645 aStyleSettings.SetCursorSize(1);
1647 // no mnemonics on macOS
1648 aStyleSettings.SetOptions( aStyleSettings.GetOptions() | StyleSettingsOptions::NoMnemonics );
1650 getAppleScrollBarVariant(aStyleSettings);
1652 // set scrollbar size
1653 aStyleSettings.SetScrollBarSize( static_cast<tools::Long>([NSScroller scrollerWidthForControlSize:NSControlSizeRegular scrollerStyle:NSScrollerStyleLegacy]) );
1654 // images in menus false for MacOSX
1655 aStyleSettings.SetPreferredUseImagesInMenus( false );
1656 aStyleSettings.SetHideDisabledMenuItems( true );
1657 aStyleSettings.SetPreferredContextMenuShortcuts( false );
1659 if (ThemeColors::IsThemeLoaded())
1660 lcl_LoadColorsFromTheme(aStyleSettings);
1662 rSettings.SetStyleSettings( aStyleSettings );
1664 // don't draw frame around each and every toolbar
1665 ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames = true;
1667 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1668 // "'unlockFocus' is deprecated: first deprecated in macOS 10.14 - To draw, subclass NSView
1669 // and implement -drawRect:; AppKit's automatic deferred display mechanism will call
1670 // -drawRect: as necessary to display the view."
1671 [mpNSView unlockFocus];
1672 SAL_WNODEPRECATED_DECLARATIONS_POP
1675 const SystemEnvData& AquaSalFrame::GetSystemData() const
1677 return maSysData;
1680 void AquaSalFrame::Beep()
1682 OSX_SALDATA_RUNINMAIN( Beep() )
1683 NSBeep();
1686 void AquaSalFrame::SetPosSize(
1687 tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt16 nFlags)
1689 if (!mpNSWindow && !Application::IsBitmapRendering())
1690 return;
1692 OSX_SALDATA_RUNINMAIN( SetPosSize( nX, nY, nWidth, nHeight, nFlags ) )
1694 SalEvent nEvent = PreparePosSize(nX, nY, nWidth, nHeight, nFlags);
1695 if (Application::IsBitmapRendering())
1696 return;
1698 if( [mpNSWindow isMiniaturized] )
1699 [mpNSWindow deminiaturize: NSApp]; // expand the window
1701 NSRect aFrameRect = [mpNSWindow frame];
1702 NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask];
1704 // position is always relative to parent frame
1705 NSRect aParentContentRect;
1707 if( mpParent )
1709 if( AllSettings::GetLayoutRTL() )
1711 if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
1712 nX = static_cast<tools::Long>(mpParent->maGeometry.width()) - nWidth - 1 - nX;
1713 else
1714 nX = static_cast<tools::Long>(mpParent->maGeometry.width()) - aContentRect.size.width - 1 - nX;
1716 NSRect aParentFrameRect = [mpParent->mpNSWindow frame];
1717 aParentContentRect = [NSWindow contentRectForFrameRect: aParentFrameRect styleMask: mpParent->mnStyleMask];
1719 else
1720 aParentContentRect = maScreenRect; // use screen if no parent
1722 CocoaToVCL( aContentRect );
1723 CocoaToVCL( aParentContentRect );
1725 bool bPaint = false;
1726 if( (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) != 0 )
1728 if( nWidth != aContentRect.size.width || nHeight != aContentRect.size.height )
1729 bPaint = true;
1732 // use old window pos if no new pos requested
1733 if( (nFlags & SAL_FRAME_POSSIZE_X) != 0 )
1734 aContentRect.origin.x = nX + aParentContentRect.origin.x;
1735 if( (nFlags & SAL_FRAME_POSSIZE_Y) != 0)
1736 aContentRect.origin.y = nY + aParentContentRect.origin.y;
1738 // use old size if no new size requested
1739 if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
1740 aContentRect.size.width = nWidth;
1741 if( (nFlags & SAL_FRAME_POSSIZE_HEIGHT) != 0)
1742 aContentRect.size.height = nHeight;
1744 VCLToCocoa( aContentRect );
1746 // do not display yet, we need to update our backbuffer
1748 [mpNSWindow setFrame: [NSWindow frameRectForContentRect: aContentRect styleMask: mnStyleMask] display: NO];
1751 UpdateFrameGeometry();
1753 if (nEvent != SalEvent::NONE)
1754 CallCallback(nEvent, nullptr);
1756 if( mbShown && bPaint )
1758 // trigger filling our backbuffer
1759 SendPaintEvent();
1761 // now inform the system that the views need to be drawn
1762 [mpNSWindow display];
1766 void AquaSalFrame::GetWorkArea( AbsoluteScreenPixelRectangle& rRect )
1768 if (!mpNSWindow)
1770 if (Application::IsBitmapRendering())
1771 rRect = AbsoluteScreenPixelRectangle(AbsoluteScreenPixelPoint(0, 0), AbsoluteScreenPixelSize(1024, 768));
1772 return;
1775 OSX_SALDATA_RUNINMAIN( GetWorkArea( rRect ) )
1777 NSScreen* pScreen = [mpNSWindow screen];
1778 if( pScreen == nil )
1779 pScreen = [NSScreen mainScreen];
1780 NSRect aRect = [pScreen visibleFrame];
1781 CocoaToVCL( aRect );
1782 rRect.SetLeft( static_cast<tools::Long>(aRect.origin.x) );
1783 rRect.SetTop( static_cast<tools::Long>(aRect.origin.y) );
1784 rRect.SetRight( static_cast<tools::Long>(aRect.origin.x + aRect.size.width - 1) );
1785 rRect.SetBottom( static_cast<tools::Long>(aRect.origin.y + aRect.size.height - 1) );
1788 SalFrame::SalPointerState AquaSalFrame::GetPointerState()
1790 OSX_SALDATA_RUNINMAIN_UNION( GetPointerState(), state )
1792 SalPointerState state;
1793 state.mnState = 0;
1795 // get position
1796 NSPoint aPt = [mpNSWindow mouseLocationOutsideOfEventStream];
1797 CocoaToVCL( aPt, false );
1798 state.maPos = Point(static_cast<tools::Long>(aPt.x), static_cast<tools::Long>(aPt.y));
1800 NSEvent* pCur = [NSApp currentEvent];
1801 bool bMouseEvent = false;
1802 if( pCur )
1804 bMouseEvent = true;
1805 switch( [pCur type] )
1807 case NSEventTypeLeftMouseDown:
1808 state.mnState |= MOUSE_LEFT;
1809 break;
1810 case NSEventTypeLeftMouseUp:
1811 break;
1812 case NSEventTypeRightMouseDown:
1813 state.mnState |= MOUSE_RIGHT;
1814 break;
1815 case NSEventTypeRightMouseUp:
1816 break;
1817 case NSEventTypeOtherMouseDown:
1818 state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0;
1819 break;
1820 case NSEventTypeOtherMouseUp:
1821 break;
1822 case NSEventTypeMouseMoved:
1823 break;
1824 case NSEventTypeLeftMouseDragged:
1825 state.mnState |= MOUSE_LEFT;
1826 break;
1827 case NSEventTypeRightMouseDragged:
1828 state.mnState |= MOUSE_RIGHT;
1829 break;
1830 case NSEventTypeOtherMouseDragged:
1831 state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0;
1832 break;
1833 default:
1834 bMouseEvent = false;
1835 break;
1838 if( bMouseEvent )
1840 unsigned int nMask = static_cast<unsigned int>([pCur modifierFlags]);
1841 if( (nMask & NSEventModifierFlagShift) != 0 )
1842 state.mnState |= KEY_SHIFT;
1843 if( (nMask & NSEventModifierFlagControl) != 0 )
1844 state.mnState |= KEY_MOD3;
1845 if( (nMask & NSEventModifierFlagOption) != 0 )
1846 state.mnState |= KEY_MOD2;
1847 if( (nMask & NSEventModifierFlagCommand) != 0 )
1848 state.mnState |= KEY_MOD1;
1851 else
1853 // FIXME: replace Carbon by Cocoa
1854 // Cocoa does not have an equivalent for GetCurrentEventButtonState
1855 // and GetCurrentEventKeyModifiers.
1856 // we could try to get away with tracking all events for modifierKeys
1857 // and all mouse events for button state in VCL_NSApplication::sendEvent,
1858 // but it is unclear whether this will get us the same result.
1859 // leave in GetCurrentEventButtonState and GetCurrentEventKeyModifiers for now
1861 // fill in button state
1862 UInt32 nState = GetCurrentEventButtonState();
1863 state.mnState = 0;
1864 if( nState & 1 )
1865 state.mnState |= MOUSE_LEFT; // primary button
1866 if( nState & 2 )
1867 state.mnState |= MOUSE_RIGHT; // secondary button
1868 if( nState & 4 )
1869 state.mnState |= MOUSE_MIDDLE; // tertiary button
1871 // fill in modifier state
1872 nState = GetCurrentEventKeyModifiers();
1873 if( nState & shiftKey )
1874 state.mnState |= KEY_SHIFT;
1875 if( nState & controlKey )
1876 state.mnState |= KEY_MOD3;
1877 if( nState & optionKey )
1878 state.mnState |= KEY_MOD2;
1879 if( nState & cmdKey )
1880 state.mnState |= KEY_MOD1;
1883 return state;
1886 KeyIndicatorState AquaSalFrame::GetIndicatorState()
1888 return KeyIndicatorState::NONE;
1891 void AquaSalFrame::SimulateKeyPress( sal_uInt16 /*nKeyCode*/ )
1895 void AquaSalFrame::SetPluginParent( SystemParentData* )
1897 // plugin parent may be killed unexpectedly by
1898 // plugging process;
1900 //TODO: implement
1903 bool AquaSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , vcl::KeyCode& )
1905 // not supported yet
1906 return false;
1909 LanguageType AquaSalFrame::GetInputLanguage()
1911 //TODO: implement
1912 return LANGUAGE_DONTKNOW;
1915 void AquaSalFrame::SetMenu( SalMenu* pSalMenu )
1917 OSX_SALDATA_RUNINMAIN( SetMenu( pSalMenu ) )
1919 AquaSalMenu* pMenu = static_cast<AquaSalMenu*>(pSalMenu);
1920 SAL_WARN_IF( pMenu && !pMenu->mbMenuBar, "vcl", "setting non menubar on frame" );
1921 mpMenu = pMenu;
1922 if( mpMenu )
1923 mpMenu->setMainMenu();
1926 void AquaSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
1928 if ( !mpNSWindow )
1930 mnExtStyle = nStyle;
1931 return;
1934 OSX_SALDATA_RUNINMAIN( SetExtendedFrameStyle( nStyle ) )
1936 if( (mnExtStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) != (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) )
1937 [mpNSWindow setDocumentEdited: (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) ? YES : NO];
1939 mnExtStyle = nStyle;
1942 SalFrame* AquaSalFrame::GetParent() const
1944 return mpParent;
1947 void AquaSalFrame::SetParent( SalFrame* pNewParent )
1949 bool bShown = mbShown;
1950 // remove from child list
1951 if (bShown)
1952 Show(false);
1953 mpParent = static_cast<AquaSalFrame*>(pNewParent);
1954 // insert to correct parent and paint
1955 Show( bShown );
1958 void AquaSalFrame::UpdateFrameGeometry()
1960 mbGeometryDidChange = false;
1962 if ( !mpNSWindow )
1963 return;
1965 OSX_SALDATA_RUNINMAIN( UpdateFrameGeometry() )
1967 // keep in mind that view and window coordinates are lower left
1968 // whereas vcl's are upper left
1970 // update screen rect
1971 NSScreen * pScreen = [mpNSWindow screen];
1972 if( pScreen )
1974 NSRect aNewScreenRect = [pScreen frame];
1975 if (!NSEqualRects(maScreenRect, aNewScreenRect))
1977 mbGeometryDidChange = true;
1978 maScreenRect = aNewScreenRect;
1980 NSArray* pScreens = [NSScreen screens];
1981 if( pScreens )
1983 unsigned int nNewDisplayScreenNumber = [pScreens indexOfObject: pScreen];
1984 if (maGeometry.screen() != nNewDisplayScreenNumber)
1986 mbGeometryDidChange = true;
1987 maGeometry.setScreen(nNewDisplayScreenNumber);
1992 NSRect aFrameRect = [mpNSWindow frame];
1993 NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask];
1995 NSRect aTrackRect = { NSZeroPoint, aContentRect.size };
1997 if (!NSEqualRects(maTrackingRect, aTrackRect))
1999 mbGeometryDidChange = true;
2000 maTrackingRect = aTrackRect;
2003 // convert to vcl convention
2004 CocoaToVCL( aFrameRect );
2005 CocoaToVCL( aContentRect );
2007 if (!NSEqualRects(maContentRect, aContentRect) || !NSEqualRects(maFrameRect, aFrameRect))
2009 mbGeometryDidChange = true;
2011 maContentRect = aContentRect;
2012 maFrameRect = aFrameRect;
2014 maGeometry.setX(static_cast<sal_Int32>(aContentRect.origin.x));
2015 maGeometry.setY(static_cast<sal_Int32>(aContentRect.origin.y));
2016 maGeometry.setWidth(static_cast<sal_uInt32>(aContentRect.size.width));
2017 maGeometry.setHeight(static_cast<sal_uInt32>(aContentRect.size.height));
2019 maGeometry.setLeftDecoration(static_cast<sal_uInt32>(aContentRect.origin.x - aFrameRect.origin.x));
2020 maGeometry.setRightDecoration(static_cast<sal_uInt32>((aFrameRect.origin.x + aFrameRect.size.width) -
2021 (aContentRect.origin.x + aContentRect.size.width)));
2022 maGeometry.setTopDecoration(static_cast<sal_uInt32>(aContentRect.origin.y - aFrameRect.origin.y));
2023 maGeometry.setBottomDecoration(static_cast<sal_uInt32>((aFrameRect.origin.y + aFrameRect.size.height) -
2024 (aContentRect.origin.y + aContentRect.size.height)));
2028 void AquaSalFrame::CaptureMouse( bool bCapture )
2030 /* Remark:
2031 we'll try to use a pidgin version of capture mouse
2032 on MacOSX (neither carbon nor cocoa) there is a
2033 CaptureMouse equivalent (in Carbon there is TrackMouseLocation
2034 but this is useless to use since it is blocking)
2036 However on cocoa the active frame seems to get mouse events
2037 also outside the window, so we'll try to forward mouse events
2038 to the capture frame in the hope that one of our frames
2039 gets a mouse event.
2041 This will break as soon as the user activates another app, but
2042 a mouse click will normally lead to a release of the mouse anyway.
2044 Let's see how far we get this way. Alternatively we could use one
2045 large overlay window like we did for the carbon implementation,
2046 however that is resource intensive.
2049 if( bCapture )
2050 s_pCaptureFrame = this;
2051 else if( ! bCapture && s_pCaptureFrame == this )
2052 s_pCaptureFrame = nullptr;
2055 void AquaSalFrame::ResetClipRegion()
2057 doResetClipRegion();
2060 void AquaSalFrame::doResetClipRegion()
2062 if ( !mpNSWindow )
2063 return;
2065 OSX_SALDATA_RUNINMAIN( ResetClipRegion() )
2067 // release old path and indicate no clipping
2068 CGPathRelease( mrClippingPath );
2069 mrClippingPath = nullptr;
2071 if( mpNSView && mbShown )
2072 [mpNSView setNeedsDisplay: YES];
2073 [mpNSWindow setOpaque: YES];
2074 [mpNSWindow invalidateShadow];
2077 void AquaSalFrame::BeginSetClipRegion( sal_uInt32 nRects )
2079 if ( !mpNSWindow )
2080 return;
2082 OSX_SALDATA_RUNINMAIN( BeginSetClipRegion( nRects ) )
2084 // release old path
2085 if( mrClippingPath )
2087 CGPathRelease( mrClippingPath );
2088 mrClippingPath = nullptr;
2091 if( maClippingRects.size() > SAL_CLIPRECT_COUNT && nRects < maClippingRects.size() )
2093 std::vector<CGRect>().swap(maClippingRects);
2095 maClippingRects.clear();
2096 maClippingRects.reserve( nRects );
2099 void AquaSalFrame::UnionClipRegion(
2100 tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
2102 // #i113170# may not be the main thread if called from UNO API
2103 SalData::ensureThreadAutoreleasePool();
2105 if( nWidth && nHeight )
2107 NSRect aRect = { { static_cast<CGFloat>(nX), static_cast<CGFloat>(nY) }, { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) } };
2108 VCLToCocoa( aRect, false );
2109 maClippingRects.push_back( CGRectMake(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height) );
2113 void AquaSalFrame::EndSetClipRegion()
2115 if ( !mpNSWindow )
2116 return;
2118 OSX_SALDATA_RUNINMAIN( EndSetClipRegion() )
2120 if( ! maClippingRects.empty() )
2122 mrClippingPath = CGPathCreateMutable();
2123 CGPathAddRects( mrClippingPath, nullptr, maClippingRects.data(), maClippingRects.size() );
2125 if( mpNSView && mbShown )
2126 [mpNSView setNeedsDisplay: YES];
2127 [mpNSWindow setOpaque: (mrClippingPath != nullptr) ? NO : YES];
2128 [mpNSWindow setBackgroundColor: [NSColor clearColor]];
2129 // shadow is invalidated when view gets drawn again
2132 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */