bump product version to 6.4.0.3
[LibreOffice.git] / vcl / osx / salframe.cxx
blob1bd88a810bc0ce1f183366c3b6d529e03add154d
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 <osl/diagnose.h>
27 #include <osl/file.h>
29 #include <vcl/event.hxx>
30 #include <vcl/inputctx.hxx>
31 #include <vcl/svapp.hxx>
32 #include <vcl/window.hxx>
33 #include <vcl/syswin.hxx>
34 #include <vcl/settings.hxx>
36 #include <osx/saldata.hxx>
37 #include <quartz/salgdi.h>
38 #include <osx/salframe.h>
39 #include <osx/salmenu.h>
40 #include <osx/salinst.h>
41 #include <osx/salframeview.h>
42 #include <osx/a11yfactory.h>
43 #include <osx/runinmain.hxx>
44 #include <quartz/utils.h>
46 #include <salwtype.hxx>
48 #include <premac.h>
49 #include <objc/objc-runtime.h>
50 // needed for theming
51 // FIXME: move theming code to salnativewidgets.cxx
52 #include <Carbon/Carbon.h>
53 #include <postmac.h>
55 using namespace std;
57 AquaSalFrame* AquaSalFrame::s_pCaptureFrame = nullptr;
59 AquaSalFrame::AquaSalFrame( SalFrame* pParent, SalFrameStyleFlags salFrameStyle ) :
60 mpNSWindow(nil),
61 mpNSView(nil),
62 mpDockMenuEntry(nil),
63 mpGraphics(nullptr),
64 mpParent(nullptr),
65 mnMinWidth(0),
66 mnMinHeight(0),
67 mnMaxWidth(0),
68 mnMaxHeight(0),
69 mbGraphics(false),
70 mbFullScreen( false ),
71 mbShown(false),
72 mbInitShow(true),
73 mbPositioned(false),
74 mbSized(false),
75 mbPresentation( false ),
76 mnStyle( salFrameStyle ),
77 mnStyleMask( 0 ),
78 mnLastEventTime( 0 ),
79 mnLastModifierFlags( 0 ),
80 mpMenu( nullptr ),
81 mnExtStyle( 0 ),
82 mePointerStyle( PointerStyle::Arrow ),
83 mnTrackingRectTag( 0 ),
84 mrClippingPath( nullptr ),
85 mnICOptions( InputContextFlags::NONE )
87 mpParent = dynamic_cast<AquaSalFrame*>(pParent);
89 initWindowAndView();
91 SalData* pSalData = GetSalData();
92 pSalData->mpInstance->insertFrame( this );
95 AquaSalFrame::~AquaSalFrame()
97 if (mbFullScreen)
98 doShowFullScreen(false, maGeometry.nDisplayScreenNumber);
100 assert( GetSalData()->mpInstance->IsMainThread() );
102 // if the frame is destroyed and has the current menubar
103 // set the default menubar
104 if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu )
105 AquaSalMenu::setDefaultMenu();
107 // cleanup clipping stuff
108 doResetClipRegion();
110 [SalFrameView unsetMouseFrame: this];
112 SalData* pSalData = GetSalData();
113 pSalData->mpInstance->eraseFrame( this );
114 pSalData->maPresentationFrames.remove( this );
116 SAL_WARN_IF( this == s_pCaptureFrame, "vcl", "capture frame destroyed" );
117 if( this == s_pCaptureFrame )
118 s_pCaptureFrame = nullptr;
120 delete mpGraphics;
122 if( mpDockMenuEntry )
124 NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu();
125 // life cycle comment: the menu has ownership of the item, so no release
126 [pDock removeItem: mpDockMenuEntry];
127 if ([pDock numberOfItems] != 0
128 && [[pDock itemAtIndex: 0] isSeparatorItem])
130 [pDock removeItemAtIndex: 0];
133 if ( mpNSView ) {
134 [AquaA11yFactory revokeView: mpNSView];
135 [mpNSView release];
137 if ( mpNSWindow )
138 [mpNSWindow release];
141 void AquaSalFrame::initWindowAndView()
143 OSX_SALDATA_RUNINMAIN( initWindowAndView() )
145 // initialize mirroring parameters
146 // FIXME: screens changing
147 NSScreen* pNSScreen = [mpNSWindow screen];
148 if( pNSScreen == nil )
149 pNSScreen = [NSScreen mainScreen];
150 maScreenRect = [pNSScreen frame];
152 // calculate some default geometry
153 NSRect aVisibleRect = [pNSScreen visibleFrame];
154 CocoaToVCL( aVisibleRect );
156 maGeometry.nX = static_cast<int>(aVisibleRect.origin.x + aVisibleRect.size.width / 10);
157 maGeometry.nY = static_cast<int>(aVisibleRect.origin.y + aVisibleRect.size.height / 10);
158 maGeometry.nWidth = static_cast<unsigned int>(aVisibleRect.size.width * 0.8);
159 maGeometry.nHeight = static_cast<unsigned int>(aVisibleRect.size.height * 0.8);
161 // calculate style mask
162 SAL_WNODEPRECATED_DECLARATIONS_PUSH
163 // 'NSBorderlessWindowMask' is deprecated: first deprecated in macOS 10.12
164 // 'NSClosableWindowMask' is deprecated: first deprecated in macOS 10.12
165 // 'NSMiniaturizableWindowMask' is deprecated: first deprecated in macOS 10.12
166 // 'NSResizableWindowMask' is deprecated: first deprecated in macOS 10.12
167 // 'NSTitledWindowMask' is deprecated: first deprecated in macOS 10.12
168 if( (mnStyle & SalFrameStyleFlags::FLOAT) ||
169 (mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION) )
170 mnStyleMask = NSBorderlessWindowMask;
171 else if( mnStyle & SalFrameStyleFlags::DEFAULT )
173 mnStyleMask = NSTitledWindowMask |
174 NSMiniaturizableWindowMask |
175 NSResizableWindowMask |
176 NSClosableWindowMask;
177 // make default window "maximized"
178 maGeometry.nX = static_cast<int>(aVisibleRect.origin.x);
179 maGeometry.nY = static_cast<int>(aVisibleRect.origin.y);
180 maGeometry.nWidth = static_cast<int>(aVisibleRect.size.width);
181 maGeometry.nHeight = static_cast<int>(aVisibleRect.size.height);
182 mbPositioned = mbSized = true;
184 else
186 if( mnStyle & SalFrameStyleFlags::MOVEABLE )
188 mnStyleMask |= NSTitledWindowMask;
189 if( mpParent == nullptr )
190 mnStyleMask |= NSMiniaturizableWindowMask;
192 if( mnStyle & SalFrameStyleFlags::SIZEABLE )
193 mnStyleMask |= NSResizableWindowMask;
194 if( mnStyle & SalFrameStyleFlags::CLOSEABLE )
195 mnStyleMask |= NSClosableWindowMask;
196 // documentation says anything other than NSBorderlessWindowMask (=0)
197 // should also include NSTitledWindowMask;
198 if( mnStyleMask != 0 )
199 mnStyleMask |= NSTitledWindowMask;
201 SAL_WNODEPRECATED_DECLARATIONS_POP
203 if (Application::IsBitmapRendering())
204 return;
206 // #i91990# support GUI-less (daemon) execution
207 @try
209 mpNSWindow = [[SalFrameWindow alloc] initWithSalFrame: this];
210 mpNSView = [[SalFrameView alloc] initWithSalFrame: this];
212 @catch ( id )
214 std::abort();
217 if( mnStyle & SalFrameStyleFlags::TOOLTIP )
218 [mpNSWindow setIgnoresMouseEvents: YES];
219 else
220 [mpNSWindow setAcceptsMouseMovedEvents: YES];
221 [mpNSWindow setHasShadow: YES];
223 [mpNSWindow setDelegate: static_cast<id<NSWindowDelegate> >(mpNSWindow)];
225 [mpNSWindow setRestorable:NO];
226 const NSRect aRect = { NSZeroPoint, NSMakeSize( maGeometry.nWidth, maGeometry.nHeight )};
227 mnTrackingRectTag = [mpNSView addTrackingRect: aRect owner: mpNSView userData: nil assumeInside: NO];
229 maSysData.mpNSView = mpNSView;
231 UpdateFrameGeometry();
233 [mpNSWindow setContentView: mpNSView];
236 void AquaSalFrame::CocoaToVCL( NSRect& io_rRect, bool bRelativeToScreen )
238 if( bRelativeToScreen )
239 io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height);
240 else
241 io_rRect.origin.y = maGeometry.nHeight - (io_rRect.origin.y+io_rRect.size.height);
244 void AquaSalFrame::VCLToCocoa( NSRect& io_rRect, bool bRelativeToScreen )
246 if( bRelativeToScreen )
247 io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height);
248 else
249 io_rRect.origin.y = maGeometry.nHeight - (io_rRect.origin.y+io_rRect.size.height);
252 void AquaSalFrame::CocoaToVCL( NSPoint& io_rPoint, bool bRelativeToScreen )
254 if( bRelativeToScreen )
255 io_rPoint.y = maScreenRect.size.height - io_rPoint.y;
256 else
257 io_rPoint.y = maGeometry.nHeight - io_rPoint.y;
260 void AquaSalFrame::VCLToCocoa( NSPoint& io_rPoint, bool bRelativeToScreen )
262 if( bRelativeToScreen )
263 io_rPoint.y = maScreenRect.size.height - io_rPoint.y;
264 else
265 io_rPoint.y = maGeometry.nHeight - io_rPoint.y;
268 void AquaSalFrame::screenParametersChanged()
270 OSX_SALDATA_RUNINMAIN( screenParametersChanged() )
272 UpdateFrameGeometry();
274 if( mpGraphics )
275 mpGraphics->updateResolution();
277 if (!mbGeometryDidChange)
278 return;
280 CallCallback( SalEvent::DisplayChanged, nullptr );
283 SalGraphics* AquaSalFrame::AcquireGraphics()
285 if ( mbGraphics )
286 return nullptr;
288 if ( !mpGraphics )
290 mpGraphics = new AquaSalGraphics;
291 mpGraphics->SetWindowGraphics( this );
294 mbGraphics = TRUE;
295 return mpGraphics;
298 void AquaSalFrame::ReleaseGraphics( SalGraphics *pGraphics )
300 SAL_WARN_IF( pGraphics != mpGraphics, "vcl", "graphics released on wrong frame" );
301 mbGraphics = FALSE;
304 bool AquaSalFrame::PostEvent(std::unique_ptr<ImplSVEvent> pData)
306 GetSalData()->mpInstance->PostEvent( this, pData.release(), SalEvent::UserEvent );
307 return TRUE;
310 void AquaSalFrame::SetTitle(const OUString& rTitle)
312 if ( !mpNSWindow )
313 return;
315 OSX_SALDATA_RUNINMAIN( SetTitle(rTitle) )
317 // #i113170# may not be the main thread if called from UNO API
318 SalData::ensureThreadAutoreleasePool();
320 NSString* pTitle = CreateNSString( rTitle );
321 [mpNSWindow setTitle: pTitle];
323 // create an entry in the dock menu
324 const SalFrameStyleFlags nAppWindowStyle = SalFrameStyleFlags::CLOSEABLE | SalFrameStyleFlags::MOVEABLE;
325 if( mpParent == nullptr &&
326 (mnStyle & nAppWindowStyle) == nAppWindowStyle )
328 if( mpDockMenuEntry == nullptr )
330 NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu();
332 if ([pDock numberOfItems] != 0) {
333 NSMenuItem* pTopItem = [pDock itemAtIndex: 0];
334 if ( [pTopItem hasSubmenu] )
335 [pDock insertItem: [NSMenuItem separatorItem] atIndex: 0];
338 mpDockMenuEntry = [pDock insertItemWithTitle: pTitle
339 action: @selector(dockMenuItemTriggered:)
340 keyEquivalent: @""
341 atIndex: 0];
342 [mpDockMenuEntry setTarget: mpNSWindow];
344 // TODO: image (either the generic window image or an icon
345 // check mark (for "main" window ?)
347 else
348 [mpDockMenuEntry setTitle: pTitle];
351 if (pTitle)
352 [pTitle release];
355 void AquaSalFrame::SetIcon( sal_uInt16 )
359 void AquaSalFrame::SetRepresentedURL( const OUString& i_rDocURL )
361 OSX_SALDATA_RUNINMAIN( SetRepresentedURL( i_rDocURL ) )
363 if( comphelper::isFileUrl(i_rDocURL) )
365 OUString aSysPath;
366 osl_getSystemPathFromFileURL( i_rDocURL.pData, &aSysPath.pData );
367 NSString* pStr = CreateNSString( aSysPath );
368 if( pStr )
370 [pStr autorelease];
371 [mpNSWindow setRepresentedFilename: pStr];
376 void AquaSalFrame::initShow()
378 OSX_SALDATA_RUNINMAIN( initShow() )
380 mbInitShow = false;
381 if( ! mbPositioned && ! mbFullScreen )
383 tools::Rectangle aScreenRect;
384 GetWorkArea( aScreenRect );
385 if( mpParent ) // center relative to parent
387 // center on parent
388 long nNewX = mpParent->maGeometry.nX + (static_cast<long>(mpParent->maGeometry.nWidth) - static_cast<long>(maGeometry.nWidth))/2;
389 if( nNewX < aScreenRect.Left() )
390 nNewX = aScreenRect.Left();
391 if( long(nNewX + maGeometry.nWidth) > aScreenRect.Right() )
392 nNewX = aScreenRect.Right() - maGeometry.nWidth-1;
393 long nNewY = mpParent->maGeometry.nY + (static_cast<long>(mpParent->maGeometry.nHeight) - static_cast<long>(maGeometry.nHeight))/2;
394 if( nNewY < aScreenRect.Top() )
395 nNewY = aScreenRect.Top();
396 if( nNewY > aScreenRect.Bottom() )
397 nNewY = aScreenRect.Bottom() - maGeometry.nHeight-1;
398 SetPosSize( nNewX - mpParent->maGeometry.nX,
399 nNewY - mpParent->maGeometry.nY,
400 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
402 else if( ! (mnStyle & SalFrameStyleFlags::SIZEABLE) )
404 // center on screen
405 long nNewX = (aScreenRect.GetWidth() - maGeometry.nWidth)/2;
406 long nNewY = (aScreenRect.GetHeight() - maGeometry.nHeight)/2;
407 SetPosSize( nNewX, nNewY, 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
411 // make sure the view is present in the wrapper list before any children receive focus
412 [AquaA11yFactory registerView: mpNSView];
415 void AquaSalFrame::SendPaintEvent( const tools::Rectangle* pRect )
417 OSX_SALDATA_RUNINMAIN( SendPaintEvent( pRect ) )
419 SalPaintEvent aPaintEvt( 0, 0, maGeometry.nWidth, maGeometry.nHeight, true );
420 if( pRect )
422 aPaintEvt.mnBoundX = pRect->Left();
423 aPaintEvt.mnBoundY = pRect->Top();
424 aPaintEvt.mnBoundWidth = pRect->GetWidth();
425 aPaintEvt.mnBoundHeight = pRect->GetHeight();
428 CallCallback(SalEvent::Paint, &aPaintEvt);
431 void AquaSalFrame::Show(bool bVisible, bool bNoActivate)
433 if ( !mpNSWindow )
434 return;
436 OSX_SALDATA_RUNINMAIN( Show(bVisible, bNoActivate) )
438 mbShown = bVisible;
439 if(bVisible)
441 if( mbInitShow )
442 initShow();
444 CallCallback(SalEvent::Resize, nullptr);
445 // trigger filling our backbuffer
446 SendPaintEvent();
448 if( bNoActivate || [mpNSWindow canBecomeKeyWindow] == NO )
449 [mpNSWindow orderFront: NSApp];
450 else
451 [mpNSWindow makeKeyAndOrderFront: NSApp];
453 if( mpParent )
455 /* #i92674# #i96433# we do not want an invisible parent to show up (which adding a visible
456 child implicitly does). However we also do not want a parentless toolbar.
458 HACK: try to decide when we should not insert a child to its parent
459 floaters and ownerdraw windows have not yet shown up in cases where
460 we don't want the parent to become visible
462 if( mpParent->mbShown || (mnStyle & (SalFrameStyleFlags::OWNERDRAWDECORATION | SalFrameStyleFlags::FLOAT) ) )
464 [mpParent->mpNSWindow addChildWindow: mpNSWindow ordered: NSWindowAbove];
468 if( mbPresentation )
469 [mpNSWindow makeMainWindow];
471 else
473 // if the frame holding the current menubar gets hidden
474 // show the default menubar
475 if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu )
476 AquaSalMenu::setDefaultMenu();
478 // #i90440# #i94443# work around the focus going back to some other window
479 // if a child gets hidden for a parent window
480 if( mpParent && mpParent->mbShown && [mpNSWindow isKeyWindow] )
481 [mpParent->mpNSWindow makeKeyAndOrderFront: NSApp];
483 [SalFrameView unsetMouseFrame: this];
484 if( mpParent && [mpNSWindow parentWindow] == mpParent->mpNSWindow )
485 [mpParent->mpNSWindow removeChildWindow: mpNSWindow];
487 [mpNSWindow orderOut: NSApp];
491 void AquaSalFrame::SetMinClientSize( long nWidth, long nHeight )
493 OSX_SALDATA_RUNINMAIN( SetMinClientSize( nWidth, nHeight ) )
495 mnMinWidth = nWidth;
496 mnMinHeight = nHeight;
498 if( mpNSWindow )
500 // Always add the decoration as the dimension concerns only
501 // the content rectangle
502 nWidth += maGeometry.nLeftDecoration + maGeometry.nRightDecoration;
503 nHeight += maGeometry.nTopDecoration + maGeometry.nBottomDecoration;
505 NSSize aSize = { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) };
507 // Size of full window (content+structure) although we only
508 // have the client size in arguments
509 [mpNSWindow setMinSize: aSize];
513 void AquaSalFrame::SetMaxClientSize( long nWidth, long nHeight )
515 OSX_SALDATA_RUNINMAIN( SetMaxClientSize( nWidth, nHeight ) )
517 mnMaxWidth = nWidth;
518 mnMaxHeight = nHeight;
520 if( mpNSWindow )
522 // Always add the decoration as the dimension concerns only
523 // the content rectangle
524 nWidth += maGeometry.nLeftDecoration + maGeometry.nRightDecoration;
525 nHeight += maGeometry.nTopDecoration + maGeometry.nBottomDecoration;
527 // Carbon windows can't have a size greater than 32767x32767
528 if (nWidth>32767) nWidth=32767;
529 if (nHeight>32767) nHeight=32767;
531 NSSize aSize = { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) };
533 // Size of full window (content+structure) although we only
534 // have the client size in arguments
535 [mpNSWindow setMaxSize: aSize];
539 void AquaSalFrame::GetClientSize( long& rWidth, long& rHeight )
541 if (mbShown || mbInitShow || Application::IsBitmapRendering())
543 rWidth = maGeometry.nWidth;
544 rHeight = maGeometry.nHeight;
546 else
548 rWidth = 0;
549 rHeight = 0;
553 SalEvent AquaSalFrame::PreparePosSize(long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags)
555 SalEvent nEvent = SalEvent::NONE;
556 assert(mpNSWindow || Application::IsBitmapRendering());
558 if (nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y))
560 mbPositioned = true;
561 nEvent = SalEvent::Move;
564 if (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT))
566 mbSized = true;
567 nEvent = (nEvent == SalEvent::Move) ? SalEvent::MoveResize : SalEvent::Resize;
570 if (Application::IsBitmapRendering())
572 if (nFlags & SAL_FRAME_POSSIZE_X)
573 maGeometry.nX = nX;
574 if (nFlags & SAL_FRAME_POSSIZE_Y)
575 maGeometry.nY = nY;
576 if (nFlags & SAL_FRAME_POSSIZE_WIDTH)
578 maGeometry.nWidth = nWidth;
579 if (mnMaxWidth > 0 && maGeometry.nWidth > static_cast<unsigned int>(mnMaxWidth))
580 maGeometry.nWidth = mnMaxWidth;
581 if (mnMinWidth > 0 && maGeometry.nWidth < static_cast<unsigned int>(mnMinWidth))
582 maGeometry.nWidth = mnMinWidth;
584 if (nFlags & SAL_FRAME_POSSIZE_HEIGHT)
586 maGeometry.nHeight = nHeight;
587 if (mnMaxHeight > 0 && maGeometry.nHeight > static_cast<unsigned int>(mnMaxHeight))
588 maGeometry.nHeight = mnMaxHeight;
589 if (mnMinHeight > 0 && maGeometry.nHeight < static_cast<unsigned int>(mnMinHeight))
590 maGeometry.nHeight = mnMinHeight;
592 if (nEvent != SalEvent::NONE)
593 CallCallback(nEvent, nullptr);
596 return nEvent;
599 void AquaSalFrame::SetWindowState( const SalFrameState* pState )
601 if (!mpNSWindow && !Application::IsBitmapRendering())
602 return;
604 OSX_SALDATA_RUNINMAIN( SetWindowState( pState ) )
606 sal_uInt16 nFlags = 0;
607 nFlags |= ((pState->mnMask & WindowStateMask::X) ? SAL_FRAME_POSSIZE_X : 0);
608 nFlags |= ((pState->mnMask & WindowStateMask::Y) ? SAL_FRAME_POSSIZE_Y : 0);
609 nFlags |= ((pState->mnMask & WindowStateMask::Width) ? SAL_FRAME_POSSIZE_WIDTH : 0);
610 nFlags |= ((pState->mnMask & WindowStateMask::Height) ? SAL_FRAME_POSSIZE_HEIGHT : 0);
612 SalEvent nEvent = PreparePosSize(pState->mnX, pState->mnY, pState->mnWidth, pState->mnHeight, nFlags);
613 if (Application::IsBitmapRendering())
614 return;
616 // set normal state
617 NSRect aStateRect = [mpNSWindow frame];
618 aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask];
619 CocoaToVCL(aStateRect);
620 if (pState->mnMask & WindowStateMask::X)
621 aStateRect.origin.x = float(pState->mnX);
622 if (pState->mnMask & WindowStateMask::Y)
623 aStateRect.origin.y = float(pState->mnY);
624 if (pState->mnMask & WindowStateMask::Width)
625 aStateRect.size.width = float(pState->mnWidth);
626 if (pState->mnMask & WindowStateMask::Height)
627 aStateRect.size.height = float(pState->mnHeight);
628 VCLToCocoa(aStateRect);
629 aStateRect = [NSWindow frameRectForContentRect: aStateRect styleMask: mnStyleMask];
630 [mpNSWindow setFrame: aStateRect display: NO];
632 if (pState->mnState == WindowStateState::Minimized)
633 [mpNSWindow miniaturize: NSApp];
634 else if ([mpNSWindow isMiniaturized])
635 [mpNSWindow deminiaturize: NSApp];
637 /* ZOOMED is not really maximized (actually it toggles between a user set size and
638 the program specified one), but comes closest since the default behavior is
639 "maximized" if the user did not intervene
641 if (pState->mnState == WindowStateState::Maximized)
643 if (![mpNSWindow isZoomed])
644 [mpNSWindow zoom: NSApp];
646 else
648 if ([mpNSWindow isZoomed])
649 [mpNSWindow zoom: NSApp];
652 // get new geometry
653 UpdateFrameGeometry();
655 // send event that we were moved/sized
656 if( nEvent != SalEvent::NONE )
657 CallCallback( nEvent, nullptr );
659 if (mbShown)
661 // trigger filling our backbuffer
662 SendPaintEvent();
664 // tell the system the views need to be updated
665 [mpNSWindow display];
669 bool AquaSalFrame::GetWindowState( SalFrameState* pState )
671 if (!mpNSWindow)
673 if (Application::IsBitmapRendering())
675 pState->mnMask = WindowStateMask::X | WindowStateMask::Y
676 | WindowStateMask::Width | WindowStateMask::Height
677 | WindowStateMask::State;
678 pState->mnX = maGeometry.nX;
679 pState->mnY = maGeometry.nY;
680 pState->mnWidth = maGeometry.nWidth;
681 pState->mnHeight = maGeometry.nHeight;
682 pState->mnState = WindowStateState::Normal;
683 return TRUE;
685 return FALSE;
688 OSX_SALDATA_RUNINMAIN_UNION( GetWindowState( pState ), boolean )
690 pState->mnMask = WindowStateMask::X |
691 WindowStateMask::Y |
692 WindowStateMask::Width |
693 WindowStateMask::Height |
694 WindowStateMask::State;
696 NSRect aStateRect = [mpNSWindow frame];
697 aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask];
698 CocoaToVCL( aStateRect );
699 pState->mnX = long(aStateRect.origin.x);
700 pState->mnY = long(aStateRect.origin.y);
701 pState->mnWidth = long(aStateRect.size.width);
702 pState->mnHeight = long(aStateRect.size.height);
704 if( [mpNSWindow isMiniaturized] )
705 pState->mnState = WindowStateState::Minimized;
706 else if( ! [mpNSWindow isZoomed] )
707 pState->mnState = WindowStateState::Normal;
708 else
709 pState->mnState = WindowStateState::Maximized;
711 return TRUE;
714 void AquaSalFrame::SetScreenNumber(unsigned int nScreen)
716 if ( !mpNSWindow )
717 return;
719 OSX_SALDATA_RUNINMAIN( SetScreenNumber( nScreen ) )
721 NSArray* pScreens = [NSScreen screens];
722 NSScreen* pScreen = nil;
723 if( pScreens && nScreen < [pScreens count] )
725 // get new screen frame
726 pScreen = [pScreens objectAtIndex: nScreen];
727 NSRect aNewScreen = [pScreen frame];
729 // get current screen frame
730 pScreen = [mpNSWindow screen];
731 if( pScreen )
733 NSRect aCurScreen = [pScreen frame];
734 if( aCurScreen.origin.x != aNewScreen.origin.x ||
735 aCurScreen.origin.y != aNewScreen.origin.y )
737 NSRect aFrameRect = [mpNSWindow frame];
738 aFrameRect.origin.x += aNewScreen.origin.x - aCurScreen.origin.x;
739 aFrameRect.origin.y += aNewScreen.origin.y - aCurScreen.origin.y;
740 [mpNSWindow setFrame: aFrameRect display: NO];
741 UpdateFrameGeometry();
747 void AquaSalFrame::SetApplicationID( const OUString &/*rApplicationID*/ )
751 void AquaSalFrame::ShowFullScreen( bool bFullScreen, sal_Int32 nDisplay )
753 doShowFullScreen(bFullScreen, nDisplay);
756 void AquaSalFrame::doShowFullScreen( bool bFullScreen, sal_Int32 nDisplay )
758 if (!mpNSWindow)
760 if (Application::IsBitmapRendering() && bFullScreen)
761 SetPosSize(0, 0, 1024, 768, SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT);
762 return;
765 SAL_INFO("vcl.osx", OSL_THIS_FUNC << ": mbFullScreen=" << mbFullScreen << ", bFullScreen=" << bFullScreen);
767 if( mbFullScreen == bFullScreen )
768 return;
770 OSX_SALDATA_RUNINMAIN( ShowFullScreen( bFullScreen, nDisplay ) )
772 mbFullScreen = bFullScreen;
774 if( bFullScreen )
776 // hide the dock and the menubar if we are on the menu screen
777 // which is always on index 0 according to documentation
778 bool bHideMenu = (nDisplay == 0);
780 NSRect aNewContentRect = NSZeroRect;
781 // get correct screen
782 NSScreen* pScreen = nil;
783 NSArray* pScreens = [NSScreen screens];
784 if( pScreens )
786 if( nDisplay >= 0 && static_cast<unsigned int>(nDisplay) < [pScreens count] )
787 pScreen = [pScreens objectAtIndex: nDisplay];
788 else
790 // this means span all screens
791 bHideMenu = true;
792 NSEnumerator* pEnum = [pScreens objectEnumerator];
793 while( (pScreen = [pEnum nextObject]) != nil )
795 NSRect aScreenRect = [pScreen frame];
796 if( aScreenRect.origin.x < aNewContentRect.origin.x )
798 aNewContentRect.size.width += aNewContentRect.origin.x - aScreenRect.origin.x;
799 aNewContentRect.origin.x = aScreenRect.origin.x;
801 if( aScreenRect.origin.y < aNewContentRect.origin.y )
803 aNewContentRect.size.height += aNewContentRect.origin.y - aScreenRect.origin.y;
804 aNewContentRect.origin.y = aScreenRect.origin.y;
806 if( aScreenRect.origin.x + aScreenRect.size.width > aNewContentRect.origin.x + aNewContentRect.size.width )
807 aNewContentRect.size.width = aScreenRect.origin.x + aScreenRect.size.width - aNewContentRect.origin.x;
808 if( aScreenRect.origin.y + aScreenRect.size.height > aNewContentRect.origin.y + aNewContentRect.size.height )
809 aNewContentRect.size.height = aScreenRect.origin.y + aScreenRect.size.height - aNewContentRect.origin.y;
813 if( aNewContentRect.size.width == 0 && aNewContentRect.size.height == 0 )
815 if( pScreen == nil )
816 pScreen = [mpNSWindow screen];
817 if( pScreen == nil )
818 pScreen = [NSScreen mainScreen];
820 aNewContentRect = [pScreen frame];
823 if( bHideMenu )
824 [NSMenu setMenuBarVisible:NO];
826 maFullScreenRect = [mpNSWindow frame];
828 [mpNSWindow setFrame: [NSWindow frameRectForContentRect: aNewContentRect styleMask: mnStyleMask] display: mbShown ? YES : NO];
830 else
832 [mpNSWindow setFrame: maFullScreenRect display: mbShown ? YES : NO];
834 // show the dock and the menubar
835 [NSMenu setMenuBarVisible:YES];
838 UpdateFrameGeometry();
839 if (mbShown)
841 CallCallback(SalEvent::MoveResize, nullptr);
843 // trigger filling our backbuffer
844 SendPaintEvent();
848 void AquaSalFrame::StartPresentation( bool bStart )
850 if ( !mpNSWindow )
851 return;
853 OSX_SALDATA_RUNINMAIN( StartPresentation( bStart ) )
855 if( bStart )
857 GetSalData()->maPresentationFrames.push_back( this );
858 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
859 kIOPMAssertionLevelOn,
860 CFSTR("LibreOffice presentation running"),
861 &mnAssertionID);
862 [mpNSWindow setLevel: NSPopUpMenuWindowLevel];
863 if( mbShown )
864 [mpNSWindow makeMainWindow];
866 else
868 GetSalData()->maPresentationFrames.remove( this );
869 IOPMAssertionRelease(mnAssertionID);
870 [mpNSWindow setLevel: NSNormalWindowLevel];
874 void AquaSalFrame::SetAlwaysOnTop( bool )
878 void AquaSalFrame::ToTop(SalFrameToTop nFlags)
880 if ( !mpNSWindow )
881 return;
883 OSX_SALDATA_RUNINMAIN( ToTop( nFlags ) )
885 if( ! (nFlags & SalFrameToTop::RestoreWhenMin) )
887 if( ! [mpNSWindow isVisible] || [mpNSWindow isMiniaturized] )
888 return;
890 if( nFlags & SalFrameToTop::GrabFocus )
891 [mpNSWindow makeKeyAndOrderFront: NSApp];
892 else
893 [mpNSWindow orderFront: NSApp];
896 NSCursor* AquaSalFrame::getCurrentCursor()
898 OSX_SALDATA_RUNINMAIN_POINTER( getCurrentCursor(), NSCursor* )
900 NSCursor* pCursor = nil;
901 switch( mePointerStyle )
903 case PointerStyle::Text: pCursor = [NSCursor IBeamCursor]; break;
904 case PointerStyle::Cross: pCursor = [NSCursor crosshairCursor]; break;
905 case PointerStyle::Hand:
906 case PointerStyle::Move: pCursor = [NSCursor openHandCursor]; break;
907 case PointerStyle::NSize: pCursor = [NSCursor resizeUpCursor]; break;
908 case PointerStyle::SSize: pCursor = [NSCursor resizeDownCursor]; break;
909 case PointerStyle::ESize: pCursor = [NSCursor resizeRightCursor]; break;
910 case PointerStyle::WSize: pCursor = [NSCursor resizeLeftCursor]; break;
911 case PointerStyle::Arrow: pCursor = [NSCursor arrowCursor]; break;
912 case PointerStyle::VSplit:
913 case PointerStyle::VSizeBar:
914 case PointerStyle::WindowNSize:
915 case PointerStyle::WindowSSize:
916 pCursor = [NSCursor resizeUpDownCursor]; break;
917 case PointerStyle::HSplit:
918 case PointerStyle::HSizeBar:
919 case PointerStyle::WindowESize:
920 case PointerStyle::WindowWSize:
921 pCursor = [NSCursor resizeLeftRightCursor]; break;
922 case PointerStyle::RefHand: pCursor = [NSCursor pointingHandCursor]; break;
924 default:
925 pCursor = GetSalData()->getCursor( mePointerStyle );
926 if( pCursor == nil )
928 assert( false && "unmapped cursor" );
929 pCursor = [NSCursor arrowCursor];
931 break;
933 return pCursor;
936 void AquaSalFrame::SetPointer( PointerStyle ePointerStyle )
938 if ( !mpNSWindow )
939 return;
940 if( ePointerStyle == mePointerStyle )
941 return;
943 OSX_SALDATA_RUNINMAIN( SetPointer( ePointerStyle ) )
945 mePointerStyle = ePointerStyle;
947 [mpNSWindow invalidateCursorRectsForView: mpNSView];
950 void AquaSalFrame::SetPointerPos( long nX, long nY )
952 OSX_SALDATA_RUNINMAIN( SetPointerPos( nX, nY ) )
954 // FIXME: use Cocoa functions
955 // FIXME: multiscreen support
956 CGPoint aPoint = { static_cast<CGFloat>(nX + maGeometry.nX), static_cast<CGFloat>(nY + maGeometry.nY) };
957 CGDirectDisplayID mainDisplayID = CGMainDisplayID();
958 CGDisplayMoveCursorToPoint( mainDisplayID, aPoint );
961 void AquaSalFrame::Flush()
963 if( !(mbGraphics && mpGraphics && mpNSView && mbShown) )
964 return;
966 OSX_SALDATA_RUNINMAIN( Flush() )
968 [mpNSView setNeedsDisplay: YES];
970 // outside of the application's event loop (e.g. IntroWindow)
971 // nothing would trigger paint event handling
972 // => fall back to synchronous painting
973 if( ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
975 [mpNSView display];
979 void AquaSalFrame::Flush( const tools::Rectangle& rRect )
981 if( !(mbGraphics && mpGraphics && mpNSView && mbShown) )
982 return;
984 OSX_SALDATA_RUNINMAIN( Flush( rRect ) )
986 NSRect aNSRect = { { static_cast<CGFloat>(rRect.Left()), static_cast<CGFloat>(rRect.Top()) }, { static_cast<CGFloat>(rRect.GetWidth()), static_cast<CGFloat>(rRect.GetHeight()) } };
987 VCLToCocoa( aNSRect, false );
988 [mpNSView setNeedsDisplayInRect: aNSRect];
990 // outside of the application's event loop (e.g. IntroWindow)
991 // nothing would trigger paint event handling
992 // => fall back to synchronous painting
993 if( ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
995 [mpNSView display];
999 void AquaSalFrame::SetInputContext( SalInputContext* pContext )
1001 if (!pContext)
1003 mnICOptions = InputContextFlags::NONE;
1004 return;
1007 mnICOptions = pContext->mnOptions;
1009 if(!(pContext->mnOptions & InputContextFlags::Text))
1010 return;
1013 void AquaSalFrame::EndExtTextInput( EndExtTextInputFlags )
1017 OUString AquaSalFrame::GetKeyName( sal_uInt16 nKeyCode )
1019 static std::map< sal_uInt16, OUString > aKeyMap;
1020 if( aKeyMap.empty() )
1022 sal_uInt16 i;
1023 for( i = KEY_A; i <= KEY_Z; i++ )
1024 aKeyMap[ i ] = OUString( sal_Unicode( 'A' + (i - KEY_A) ) );
1025 for( i = KEY_0; i <= KEY_9; i++ )
1026 aKeyMap[ i ] = OUString( sal_Unicode( '0' + (i - KEY_0) ) );
1027 for( i = KEY_F1; i <= KEY_F26; i++ )
1029 aKeyMap[ i ] = "F" + OUString::number(i - KEY_F1 + 1);
1032 aKeyMap[ KEY_DOWN ] = OUString( u'\x21e3' );
1033 aKeyMap[ KEY_UP ] = OUString( u'\x21e1' );
1034 aKeyMap[ KEY_LEFT ] = OUString( u'\x21e0' );
1035 aKeyMap[ KEY_RIGHT ] = OUString( u'\x21e2' );
1036 aKeyMap[ KEY_HOME ] = OUString( u'\x2196' );
1037 aKeyMap[ KEY_END ] = OUString( u'\x2198' );
1038 aKeyMap[ KEY_PAGEUP ] = OUString( u'\x21de' );
1039 aKeyMap[ KEY_PAGEDOWN ] = OUString( u'\x21df' );
1040 aKeyMap[ KEY_RETURN ] = OUString( u'\x21a9' );
1041 aKeyMap[ KEY_ESCAPE ] = "esc";
1042 aKeyMap[ KEY_TAB ] = OUString( u'\x21e5' );
1043 aKeyMap[ KEY_BACKSPACE ]= OUString( u'\x232b' );
1044 aKeyMap[ KEY_SPACE ] = OUString( u'\x2423' );
1045 aKeyMap[ KEY_DELETE ] = OUString( u'\x2326' );
1046 aKeyMap[ KEY_ADD ] = "+";
1047 aKeyMap[ KEY_SUBTRACT ] = "-";
1048 aKeyMap[ KEY_DIVIDE ] = "/";
1049 aKeyMap[ KEY_MULTIPLY ] = "*";
1050 aKeyMap[ KEY_POINT ] = ".";
1051 aKeyMap[ KEY_COMMA ] = ",";
1052 aKeyMap[ KEY_LESS ] = "<";
1053 aKeyMap[ KEY_GREATER ] = ">";
1054 aKeyMap[ KEY_EQUAL ] = "=";
1055 aKeyMap[ KEY_OPEN ] = OUString( u'\x23cf' );
1056 aKeyMap[ KEY_TILDE ] = "~";
1057 aKeyMap[ KEY_BRACKETLEFT ] = "[";
1058 aKeyMap[ KEY_BRACKETRIGHT ] = "]";
1059 aKeyMap[ KEY_SEMICOLON ] = ";";
1060 aKeyMap[ KEY_QUOTERIGHT ] = "'";
1062 /* yet unmapped KEYCODES:
1063 aKeyMap[ KEY_INSERT ] = OUString( sal_Unicode( ) );
1064 aKeyMap[ KEY_CUT ] = OUString( sal_Unicode( ) );
1065 aKeyMap[ KEY_COPY ] = OUString( sal_Unicode( ) );
1066 aKeyMap[ KEY_PASTE ] = OUString( sal_Unicode( ) );
1067 aKeyMap[ KEY_UNDO ] = OUString( sal_Unicode( ) );
1068 aKeyMap[ KEY_REPEAT ] = OUString( sal_Unicode( ) );
1069 aKeyMap[ KEY_FIND ] = OUString( sal_Unicode( ) );
1070 aKeyMap[ KEY_PROPERTIES ] = OUString( sal_Unicode( ) );
1071 aKeyMap[ KEY_FRONT ] = OUString( sal_Unicode( ) );
1072 aKeyMap[ KEY_CONTEXTMENU ] = OUString( sal_Unicode( ) );
1073 aKeyMap[ KEY_MENU ] = OUString( sal_Unicode( ) );
1074 aKeyMap[ KEY_HELP ] = OUString( sal_Unicode( ) );
1075 aKeyMap[ KEY_HANGUL_HANJA ] = OUString( sal_Unicode( ) );
1076 aKeyMap[ KEY_DECIMAL ] = OUString( sal_Unicode( ) );
1077 aKeyMap[ KEY_QUOTELEFT ]= OUString( sal_Unicode( ) );
1078 aKeyMap[ KEY_CAPSLOCK ]= OUString( sal_Unicode( ) );
1079 aKeyMap[ KEY_NUMLOCK ]= OUString( sal_Unicode( ) );
1080 aKeyMap[ KEY_SCROLLLOCK ]= OUString( sal_Unicode( ) );
1085 OUStringBuffer aResult( 16 );
1087 sal_uInt16 nUnmodifiedCode = (nKeyCode & KEY_CODE_MASK);
1088 std::map< sal_uInt16, OUString >::const_iterator it = aKeyMap.find( nUnmodifiedCode );
1089 if( it != aKeyMap.end() )
1091 if( (nKeyCode & KEY_SHIFT) != 0 )
1092 aResult.append( u'\x21e7' ); //⇧
1093 if( (nKeyCode & KEY_MOD1) != 0 )
1094 aResult.append( u'\x2318' ); //⌘
1095 if( (nKeyCode & KEY_MOD2) != 0 )
1096 aResult.append( u'\x2325' ); //⌥
1097 if( (nKeyCode & KEY_MOD3) != 0 )
1098 aResult.append( u'\x2303' ); //⌃
1100 aResult.append( it->second );
1103 return aResult.makeStringAndClear();
1106 static void getAppleScrollBarVariant(StyleSettings &rSettings)
1108 bool bIsScrollbarDoubleMax = true; // default is DoubleMax
1110 CFStringRef AppleScrollBarType = CFSTR("AppleScrollBarVariant");
1111 if( AppleScrollBarType )
1113 CFStringRef ScrollBarVariant = static_cast<CFStringRef>(CFPreferencesCopyAppValue( AppleScrollBarType, kCFPreferencesCurrentApplication ));
1114 if( ScrollBarVariant )
1116 if( CFGetTypeID( ScrollBarVariant ) == CFStringGetTypeID() )
1118 // TODO: check for the less important variants "DoubleMin" and "DoubleBoth" too
1119 CFStringRef DoubleMax = CFSTR("DoubleMax");
1120 if (DoubleMax)
1122 if ( !CFStringCompare(ScrollBarVariant, DoubleMax, kCFCompareCaseInsensitive) )
1123 bIsScrollbarDoubleMax = true;
1124 else
1125 bIsScrollbarDoubleMax = false;
1126 CFRelease(DoubleMax);
1129 CFRelease( ScrollBarVariant );
1131 CFRelease(AppleScrollBarType);
1134 GetSalData()->mbIsScrollbarDoubleMax = bIsScrollbarDoubleMax;
1136 CFStringRef jumpScroll = CFSTR("AppleScrollerPagingBehavior");
1137 if( jumpScroll )
1139 CFBooleanRef jumpStr = static_cast<CFBooleanRef>(CFPreferencesCopyAppValue( jumpScroll, kCFPreferencesCurrentApplication ));
1140 if( jumpStr )
1142 if( CFGetTypeID( jumpStr ) == CFBooleanGetTypeID() )
1143 rSettings.SetPrimaryButtonWarpsSlider(jumpStr == kCFBooleanTrue);
1144 CFRelease( jumpStr );
1146 CFRelease( jumpScroll );
1150 static Color getColor( NSColor* pSysColor, const Color& rDefault, NSWindow* pWin )
1152 Color aRet( rDefault );
1153 if( pSysColor )
1155 // transform to RGB
1156 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1157 // "'colorUsingColorSpaceName:device:' is deprecated: first deprecated in macOS 10.14 -
1158 // Use -colorUsingType: or -colorUsingColorSpace: instead"
1159 NSColor* pRBGColor = [pSysColor colorUsingColorSpaceName: NSDeviceRGBColorSpace device: [pWin deviceDescription]];
1160 SAL_WNODEPRECATED_DECLARATIONS_POP
1161 if( pRBGColor )
1163 CGFloat r = 0, g = 0, b = 0, a = 0;
1164 [pRBGColor getRed: &r green: &g blue: &b alpha: &a];
1165 aRet = Color( int(r*255.999), int(g*255.999), int(b*255.999) );
1167 do not release here; leads to duplicate free in yield
1168 it seems the converted color comes out autoreleased, although this
1169 is not documented
1170 [pRBGColor release];
1174 return aRet;
1177 static vcl::Font getFont( NSFont* pFont, long nDPIY, const vcl::Font& rDefault )
1179 vcl::Font aResult( rDefault );
1180 if( pFont )
1182 aResult.SetFamilyName( GetOUString( [pFont familyName] ) );
1183 aResult.SetFontHeight( static_cast<int>(([pFont pointSize] * 72.0 / static_cast<float>(nDPIY))+0.5) );
1184 aResult.SetItalic( ([pFont italicAngle] != 0.0) ? ITALIC_NORMAL : ITALIC_NONE );
1185 // FIMXE: bold ?
1188 return aResult;
1191 void AquaSalFrame::getResolution( sal_Int32& o_rDPIX, sal_Int32& o_rDPIY )
1193 OSX_SALDATA_RUNINMAIN( getResolution( o_rDPIX, o_rDPIY ) )
1195 if( ! mpGraphics )
1197 AcquireGraphics();
1198 ReleaseGraphics( mpGraphics );
1200 mpGraphics->GetResolution( o_rDPIX, o_rDPIY );
1203 // on OSX-Aqua the style settings are independent of the frame, so it does
1204 // not really belong here. Since the connection to the Appearance_Manager
1205 // is currently done in salnativewidgets.cxx this would be a good place.
1206 // On the other hand VCL's platform independent code currently only asks
1207 // SalFrames for system settings anyway, so moving the code somewhere else
1208 // doesn't make the anything cleaner for now
1209 void AquaSalFrame::UpdateSettings( AllSettings& rSettings )
1211 if ( !mpNSWindow )
1212 return;
1214 OSX_SALDATA_RUNINMAIN( UpdateSettings( rSettings ) )
1216 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1217 // "'lockFocus' is deprecated: first deprecated in macOS 10.14 - To draw, subclass NSView
1218 // and implement -drawRect:; AppKit's automatic deferred display mechanism will call
1219 // -drawRect: as necessary to display the view."
1220 if (![mpNSView lockFocusIfCanDraw])
1221 return;
1222 SAL_WNODEPRECATED_DECLARATIONS_POP
1224 StyleSettings aStyleSettings = rSettings.GetStyleSettings();
1226 // Background Color
1227 Color aBackgroundColor( 0xEC, 0xEC, 0xEC );
1228 aStyleSettings.BatchSetBackgrounds( aBackgroundColor, false );
1229 aStyleSettings.SetLightBorderColor( aBackgroundColor );
1231 Color aInactiveTabColor( aBackgroundColor );
1232 aInactiveTabColor.DecreaseLuminance( 32 );
1233 aStyleSettings.SetInactiveTabColor( aInactiveTabColor );
1235 Color aShadowColor( aStyleSettings.GetShadowColor() );
1236 aShadowColor.IncreaseLuminance( 32 );
1237 aStyleSettings.SetShadowColor( aShadowColor );
1239 // get the system font settings
1240 vcl::Font aAppFont = aStyleSettings.GetAppFont();
1241 sal_Int32 nDPIX = 72, nDPIY = 72;
1242 getResolution( nDPIX, nDPIY );
1243 aAppFont = getFont( [NSFont systemFontOfSize: 0], nDPIY, aAppFont );
1245 aStyleSettings.SetToolbarIconSize( ToolbarIconSize::Large );
1247 // TODO: better mapping of macOS<->LibreOffice font settings
1248 vcl::Font aLabelFont( getFont( [NSFont labelFontOfSize: 0], nDPIY, aAppFont ) );
1249 aStyleSettings.BatchSetFonts( aAppFont, aLabelFont );
1250 vcl::Font aMenuFont( getFont( [NSFont menuFontOfSize: 0], nDPIY, aAppFont ) );
1251 aStyleSettings.SetMenuFont( aMenuFont );
1253 vcl::Font aTitleFont( getFont( [NSFont titleBarFontOfSize: 0], nDPIY, aAppFont ) );
1254 aStyleSettings.SetTitleFont( aTitleFont );
1255 aStyleSettings.SetFloatTitleFont( aTitleFont );
1257 vcl::Font aTooltipFont(getFont([NSFont toolTipsFontOfSize: 0], nDPIY, aAppFont));
1258 aStyleSettings.SetHelpFont(aTooltipFont);
1260 Color aHighlightColor( getColor( [NSColor selectedTextBackgroundColor],
1261 aStyleSettings.GetHighlightColor(), mpNSWindow ) );
1262 aStyleSettings.SetHighlightColor( aHighlightColor );
1263 Color aHighlightTextColor( getColor( [NSColor selectedTextColor],
1264 aStyleSettings.GetHighlightTextColor(), mpNSWindow ) );
1265 aStyleSettings.SetHighlightTextColor( aHighlightTextColor );
1267 Color aMenuHighlightColor( getColor( [NSColor selectedMenuItemColor],
1268 aStyleSettings.GetMenuHighlightColor(), mpNSWindow ) );
1269 aStyleSettings.SetMenuHighlightColor( aMenuHighlightColor );
1270 Color aMenuHighlightTextColor( getColor( [NSColor selectedMenuItemTextColor],
1271 aStyleSettings.GetMenuHighlightTextColor(), mpNSWindow ) );
1272 aStyleSettings.SetMenuHighlightTextColor( aMenuHighlightTextColor );
1274 aStyleSettings.SetMenuColor( aBackgroundColor );
1275 Color aMenuTextColor( getColor( [NSColor textColor],
1276 aStyleSettings.GetMenuTextColor(), mpNSWindow ) );
1277 aStyleSettings.SetMenuTextColor( aMenuTextColor );
1278 aStyleSettings.SetMenuBarTextColor( aMenuTextColor );
1279 aStyleSettings.SetMenuBarRolloverTextColor( aMenuTextColor );
1280 aStyleSettings.SetMenuBarHighlightTextColor(aStyleSettings.GetMenuHighlightTextColor());
1282 aStyleSettings.SetCursorBlinkTime( 500 );
1284 // no mnemonics on macOS
1285 aStyleSettings.SetOptions( aStyleSettings.GetOptions() | StyleSettingsOptions::NoMnemonics );
1287 getAppleScrollBarVariant(aStyleSettings);
1289 // set scrollbar size
1290 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1291 // 'NSRegularControlSize' is deprecated: first deprecated in macOS 10.12
1292 aStyleSettings.SetScrollBarSize( static_cast<long int>([NSScroller scrollerWidthForControlSize:NSRegularControlSize scrollerStyle:NSScrollerStyleLegacy]) );
1293 SAL_WNODEPRECATED_DECLARATIONS_POP
1294 // images in menus false for MacOSX
1295 aStyleSettings.SetPreferredUseImagesInMenus( false );
1296 aStyleSettings.SetHideDisabledMenuItems( true );
1297 aStyleSettings.SetPreferredContextMenuShortcuts( false );
1299 rSettings.SetStyleSettings( aStyleSettings );
1301 // don't draw frame around each and every toolbar
1302 ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames = true;
1304 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1305 // "'unlockFocus' is deprecated: first deprecated in macOS 10.14 - To draw, subclass NSView
1306 // and implement -drawRect:; AppKit's automatic deferred display mechanism will call
1307 // -drawRect: as necessary to display the view."
1308 [mpNSView unlockFocus];
1309 SAL_WNODEPRECATED_DECLARATIONS_POP
1312 const SystemEnvData* AquaSalFrame::GetSystemData() const
1314 return &maSysData;
1317 void AquaSalFrame::Beep()
1319 OSX_SALDATA_RUNINMAIN( Beep() )
1320 NSBeep();
1323 void AquaSalFrame::SetPosSize(long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags)
1325 if (!mpNSWindow && !Application::IsBitmapRendering())
1326 return;
1328 OSX_SALDATA_RUNINMAIN( SetPosSize( nX, nY, nWidth, nHeight, nFlags ) )
1330 SalEvent nEvent = PreparePosSize(nX, nY, nWidth, nHeight, nFlags);
1331 if (Application::IsBitmapRendering())
1332 return;
1334 if( [mpNSWindow isMiniaturized] )
1335 [mpNSWindow deminiaturize: NSApp]; // expand the window
1337 NSRect aFrameRect = [mpNSWindow frame];
1338 NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask];
1340 // position is always relative to parent frame
1341 NSRect aParentContentRect;
1343 if( mpParent )
1345 if( AllSettings::GetLayoutRTL() )
1347 if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
1348 nX = mpParent->maGeometry.nWidth - nWidth-1 - nX;
1349 else
1350 nX = mpParent->maGeometry.nWidth - static_cast<long int>( aContentRect.size.width-1) - nX;
1352 NSRect aParentFrameRect = [mpParent->mpNSWindow frame];
1353 aParentContentRect = [NSWindow contentRectForFrameRect: aParentFrameRect styleMask: mpParent->mnStyleMask];
1355 else
1356 aParentContentRect = maScreenRect; // use screen if no parent
1358 CocoaToVCL( aContentRect );
1359 CocoaToVCL( aParentContentRect );
1361 bool bPaint = false;
1362 if( (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) != 0 )
1364 if( nWidth != aContentRect.size.width || nHeight != aContentRect.size.height )
1365 bPaint = true;
1368 // use old window pos if no new pos requested
1369 if( (nFlags & SAL_FRAME_POSSIZE_X) != 0 )
1370 aContentRect.origin.x = nX + aParentContentRect.origin.x;
1371 if( (nFlags & SAL_FRAME_POSSIZE_Y) != 0)
1372 aContentRect.origin.y = nY + aParentContentRect.origin.y;
1374 // use old size if no new size requested
1375 if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
1376 aContentRect.size.width = nWidth;
1377 if( (nFlags & SAL_FRAME_POSSIZE_HEIGHT) != 0)
1378 aContentRect.size.height = nHeight;
1380 VCLToCocoa( aContentRect );
1382 // do not display yet, we need to update our backbuffer
1384 [mpNSWindow setFrame: [NSWindow frameRectForContentRect: aContentRect styleMask: mnStyleMask] display: NO];
1387 UpdateFrameGeometry();
1389 if (nEvent != SalEvent::NONE)
1390 CallCallback(nEvent, nullptr);
1392 if( mbShown && bPaint )
1394 // trigger filling our backbuffer
1395 SendPaintEvent();
1397 // now inform the system that the views need to be drawn
1398 [mpNSWindow display];
1402 void AquaSalFrame::GetWorkArea( tools::Rectangle& rRect )
1404 if (!mpNSWindow)
1406 if (Application::IsBitmapRendering())
1407 rRect = tools::Rectangle(Point(0, 0), Size(1024, 768));
1408 return;
1411 OSX_SALDATA_RUNINMAIN( GetWorkArea( rRect ) )
1413 NSScreen* pScreen = [mpNSWindow screen];
1414 if( pScreen == nil )
1415 pScreen = [NSScreen mainScreen];
1416 NSRect aRect = [pScreen visibleFrame];
1417 CocoaToVCL( aRect );
1418 rRect.SetLeft( static_cast<long>(aRect.origin.x) );
1419 rRect.SetTop( static_cast<long>(aRect.origin.y) );
1420 rRect.SetRight( static_cast<long>(aRect.origin.x + aRect.size.width - 1) );
1421 rRect.SetBottom( static_cast<long>(aRect.origin.y + aRect.size.height - 1) );
1424 SalFrame::SalPointerState AquaSalFrame::GetPointerState()
1426 OSX_SALDATA_RUNINMAIN_UNION( GetPointerState(), state )
1428 SalPointerState state;
1429 state.mnState = 0;
1431 // get position
1432 NSPoint aPt = [mpNSWindow mouseLocationOutsideOfEventStream];
1433 CocoaToVCL( aPt, false );
1434 state.maPos = Point(static_cast<long>(aPt.x), static_cast<long>(aPt.y));
1436 NSEvent* pCur = [NSApp currentEvent];
1437 bool bMouseEvent = false;
1438 if( pCur )
1440 bMouseEvent = true;
1441 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1442 // 'NSLeftMouseDown' is deprecated: first deprecated in macOS 10.12
1443 // 'NSLeftMouseDragged' is deprecated: first deprecated in macOS 10.12
1444 // 'NSLeftMouseUp' is deprecated: first deprecated in macOS 10.12
1445 // 'NSMouseMoved' is deprecated: first deprecated in macOS 10.12
1446 // 'NSOtherMouseDown' is deprecated: first deprecated in macOS 10.12
1447 // 'NSOtherMouseDragged' is deprecated: first deprecated in macOS 10.12
1448 // 'NSOtherMouseUp' is deprecated: first deprecated in macOS 10.12
1449 // 'NSRightMouseDown' is deprecated: first deprecated in macOS 10.12
1450 // 'NSRightMouseDragged' is deprecated: first deprecated in macOS 10.12
1451 // 'NSRightMouseUp' is deprecated: first deprecated in macOS 10.12
1452 switch( [pCur type] )
1454 case NSLeftMouseDown: state.mnState |= MOUSE_LEFT; break;
1455 case NSLeftMouseUp: break;
1456 case NSRightMouseDown: state.mnState |= MOUSE_RIGHT; break;
1457 case NSRightMouseUp: break;
1458 case NSOtherMouseDown: state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0; break;
1459 case NSOtherMouseUp: break;
1460 case NSMouseMoved: break;
1461 case NSLeftMouseDragged: state.mnState |= MOUSE_LEFT; break;
1462 case NSRightMouseDragged: state.mnState |= MOUSE_RIGHT; break;
1463 case NSOtherMouseDragged: state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0; break;
1464 break;
1465 default:
1466 bMouseEvent = false;
1467 break;
1469 SAL_WNODEPRECATED_DECLARATIONS_POP
1471 if( bMouseEvent )
1473 unsigned int nMask = static_cast<unsigned int>([pCur modifierFlags]);
1474 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1475 // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12
1476 // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12
1477 // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12
1478 // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12
1479 if( (nMask & NSShiftKeyMask) != 0 )
1480 state.mnState |= KEY_SHIFT;
1481 if( (nMask & NSControlKeyMask) != 0 )
1482 state.mnState |= KEY_MOD3;
1483 if( (nMask & NSAlternateKeyMask) != 0 )
1484 state.mnState |= KEY_MOD2;
1485 if( (nMask & NSCommandKeyMask) != 0 )
1486 state.mnState |= KEY_MOD1;
1487 SAL_WNODEPRECATED_DECLARATIONS_POP
1490 else
1492 // FIXME: replace Carbon by Cocoa
1493 // Cocoa does not have an equivalent for GetCurrentEventButtonState
1494 // and GetCurrentEventKeyModifiers.
1495 // we could try to get away with tracking all events for modifierKeys
1496 // and all mouse events for button state in VCL_NSApplication::sendEvent,
1497 // but it is unclear whether this will get us the same result.
1498 // leave in GetCurrentEventButtonState and GetCurrentEventKeyModifiers for now
1500 // fill in button state
1501 UInt32 nState = GetCurrentEventButtonState();
1502 state.mnState = 0;
1503 if( nState & 1 )
1504 state.mnState |= MOUSE_LEFT; // primary button
1505 if( nState & 2 )
1506 state.mnState |= MOUSE_RIGHT; // secondary button
1507 if( nState & 4 )
1508 state.mnState |= MOUSE_MIDDLE; // tertiary button
1510 // fill in modifier state
1511 nState = GetCurrentEventKeyModifiers();
1512 if( nState & shiftKey )
1513 state.mnState |= KEY_SHIFT;
1514 if( nState & controlKey )
1515 state.mnState |= KEY_MOD3;
1516 if( nState & optionKey )
1517 state.mnState |= KEY_MOD2;
1518 if( nState & cmdKey )
1519 state.mnState |= KEY_MOD1;
1522 return state;
1525 KeyIndicatorState AquaSalFrame::GetIndicatorState()
1527 return KeyIndicatorState::NONE;
1530 void AquaSalFrame::SimulateKeyPress( sal_uInt16 /*nKeyCode*/ )
1534 bool AquaSalFrame::SetPluginParent( SystemParentData* )
1536 // plugin parent may be killed unexpectedly by
1537 // plugging process;
1539 //TODO: implement
1540 return false;
1543 bool AquaSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , vcl::KeyCode& )
1545 // not supported yet
1546 return FALSE;
1549 LanguageType AquaSalFrame::GetInputLanguage()
1551 //TODO: implement
1552 return LANGUAGE_DONTKNOW;
1555 void AquaSalFrame::DrawMenuBar()
1559 void AquaSalFrame::SetMenu( SalMenu* pSalMenu )
1561 OSX_SALDATA_RUNINMAIN( SetMenu( pSalMenu ) )
1563 AquaSalMenu* pMenu = static_cast<AquaSalMenu*>(pSalMenu);
1564 SAL_WARN_IF( pMenu && !pMenu->mbMenuBar, "vcl", "setting non menubar on frame" );
1565 mpMenu = pMenu;
1566 if( mpMenu )
1567 mpMenu->setMainMenu();
1570 void AquaSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
1572 if ( !mpNSWindow )
1574 mnExtStyle = nStyle;
1575 return;
1578 OSX_SALDATA_RUNINMAIN( SetExtendedFrameStyle( nStyle ) )
1580 if( (mnExtStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) != (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) )
1581 [mpNSWindow setDocumentEdited: (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) ? YES : NO];
1583 mnExtStyle = nStyle;
1586 SalFrame* AquaSalFrame::GetParent() const
1588 return mpParent;
1591 void AquaSalFrame::SetParent( SalFrame* pNewParent )
1593 bool bShown = mbShown;
1594 // remove from child list
1595 if (bShown)
1596 Show(FALSE);
1597 mpParent = static_cast<AquaSalFrame*>(pNewParent);
1598 // insert to correct parent and paint
1599 Show( bShown );
1602 void AquaSalFrame::UpdateFrameGeometry()
1604 bool bFirstTime = (mnTrackingRectTag == 0);
1605 mbGeometryDidChange = false;
1607 if ( !mpNSWindow )
1608 return;
1610 OSX_SALDATA_RUNINMAIN( UpdateFrameGeometry() )
1612 // keep in mind that view and window coordinates are lower left
1613 // whereas vcl's are upper left
1615 // update screen rect
1616 NSScreen * pScreen = [mpNSWindow screen];
1617 if( pScreen )
1619 NSRect aNewScreenRect = [pScreen frame];
1620 if (bFirstTime || !NSEqualRects(maScreenRect, aNewScreenRect))
1622 mbGeometryDidChange = true;
1623 maScreenRect = aNewScreenRect;
1625 NSArray* pScreens = [NSScreen screens];
1626 if( pScreens )
1628 unsigned int nNewDisplayScreenNumber = [pScreens indexOfObject: pScreen];
1629 if (bFirstTime || maGeometry.nDisplayScreenNumber != nNewDisplayScreenNumber)
1631 mbGeometryDidChange = true;
1632 maGeometry.nDisplayScreenNumber = nNewDisplayScreenNumber;
1637 NSRect aFrameRect = [mpNSWindow frame];
1638 NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask];
1640 NSRect aTrackRect = { NSZeroPoint, aContentRect.size };
1642 if (bFirstTime || !NSEqualRects(maTrackingRect, aTrackRect))
1644 mbGeometryDidChange = true;
1645 maTrackingRect = aTrackRect;
1647 // release old track rect
1648 [mpNSView removeTrackingRect: mnTrackingRectTag];
1649 // install the new track rect
1650 mnTrackingRectTag = [mpNSView addTrackingRect: aTrackRect owner: mpNSView userData: nil assumeInside: NO];
1653 // convert to vcl convention
1654 CocoaToVCL( aFrameRect );
1655 CocoaToVCL( aContentRect );
1657 if (bFirstTime || !NSEqualRects(maContentRect, aContentRect) || !NSEqualRects(maFrameRect, aFrameRect))
1659 mbGeometryDidChange = true;
1661 maContentRect = aContentRect;
1662 maFrameRect = aFrameRect;
1664 maGeometry.nX = static_cast<int>(aContentRect.origin.x);
1665 maGeometry.nY = static_cast<int>(aContentRect.origin.y);
1667 maGeometry.nLeftDecoration = static_cast<unsigned int>(aContentRect.origin.x - aFrameRect.origin.x);
1668 maGeometry.nRightDecoration = static_cast<unsigned int>((aFrameRect.origin.x + aFrameRect.size.width) -
1669 (aContentRect.origin.x + aContentRect.size.width));
1671 maGeometry.nTopDecoration = static_cast<unsigned int>(aContentRect.origin.y - aFrameRect.origin.y);
1672 maGeometry.nBottomDecoration = static_cast<unsigned int>((aFrameRect.origin.y + aFrameRect.size.height) -
1673 (aContentRect.origin.y + aContentRect.size.height));
1675 maGeometry.nWidth = static_cast<unsigned int>(aContentRect.size.width);
1676 maGeometry.nHeight = static_cast<unsigned int>(aContentRect.size.height);
1680 void AquaSalFrame::CaptureMouse( bool bCapture )
1682 /* Remark:
1683 we'll try to use a pidgin version of capture mouse
1684 on MacOSX (neither carbon nor cocoa) there is a
1685 CaptureMouse equivalent (in Carbon there is TrackMouseLocation
1686 but this is useless to use since it is blocking)
1688 However on cocoa the active frame seems to get mouse events
1689 also outside the window, so we'll try to forward mouse events
1690 to the capture frame in the hope that one of our frames
1691 gets a mouse event.
1693 This will break as soon as the user activates another app, but
1694 a mouse click will normally lead to a release of the mouse anyway.
1696 Let's see how far we get this way. Alternatively we could use one
1697 large overlay window like we did for the carbon implementation,
1698 however that is resource intensive.
1701 if( bCapture )
1702 s_pCaptureFrame = this;
1703 else if( ! bCapture && s_pCaptureFrame == this )
1704 s_pCaptureFrame = nullptr;
1707 void AquaSalFrame::ResetClipRegion()
1709 doResetClipRegion();
1712 void AquaSalFrame::doResetClipRegion()
1714 if ( !mpNSWindow )
1715 return;
1717 OSX_SALDATA_RUNINMAIN( ResetClipRegion() )
1719 // release old path and indicate no clipping
1720 CGPathRelease( mrClippingPath );
1721 mrClippingPath = nullptr;
1723 if( mpNSView && mbShown )
1724 [mpNSView setNeedsDisplay: YES];
1725 [mpNSWindow setOpaque: YES];
1726 [mpNSWindow invalidateShadow];
1729 void AquaSalFrame::BeginSetClipRegion( sal_uInt32 nRects )
1731 if ( !mpNSWindow )
1732 return;
1734 OSX_SALDATA_RUNINMAIN( BeginSetClipRegion( nRects ) )
1736 // release old path
1737 if( mrClippingPath )
1739 CGPathRelease( mrClippingPath );
1740 mrClippingPath = nullptr;
1743 if( maClippingRects.size() > SAL_CLIPRECT_COUNT && nRects < maClippingRects.size() )
1745 std::vector<CGRect> aEmptyVec;
1746 maClippingRects.swap( aEmptyVec );
1748 maClippingRects.clear();
1749 maClippingRects.reserve( nRects );
1752 void AquaSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
1754 // #i113170# may not be the main thread if called from UNO API
1755 SalData::ensureThreadAutoreleasePool();
1757 if( nWidth && nHeight )
1759 NSRect aRect = { { static_cast<CGFloat>(nX), static_cast<CGFloat>(nY) }, { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) } };
1760 VCLToCocoa( aRect, false );
1761 maClippingRects.push_back( CGRectMake(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height) );
1765 void AquaSalFrame::EndSetClipRegion()
1767 if ( !mpNSWindow )
1768 return;
1770 OSX_SALDATA_RUNINMAIN( EndSetClipRegion() )
1772 if( ! maClippingRects.empty() )
1774 mrClippingPath = CGPathCreateMutable();
1775 CGPathAddRects( mrClippingPath, nullptr, maClippingRects.data(), maClippingRects.size() );
1777 if( mpNSView && mbShown )
1778 [mpNSView setNeedsDisplay: YES];
1779 [mpNSWindow setOpaque: (mrClippingPath != nullptr) ? NO : YES];
1780 [mpNSWindow setBackgroundColor: [NSColor clearColor]];
1781 // shadow is invalidated when view gets drawn again
1784 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */