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