calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / vcl / osx / salframe.cxx
blob401b20813fbb77a7a079f3d11cc650888c14b017
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 <quartz/CGHelpers.hxx>
56 #include <postmac.h>
59 const int nMinBlinkCursorDelay = 500;
61 AquaSalFrame* AquaSalFrame::s_pCaptureFrame = nullptr;
63 AquaSalFrame::AquaSalFrame( SalFrame* pParent, SalFrameStyleFlags salFrameStyle ) :
64 mpNSWindow(nil),
65 mpNSView(nil),
66 mpDockMenuEntry(nil),
67 mpGraphics(nullptr),
68 mpParent(nullptr),
69 mnMinWidth(0),
70 mnMinHeight(0),
71 mnMaxWidth(0),
72 mnMaxHeight(0),
73 mbGraphics(false),
74 mbFullScreen( false ),
75 mbShown(false),
76 mbInitShow(true),
77 mbPositioned(false),
78 mbSized(false),
79 mbPresentation( false ),
80 mnStyle( salFrameStyle ),
81 mnStyleMask( 0 ),
82 mnLastEventTime( 0 ),
83 mnLastModifierFlags( 0 ),
84 mpMenu( nullptr ),
85 mnExtStyle( 0 ),
86 mePointerStyle( PointerStyle::Arrow ),
87 mnTrackingRectTag( 0 ),
88 mrClippingPath( nullptr ),
89 mnICOptions( InputContextFlags::NONE ),
90 mnBlinkCursorDelay( nMinBlinkCursorDelay ),
91 mbForceFlush( false )
93 mpParent = dynamic_cast<AquaSalFrame*>(pParent);
95 initWindowAndView();
97 SalData* pSalData = GetSalData();
98 pSalData->mpInstance->insertFrame( this );
99 NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
101 // tdf#150177 Limit minimum blink cursor rate
102 // This bug occurs when the values for NSTextInsertionPointBlinkPeriodOn or
103 // NSTextInsertionPointBlinkPeriodOff are set to zero or close to zero.
104 // LibreOffice becomes very sluggish opening documents when either is set
105 // at 100 milliseconds or less so set the blink rate to the maximum of
106 // nMinBlinkCursorDelay, NSTextInsertionPointBlinkPeriodOn, and
107 // NSTextInsertionPointBlinkPeriodOff.
108 mnBlinkCursorDelay = nMinBlinkCursorDelay;
109 if (userDefaults != nil)
111 id setting = [userDefaults objectForKey: @"NSTextInsertionPointBlinkPeriodOn"];
112 if (setting && [setting isKindOfClass:[NSNumber class]])
113 mnBlinkCursorDelay = std::max(mnBlinkCursorDelay, [setting intValue]);
115 setting = [userDefaults objectForKey: @"NSTextInsertionPointBlinkPeriodOff"];
116 if (setting && [setting isKindOfClass:[NSNumber class]])
117 mnBlinkCursorDelay = std::max(mnBlinkCursorDelay, [setting intValue]);
121 AquaSalFrame::~AquaSalFrame()
123 if (mbFullScreen)
124 doShowFullScreen(false, maGeometry.screen());
126 assert( GetSalData()->mpInstance->IsMainThread() );
128 // if the frame is destroyed and has the current menubar
129 // set the default menubar
130 if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu )
131 AquaSalMenu::setDefaultMenu();
133 // cleanup clipping stuff
134 doResetClipRegion();
136 [SalFrameView unsetMouseFrame: this];
138 SalData* pSalData = GetSalData();
139 pSalData->mpInstance->eraseFrame( this );
140 pSalData->maPresentationFrames.remove( this );
142 SAL_WARN_IF( this == s_pCaptureFrame, "vcl", "capture frame destroyed" );
143 if( this == s_pCaptureFrame )
144 s_pCaptureFrame = nullptr;
146 delete mpGraphics;
148 if( mpDockMenuEntry )
150 NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu();
151 // life cycle comment: the menu has ownership of the item, so no release
152 [pDock removeItem: mpDockMenuEntry];
153 if ([pDock numberOfItems] != 0
154 && [[pDock itemAtIndex: 0] isSeparatorItem])
156 [pDock removeItemAtIndex: 0];
159 if ( mpNSView ) {
160 [AquaA11yFactory revokeView: mpNSView];
161 [mpNSView release];
163 if ( mpNSWindow )
164 [mpNSWindow release];
167 void AquaSalFrame::initWindowAndView()
169 OSX_SALDATA_RUNINMAIN( initWindowAndView() )
171 // initialize mirroring parameters
172 // FIXME: screens changing
173 NSScreen* pNSScreen = [mpNSWindow screen];
174 if( pNSScreen == nil )
175 pNSScreen = [NSScreen mainScreen];
176 maScreenRect = [pNSScreen frame];
178 // calculate some default geometry
179 NSRect aVisibleRect = [pNSScreen visibleFrame];
180 CocoaToVCL( aVisibleRect );
182 maGeometry.setX(static_cast<sal_Int32>(aVisibleRect.origin.x + aVisibleRect.size.width / 10));
183 maGeometry.setY(static_cast<sal_Int32>(aVisibleRect.origin.y + aVisibleRect.size.height / 10));
184 maGeometry.setWidth(static_cast<sal_uInt32>(aVisibleRect.size.width * 0.8));
185 maGeometry.setHeight(static_cast<sal_uInt32>(aVisibleRect.size.height * 0.8));
187 // calculate style mask
188 if( (mnStyle & SalFrameStyleFlags::FLOAT) ||
189 (mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION) )
190 mnStyleMask = NSWindowStyleMaskBorderless;
191 else if( mnStyle & SalFrameStyleFlags::DEFAULT )
193 mnStyleMask = NSWindowStyleMaskTitled |
194 NSWindowStyleMaskMiniaturizable |
195 NSWindowStyleMaskResizable |
196 NSWindowStyleMaskClosable;
197 // make default window "maximized"
198 maGeometry.setX(static_cast<sal_Int32>(aVisibleRect.origin.x));
199 maGeometry.setY(static_cast<sal_Int32>(aVisibleRect.origin.y));
200 maGeometry.setWidth(static_cast<sal_uInt32>(aVisibleRect.size.width));
201 maGeometry.setHeight(static_cast<sal_uInt32>(aVisibleRect.size.height));
202 mbPositioned = mbSized = true;
204 else
206 if( mnStyle & SalFrameStyleFlags::MOVEABLE )
208 mnStyleMask |= NSWindowStyleMaskTitled;
209 if( mpParent == nullptr )
210 mnStyleMask |= NSWindowStyleMaskMiniaturizable;
212 if( mnStyle & SalFrameStyleFlags::SIZEABLE )
213 mnStyleMask |= NSWindowStyleMaskResizable;
214 if( mnStyle & SalFrameStyleFlags::CLOSEABLE )
215 mnStyleMask |= NSWindowStyleMaskClosable;
216 // documentation says anything other than NSWindowStyleMaskBorderless (=0)
217 // should also include NSWindowStyleMaskTitled;
218 if( mnStyleMask != 0 )
219 mnStyleMask |= NSWindowStyleMaskTitled;
222 if (Application::IsBitmapRendering())
223 return;
225 // #i91990# support GUI-less (daemon) execution
226 @try
228 mpNSWindow = [[SalFrameWindow alloc] initWithSalFrame: this];
229 mpNSView = [[SalFrameView alloc] initWithSalFrame: this];
231 @catch ( id )
233 std::abort();
236 if( mnStyle & SalFrameStyleFlags::TOOLTIP )
237 [mpNSWindow setIgnoresMouseEvents: YES];
238 else
239 [mpNSWindow setAcceptsMouseMovedEvents: YES];
240 [mpNSWindow setHasShadow: YES];
242 [mpNSWindow setDelegate: static_cast<id<NSWindowDelegate> >(mpNSWindow)];
244 [mpNSWindow setRestorable:NO];
245 const NSRect aRect = { NSZeroPoint, NSMakeSize(maGeometry.width(), maGeometry.height()) };
246 mnTrackingRectTag = [mpNSView addTrackingRect: aRect owner: mpNSView userData: nil assumeInside: NO];
248 maSysData.mpNSView = mpNSView;
250 UpdateFrameGeometry();
252 [mpNSWindow setContentView: mpNSView];
255 void AquaSalFrame::CocoaToVCL( NSRect& io_rRect, bool bRelativeToScreen )
257 if( bRelativeToScreen )
258 io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height);
259 else
260 io_rRect.origin.y = maGeometry.height() - (io_rRect.origin.y+io_rRect.size.height);
263 void AquaSalFrame::VCLToCocoa( NSRect& io_rRect, bool bRelativeToScreen )
265 if( bRelativeToScreen )
266 io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height);
267 else
268 io_rRect.origin.y = maGeometry.height() - (io_rRect.origin.y+io_rRect.size.height);
271 void AquaSalFrame::CocoaToVCL( NSPoint& io_rPoint, bool bRelativeToScreen )
273 if( bRelativeToScreen )
274 io_rPoint.y = maScreenRect.size.height - io_rPoint.y;
275 else
276 io_rPoint.y = maGeometry.height() - io_rPoint.y;
279 void AquaSalFrame::VCLToCocoa( NSPoint& io_rPoint, bool bRelativeToScreen )
281 if( bRelativeToScreen )
282 io_rPoint.y = maScreenRect.size.height - io_rPoint.y;
283 else
284 io_rPoint.y = maGeometry.height() - io_rPoint.y;
287 void AquaSalFrame::screenParametersChanged()
289 OSX_SALDATA_RUNINMAIN( screenParametersChanged() )
291 sal::aqua::resetWindowScaling();
293 UpdateFrameGeometry();
295 if( mpGraphics )
296 mpGraphics->updateResolution();
298 if (!mbGeometryDidChange)
299 return;
301 CallCallback( SalEvent::DisplayChanged, nullptr );
304 SalGraphics* AquaSalFrame::AcquireGraphics()
306 if ( mbGraphics )
307 return nullptr;
309 if ( !mpGraphics )
311 mpGraphics = new AquaSalGraphics;
312 mpGraphics->SetWindowGraphics( this );
315 mbGraphics = true;
316 return mpGraphics;
319 void AquaSalFrame::ReleaseGraphics( SalGraphics *pGraphics )
321 SAL_WARN_IF( pGraphics != mpGraphics, "vcl", "graphics released on wrong frame" );
322 mbGraphics = false;
325 bool AquaSalFrame::PostEvent(std::unique_ptr<ImplSVEvent> pData)
327 GetSalData()->mpInstance->PostEvent( this, pData.release(), SalEvent::UserEvent );
328 return true;
331 void AquaSalFrame::SetTitle(const OUString& rTitle)
333 if ( !mpNSWindow )
334 return;
336 OSX_SALDATA_RUNINMAIN( SetTitle(rTitle) )
338 // #i113170# may not be the main thread if called from UNO API
339 SalData::ensureThreadAutoreleasePool();
341 NSString* pTitle = CreateNSString( rTitle );
342 [mpNSWindow setTitle: pTitle];
344 // create an entry in the dock menu
345 const SalFrameStyleFlags nAppWindowStyle = SalFrameStyleFlags::CLOSEABLE | SalFrameStyleFlags::MOVEABLE;
346 if( mpParent == nullptr &&
347 (mnStyle & nAppWindowStyle) == nAppWindowStyle )
349 if( mpDockMenuEntry == nullptr )
351 NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu();
353 if ([pDock numberOfItems] != 0) {
354 NSMenuItem* pTopItem = [pDock itemAtIndex: 0];
355 if ( [pTopItem hasSubmenu] )
356 [pDock insertItem: [NSMenuItem separatorItem] atIndex: 0];
359 mpDockMenuEntry = [pDock insertItemWithTitle: pTitle
360 action: @selector(dockMenuItemTriggered:)
361 keyEquivalent: @""
362 atIndex: 0];
363 [mpDockMenuEntry setTarget: mpNSWindow];
365 // TODO: image (either the generic window image or an icon
366 // check mark (for "main" window ?)
368 else
369 [mpDockMenuEntry setTitle: pTitle];
372 if (pTitle)
373 [pTitle release];
376 void AquaSalFrame::SetIcon( sal_uInt16 )
380 void AquaSalFrame::SetRepresentedURL( const OUString& i_rDocURL )
382 OSX_SALDATA_RUNINMAIN( SetRepresentedURL( i_rDocURL ) )
384 if( comphelper::isFileUrl(i_rDocURL) )
386 OUString aSysPath;
387 osl_getSystemPathFromFileURL( i_rDocURL.pData, &aSysPath.pData );
388 NSString* pStr = CreateNSString( aSysPath );
389 if( pStr )
391 [pStr autorelease];
392 [mpNSWindow setRepresentedFilename: pStr];
397 void AquaSalFrame::initShow()
399 OSX_SALDATA_RUNINMAIN( initShow() )
401 mbInitShow = false;
402 if( ! mbPositioned && ! mbFullScreen )
404 tools::Rectangle aScreenRect;
405 GetWorkArea( aScreenRect );
406 if( mpParent ) // center relative to parent
408 // center on parent
409 tools::Long nNewX = mpParent->maGeometry.x() + (static_cast<tools::Long>(mpParent->maGeometry.width()) - static_cast<tools::Long>(maGeometry.width())) / 2;
410 if( nNewX < aScreenRect.Left() )
411 nNewX = aScreenRect.Left();
412 if (static_cast<tools::Long>(nNewX + maGeometry.width()) > aScreenRect.Right())
413 nNewX = aScreenRect.Right() - maGeometry.width() - 1;
414 tools::Long nNewY = mpParent->maGeometry.y() + (static_cast<tools::Long>(mpParent->maGeometry.height()) - static_cast<tools::Long>(maGeometry.height())) / 2;
415 if( nNewY < aScreenRect.Top() )
416 nNewY = aScreenRect.Top();
417 if( nNewY > aScreenRect.Bottom() )
418 nNewY = aScreenRect.Bottom() - maGeometry.height() - 1;
419 SetPosSize( nNewX - mpParent->maGeometry.x(),
420 nNewY - mpParent->maGeometry.y(),
421 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
423 else if( ! (mnStyle & SalFrameStyleFlags::SIZEABLE) )
425 // center on screen
426 tools::Long nNewX = (aScreenRect.GetWidth() - maGeometry.width()) / 2;
427 tools::Long nNewY = (aScreenRect.GetHeight() - maGeometry.height()) / 2;
428 SetPosSize( nNewX, nNewY, 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
432 // make sure the view is present in the wrapper list before any children receive focus
433 [AquaA11yFactory registerView: mpNSView];
436 void AquaSalFrame::SendPaintEvent( const tools::Rectangle* pRect )
438 OSX_SALDATA_RUNINMAIN( SendPaintEvent( pRect ) )
440 SalPaintEvent aPaintEvt(0, 0, maGeometry.width(), maGeometry.height(), true);
441 if( pRect )
443 aPaintEvt.mnBoundX = pRect->Left();
444 aPaintEvt.mnBoundY = pRect->Top();
445 aPaintEvt.mnBoundWidth = pRect->GetWidth();
446 aPaintEvt.mnBoundHeight = pRect->GetHeight();
449 CallCallback(SalEvent::Paint, &aPaintEvt);
452 void AquaSalFrame::Show(bool bVisible, bool bNoActivate)
454 if ( !mpNSWindow )
455 return;
457 OSX_SALDATA_RUNINMAIN( Show(bVisible, bNoActivate) )
459 // tdf#152173 Don't display tooltip windows when application is inactive
460 // Starting with macOS 13 Ventura, inactive applications receive mouse
461 // move events so when LibreOffice is inactive, a mouse move event causes
462 // a tooltip to be displayed. Since the tooltip window is attached to its
463 // parent window (to ensure that the tooltip is above the parent window),
464 // displaying a tooltip pulls the parent window in front of the windows
465 // of all other inactive applications.
466 // Also, don't display tooltips when mousing over non-key windows even if
467 // the application is active as the tooltip window will pull the non-key
468 // window in front of the key window.
469 if (bVisible && (mnStyle & SalFrameStyleFlags::TOOLTIP))
471 if (![NSApp isActive])
472 return;
474 if (mpParent)
476 // tdf#157565 show tooltip if any parent window is the key window
477 bool bKeyWindowFound = false;
478 NSWindow *pParent = mpParent->mpNSWindow;
479 while (pParent)
481 if ([pParent isKeyWindow])
483 bKeyWindowFound = true;
484 break;
486 pParent = [pParent parentWindow];
488 if (!bKeyWindowFound)
489 return;
493 mbShown = bVisible;
494 if(bVisible)
496 if( mbInitShow )
497 initShow();
499 CallCallback(SalEvent::Resize, nullptr);
500 // trigger filling our backbuffer
501 SendPaintEvent();
503 if( bNoActivate || [mpNSWindow canBecomeKeyWindow] == NO )
504 [mpNSWindow orderFront: NSApp];
505 else
506 [mpNSWindow makeKeyAndOrderFront: NSApp];
508 if( mpParent )
510 /* #i92674# #i96433# we do not want an invisible parent to show up (which adding a visible
511 child implicitly does). However we also do not want a parentless toolbar.
513 HACK: try to decide when we should not insert a child to its parent
514 floaters and ownerdraw windows have not yet shown up in cases where
515 we don't want the parent to become visible
517 if( mpParent->mbShown || (mnStyle & (SalFrameStyleFlags::OWNERDRAWDECORATION | SalFrameStyleFlags::FLOAT) ) )
519 [mpParent->mpNSWindow addChildWindow: mpNSWindow ordered: NSWindowAbove];
523 if( mbPresentation )
524 [mpNSWindow makeMainWindow];
526 else
528 // if the frame holding the current menubar gets hidden
529 // show the default menubar
530 if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu )
531 AquaSalMenu::setDefaultMenu();
533 // #i90440# #i94443# work around the focus going back to some other window
534 // if a child gets hidden for a parent window
535 if( mpParent && mpParent->mbShown && [mpNSWindow isKeyWindow] )
536 [mpParent->mpNSWindow makeKeyAndOrderFront: NSApp];
538 [SalFrameView unsetMouseFrame: this];
539 if( mpParent && [mpNSWindow parentWindow] == mpParent->mpNSWindow )
540 [mpParent->mpNSWindow removeChildWindow: mpNSWindow];
542 [mpNSWindow orderOut: NSApp];
546 void AquaSalFrame::SetMinClientSize( tools::Long nWidth, tools::Long nHeight )
548 OSX_SALDATA_RUNINMAIN( SetMinClientSize( nWidth, nHeight ) )
550 mnMinWidth = nWidth;
551 mnMinHeight = nHeight;
553 if( mpNSWindow )
555 // Always add the decoration as the dimension concerns only
556 // the content rectangle
557 nWidth += maGeometry.leftDecoration() + maGeometry.rightDecoration();
558 nHeight += maGeometry.topDecoration() + maGeometry.bottomDecoration();
560 NSSize aSize = { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) };
562 // Size of full window (content+structure) although we only
563 // have the client size in arguments
564 [mpNSWindow setMinSize: aSize];
568 void AquaSalFrame::SetMaxClientSize( tools::Long nWidth, tools::Long nHeight )
570 OSX_SALDATA_RUNINMAIN( SetMaxClientSize( nWidth, nHeight ) )
572 mnMaxWidth = nWidth;
573 mnMaxHeight = nHeight;
575 if( mpNSWindow )
577 // Always add the decoration as the dimension concerns only
578 // the content rectangle
579 nWidth += maGeometry.leftDecoration() + maGeometry.rightDecoration();
580 nHeight += maGeometry.topDecoration() + maGeometry.bottomDecoration();
582 // Carbon windows can't have a size greater than 32767x32767
583 if (nWidth>32767) nWidth=32767;
584 if (nHeight>32767) nHeight=32767;
586 NSSize aSize = { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) };
588 // Size of full window (content+structure) although we only
589 // have the client size in arguments
590 [mpNSWindow setMaxSize: aSize];
594 void AquaSalFrame::GetClientSize( tools::Long& rWidth, tools::Long& rHeight )
596 if (mbShown || mbInitShow || Application::IsBitmapRendering())
598 rWidth = maGeometry.width();
599 rHeight = maGeometry.height();
601 else
603 rWidth = 0;
604 rHeight = 0;
608 SalEvent AquaSalFrame::PreparePosSize(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt16 nFlags)
610 SalEvent nEvent = SalEvent::NONE;
611 assert(mpNSWindow || Application::IsBitmapRendering());
613 if (nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y))
615 mbPositioned = true;
616 nEvent = SalEvent::Move;
619 if (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT))
621 mbSized = true;
622 nEvent = (nEvent == SalEvent::Move) ? SalEvent::MoveResize : SalEvent::Resize;
625 if (Application::IsBitmapRendering())
627 if (nFlags & SAL_FRAME_POSSIZE_X)
628 maGeometry.setX(nX);
629 if (nFlags & SAL_FRAME_POSSIZE_Y)
630 maGeometry.setY(nY);
631 if (nFlags & SAL_FRAME_POSSIZE_WIDTH)
633 maGeometry.setWidth(nWidth);
634 if (mnMaxWidth > 0 && maGeometry.width() > mnMaxWidth)
635 maGeometry.setWidth(mnMaxWidth);
636 if (mnMinWidth > 0 && maGeometry.width() < mnMinWidth)
637 maGeometry.setWidth(mnMinWidth);
639 if (nFlags & SAL_FRAME_POSSIZE_HEIGHT)
641 maGeometry.setHeight(nHeight);
642 if (mnMaxHeight > 0 && maGeometry.height() > mnMaxHeight)
643 maGeometry.setHeight(mnMaxHeight);
644 if (mnMinHeight > 0 && maGeometry.height() < mnMinHeight)
645 maGeometry.setHeight(mnMinHeight);
647 if (nEvent != SalEvent::NONE)
648 CallCallback(nEvent, nullptr);
651 return nEvent;
654 void AquaSalFrame::SetWindowState(const vcl::WindowData* pState)
656 if (!mpNSWindow && !Application::IsBitmapRendering())
657 return;
659 OSX_SALDATA_RUNINMAIN( SetWindowState( pState ) )
661 sal_uInt16 nFlags = 0;
662 nFlags |= ((pState->mask() & vcl::WindowDataMask::X) ? SAL_FRAME_POSSIZE_X : 0);
663 nFlags |= ((pState->mask() & vcl::WindowDataMask::Y) ? SAL_FRAME_POSSIZE_Y : 0);
664 nFlags |= ((pState->mask() & vcl::WindowDataMask::Width) ? SAL_FRAME_POSSIZE_WIDTH : 0);
665 nFlags |= ((pState->mask() & vcl::WindowDataMask::Height) ? SAL_FRAME_POSSIZE_HEIGHT : 0);
667 SalEvent nEvent = PreparePosSize(pState->x(), pState->y(), pState->width(), pState->height(), nFlags);
668 if (Application::IsBitmapRendering())
669 return;
671 // set normal state
672 NSRect aStateRect = [mpNSWindow frame];
673 aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask];
674 CocoaToVCL(aStateRect);
675 if (pState->mask() & vcl::WindowDataMask::X)
676 aStateRect.origin.x = float(pState->x());
677 if (pState->mask() & vcl::WindowDataMask::Y)
678 aStateRect.origin.y = float(pState->y());
679 if (pState->mask() & vcl::WindowDataMask::Width)
680 aStateRect.size.width = float(pState->width());
681 if (pState->mask() & vcl::WindowDataMask::Height)
682 aStateRect.size.height = float(pState->height());
683 VCLToCocoa(aStateRect);
684 aStateRect = [NSWindow frameRectForContentRect: aStateRect styleMask: mnStyleMask];
685 [mpNSWindow setFrame: aStateRect display: NO];
687 if (pState->state() == vcl::WindowState::Minimized)
688 [mpNSWindow miniaturize: NSApp];
689 else if ([mpNSWindow isMiniaturized])
690 [mpNSWindow deminiaturize: NSApp];
692 /* ZOOMED is not really maximized (actually it toggles between a user set size and
693 the program specified one), but comes closest since the default behavior is
694 "maximized" if the user did not intervene
696 if (pState->state() == vcl::WindowState::Maximized)
698 if (![mpNSWindow isZoomed])
699 [mpNSWindow zoom: NSApp];
701 else
703 if ([mpNSWindow isZoomed])
704 [mpNSWindow zoom: NSApp];
707 // get new geometry
708 UpdateFrameGeometry();
710 // send event that we were moved/sized
711 if( nEvent != SalEvent::NONE )
712 CallCallback( nEvent, nullptr );
714 if (mbShown)
716 // trigger filling our backbuffer
717 SendPaintEvent();
719 // tell the system the views need to be updated
720 [mpNSWindow display];
724 bool AquaSalFrame::GetWindowState(vcl::WindowData* pState)
726 if (!mpNSWindow)
728 if (Application::IsBitmapRendering())
730 pState->setMask(vcl::WindowDataMask::PosSizeState);
731 pState->setPosSize(maGeometry.posSize());
732 pState->setState(vcl::WindowState::Normal);
733 return true;
735 return false;
738 OSX_SALDATA_RUNINMAIN_UNION( GetWindowState( pState ), boolean )
740 pState->setMask(vcl::WindowDataMask::PosSizeState);
742 NSRect aStateRect = [mpNSWindow frame];
743 aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask];
744 CocoaToVCL( aStateRect );
745 pState->setX(static_cast<sal_Int32>(aStateRect.origin.x));
746 pState->setY(static_cast<sal_Int32>(aStateRect.origin.y));
747 pState->setWidth(static_cast<sal_uInt32>(aStateRect.size.width));
748 pState->setHeight(static_cast<sal_uInt32>(aStateRect.size.height));
750 if( [mpNSWindow isMiniaturized] )
751 pState->setState(vcl::WindowState::Minimized);
752 else if( ! [mpNSWindow isZoomed] )
753 pState->setState(vcl::WindowState::Normal);
754 else
755 pState->setState(vcl::WindowState::Maximized);
757 return true;
760 void AquaSalFrame::SetScreenNumber(unsigned int nScreen)
762 if ( !mpNSWindow )
763 return;
765 OSX_SALDATA_RUNINMAIN( SetScreenNumber( nScreen ) )
767 NSArray* pScreens = [NSScreen screens];
768 NSScreen* pScreen = nil;
769 if( pScreens && nScreen < [pScreens count] )
771 // get new screen frame
772 pScreen = [pScreens objectAtIndex: nScreen];
773 NSRect aNewScreen = [pScreen frame];
775 // get current screen frame
776 pScreen = [mpNSWindow screen];
777 if( pScreen )
779 NSRect aCurScreen = [pScreen frame];
780 if( aCurScreen.origin.x != aNewScreen.origin.x ||
781 aCurScreen.origin.y != aNewScreen.origin.y )
783 NSRect aFrameRect = [mpNSWindow frame];
784 aFrameRect.origin.x += aNewScreen.origin.x - aCurScreen.origin.x;
785 aFrameRect.origin.y += aNewScreen.origin.y - aCurScreen.origin.y;
786 [mpNSWindow setFrame: aFrameRect display: NO];
787 UpdateFrameGeometry();
793 void AquaSalFrame::SetApplicationID( const OUString &/*rApplicationID*/ )
797 void AquaSalFrame::ShowFullScreen( bool bFullScreen, sal_Int32 nDisplay )
799 doShowFullScreen(bFullScreen, nDisplay);
802 void AquaSalFrame::doShowFullScreen( bool bFullScreen, sal_Int32 nDisplay )
804 if (!mpNSWindow)
806 if (Application::IsBitmapRendering() && bFullScreen)
807 SetPosSize(0, 0, 1024, 768, SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT);
808 return;
811 SAL_INFO("vcl.osx", __func__ << ": mbFullScreen=" << mbFullScreen << ", bFullScreen=" << bFullScreen);
813 if( mbFullScreen == bFullScreen )
814 return;
816 OSX_SALDATA_RUNINMAIN( ShowFullScreen( bFullScreen, nDisplay ) )
818 mbFullScreen = bFullScreen;
820 if( bFullScreen )
822 // hide the dock and the menubar if we are on the menu screen
823 // which is always on index 0 according to documentation
824 bool bHideMenu = (nDisplay == 0);
826 NSRect aNewContentRect = NSZeroRect;
827 // get correct screen
828 NSScreen* pScreen = nil;
829 NSArray* pScreens = [NSScreen screens];
830 if( pScreens )
832 if( nDisplay >= 0 && o3tl::make_unsigned(nDisplay) < [pScreens count] )
833 pScreen = [pScreens objectAtIndex: nDisplay];
834 else
836 // this means span all screens
837 bHideMenu = true;
838 NSEnumerator* pEnum = [pScreens objectEnumerator];
839 while( (pScreen = [pEnum nextObject]) != nil )
841 NSRect aScreenRect = [pScreen frame];
842 if( aScreenRect.origin.x < aNewContentRect.origin.x )
844 aNewContentRect.size.width += aNewContentRect.origin.x - aScreenRect.origin.x;
845 aNewContentRect.origin.x = aScreenRect.origin.x;
847 if( aScreenRect.origin.y < aNewContentRect.origin.y )
849 aNewContentRect.size.height += aNewContentRect.origin.y - aScreenRect.origin.y;
850 aNewContentRect.origin.y = aScreenRect.origin.y;
852 if( aScreenRect.origin.x + aScreenRect.size.width > aNewContentRect.origin.x + aNewContentRect.size.width )
853 aNewContentRect.size.width = aScreenRect.origin.x + aScreenRect.size.width - aNewContentRect.origin.x;
854 if( aScreenRect.origin.y + aScreenRect.size.height > aNewContentRect.origin.y + aNewContentRect.size.height )
855 aNewContentRect.size.height = aScreenRect.origin.y + aScreenRect.size.height - aNewContentRect.origin.y;
859 if( aNewContentRect.size.width == 0 && aNewContentRect.size.height == 0 )
861 if( pScreen == nil )
862 pScreen = [mpNSWindow screen];
863 if( pScreen == nil )
864 pScreen = [NSScreen mainScreen];
866 aNewContentRect = [pScreen frame];
869 if( bHideMenu )
870 [NSMenu setMenuBarVisible:NO];
872 maFullScreenRect = [mpNSWindow frame];
874 [mpNSWindow setFrame: [NSWindow frameRectForContentRect: aNewContentRect styleMask: mnStyleMask] display: mbShown ? YES : NO];
876 else
878 [mpNSWindow setFrame: maFullScreenRect display: mbShown ? YES : NO];
880 // show the dock and the menubar
881 [NSMenu setMenuBarVisible:YES];
884 UpdateFrameGeometry();
885 if (mbShown)
887 CallCallback(SalEvent::MoveResize, nullptr);
889 // trigger filling our backbuffer
890 SendPaintEvent();
894 void AquaSalFrame::StartPresentation( bool bStart )
896 if ( !mpNSWindow )
897 return;
899 OSX_SALDATA_RUNINMAIN( StartPresentation( bStart ) )
901 if( bStart )
903 GetSalData()->maPresentationFrames.push_back( this );
904 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
905 kIOPMAssertionLevelOn,
906 CFSTR("LibreOffice presentation running"),
907 &mnAssertionID);
908 [mpNSWindow setLevel: NSPopUpMenuWindowLevel];
909 if( mbShown )
910 [mpNSWindow makeMainWindow];
912 else
914 GetSalData()->maPresentationFrames.remove( this );
915 IOPMAssertionRelease(mnAssertionID);
916 [mpNSWindow setLevel: NSNormalWindowLevel];
920 void AquaSalFrame::SetAlwaysOnTop( bool )
924 void AquaSalFrame::ToTop(SalFrameToTop nFlags)
926 if ( !mpNSWindow )
927 return;
929 OSX_SALDATA_RUNINMAIN( ToTop( nFlags ) )
931 if( ! (nFlags & SalFrameToTop::RestoreWhenMin) )
933 if( ! [mpNSWindow isVisible] || [mpNSWindow isMiniaturized] )
934 return;
936 if( nFlags & SalFrameToTop::GrabFocus )
937 [mpNSWindow makeKeyAndOrderFront: NSApp];
938 else
939 [mpNSWindow orderFront: NSApp];
942 NSCursor* AquaSalFrame::getCurrentCursor()
944 OSX_SALDATA_RUNINMAIN_POINTER( getCurrentCursor(), NSCursor* )
946 NSCursor* pCursor = nil;
947 switch( mePointerStyle )
949 case PointerStyle::Text: pCursor = [NSCursor IBeamCursor]; break;
950 case PointerStyle::Cross: pCursor = [NSCursor crosshairCursor]; break;
951 case PointerStyle::Hand:
952 case PointerStyle::Move: pCursor = [NSCursor openHandCursor]; break;
953 case PointerStyle::NSize: pCursor = [NSCursor resizeUpCursor]; break;
954 case PointerStyle::SSize: pCursor = [NSCursor resizeDownCursor]; break;
955 case PointerStyle::ESize: pCursor = [NSCursor resizeRightCursor]; break;
956 case PointerStyle::WSize: pCursor = [NSCursor resizeLeftCursor]; break;
957 case PointerStyle::Arrow: pCursor = [NSCursor arrowCursor]; break;
958 case PointerStyle::VSplit:
959 case PointerStyle::VSizeBar:
960 case PointerStyle::WindowNSize:
961 case PointerStyle::WindowSSize:
962 pCursor = [NSCursor resizeUpDownCursor]; break;
963 case PointerStyle::HSplit:
964 case PointerStyle::HSizeBar:
965 case PointerStyle::WindowESize:
966 case PointerStyle::WindowWSize:
967 pCursor = [NSCursor resizeLeftRightCursor]; break;
968 case PointerStyle::RefHand: pCursor = [NSCursor pointingHandCursor]; break;
970 default:
971 pCursor = GetSalData()->getCursor( mePointerStyle );
972 if( pCursor == nil )
974 assert( false && "unmapped cursor" );
975 pCursor = [NSCursor arrowCursor];
977 break;
979 return pCursor;
982 void AquaSalFrame::SetPointer( PointerStyle ePointerStyle )
984 if ( !mpNSWindow )
985 return;
986 if( ePointerStyle == mePointerStyle )
987 return;
989 OSX_SALDATA_RUNINMAIN( SetPointer( ePointerStyle ) )
991 mePointerStyle = ePointerStyle;
993 [mpNSWindow invalidateCursorRectsForView: mpNSView];
996 void AquaSalFrame::SetPointerPos( tools::Long nX, tools::Long nY )
998 OSX_SALDATA_RUNINMAIN( SetPointerPos( nX, nY ) )
1000 // FIXME: use Cocoa functions
1001 // FIXME: multiscreen support
1002 CGPoint aPoint = { static_cast<CGFloat>(nX + maGeometry.x()), static_cast<CGFloat>(nY + maGeometry.y()) };
1003 CGDirectDisplayID mainDisplayID = CGMainDisplayID();
1004 CGDisplayMoveCursorToPoint( mainDisplayID, aPoint );
1007 void AquaSalFrame::Flush()
1009 if( !(mbGraphics && mpGraphics && mpNSView && mbShown) )
1010 return;
1012 OSX_SALDATA_RUNINMAIN( Flush() )
1014 [mpNSView setNeedsDisplay: YES];
1016 // outside of the application's event loop (e.g. IntroWindow)
1017 // nothing would trigger paint event handling
1018 // => fall back to synchronous painting
1019 if( mbForceFlush || ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
1021 mbForceFlush = false;
1022 mpGraphics->Flush();
1023 [mpNSView display];
1027 void AquaSalFrame::Flush( const tools::Rectangle& rRect )
1029 if( !(mbGraphics && mpGraphics && mpNSView && mbShown) )
1030 return;
1032 OSX_SALDATA_RUNINMAIN( Flush( rRect ) )
1034 NSRect aNSRect = { { static_cast<CGFloat>(rRect.Left()), static_cast<CGFloat>(rRect.Top()) }, { static_cast<CGFloat>(rRect.GetWidth()), static_cast<CGFloat>(rRect.GetHeight()) } };
1035 VCLToCocoa( aNSRect, false );
1036 [mpNSView setNeedsDisplayInRect: aNSRect];
1038 // outside of the application's event loop (e.g. IntroWindow)
1039 // nothing would trigger paint event handling
1040 // => fall back to synchronous painting
1041 if( mbForceFlush || ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
1043 mbForceFlush = false;
1044 mpGraphics->Flush( rRect );
1045 [mpNSView display];
1049 void AquaSalFrame::SetInputContext( SalInputContext* pContext )
1051 if (!pContext)
1053 mnICOptions = InputContextFlags::NONE;
1054 return;
1057 mnICOptions = pContext->mnOptions;
1059 if(!(pContext->mnOptions & InputContextFlags::Text))
1060 return;
1063 void AquaSalFrame::EndExtTextInput( EndExtTextInputFlags nFlags )
1065 // tdf#82115 Commit uncommitted text when a popup menu is opened
1066 // The Windows implementation of this method commits or discards the native
1067 // input method session. It appears that very few, if any, macOS
1068 // applications discard the uncommitted text when cancelling a session so
1069 // always commit the uncommitted text.
1070 SalFrameWindow *pWindow = static_cast<SalFrameWindow*>(mpNSWindow);
1071 if (pWindow && [pWindow isKindOfClass:[SalFrameWindow class]])
1072 [pWindow endExtTextInput:nFlags];
1075 OUString AquaSalFrame::GetKeyName( sal_uInt16 nKeyCode )
1077 static std::map< sal_uInt16, OUString > aKeyMap;
1078 if( aKeyMap.empty() )
1080 sal_uInt16 i;
1081 for( i = KEY_A; i <= KEY_Z; i++ )
1082 aKeyMap[ i ] = OUString( sal_Unicode( 'A' + (i - KEY_A) ) );
1083 for( i = KEY_0; i <= KEY_9; i++ )
1084 aKeyMap[ i ] = OUString( sal_Unicode( '0' + (i - KEY_0) ) );
1085 for( i = KEY_F1; i <= KEY_F26; i++ )
1087 aKeyMap[ i ] = "F" + OUString::number(i - KEY_F1 + 1);
1090 aKeyMap[ KEY_DOWN ] = OUString( u'\x21e3' );
1091 aKeyMap[ KEY_UP ] = OUString( u'\x21e1' );
1092 aKeyMap[ KEY_LEFT ] = OUString( u'\x21e0' );
1093 aKeyMap[ KEY_RIGHT ] = OUString( u'\x21e2' );
1094 aKeyMap[ KEY_HOME ] = OUString( u'\x2196' );
1095 aKeyMap[ KEY_END ] = OUString( u'\x2198' );
1096 aKeyMap[ KEY_PAGEUP ] = OUString( u'\x21de' );
1097 aKeyMap[ KEY_PAGEDOWN ] = OUString( u'\x21df' );
1098 aKeyMap[ KEY_RETURN ] = OUString( u'\x21a9' );
1099 aKeyMap[ KEY_ESCAPE ] = "esc";
1100 aKeyMap[ KEY_TAB ] = OUString( u'\x21e5' );
1101 aKeyMap[ KEY_BACKSPACE ]= OUString( u'\x232b' );
1102 aKeyMap[ KEY_SPACE ] = OUString( u'\x2423' );
1103 aKeyMap[ KEY_DELETE ] = OUString( u'\x2326' );
1104 aKeyMap[ KEY_ADD ] = "+";
1105 aKeyMap[ KEY_SUBTRACT ] = "-";
1106 aKeyMap[ KEY_DIVIDE ] = "/";
1107 aKeyMap[ KEY_MULTIPLY ] = "*";
1108 aKeyMap[ KEY_POINT ] = ".";
1109 aKeyMap[ KEY_COMMA ] = ",";
1110 aKeyMap[ KEY_LESS ] = "<";
1111 aKeyMap[ KEY_GREATER ] = ">";
1112 aKeyMap[ KEY_EQUAL ] = "=";
1113 aKeyMap[ KEY_OPEN ] = OUString( u'\x23cf' );
1114 aKeyMap[ KEY_TILDE ] = "~";
1115 aKeyMap[ KEY_BRACKETLEFT ] = "[";
1116 aKeyMap[ KEY_BRACKETRIGHT ] = "]";
1117 aKeyMap[ KEY_SEMICOLON ] = ";";
1118 aKeyMap[ KEY_QUOTERIGHT ] = "'";
1119 aKeyMap[ KEY_RIGHTCURLYBRACKET ] = "}";
1120 aKeyMap[ KEY_NUMBERSIGN ] = "#";
1121 aKeyMap[ KEY_COLON ] = ":";
1123 /* yet unmapped KEYCODES:
1124 aKeyMap[ KEY_INSERT ] = OUString( sal_Unicode( ) );
1125 aKeyMap[ KEY_CUT ] = OUString( sal_Unicode( ) );
1126 aKeyMap[ KEY_COPY ] = OUString( sal_Unicode( ) );
1127 aKeyMap[ KEY_PASTE ] = OUString( sal_Unicode( ) );
1128 aKeyMap[ KEY_UNDO ] = OUString( sal_Unicode( ) );
1129 aKeyMap[ KEY_REPEAT ] = OUString( sal_Unicode( ) );
1130 aKeyMap[ KEY_FIND ] = OUString( sal_Unicode( ) );
1131 aKeyMap[ KEY_PROPERTIES ] = OUString( sal_Unicode( ) );
1132 aKeyMap[ KEY_FRONT ] = OUString( sal_Unicode( ) );
1133 aKeyMap[ KEY_CONTEXTMENU ] = OUString( sal_Unicode( ) );
1134 aKeyMap[ KEY_MENU ] = OUString( sal_Unicode( ) );
1135 aKeyMap[ KEY_HELP ] = OUString( sal_Unicode( ) );
1136 aKeyMap[ KEY_HANGUL_HANJA ] = OUString( sal_Unicode( ) );
1137 aKeyMap[ KEY_DECIMAL ] = OUString( sal_Unicode( ) );
1138 aKeyMap[ KEY_QUOTELEFT ]= OUString( sal_Unicode( ) );
1139 aKeyMap[ KEY_CAPSLOCK ]= OUString( sal_Unicode( ) );
1140 aKeyMap[ KEY_NUMLOCK ]= OUString( sal_Unicode( ) );
1141 aKeyMap[ KEY_SCROLLLOCK ]= OUString( sal_Unicode( ) );
1146 OUStringBuffer aResult( 16 );
1148 sal_uInt16 nUnmodifiedCode = (nKeyCode & KEY_CODE_MASK);
1149 std::map< sal_uInt16, OUString >::const_iterator it = aKeyMap.find( nUnmodifiedCode );
1150 if( it != aKeyMap.end() )
1152 if( (nKeyCode & KEY_SHIFT) != 0 )
1153 aResult.append( u'\x21e7' ); // shift
1154 if( (nKeyCode & KEY_MOD1) != 0 )
1155 aResult.append( u'\x2318' ); // command
1156 if( (nKeyCode & KEY_MOD2) != 0 )
1157 aResult.append( u'\x2325' ); // alternate
1158 if( (nKeyCode & KEY_MOD3) != 0 )
1159 aResult.append( u'\x2303' ); // control
1161 aResult.append( it->second );
1164 return aResult.makeStringAndClear();
1167 static void getAppleScrollBarVariant(StyleSettings &rSettings)
1169 bool bIsScrollbarDoubleMax = true; // default is DoubleMax
1171 CFStringRef AppleScrollBarType = CFSTR("AppleScrollBarVariant");
1172 if( AppleScrollBarType )
1174 CFStringRef ScrollBarVariant = static_cast<CFStringRef>(CFPreferencesCopyAppValue( AppleScrollBarType, kCFPreferencesCurrentApplication ));
1175 if( ScrollBarVariant )
1177 if( CFGetTypeID( ScrollBarVariant ) == CFStringGetTypeID() )
1179 // TODO: check for the less important variants "DoubleMin" and "DoubleBoth" too
1180 CFStringRef DoubleMax = CFSTR("DoubleMax");
1181 if (DoubleMax)
1183 if ( !CFStringCompare(ScrollBarVariant, DoubleMax, kCFCompareCaseInsensitive) )
1184 bIsScrollbarDoubleMax = true;
1185 else
1186 bIsScrollbarDoubleMax = false;
1187 CFRelease(DoubleMax);
1190 CFRelease( ScrollBarVariant );
1192 CFRelease(AppleScrollBarType);
1195 GetSalData()->mbIsScrollbarDoubleMax = bIsScrollbarDoubleMax;
1197 CFStringRef jumpScroll = CFSTR("AppleScrollerPagingBehavior");
1198 if( jumpScroll )
1200 CFBooleanRef jumpStr = static_cast<CFBooleanRef>(CFPreferencesCopyAppValue( jumpScroll, kCFPreferencesCurrentApplication ));
1201 if( jumpStr )
1203 if( CFGetTypeID( jumpStr ) == CFBooleanGetTypeID() )
1204 rSettings.SetPrimaryButtonWarpsSlider(jumpStr == kCFBooleanTrue);
1205 CFRelease( jumpStr );
1207 CFRelease( jumpScroll );
1211 static Color getNSBoxBackgroundColor(NSColor* pSysColor)
1213 // Figuring out what a NSBox will draw for windowBackground, etc. seems very difficult.
1214 // So just draw to a 1x1 surface and read what actually gets drawn
1215 // This is similar to getPixel
1216 #if defined OSL_BIGENDIAN
1217 struct
1219 unsigned char b, g, r, a;
1220 } aPixel;
1221 #else
1222 struct
1224 unsigned char a, r, g, b;
1225 } aPixel;
1226 #endif
1228 // create a one-pixel bitmap context
1229 CGContextRef xOnePixelContext = CGBitmapContextCreate(
1230 &aPixel, 1, 1, 8, 32, GetSalData()->mxRGBSpace,
1231 uint32_t(kCGImageAlphaNoneSkipFirst) | uint32_t(kCGBitmapByteOrder32Big));
1233 NSGraphicsContext* graphicsContext = [NSGraphicsContext graphicsContextWithCGContext:xOnePixelContext flipped:NO];
1235 NSRect rect = { NSZeroPoint, NSMakeSize(1, 1) };
1236 NSBox* pBox = [[NSBox alloc] initWithFrame: rect];
1238 [pBox setBoxType: NSBoxCustom];
1239 [pBox setFillColor: pSysColor];
1240 SAL_WNODEPRECATED_DECLARATIONS_PUSH // setBorderType first deprecated in macOS 10.15
1241 [pBox setBorderType: NSNoBorder];
1242 SAL_WNODEPRECATED_DECLARATIONS_POP
1244 [pBox displayRectIgnoringOpacity: rect inContext: graphicsContext];
1246 [pBox release];
1248 CGContextRelease(xOnePixelContext);
1250 return Color(aPixel.r, aPixel.g, aPixel.b);
1253 static Color getColor( NSColor* pSysColor, const Color& rDefault, NSWindow* pWin )
1255 Color aRet( rDefault );
1256 if( pSysColor )
1258 // transform to RGB
1259 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1260 // "'colorUsingColorSpaceName:device:' is deprecated: first deprecated in macOS 10.14 -
1261 // Use -colorUsingType: or -colorUsingColorSpace: instead"
1262 NSColor* pRBGColor = [pSysColor colorUsingColorSpaceName: NSDeviceRGBColorSpace device: [pWin deviceDescription]];
1263 SAL_WNODEPRECATED_DECLARATIONS_POP
1264 if( pRBGColor )
1266 CGFloat r = 0, g = 0, b = 0, a = 0;
1267 [pRBGColor getRed: &r green: &g blue: &b alpha: &a];
1268 aRet = Color( int(r*255.999), int(g*255.999), int(b*255.999) );
1271 return aRet;
1274 static vcl::Font getFont( NSFont* pFont, sal_Int32 nDPIY, const vcl::Font& rDefault )
1276 vcl::Font aResult( rDefault );
1277 if( pFont )
1279 aResult.SetFamilyName( GetOUString( [pFont familyName] ) );
1280 aResult.SetFontHeight( static_cast<int>(ceil([pFont pointSize] * 72.0 / static_cast<float>(nDPIY))) );
1281 aResult.SetItalic( ([pFont italicAngle] != 0.0) ? ITALIC_NORMAL : ITALIC_NONE );
1282 // FIMXE: bold ?
1285 return aResult;
1288 void AquaSalFrame::getResolution( sal_Int32& o_rDPIX, sal_Int32& o_rDPIY )
1290 OSX_SALDATA_RUNINMAIN( getResolution( o_rDPIX, o_rDPIY ) )
1292 if( ! mpGraphics )
1294 AcquireGraphics();
1295 ReleaseGraphics( mpGraphics );
1297 mpGraphics->GetResolution( o_rDPIX, o_rDPIY );
1300 void AquaSalFrame::UpdateDarkMode()
1302 if (@available(macOS 10.14, iOS 13, *))
1304 switch (MiscSettings::GetDarkMode())
1306 case 0: // auto
1307 default:
1308 [NSApp setAppearance: nil];
1309 break;
1310 case 1: // light
1311 [NSApp setAppearance: [NSAppearance appearanceNamed: NSAppearanceNameAqua]];
1312 break;
1313 case 2: // dark
1314 [NSApp setAppearance: [NSAppearance appearanceNamed: NSAppearanceNameDarkAqua]];
1315 break;
1320 // on OSX-Aqua the style settings are independent of the frame, so it does
1321 // not really belong here. Since the connection to the Appearance_Manager
1322 // is currently done in salnativewidgets.cxx this would be a good place.
1323 // On the other hand VCL's platform independent code currently only asks
1324 // SalFrames for system settings anyway, so moving the code somewhere else
1325 // doesn't make the anything cleaner for now
1326 void AquaSalFrame::UpdateSettings( AllSettings& rSettings )
1328 if ( !mpNSWindow )
1329 return;
1331 OSX_SALDATA_RUNINMAIN( UpdateSettings( rSettings ) )
1333 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1334 // "'lockFocus' is deprecated: first deprecated in macOS 10.14 - To draw, subclass NSView
1335 // and implement -drawRect:; AppKit's automatic deferred display mechanism will call
1336 // -drawRect: as necessary to display the view."
1337 if (![mpNSView lockFocusIfCanDraw])
1338 return;
1339 SAL_WNODEPRECATED_DECLARATIONS_POP
1341 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1342 // "'setCurrentAppearance:' is deprecated: first deprecated in macOS 12.0 - Use
1343 // -performAsCurrentDrawingAppearance: to temporarily set the drawing appearance, or
1344 // +currentDrawingAppearance to access the currently drawing appearance."
1345 [NSAppearance setCurrentAppearance: mpNSView.effectiveAppearance];
1346 SAL_WNODEPRECATED_DECLARATIONS_POP
1348 StyleSettings aStyleSettings = rSettings.GetStyleSettings();
1350 bool bUseDarkMode(false);
1351 if (@available(macOS 10.14, iOS 13, *))
1353 NSAppearanceName match = [mpNSView.effectiveAppearance bestMatchFromAppearancesWithNames: @[
1354 NSAppearanceNameAqua, NSAppearanceNameDarkAqua]];
1355 bUseDarkMode = [match isEqualToString: NSAppearanceNameDarkAqua];
1357 OUString sThemeName(!bUseDarkMode ? u"sukapura" : u"sukapura_dark");
1358 aStyleSettings.SetPreferredIconTheme(sThemeName, bUseDarkMode);
1360 Color aControlBackgroundColor(getNSBoxBackgroundColor([NSColor controlBackgroundColor]));
1361 Color aWindowBackgroundColor(getNSBoxBackgroundColor([NSColor windowBackgroundColor]));
1362 Color aUnderPageBackgroundColor(getNSBoxBackgroundColor([NSColor underPageBackgroundColor]));
1364 // Background Color
1365 aStyleSettings.BatchSetBackgrounds( aWindowBackgroundColor, false );
1366 aStyleSettings.SetLightBorderColor( aWindowBackgroundColor );
1368 aStyleSettings.SetActiveTabColor(aWindowBackgroundColor);
1369 Color aInactiveTabColor( aWindowBackgroundColor );
1370 aInactiveTabColor.DecreaseLuminance( 32 );
1371 aStyleSettings.SetInactiveTabColor( aInactiveTabColor );
1373 Color aShadowColor = getColor( [NSColor systemGrayColor ],
1374 aStyleSettings.GetShadowColor(), mpNSWindow );
1375 aStyleSettings.SetShadowColor( aShadowColor );
1377 // tdf#152284 for DarkMode brighten it, while darken for BrightMode
1378 NSColor* pDarkColor = bUseDarkMode ? [[NSColor systemGrayColor] highlightWithLevel: 0.5]
1379 : [[NSColor systemGrayColor] shadowWithLevel: 0.5];
1380 Color aDarkShadowColor = getColor( pDarkColor, aStyleSettings.GetDarkShadowColor(), mpNSWindow );
1381 aStyleSettings.SetDarkShadowColor(aDarkShadowColor);
1383 // get the system font settings
1384 vcl::Font aAppFont = aStyleSettings.GetAppFont();
1385 sal_Int32 nDPIX = 72, nDPIY = 72;
1386 getResolution( nDPIX, nDPIY );
1387 aAppFont = getFont( [NSFont systemFontOfSize: 0], nDPIY, aAppFont );
1389 aStyleSettings.SetToolbarIconSize( ToolbarIconSize::Large );
1391 // TODO: better mapping of macOS<->LibreOffice font settings
1392 vcl::Font aLabelFont( getFont( [NSFont labelFontOfSize: 0], nDPIY, aAppFont ) );
1393 aStyleSettings.BatchSetFonts( aAppFont, aLabelFont );
1394 vcl::Font aMenuFont( getFont( [NSFont menuFontOfSize: 0], nDPIY, aAppFont ) );
1395 aStyleSettings.SetMenuFont( aMenuFont );
1397 vcl::Font aTitleFont( getFont( [NSFont titleBarFontOfSize: 0], nDPIY, aAppFont ) );
1398 aStyleSettings.SetTitleFont( aTitleFont );
1399 aStyleSettings.SetFloatTitleFont( aTitleFont );
1401 vcl::Font aTooltipFont(getFont([NSFont toolTipsFontOfSize: 0], nDPIY, aAppFont));
1402 aStyleSettings.SetHelpFont(aTooltipFont);
1404 Color aHighlightColor( getColor( [NSColor selectedTextBackgroundColor],
1405 aStyleSettings.GetHighlightColor(), mpNSWindow ) );
1406 aStyleSettings.SetHighlightColor( aHighlightColor );
1407 Color aHighlightTextColor( getColor( [NSColor selectedTextColor],
1408 aStyleSettings.GetHighlightTextColor(), mpNSWindow ) );
1409 aStyleSettings.SetHighlightTextColor( aHighlightTextColor );
1411 aStyleSettings.SetLinkColor(getColor( [NSColor linkColor],
1412 aStyleSettings.GetLinkColor(), mpNSWindow ) );
1413 aStyleSettings.SetVisitedLinkColor(getColor( [NSColor purpleColor],
1414 aStyleSettings.GetVisitedLinkColor(), mpNSWindow ) );
1416 #pragma clang diagnostic push
1417 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1418 Color aMenuHighlightColor( getColor( [NSColor selectedMenuItemColor],
1419 aStyleSettings.GetMenuHighlightColor(), mpNSWindow ) );
1420 #pragma clang diagnostic pop
1421 aStyleSettings.SetMenuHighlightColor( aMenuHighlightColor );
1422 Color aMenuHighlightTextColor( getColor( [NSColor selectedMenuItemTextColor],
1423 aStyleSettings.GetMenuHighlightTextColor(), mpNSWindow ) );
1424 aStyleSettings.SetMenuHighlightTextColor( aMenuHighlightTextColor );
1426 aStyleSettings.SetMenuColor( aWindowBackgroundColor );
1427 Color aMenuTextColor( getColor( [NSColor textColor],
1428 aStyleSettings.GetMenuTextColor(), mpNSWindow ) );
1429 aStyleSettings.SetMenuTextColor( aMenuTextColor );
1430 aStyleSettings.SetMenuBarTextColor( aMenuTextColor );
1431 aStyleSettings.SetMenuBarRolloverTextColor( aMenuTextColor );
1432 aStyleSettings.SetMenuBarHighlightTextColor(aStyleSettings.GetMenuHighlightTextColor());
1434 aStyleSettings.SetListBoxWindowBackgroundColor( aWindowBackgroundColor );
1435 aStyleSettings.SetListBoxWindowTextColor( aMenuTextColor );
1436 aStyleSettings.SetListBoxWindowHighlightColor( aMenuHighlightColor );
1437 aStyleSettings.SetListBoxWindowHighlightTextColor( aMenuHighlightTextColor );
1439 // FIXME: Starting with macOS Big Sur, coloring has changed. Currently there is no documentation which system color should be
1440 // used for some button states and for selected tab text. As a workaround the current OS version has to be considered. This code
1441 // has to be reviewed once issue is covered by documentation.
1443 // Set text colors for buttons and their different status according to OS settings, typically white for selected buttons,
1444 // black otherwise
1446 NSOperatingSystemVersion aOSVersion = { .majorVersion = 10, .minorVersion = 16, .patchVersion = 0 };
1447 Color aControlTextColor(getColor([NSColor controlTextColor], COL_BLACK, mpNSWindow ));
1448 Color aSelectedControlTextColor(getColor([NSColor selectedControlTextColor], COL_BLACK, mpNSWindow ));
1449 Color aAlternateSelectedControlTextColor(getColor([NSColor alternateSelectedControlTextColor], COL_WHITE, mpNSWindow ));
1450 aStyleSettings.SetWindowColor(aWindowBackgroundColor);
1451 aStyleSettings.SetListBoxWindowBackgroundColor(aWindowBackgroundColor);
1453 aStyleSettings.SetDialogTextColor(aControlTextColor);
1454 aStyleSettings.SetButtonTextColor(aControlTextColor);
1455 aStyleSettings.SetActionButtonTextColor(aControlTextColor);
1456 aStyleSettings.SetRadioCheckTextColor(aControlTextColor);
1457 aStyleSettings.SetGroupTextColor(aControlTextColor);
1458 aStyleSettings.SetLabelTextColor(aControlTextColor);
1459 aStyleSettings.SetWindowTextColor(aControlTextColor);
1460 aStyleSettings.SetFieldTextColor(aControlTextColor);
1462 aStyleSettings.SetFieldRolloverTextColor(aControlTextColor);
1463 aStyleSettings.SetFieldColor(aControlBackgroundColor);
1464 aStyleSettings.SetDefaultActionButtonTextColor(aAlternateSelectedControlTextColor);
1465 aStyleSettings.SetFlatButtonTextColor(aControlTextColor);
1466 aStyleSettings.SetDefaultButtonRolloverTextColor(aAlternateSelectedControlTextColor);
1467 aStyleSettings.SetButtonRolloverTextColor(aControlTextColor);
1468 aStyleSettings.SetDefaultActionButtonRolloverTextColor(aAlternateSelectedControlTextColor);
1469 aStyleSettings.SetActionButtonRolloverTextColor(aControlTextColor);
1470 aStyleSettings.SetFlatButtonRolloverTextColor(aControlTextColor);
1471 aStyleSettings.SetDefaultButtonPressedRolloverTextColor(aAlternateSelectedControlTextColor);
1472 aStyleSettings.SetDefaultActionButtonPressedRolloverTextColor(aAlternateSelectedControlTextColor);
1473 aStyleSettings.SetFlatButtonPressedRolloverTextColor(aControlTextColor);
1474 if ([NSProcessInfo.processInfo isOperatingSystemAtLeastVersion: aOSVersion])
1476 aStyleSettings.SetDefaultButtonTextColor(aAlternateSelectedControlTextColor);
1477 aStyleSettings.SetButtonPressedRolloverTextColor(aSelectedControlTextColor);
1478 aStyleSettings.SetActionButtonPressedRolloverTextColor(aSelectedControlTextColor);
1480 else
1482 aStyleSettings.SetButtonPressedRolloverTextColor(aAlternateSelectedControlTextColor);
1483 aStyleSettings.SetActionButtonPressedRolloverTextColor(aAlternateSelectedControlTextColor);
1484 aStyleSettings.SetDefaultButtonTextColor(aSelectedControlTextColor);
1487 aStyleSettings.SetWorkspaceColor(aUnderPageBackgroundColor);
1489 aStyleSettings.SetHelpColor(aControlBackgroundColor);
1490 aStyleSettings.SetHelpTextColor(aControlTextColor);
1491 aStyleSettings.SetToolTextColor(aControlTextColor);
1493 // Set text colors for tabs according to OS settings
1495 aStyleSettings.SetTabTextColor(aControlTextColor);
1496 aStyleSettings.SetTabRolloverTextColor(aControlTextColor);
1497 if ([NSProcessInfo.processInfo isOperatingSystemAtLeastVersion: aOSVersion])
1498 aStyleSettings.SetTabHighlightTextColor(aSelectedControlTextColor);
1499 else
1500 aStyleSettings.SetTabHighlightTextColor(aAlternateSelectedControlTextColor);
1502 aStyleSettings.SetCursorBlinkTime( mnBlinkCursorDelay );
1503 aStyleSettings.SetCursorSize(1);
1505 // no mnemonics on macOS
1506 aStyleSettings.SetOptions( aStyleSettings.GetOptions() | StyleSettingsOptions::NoMnemonics );
1508 getAppleScrollBarVariant(aStyleSettings);
1510 // set scrollbar size
1511 aStyleSettings.SetScrollBarSize( static_cast<tools::Long>([NSScroller scrollerWidthForControlSize:NSControlSizeRegular scrollerStyle:NSScrollerStyleLegacy]) );
1512 // images in menus false for MacOSX
1513 aStyleSettings.SetPreferredUseImagesInMenus( false );
1514 aStyleSettings.SetHideDisabledMenuItems( true );
1515 aStyleSettings.SetPreferredContextMenuShortcuts( false );
1517 rSettings.SetStyleSettings( aStyleSettings );
1519 // don't draw frame around each and every toolbar
1520 ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames = true;
1522 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1523 // "'unlockFocus' is deprecated: first deprecated in macOS 10.14 - To draw, subclass NSView
1524 // and implement -drawRect:; AppKit's automatic deferred display mechanism will call
1525 // -drawRect: as necessary to display the view."
1526 [mpNSView unlockFocus];
1527 SAL_WNODEPRECATED_DECLARATIONS_POP
1530 const SystemEnvData* AquaSalFrame::GetSystemData() const
1532 return &maSysData;
1535 void AquaSalFrame::Beep()
1537 OSX_SALDATA_RUNINMAIN( Beep() )
1538 NSBeep();
1541 void AquaSalFrame::SetPosSize(
1542 tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt16 nFlags)
1544 if (!mpNSWindow && !Application::IsBitmapRendering())
1545 return;
1547 OSX_SALDATA_RUNINMAIN( SetPosSize( nX, nY, nWidth, nHeight, nFlags ) )
1549 SalEvent nEvent = PreparePosSize(nX, nY, nWidth, nHeight, nFlags);
1550 if (Application::IsBitmapRendering())
1551 return;
1553 if( [mpNSWindow isMiniaturized] )
1554 [mpNSWindow deminiaturize: NSApp]; // expand the window
1556 NSRect aFrameRect = [mpNSWindow frame];
1557 NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask];
1559 // position is always relative to parent frame
1560 NSRect aParentContentRect;
1562 if( mpParent )
1564 if( AllSettings::GetLayoutRTL() )
1566 if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
1567 nX = static_cast<tools::Long>(mpParent->maGeometry.width()) - nWidth - 1 - nX;
1568 else
1569 nX = static_cast<tools::Long>(mpParent->maGeometry.width()) - aContentRect.size.width - 1 - nX;
1571 NSRect aParentFrameRect = [mpParent->mpNSWindow frame];
1572 aParentContentRect = [NSWindow contentRectForFrameRect: aParentFrameRect styleMask: mpParent->mnStyleMask];
1574 else
1575 aParentContentRect = maScreenRect; // use screen if no parent
1577 CocoaToVCL( aContentRect );
1578 CocoaToVCL( aParentContentRect );
1580 bool bPaint = false;
1581 if( (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) != 0 )
1583 if( nWidth != aContentRect.size.width || nHeight != aContentRect.size.height )
1584 bPaint = true;
1587 // use old window pos if no new pos requested
1588 if( (nFlags & SAL_FRAME_POSSIZE_X) != 0 )
1589 aContentRect.origin.x = nX + aParentContentRect.origin.x;
1590 if( (nFlags & SAL_FRAME_POSSIZE_Y) != 0)
1591 aContentRect.origin.y = nY + aParentContentRect.origin.y;
1593 // use old size if no new size requested
1594 if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
1595 aContentRect.size.width = nWidth;
1596 if( (nFlags & SAL_FRAME_POSSIZE_HEIGHT) != 0)
1597 aContentRect.size.height = nHeight;
1599 VCLToCocoa( aContentRect );
1601 // do not display yet, we need to update our backbuffer
1603 [mpNSWindow setFrame: [NSWindow frameRectForContentRect: aContentRect styleMask: mnStyleMask] display: NO];
1606 UpdateFrameGeometry();
1608 if (nEvent != SalEvent::NONE)
1609 CallCallback(nEvent, nullptr);
1611 if( mbShown && bPaint )
1613 // trigger filling our backbuffer
1614 SendPaintEvent();
1616 // now inform the system that the views need to be drawn
1617 [mpNSWindow display];
1621 void AquaSalFrame::GetWorkArea( tools::Rectangle& rRect )
1623 if (!mpNSWindow)
1625 if (Application::IsBitmapRendering())
1626 rRect = tools::Rectangle(Point(0, 0), Size(1024, 768));
1627 return;
1630 OSX_SALDATA_RUNINMAIN( GetWorkArea( rRect ) )
1632 NSScreen* pScreen = [mpNSWindow screen];
1633 if( pScreen == nil )
1634 pScreen = [NSScreen mainScreen];
1635 NSRect aRect = [pScreen visibleFrame];
1636 CocoaToVCL( aRect );
1637 rRect.SetLeft( static_cast<tools::Long>(aRect.origin.x) );
1638 rRect.SetTop( static_cast<tools::Long>(aRect.origin.y) );
1639 rRect.SetRight( static_cast<tools::Long>(aRect.origin.x + aRect.size.width - 1) );
1640 rRect.SetBottom( static_cast<tools::Long>(aRect.origin.y + aRect.size.height - 1) );
1643 SalFrame::SalPointerState AquaSalFrame::GetPointerState()
1645 OSX_SALDATA_RUNINMAIN_UNION( GetPointerState(), state )
1647 SalPointerState state;
1648 state.mnState = 0;
1650 // get position
1651 NSPoint aPt = [mpNSWindow mouseLocationOutsideOfEventStream];
1652 CocoaToVCL( aPt, false );
1653 state.maPos = Point(static_cast<tools::Long>(aPt.x), static_cast<tools::Long>(aPt.y));
1655 NSEvent* pCur = [NSApp currentEvent];
1656 bool bMouseEvent = false;
1657 if( pCur )
1659 bMouseEvent = true;
1660 switch( [pCur type] )
1662 case NSEventTypeLeftMouseDown:
1663 state.mnState |= MOUSE_LEFT;
1664 break;
1665 case NSEventTypeLeftMouseUp:
1666 break;
1667 case NSEventTypeRightMouseDown:
1668 state.mnState |= MOUSE_RIGHT;
1669 break;
1670 case NSEventTypeRightMouseUp:
1671 break;
1672 case NSEventTypeOtherMouseDown:
1673 state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0;
1674 break;
1675 case NSEventTypeOtherMouseUp:
1676 break;
1677 case NSEventTypeMouseMoved:
1678 break;
1679 case NSEventTypeLeftMouseDragged:
1680 state.mnState |= MOUSE_LEFT;
1681 break;
1682 case NSEventTypeRightMouseDragged:
1683 state.mnState |= MOUSE_RIGHT;
1684 break;
1685 case NSEventTypeOtherMouseDragged:
1686 state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0;
1687 break;
1688 default:
1689 bMouseEvent = false;
1690 break;
1693 if( bMouseEvent )
1695 unsigned int nMask = static_cast<unsigned int>([pCur modifierFlags]);
1696 if( (nMask & NSEventModifierFlagShift) != 0 )
1697 state.mnState |= KEY_SHIFT;
1698 if( (nMask & NSEventModifierFlagControl) != 0 )
1699 state.mnState |= KEY_MOD3;
1700 if( (nMask & NSEventModifierFlagOption) != 0 )
1701 state.mnState |= KEY_MOD2;
1702 if( (nMask & NSEventModifierFlagCommand) != 0 )
1703 state.mnState |= KEY_MOD1;
1706 else
1708 // FIXME: replace Carbon by Cocoa
1709 // Cocoa does not have an equivalent for GetCurrentEventButtonState
1710 // and GetCurrentEventKeyModifiers.
1711 // we could try to get away with tracking all events for modifierKeys
1712 // and all mouse events for button state in VCL_NSApplication::sendEvent,
1713 // but it is unclear whether this will get us the same result.
1714 // leave in GetCurrentEventButtonState and GetCurrentEventKeyModifiers for now
1716 // fill in button state
1717 UInt32 nState = GetCurrentEventButtonState();
1718 state.mnState = 0;
1719 if( nState & 1 )
1720 state.mnState |= MOUSE_LEFT; // primary button
1721 if( nState & 2 )
1722 state.mnState |= MOUSE_RIGHT; // secondary button
1723 if( nState & 4 )
1724 state.mnState |= MOUSE_MIDDLE; // tertiary button
1726 // fill in modifier state
1727 nState = GetCurrentEventKeyModifiers();
1728 if( nState & shiftKey )
1729 state.mnState |= KEY_SHIFT;
1730 if( nState & controlKey )
1731 state.mnState |= KEY_MOD3;
1732 if( nState & optionKey )
1733 state.mnState |= KEY_MOD2;
1734 if( nState & cmdKey )
1735 state.mnState |= KEY_MOD1;
1738 return state;
1741 KeyIndicatorState AquaSalFrame::GetIndicatorState()
1743 return KeyIndicatorState::NONE;
1746 void AquaSalFrame::SimulateKeyPress( sal_uInt16 /*nKeyCode*/ )
1750 void AquaSalFrame::SetPluginParent( SystemParentData* )
1752 // plugin parent may be killed unexpectedly by
1753 // plugging process;
1755 //TODO: implement
1758 bool AquaSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , vcl::KeyCode& )
1760 // not supported yet
1761 return false;
1764 LanguageType AquaSalFrame::GetInputLanguage()
1766 //TODO: implement
1767 return LANGUAGE_DONTKNOW;
1770 void AquaSalFrame::SetMenu( SalMenu* pSalMenu )
1772 OSX_SALDATA_RUNINMAIN( SetMenu( pSalMenu ) )
1774 AquaSalMenu* pMenu = static_cast<AquaSalMenu*>(pSalMenu);
1775 SAL_WARN_IF( pMenu && !pMenu->mbMenuBar, "vcl", "setting non menubar on frame" );
1776 mpMenu = pMenu;
1777 if( mpMenu )
1778 mpMenu->setMainMenu();
1781 void AquaSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
1783 if ( !mpNSWindow )
1785 mnExtStyle = nStyle;
1786 return;
1789 OSX_SALDATA_RUNINMAIN( SetExtendedFrameStyle( nStyle ) )
1791 if( (mnExtStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) != (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) )
1792 [mpNSWindow setDocumentEdited: (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) ? YES : NO];
1794 mnExtStyle = nStyle;
1797 SalFrame* AquaSalFrame::GetParent() const
1799 return mpParent;
1802 void AquaSalFrame::SetParent( SalFrame* pNewParent )
1804 bool bShown = mbShown;
1805 // remove from child list
1806 if (bShown)
1807 Show(false);
1808 mpParent = static_cast<AquaSalFrame*>(pNewParent);
1809 // insert to correct parent and paint
1810 Show( bShown );
1813 void AquaSalFrame::UpdateFrameGeometry()
1815 bool bFirstTime = (mnTrackingRectTag == 0);
1816 mbGeometryDidChange = false;
1818 if ( !mpNSWindow )
1819 return;
1821 OSX_SALDATA_RUNINMAIN( UpdateFrameGeometry() )
1823 // keep in mind that view and window coordinates are lower left
1824 // whereas vcl's are upper left
1826 // update screen rect
1827 NSScreen * pScreen = [mpNSWindow screen];
1828 if( pScreen )
1830 NSRect aNewScreenRect = [pScreen frame];
1831 if (bFirstTime || !NSEqualRects(maScreenRect, aNewScreenRect))
1833 mbGeometryDidChange = true;
1834 maScreenRect = aNewScreenRect;
1836 NSArray* pScreens = [NSScreen screens];
1837 if( pScreens )
1839 unsigned int nNewDisplayScreenNumber = [pScreens indexOfObject: pScreen];
1840 if (bFirstTime || maGeometry.screen() != nNewDisplayScreenNumber)
1842 mbGeometryDidChange = true;
1843 maGeometry.setScreen(nNewDisplayScreenNumber);
1848 NSRect aFrameRect = [mpNSWindow frame];
1849 NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask];
1851 NSRect aTrackRect = { NSZeroPoint, aContentRect.size };
1853 if (bFirstTime || !NSEqualRects(maTrackingRect, aTrackRect))
1855 mbGeometryDidChange = true;
1856 maTrackingRect = aTrackRect;
1858 // release old track rect
1859 [mpNSView removeTrackingRect: mnTrackingRectTag];
1860 // install the new track rect
1861 mnTrackingRectTag = [mpNSView addTrackingRect: aTrackRect owner: mpNSView userData: nil assumeInside: NO];
1864 // convert to vcl convention
1865 CocoaToVCL( aFrameRect );
1866 CocoaToVCL( aContentRect );
1868 if (bFirstTime || !NSEqualRects(maContentRect, aContentRect) || !NSEqualRects(maFrameRect, aFrameRect))
1870 mbGeometryDidChange = true;
1872 maContentRect = aContentRect;
1873 maFrameRect = aFrameRect;
1875 maGeometry.setX(static_cast<sal_Int32>(aContentRect.origin.x));
1876 maGeometry.setY(static_cast<sal_Int32>(aContentRect.origin.y));
1877 maGeometry.setWidth(static_cast<sal_uInt32>(aContentRect.size.width));
1878 maGeometry.setHeight(static_cast<sal_uInt32>(aContentRect.size.height));
1880 maGeometry.setLeftDecoration(static_cast<sal_uInt32>(aContentRect.origin.x - aFrameRect.origin.x));
1881 maGeometry.setRightDecoration(static_cast<sal_uInt32>((aFrameRect.origin.x + aFrameRect.size.width) -
1882 (aContentRect.origin.x + aContentRect.size.width)));
1883 maGeometry.setTopDecoration(static_cast<sal_uInt32>(aContentRect.origin.y - aFrameRect.origin.y));
1884 maGeometry.setBottomDecoration(static_cast<sal_uInt32>((aFrameRect.origin.y + aFrameRect.size.height) -
1885 (aContentRect.origin.y + aContentRect.size.height)));
1889 void AquaSalFrame::CaptureMouse( bool bCapture )
1891 /* Remark:
1892 we'll try to use a pidgin version of capture mouse
1893 on MacOSX (neither carbon nor cocoa) there is a
1894 CaptureMouse equivalent (in Carbon there is TrackMouseLocation
1895 but this is useless to use since it is blocking)
1897 However on cocoa the active frame seems to get mouse events
1898 also outside the window, so we'll try to forward mouse events
1899 to the capture frame in the hope that one of our frames
1900 gets a mouse event.
1902 This will break as soon as the user activates another app, but
1903 a mouse click will normally lead to a release of the mouse anyway.
1905 Let's see how far we get this way. Alternatively we could use one
1906 large overlay window like we did for the carbon implementation,
1907 however that is resource intensive.
1910 if( bCapture )
1911 s_pCaptureFrame = this;
1912 else if( ! bCapture && s_pCaptureFrame == this )
1913 s_pCaptureFrame = nullptr;
1916 void AquaSalFrame::ResetClipRegion()
1918 doResetClipRegion();
1921 void AquaSalFrame::doResetClipRegion()
1923 if ( !mpNSWindow )
1924 return;
1926 OSX_SALDATA_RUNINMAIN( ResetClipRegion() )
1928 // release old path and indicate no clipping
1929 CGPathRelease( mrClippingPath );
1930 mrClippingPath = nullptr;
1932 if( mpNSView && mbShown )
1933 [mpNSView setNeedsDisplay: YES];
1934 [mpNSWindow setOpaque: YES];
1935 [mpNSWindow invalidateShadow];
1938 void AquaSalFrame::BeginSetClipRegion( sal_uInt32 nRects )
1940 if ( !mpNSWindow )
1941 return;
1943 OSX_SALDATA_RUNINMAIN( BeginSetClipRegion( nRects ) )
1945 // release old path
1946 if( mrClippingPath )
1948 CGPathRelease( mrClippingPath );
1949 mrClippingPath = nullptr;
1952 if( maClippingRects.size() > SAL_CLIPRECT_COUNT && nRects < maClippingRects.size() )
1954 std::vector<CGRect>().swap(maClippingRects);
1956 maClippingRects.clear();
1957 maClippingRects.reserve( nRects );
1960 void AquaSalFrame::UnionClipRegion(
1961 tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
1963 // #i113170# may not be the main thread if called from UNO API
1964 SalData::ensureThreadAutoreleasePool();
1966 if( nWidth && nHeight )
1968 NSRect aRect = { { static_cast<CGFloat>(nX), static_cast<CGFloat>(nY) }, { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) } };
1969 VCLToCocoa( aRect, false );
1970 maClippingRects.push_back( CGRectMake(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height) );
1974 void AquaSalFrame::EndSetClipRegion()
1976 if ( !mpNSWindow )
1977 return;
1979 OSX_SALDATA_RUNINMAIN( EndSetClipRegion() )
1981 if( ! maClippingRects.empty() )
1983 mrClippingPath = CGPathCreateMutable();
1984 CGPathAddRects( mrClippingPath, nullptr, maClippingRects.data(), maClippingRects.size() );
1986 if( mpNSView && mbShown )
1987 [mpNSView setNeedsDisplay: YES];
1988 [mpNSWindow setOpaque: (mrClippingPath != nullptr) ? NO : YES];
1989 [mpNSWindow setBackgroundColor: [NSColor clearColor]];
1990 // shadow is invalidated when view gets drawn again
1993 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */