1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <string>
21
22 #include <comphelper/fileurl.hxx>
23 #include <rtl/ustrbuf.hxx>
24 #include <sal/log.hxx>
25 #include <osl/diagnose.h>
26
27 #include <osl/file.h>
28
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>
35
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>
45
46 #include <salwtype.hxx>
47
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>
54
55 using namespace std;
56
57 AquaSalFrame* AquaSalFrame::s_pCaptureFrame = nullptr;
58
AquaSalFrame(SalFrame * pParent,SalFrameStyleFlags salFrameStyle)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 ),
86 mnBlinkCursorDelay ( 500 )
87 {
88 mpParent = dynamic_cast<AquaSalFrame*>(pParent);
89
90 initWindowAndView();
91
92 SalData* pSalData = GetSalData();
93 pSalData->mpInstance->insertFrame( this );
94 NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
95 if (userDefaults != nil)
96 {
97 id setting = [userDefaults objectForKey: @"NSTextInsertionPointBlinkPeriodOn"];
98 if (setting)
99 mnBlinkCursorDelay = [setting intValue];
100 else
101 {
102 setting = [userDefaults objectForKey: @"NSTextInsertionPointBlinkPeriodOff"];
103 if (setting)
104 mnBlinkCursorDelay = [setting intValue];
105 }
106 }
107 }
108
~AquaSalFrame()109 AquaSalFrame::~AquaSalFrame()
110 {
111 if (mbFullScreen)
112 doShowFullScreen(false, maGeometry.nDisplayScreenNumber);
113
114 assert( GetSalData()->mpInstance->IsMainThread() );
115
116 // if the frame is destroyed and has the current menubar
117 // set the default menubar
118 if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu )
119 AquaSalMenu::setDefaultMenu();
120
121 // cleanup clipping stuff
122 doResetClipRegion();
123
124 [SalFrameView unsetMouseFrame: this];
125
126 SalData* pSalData = GetSalData();
127 pSalData->mpInstance->eraseFrame( this );
128 pSalData->maPresentationFrames.remove( this );
129
130 SAL_WARN_IF( this == s_pCaptureFrame, "vcl", "capture frame destroyed" );
131 if( this == s_pCaptureFrame )
132 s_pCaptureFrame = nullptr;
133
134 delete mpGraphics;
135
136 if( mpDockMenuEntry )
137 {
138 NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu();
139 // life cycle comment: the menu has ownership of the item, so no release
140 [pDock removeItem: mpDockMenuEntry];
141 if ([pDock numberOfItems] != 0
142 && [[pDock itemAtIndex: 0] isSeparatorItem])
143 {
144 [pDock removeItemAtIndex: 0];
145 }
146 }
147 if ( mpNSView ) {
148 [AquaA11yFactory revokeView: mpNSView];
149 [mpNSView release];
150 }
151 if ( mpNSWindow )
152 [mpNSWindow release];
153 }
154
initWindowAndView()155 void AquaSalFrame::initWindowAndView()
156 {
157 OSX_SALDATA_RUNINMAIN( initWindowAndView() )
158
159 // initialize mirroring parameters
160 // FIXME: screens changing
161 NSScreen* pNSScreen = [mpNSWindow screen];
162 if( pNSScreen == nil )
163 pNSScreen = [NSScreen mainScreen];
164 maScreenRect = [pNSScreen frame];
165
166 // calculate some default geometry
167 NSRect aVisibleRect = [pNSScreen visibleFrame];
168 CocoaToVCL( aVisibleRect );
169
170 maGeometry.nX = static_cast<int>(aVisibleRect.origin.x + aVisibleRect.size.width / 10);
171 maGeometry.nY = static_cast<int>(aVisibleRect.origin.y + aVisibleRect.size.height / 10);
172 maGeometry.nWidth = static_cast<unsigned int>(aVisibleRect.size.width * 0.8);
173 maGeometry.nHeight = static_cast<unsigned int>(aVisibleRect.size.height * 0.8);
174
175 // calculate style mask
176 SAL_WNODEPRECATED_DECLARATIONS_PUSH
177 // 'NSBorderlessWindowMask' is deprecated: first deprecated in macOS 10.12
178 // 'NSClosableWindowMask' is deprecated: first deprecated in macOS 10.12
179 // 'NSMiniaturizableWindowMask' is deprecated: first deprecated in macOS 10.12
180 // 'NSResizableWindowMask' is deprecated: first deprecated in macOS 10.12
181 // 'NSTitledWindowMask' is deprecated: first deprecated in macOS 10.12
182 if( (mnStyle & SalFrameStyleFlags::FLOAT) ||
183 (mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION) )
184 mnStyleMask = NSBorderlessWindowMask;
185 else if( mnStyle & SalFrameStyleFlags::DEFAULT )
186 {
187 mnStyleMask = NSTitledWindowMask |
188 NSMiniaturizableWindowMask |
189 NSResizableWindowMask |
190 NSClosableWindowMask;
191 // make default window "maximized"
192 maGeometry.nX = static_cast<int>(aVisibleRect.origin.x);
193 maGeometry.nY = static_cast<int>(aVisibleRect.origin.y);
194 maGeometry.nWidth = static_cast<int>(aVisibleRect.size.width);
195 maGeometry.nHeight = static_cast<int>(aVisibleRect.size.height);
196 mbPositioned = mbSized = true;
197 }
198 else
199 {
200 if( mnStyle & SalFrameStyleFlags::MOVEABLE )
201 {
202 mnStyleMask |= NSTitledWindowMask;
203 if( mpParent == nullptr )
204 mnStyleMask |= NSMiniaturizableWindowMask;
205 }
206 if( mnStyle & SalFrameStyleFlags::SIZEABLE )
207 mnStyleMask |= NSResizableWindowMask;
208 if( mnStyle & SalFrameStyleFlags::CLOSEABLE )
209 mnStyleMask |= NSClosableWindowMask;
210 // documentation says anything other than NSBorderlessWindowMask (=0)
211 // should also include NSTitledWindowMask;
212 if( mnStyleMask != 0 )
213 mnStyleMask |= NSTitledWindowMask;
214 }
215 SAL_WNODEPRECATED_DECLARATIONS_POP
216
217 if (Application::IsBitmapRendering())
218 return;
219
220 // #i91990# support GUI-less (daemon) execution
221 @try
222 {
223 mpNSWindow = [[SalFrameWindow alloc] initWithSalFrame: this];
224 mpNSView = [[SalFrameView alloc] initWithSalFrame: this];
225 }
226 @catch ( id )
227 {
228 std::abort();
229 }
230
231 if( mnStyle & SalFrameStyleFlags::TOOLTIP )
232 [mpNSWindow setIgnoresMouseEvents: YES];
233 else
234 [mpNSWindow setAcceptsMouseMovedEvents: YES];
235 [mpNSWindow setHasShadow: YES];
236
237 [mpNSWindow setDelegate: static_cast<id<NSWindowDelegate> >(mpNSWindow)];
238
239 [mpNSWindow setRestorable:NO];
240 const NSRect aRect = { NSZeroPoint, NSMakeSize( maGeometry.nWidth, maGeometry.nHeight )};
241 mnTrackingRectTag = [mpNSView addTrackingRect: aRect owner: mpNSView userData: nil assumeInside: NO];
242
243 maSysData.mpNSView = mpNSView;
244
245 UpdateFrameGeometry();
246
247 [mpNSWindow setContentView: mpNSView];
248 }
249
CocoaToVCL(NSRect & io_rRect,bool bRelativeToScreen)250 void AquaSalFrame::CocoaToVCL( NSRect& io_rRect, bool bRelativeToScreen )
251 {
252 if( bRelativeToScreen )
253 io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height);
254 else
255 io_rRect.origin.y = maGeometry.nHeight - (io_rRect.origin.y+io_rRect.size.height);
256 }
257
VCLToCocoa(NSRect & io_rRect,bool bRelativeToScreen)258 void AquaSalFrame::VCLToCocoa( NSRect& io_rRect, bool bRelativeToScreen )
259 {
260 if( bRelativeToScreen )
261 io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height);
262 else
263 io_rRect.origin.y = maGeometry.nHeight - (io_rRect.origin.y+io_rRect.size.height);
264 }
265
CocoaToVCL(NSPoint & io_rPoint,bool bRelativeToScreen)266 void AquaSalFrame::CocoaToVCL( NSPoint& io_rPoint, bool bRelativeToScreen )
267 {
268 if( bRelativeToScreen )
269 io_rPoint.y = maScreenRect.size.height - io_rPoint.y;
270 else
271 io_rPoint.y = maGeometry.nHeight - io_rPoint.y;
272 }
273
VCLToCocoa(NSPoint & io_rPoint,bool bRelativeToScreen)274 void AquaSalFrame::VCLToCocoa( NSPoint& io_rPoint, bool bRelativeToScreen )
275 {
276 if( bRelativeToScreen )
277 io_rPoint.y = maScreenRect.size.height - io_rPoint.y;
278 else
279 io_rPoint.y = maGeometry.nHeight - io_rPoint.y;
280 }
281
screenParametersChanged()282 void AquaSalFrame::screenParametersChanged()
283 {
284 OSX_SALDATA_RUNINMAIN( screenParametersChanged() )
285
286 UpdateFrameGeometry();
287
288 if( mpGraphics )
289 mpGraphics->updateResolution();
290
291 if (!mbGeometryDidChange)
292 return;
293
294 CallCallback( SalEvent::DisplayChanged, nullptr );
295 }
296
AcquireGraphics()297 SalGraphics* AquaSalFrame::AcquireGraphics()
298 {
299 if ( mbGraphics )
300 return nullptr;
301
302 if ( !mpGraphics )
303 {
304 mpGraphics = new AquaSalGraphics;
305 mpGraphics->SetWindowGraphics( this );
306 }
307
308 mbGraphics = TRUE;
309 return mpGraphics;
310 }
311
ReleaseGraphics(SalGraphics * pGraphics)312 void AquaSalFrame::ReleaseGraphics( SalGraphics *pGraphics )
313 {
314 SAL_WARN_IF( pGraphics != mpGraphics, "vcl", "graphics released on wrong frame" );
315 mbGraphics = FALSE;
316 }
317
PostEvent(std::unique_ptr<ImplSVEvent> pData)318 bool AquaSalFrame::PostEvent(std::unique_ptr<ImplSVEvent> pData)
319 {
320 GetSalData()->mpInstance->PostEvent( this, pData.release(), SalEvent::UserEvent );
321 return TRUE;
322 }
323
SetTitle(const OUString & rTitle)324 void AquaSalFrame::SetTitle(const OUString& rTitle)
325 {
326 if ( !mpNSWindow )
327 return;
328
329 OSX_SALDATA_RUNINMAIN( SetTitle(rTitle) )
330
331 // #i113170# may not be the main thread if called from UNO API
332 SalData::ensureThreadAutoreleasePool();
333
334 NSString* pTitle = CreateNSString( rTitle );
335 [mpNSWindow setTitle: pTitle];
336
337 // create an entry in the dock menu
338 const SalFrameStyleFlags nAppWindowStyle = SalFrameStyleFlags::CLOSEABLE | SalFrameStyleFlags::MOVEABLE;
339 if( mpParent == nullptr &&
340 (mnStyle & nAppWindowStyle) == nAppWindowStyle )
341 {
342 if( mpDockMenuEntry == nullptr )
343 {
344 NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu();
345
346 if ([pDock numberOfItems] != 0) {
347 NSMenuItem* pTopItem = [pDock itemAtIndex: 0];
348 if ( [pTopItem hasSubmenu] )
349 [pDock insertItem: [NSMenuItem separatorItem] atIndex: 0];
350 }
351
352 mpDockMenuEntry = [pDock insertItemWithTitle: pTitle
353 action: @selector(dockMenuItemTriggered:)
354 keyEquivalent: @""
355 atIndex: 0];
356 [mpDockMenuEntry setTarget: mpNSWindow];
357
358 // TODO: image (either the generic window image or an icon
359 // check mark (for "main" window ?)
360 }
361 else
362 [mpDockMenuEntry setTitle: pTitle];
363 }
364
365 if (pTitle)
366 [pTitle release];
367 }
368
SetIcon(sal_uInt16)369 void AquaSalFrame::SetIcon( sal_uInt16 )
370 {
371 }
372
SetRepresentedURL(const OUString & i_rDocURL)373 void AquaSalFrame::SetRepresentedURL( const OUString& i_rDocURL )
374 {
375 OSX_SALDATA_RUNINMAIN( SetRepresentedURL( i_rDocURL ) )
376
377 if( comphelper::isFileUrl(i_rDocURL) )
378 {
379 OUString aSysPath;
380 osl_getSystemPathFromFileURL( i_rDocURL.pData, &aSysPath.pData );
381 NSString* pStr = CreateNSString( aSysPath );
382 if( pStr )
383 {
384 [pStr autorelease];
385 [mpNSWindow setRepresentedFilename: pStr];
386 }
387 }
388 }
389
initShow()390 void AquaSalFrame::initShow()
391 {
392 OSX_SALDATA_RUNINMAIN( initShow() )
393
394 mbInitShow = false;
395 if( ! mbPositioned && ! mbFullScreen )
396 {
397 tools::Rectangle aScreenRect;
398 GetWorkArea( aScreenRect );
399 if( mpParent ) // center relative to parent
400 {
401 // center on parent
402 long nNewX = mpParent->maGeometry.nX + (static_cast<long>(mpParent->maGeometry.nWidth) - static_cast<long>(maGeometry.nWidth))/2;
403 if( nNewX < aScreenRect.Left() )
404 nNewX = aScreenRect.Left();
405 if( long(nNewX + maGeometry.nWidth) > aScreenRect.Right() )
406 nNewX = aScreenRect.Right() - maGeometry.nWidth-1;
407 long nNewY = mpParent->maGeometry.nY + (static_cast<long>(mpParent->maGeometry.nHeight) - static_cast<long>(maGeometry.nHeight))/2;
408 if( nNewY < aScreenRect.Top() )
409 nNewY = aScreenRect.Top();
410 if( nNewY > aScreenRect.Bottom() )
411 nNewY = aScreenRect.Bottom() - maGeometry.nHeight-1;
412 SetPosSize( nNewX - mpParent->maGeometry.nX,
413 nNewY - mpParent->maGeometry.nY,
414 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
415 }
416 else if( ! (mnStyle & SalFrameStyleFlags::SIZEABLE) )
417 {
418 // center on screen
419 long nNewX = (aScreenRect.GetWidth() - maGeometry.nWidth)/2;
420 long nNewY = (aScreenRect.GetHeight() - maGeometry.nHeight)/2;
421 SetPosSize( nNewX, nNewY, 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
422 }
423 }
424
425 // make sure the view is present in the wrapper list before any children receive focus
426 [AquaA11yFactory registerView: mpNSView];
427 }
428
SendPaintEvent(const tools::Rectangle * pRect)429 void AquaSalFrame::SendPaintEvent( const tools::Rectangle* pRect )
430 {
431 OSX_SALDATA_RUNINMAIN( SendPaintEvent( pRect ) )
432
433 SalPaintEvent aPaintEvt( 0, 0, maGeometry.nWidth, maGeometry.nHeight, true );
434 if( pRect )
435 {
436 aPaintEvt.mnBoundX = pRect->Left();
437 aPaintEvt.mnBoundY = pRect->Top();
438 aPaintEvt.mnBoundWidth = pRect->GetWidth();
439 aPaintEvt.mnBoundHeight = pRect->GetHeight();
440 }
441
442 CallCallback(SalEvent::Paint, &aPaintEvt);
443 }
444
Show(bool bVisible,bool bNoActivate)445 void AquaSalFrame::Show(bool bVisible, bool bNoActivate)
446 {
447 if ( !mpNSWindow )
448 return;
449
450 OSX_SALDATA_RUNINMAIN( Show(bVisible, bNoActivate) )
451
452 mbShown = bVisible;
453 if(bVisible)
454 {
455 if( mbInitShow )
456 initShow();
457
458 CallCallback(SalEvent::Resize, nullptr);
459 // trigger filling our backbuffer
460 SendPaintEvent();
461
462 if( bNoActivate || [mpNSWindow canBecomeKeyWindow] == NO )
463 [mpNSWindow orderFront: NSApp];
464 else
465 [mpNSWindow makeKeyAndOrderFront: NSApp];
466
467 if( mpParent )
468 {
469 /* #i92674# #i96433# we do not want an invisible parent to show up (which adding a visible
470 child implicitly does). However we also do not want a parentless toolbar.
471
472 HACK: try to decide when we should not insert a child to its parent
473 floaters and ownerdraw windows have not yet shown up in cases where
474 we don't want the parent to become visible
475 */
476 if( mpParent->mbShown || (mnStyle & (SalFrameStyleFlags::OWNERDRAWDECORATION | SalFrameStyleFlags::FLOAT) ) )
477 {
478 [mpParent->mpNSWindow addChildWindow: mpNSWindow ordered: NSWindowAbove];
479 }
480 }
481
482 if( mbPresentation )
483 [mpNSWindow makeMainWindow];
484 }
485 else
486 {
487 // if the frame holding the current menubar gets hidden
488 // show the default menubar
489 if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu )
490 AquaSalMenu::setDefaultMenu();
491
492 // #i90440# #i94443# work around the focus going back to some other window
493 // if a child gets hidden for a parent window
494 if( mpParent && mpParent->mbShown && [mpNSWindow isKeyWindow] )
495 [mpParent->mpNSWindow makeKeyAndOrderFront: NSApp];
496
497 [SalFrameView unsetMouseFrame: this];
498 if( mpParent && [mpNSWindow parentWindow] == mpParent->mpNSWindow )
499 [mpParent->mpNSWindow removeChildWindow: mpNSWindow];
500
501 [mpNSWindow orderOut: NSApp];
502 }
503 }
504
SetMinClientSize(long nWidth,long nHeight)505 void AquaSalFrame::SetMinClientSize( long nWidth, long nHeight )
506 {
507 OSX_SALDATA_RUNINMAIN( SetMinClientSize( nWidth, nHeight ) )
508
509 mnMinWidth = nWidth;
510 mnMinHeight = nHeight;
511
512 if( mpNSWindow )
513 {
514 // Always add the decoration as the dimension concerns only
515 // the content rectangle
516 nWidth += maGeometry.nLeftDecoration + maGeometry.nRightDecoration;
517 nHeight += maGeometry.nTopDecoration + maGeometry.nBottomDecoration;
518
519 NSSize aSize = { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) };
520
521 // Size of full window (content+structure) although we only
522 // have the client size in arguments
523 [mpNSWindow setMinSize: aSize];
524 }
525 }
526
SetMaxClientSize(long nWidth,long nHeight)527 void AquaSalFrame::SetMaxClientSize( long nWidth, long nHeight )
528 {
529 OSX_SALDATA_RUNINMAIN( SetMaxClientSize( nWidth, nHeight ) )
530
531 mnMaxWidth = nWidth;
532 mnMaxHeight = nHeight;
533
534 if( mpNSWindow )
535 {
536 // Always add the decoration as the dimension concerns only
537 // the content rectangle
538 nWidth += maGeometry.nLeftDecoration + maGeometry.nRightDecoration;
539 nHeight += maGeometry.nTopDecoration + maGeometry.nBottomDecoration;
540
541 // Carbon windows can't have a size greater than 32767x32767
542 if (nWidth>32767) nWidth=32767;
543 if (nHeight>32767) nHeight=32767;
544
545 NSSize aSize = { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) };
546
547 // Size of full window (content+structure) although we only
548 // have the client size in arguments
549 [mpNSWindow setMaxSize: aSize];
550 }
551 }
552
GetClientSize(long & rWidth,long & rHeight)553 void AquaSalFrame::GetClientSize( long& rWidth, long& rHeight )
554 {
555 if (mbShown || mbInitShow || Application::IsBitmapRendering())
556 {
557 rWidth = maGeometry.nWidth;
558 rHeight = maGeometry.nHeight;
559 }
560 else
561 {
562 rWidth = 0;
563 rHeight = 0;
564 }
565 }
566
PreparePosSize(long nX,long nY,long nWidth,long nHeight,sal_uInt16 nFlags)567 SalEvent AquaSalFrame::PreparePosSize(long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags)
568 {
569 SalEvent nEvent = SalEvent::NONE;
570 assert(mpNSWindow || Application::IsBitmapRendering());
571
572 if (nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y))
573 {
574 mbPositioned = true;
575 nEvent = SalEvent::Move;
576 }
577
578 if (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT))
579 {
580 mbSized = true;
581 nEvent = (nEvent == SalEvent::Move) ? SalEvent::MoveResize : SalEvent::Resize;
582 }
583
584 if (Application::IsBitmapRendering())
585 {
586 if (nFlags & SAL_FRAME_POSSIZE_X)
587 maGeometry.nX = nX;
588 if (nFlags & SAL_FRAME_POSSIZE_Y)
589 maGeometry.nY = nY;
590 if (nFlags & SAL_FRAME_POSSIZE_WIDTH)
591 {
592 maGeometry.nWidth = nWidth;
593 if (mnMaxWidth > 0 && maGeometry.nWidth > static_cast<unsigned int>(mnMaxWidth))
594 maGeometry.nWidth = mnMaxWidth;
595 if (mnMinWidth > 0 && maGeometry.nWidth < static_cast<unsigned int>(mnMinWidth))
596 maGeometry.nWidth = mnMinWidth;
597 }
598 if (nFlags & SAL_FRAME_POSSIZE_HEIGHT)
599 {
600 maGeometry.nHeight = nHeight;
601 if (mnMaxHeight > 0 && maGeometry.nHeight > static_cast<unsigned int>(mnMaxHeight))
602 maGeometry.nHeight = mnMaxHeight;
603 if (mnMinHeight > 0 && maGeometry.nHeight < static_cast<unsigned int>(mnMinHeight))
604 maGeometry.nHeight = mnMinHeight;
605 }
606 if (nEvent != SalEvent::NONE)
607 CallCallback(nEvent, nullptr);
608 }
609
610 return nEvent;
611 }
612
SetWindowState(const SalFrameState * pState)613 void AquaSalFrame::SetWindowState( const SalFrameState* pState )
614 {
615 if (!mpNSWindow && !Application::IsBitmapRendering())
616 return;
617
618 OSX_SALDATA_RUNINMAIN( SetWindowState( pState ) )
619
620 sal_uInt16 nFlags = 0;
621 nFlags |= ((pState->mnMask & WindowStateMask::X) ? SAL_FRAME_POSSIZE_X : 0);
622 nFlags |= ((pState->mnMask & WindowStateMask::Y) ? SAL_FRAME_POSSIZE_Y : 0);
623 nFlags |= ((pState->mnMask & WindowStateMask::Width) ? SAL_FRAME_POSSIZE_WIDTH : 0);
624 nFlags |= ((pState->mnMask & WindowStateMask::Height) ? SAL_FRAME_POSSIZE_HEIGHT : 0);
625
626 SalEvent nEvent = PreparePosSize(pState->mnX, pState->mnY, pState->mnWidth, pState->mnHeight, nFlags);
627 if (Application::IsBitmapRendering())
628 return;
629
630 // set normal state
631 NSRect aStateRect = [mpNSWindow frame];
632 aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask];
633 CocoaToVCL(aStateRect);
634 if (pState->mnMask & WindowStateMask::X)
635 aStateRect.origin.x = float(pState->mnX);
636 if (pState->mnMask & WindowStateMask::Y)
637 aStateRect.origin.y = float(pState->mnY);
638 if (pState->mnMask & WindowStateMask::Width)
639 aStateRect.size.width = float(pState->mnWidth);
640 if (pState->mnMask & WindowStateMask::Height)
641 aStateRect.size.height = float(pState->mnHeight);
642 VCLToCocoa(aStateRect);
643 aStateRect = [NSWindow frameRectForContentRect: aStateRect styleMask: mnStyleMask];
644 [mpNSWindow setFrame: aStateRect display: NO];
645
646 if (pState->mnState == WindowStateState::Minimized)
647 [mpNSWindow miniaturize: NSApp];
648 else if ([mpNSWindow isMiniaturized])
649 [mpNSWindow deminiaturize: NSApp];
650
651 /* ZOOMED is not really maximized (actually it toggles between a user set size and
652 the program specified one), but comes closest since the default behavior is
653 "maximized" if the user did not intervene
654 */
655 if (pState->mnState == WindowStateState::Maximized)
656 {
657 if (![mpNSWindow isZoomed])
658 [mpNSWindow zoom: NSApp];
659 }
660 else
661 {
662 if ([mpNSWindow isZoomed])
663 [mpNSWindow zoom: NSApp];
664 }
665
666 // get new geometry
667 UpdateFrameGeometry();
668
669 // send event that we were moved/sized
670 if( nEvent != SalEvent::NONE )
671 CallCallback( nEvent, nullptr );
672
673 if (mbShown)
674 {
675 // trigger filling our backbuffer
676 SendPaintEvent();
677
678 // tell the system the views need to be updated
679 [mpNSWindow display];
680 }
681 }
682
GetWindowState(SalFrameState * pState)683 bool AquaSalFrame::GetWindowState( SalFrameState* pState )
684 {
685 if (!mpNSWindow)
686 {
687 if (Application::IsBitmapRendering())
688 {
689 pState->mnMask = WindowStateMask::X | WindowStateMask::Y
690 | WindowStateMask::Width | WindowStateMask::Height
691 | WindowStateMask::State;
692 pState->mnX = maGeometry.nX;
693 pState->mnY = maGeometry.nY;
694 pState->mnWidth = maGeometry.nWidth;
695 pState->mnHeight = maGeometry.nHeight;
696 pState->mnState = WindowStateState::Normal;
697 return TRUE;
698 }
699 return FALSE;
700 }
701
702 OSX_SALDATA_RUNINMAIN_UNION( GetWindowState( pState ), boolean )
703
704 pState->mnMask = WindowStateMask::X |
705 WindowStateMask::Y |
706 WindowStateMask::Width |
707 WindowStateMask::Height |
708 WindowStateMask::State;
709
710 NSRect aStateRect = [mpNSWindow frame];
711 aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask];
712 CocoaToVCL( aStateRect );
713 pState->mnX = long(aStateRect.origin.x);
714 pState->mnY = long(aStateRect.origin.y);
715 pState->mnWidth = long(aStateRect.size.width);
716 pState->mnHeight = long(aStateRect.size.height);
717
718 if( [mpNSWindow isMiniaturized] )
719 pState->mnState = WindowStateState::Minimized;
720 else if( ! [mpNSWindow isZoomed] )
721 pState->mnState = WindowStateState::Normal;
722 else
723 pState->mnState = WindowStateState::Maximized;
724
725 return TRUE;
726 }
727
SetScreenNumber(unsigned int nScreen)728 void AquaSalFrame::SetScreenNumber(unsigned int nScreen)
729 {
730 if ( !mpNSWindow )
731 return;
732
733 OSX_SALDATA_RUNINMAIN( SetScreenNumber( nScreen ) )
734
735 NSArray* pScreens = [NSScreen screens];
736 NSScreen* pScreen = nil;
737 if( pScreens && nScreen < [pScreens count] )
738 {
739 // get new screen frame
740 pScreen = [pScreens objectAtIndex: nScreen];
741 NSRect aNewScreen = [pScreen frame];
742
743 // get current screen frame
744 pScreen = [mpNSWindow screen];
745 if( pScreen )
746 {
747 NSRect aCurScreen = [pScreen frame];
748 if( aCurScreen.origin.x != aNewScreen.origin.x ||
749 aCurScreen.origin.y != aNewScreen.origin.y )
750 {
751 NSRect aFrameRect = [mpNSWindow frame];
752 aFrameRect.origin.x += aNewScreen.origin.x - aCurScreen.origin.x;
753 aFrameRect.origin.y += aNewScreen.origin.y - aCurScreen.origin.y;
754 [mpNSWindow setFrame: aFrameRect display: NO];
755 UpdateFrameGeometry();
756 }
757 }
758 }
759 }
760
SetApplicationID(const OUString &)761 void AquaSalFrame::SetApplicationID( const OUString &/*rApplicationID*/ )
762 {
763 }
764
ShowFullScreen(bool bFullScreen,sal_Int32 nDisplay)765 void AquaSalFrame::ShowFullScreen( bool bFullScreen, sal_Int32 nDisplay )
766 {
767 doShowFullScreen(bFullScreen, nDisplay);
768 }
769
doShowFullScreen(bool bFullScreen,sal_Int32 nDisplay)770 void AquaSalFrame::doShowFullScreen( bool bFullScreen, sal_Int32 nDisplay )
771 {
772 if (!mpNSWindow)
773 {
774 if (Application::IsBitmapRendering() && bFullScreen)
775 SetPosSize(0, 0, 1024, 768, SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT);
776 return;
777 }
778
779 SAL_INFO("vcl.osx", OSL_THIS_FUNC << ": mbFullScreen=" << mbFullScreen << ", bFullScreen=" << bFullScreen);
780
781 if( mbFullScreen == bFullScreen )
782 return;
783
784 OSX_SALDATA_RUNINMAIN( ShowFullScreen( bFullScreen, nDisplay ) )
785
786 mbFullScreen = bFullScreen;
787
788 if( bFullScreen )
789 {
790 // hide the dock and the menubar if we are on the menu screen
791 // which is always on index 0 according to documentation
792 bool bHideMenu = (nDisplay == 0);
793
794 NSRect aNewContentRect = NSZeroRect;
795 // get correct screen
796 NSScreen* pScreen = nil;
797 NSArray* pScreens = [NSScreen screens];
798 if( pScreens )
799 {
800 if( nDisplay >= 0 && static_cast<unsigned int>(nDisplay) < [pScreens count] )
801 pScreen = [pScreens objectAtIndex: nDisplay];
802 else
803 {
804 // this means span all screens
805 bHideMenu = true;
806 NSEnumerator* pEnum = [pScreens objectEnumerator];
807 while( (pScreen = [pEnum nextObject]) != nil )
808 {
809 NSRect aScreenRect = [pScreen frame];
810 if( aScreenRect.origin.x < aNewContentRect.origin.x )
811 {
812 aNewContentRect.size.width += aNewContentRect.origin.x - aScreenRect.origin.x;
813 aNewContentRect.origin.x = aScreenRect.origin.x;
814 }
815 if( aScreenRect.origin.y < aNewContentRect.origin.y )
816 {
817 aNewContentRect.size.height += aNewContentRect.origin.y - aScreenRect.origin.y;
818 aNewContentRect.origin.y = aScreenRect.origin.y;
819 }
820 if( aScreenRect.origin.x + aScreenRect.size.width > aNewContentRect.origin.x + aNewContentRect.size.width )
821 aNewContentRect.size.width = aScreenRect.origin.x + aScreenRect.size.width - aNewContentRect.origin.x;
822 if( aScreenRect.origin.y + aScreenRect.size.height > aNewContentRect.origin.y + aNewContentRect.size.height )
823 aNewContentRect.size.height = aScreenRect.origin.y + aScreenRect.size.height - aNewContentRect.origin.y;
824 }
825 }
826 }
827 if( aNewContentRect.size.width == 0 && aNewContentRect.size.height == 0 )
828 {
829 if( pScreen == nil )
830 pScreen = [mpNSWindow screen];
831 if( pScreen == nil )
832 pScreen = [NSScreen mainScreen];
833
834 aNewContentRect = [pScreen frame];
835 }
836
837 if( bHideMenu )
838 [NSMenu setMenuBarVisible:NO];
839
840 maFullScreenRect = [mpNSWindow frame];
841
842 [mpNSWindow setFrame: [NSWindow frameRectForContentRect: aNewContentRect styleMask: mnStyleMask] display: mbShown ? YES : NO];
843 }
844 else
845 {
846 [mpNSWindow setFrame: maFullScreenRect display: mbShown ? YES : NO];
847
848 // show the dock and the menubar
849 [NSMenu setMenuBarVisible:YES];
850 }
851
852 UpdateFrameGeometry();
853 if (mbShown)
854 {
855 CallCallback(SalEvent::MoveResize, nullptr);
856
857 // trigger filling our backbuffer
858 SendPaintEvent();
859 }
860 }
861
StartPresentation(bool bStart)862 void AquaSalFrame::StartPresentation( bool bStart )
863 {
864 if ( !mpNSWindow )
865 return;
866
867 OSX_SALDATA_RUNINMAIN( StartPresentation( bStart ) )
868
869 if( bStart )
870 {
871 GetSalData()->maPresentationFrames.push_back( this );
872 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
873 kIOPMAssertionLevelOn,
874 CFSTR("LibreOffice presentation running"),
875 &mnAssertionID);
876 [mpNSWindow setLevel: NSPopUpMenuWindowLevel];
877 if( mbShown )
878 [mpNSWindow makeMainWindow];
879 }
880 else
881 {
882 GetSalData()->maPresentationFrames.remove( this );
883 IOPMAssertionRelease(mnAssertionID);
884 [mpNSWindow setLevel: NSNormalWindowLevel];
885 }
886 }
887
SetAlwaysOnTop(bool)888 void AquaSalFrame::SetAlwaysOnTop( bool )
889 {
890 }
891
ToTop(SalFrameToTop nFlags)892 void AquaSalFrame::ToTop(SalFrameToTop nFlags)
893 {
894 if ( !mpNSWindow )
895 return;
896
897 OSX_SALDATA_RUNINMAIN( ToTop( nFlags ) )
898
899 if( ! (nFlags & SalFrameToTop::RestoreWhenMin) )
900 {
901 if( ! [mpNSWindow isVisible] || [mpNSWindow isMiniaturized] )
902 return;
903 }
904 if( nFlags & SalFrameToTop::GrabFocus )
905 [mpNSWindow makeKeyAndOrderFront: NSApp];
906 else
907 [mpNSWindow orderFront: NSApp];
908 }
909
getCurrentCursor()910 NSCursor* AquaSalFrame::getCurrentCursor()
911 {
912 OSX_SALDATA_RUNINMAIN_POINTER( getCurrentCursor(), NSCursor* )
913
914 NSCursor* pCursor = nil;
915 switch( mePointerStyle )
916 {
917 case PointerStyle::Text: pCursor = [NSCursor IBeamCursor]; break;
918 case PointerStyle::Cross: pCursor = [NSCursor crosshairCursor]; break;
919 case PointerStyle::Hand:
920 case PointerStyle::Move: pCursor = [NSCursor openHandCursor]; break;
921 case PointerStyle::NSize: pCursor = [NSCursor resizeUpCursor]; break;
922 case PointerStyle::SSize: pCursor = [NSCursor resizeDownCursor]; break;
923 case PointerStyle::ESize: pCursor = [NSCursor resizeRightCursor]; break;
924 case PointerStyle::WSize: pCursor = [NSCursor resizeLeftCursor]; break;
925 case PointerStyle::Arrow: pCursor = [NSCursor arrowCursor]; break;
926 case PointerStyle::VSplit:
927 case PointerStyle::VSizeBar:
928 case PointerStyle::WindowNSize:
929 case PointerStyle::WindowSSize:
930 pCursor = [NSCursor resizeUpDownCursor]; break;
931 case PointerStyle::HSplit:
932 case PointerStyle::HSizeBar:
933 case PointerStyle::WindowESize:
934 case PointerStyle::WindowWSize:
935 pCursor = [NSCursor resizeLeftRightCursor]; break;
936 case PointerStyle::RefHand: pCursor = [NSCursor pointingHandCursor]; break;
937
938 default:
939 pCursor = GetSalData()->getCursor( mePointerStyle );
940 if( pCursor == nil )
941 {
942 assert( false && "unmapped cursor" );
943 pCursor = [NSCursor arrowCursor];
944 }
945 break;
946 }
947 return pCursor;
948 }
949
SetPointer(PointerStyle ePointerStyle)950 void AquaSalFrame::SetPointer( PointerStyle ePointerStyle )
951 {
952 if ( !mpNSWindow )
953 return;
954 if( ePointerStyle == mePointerStyle )
955 return;
956
957 OSX_SALDATA_RUNINMAIN( SetPointer( ePointerStyle ) )
958
959 mePointerStyle = ePointerStyle;
960
961 [mpNSWindow invalidateCursorRectsForView: mpNSView];
962 }
963
SetPointerPos(long nX,long nY)964 void AquaSalFrame::SetPointerPos( long nX, long nY )
965 {
966 OSX_SALDATA_RUNINMAIN( SetPointerPos( nX, nY ) )
967
968 // FIXME: use Cocoa functions
969 // FIXME: multiscreen support
970 CGPoint aPoint = { static_cast<CGFloat>(nX + maGeometry.nX), static_cast<CGFloat>(nY + maGeometry.nY) };
971 CGDirectDisplayID mainDisplayID = CGMainDisplayID();
972 CGDisplayMoveCursorToPoint( mainDisplayID, aPoint );
973 }
974
Flush()975 void AquaSalFrame::Flush()
976 {
977 if( !(mbGraphics && mpGraphics && mpNSView && mbShown) )
978 return;
979
980 OSX_SALDATA_RUNINMAIN( Flush() )
981
982 [mpNSView setNeedsDisplay: YES];
983
984 // outside of the application's event loop (e.g. IntroWindow)
985 // nothing would trigger paint event handling
986 // => fall back to synchronous painting
987 if( ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
988 {
989 [mpNSView display];
990 }
991 }
992
Flush(const tools::Rectangle & rRect)993 void AquaSalFrame::Flush( const tools::Rectangle& rRect )
994 {
995 if( !(mbGraphics && mpGraphics && mpNSView && mbShown) )
996 return;
997
998 OSX_SALDATA_RUNINMAIN( Flush( rRect ) )
999
1000 NSRect aNSRect = { { static_cast<CGFloat>(rRect.Left()), static_cast<CGFloat>(rRect.Top()) }, { static_cast<CGFloat>(rRect.GetWidth()), static_cast<CGFloat>(rRect.GetHeight()) } };
1001 VCLToCocoa( aNSRect, false );
1002 [mpNSView setNeedsDisplayInRect: aNSRect];
1003
1004 // outside of the application's event loop (e.g. IntroWindow)
1005 // nothing would trigger paint event handling
1006 // => fall back to synchronous painting
1007 if( ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
1008 {
1009 [mpNSView display];
1010 }
1011 }
1012
SetInputContext(SalInputContext * pContext)1013 void AquaSalFrame::SetInputContext( SalInputContext* pContext )
1014 {
1015 if (!pContext)
1016 {
1017 mnICOptions = InputContextFlags::NONE;
1018 return;
1019 }
1020
1021 mnICOptions = pContext->mnOptions;
1022
1023 if(!(pContext->mnOptions & InputContextFlags::Text))
1024 return;
1025 }
1026
EndExtTextInput(EndExtTextInputFlags)1027 void AquaSalFrame::EndExtTextInput( EndExtTextInputFlags )
1028 {
1029 }
1030
GetKeyName(sal_uInt16 nKeyCode)1031 OUString AquaSalFrame::GetKeyName( sal_uInt16 nKeyCode )
1032 {
1033 static std::map< sal_uInt16, OUString > aKeyMap;
1034 if( aKeyMap.empty() )
1035 {
1036 sal_uInt16 i;
1037 for( i = KEY_A; i <= KEY_Z; i++ )
1038 aKeyMap[ i ] = OUString( sal_Unicode( 'A' + (i - KEY_A) ) );
1039 for( i = KEY_0; i <= KEY_9; i++ )
1040 aKeyMap[ i ] = OUString( sal_Unicode( '0' + (i - KEY_0) ) );
1041 for( i = KEY_F1; i <= KEY_F26; i++ )
1042 {
1043 aKeyMap[ i ] = "F" + OUString::number(i - KEY_F1 + 1);
1044 }
1045
1046 aKeyMap[ KEY_DOWN ] = OUString( u'\x21e3' );
1047 aKeyMap[ KEY_UP ] = OUString( u'\x21e1' );
1048 aKeyMap[ KEY_LEFT ] = OUString( u'\x21e0' );
1049 aKeyMap[ KEY_RIGHT ] = OUString( u'\x21e2' );
1050 aKeyMap[ KEY_HOME ] = OUString( u'\x2196' );
1051 aKeyMap[ KEY_END ] = OUString( u'\x2198' );
1052 aKeyMap[ KEY_PAGEUP ] = OUString( u'\x21de' );
1053 aKeyMap[ KEY_PAGEDOWN ] = OUString( u'\x21df' );
1054 aKeyMap[ KEY_RETURN ] = OUString( u'\x21a9' );
1055 aKeyMap[ KEY_ESCAPE ] = "esc";
1056 aKeyMap[ KEY_TAB ] = OUString( u'\x21e5' );
1057 aKeyMap[ KEY_BACKSPACE ]= OUString( u'\x232b' );
1058 aKeyMap[ KEY_SPACE ] = OUString( u'\x2423' );
1059 aKeyMap[ KEY_DELETE ] = OUString( u'\x2326' );
1060 aKeyMap[ KEY_ADD ] = "+";
1061 aKeyMap[ KEY_SUBTRACT ] = "-";
1062 aKeyMap[ KEY_DIVIDE ] = "/";
1063 aKeyMap[ KEY_MULTIPLY ] = "*";
1064 aKeyMap[ KEY_POINT ] = ".";
1065 aKeyMap[ KEY_COMMA ] = ",";
1066 aKeyMap[ KEY_LESS ] = "<";
1067 aKeyMap[ KEY_GREATER ] = ">";
1068 aKeyMap[ KEY_EQUAL ] = "=";
1069 aKeyMap[ KEY_OPEN ] = OUString( u'\x23cf' );
1070 aKeyMap[ KEY_TILDE ] = "~";
1071 aKeyMap[ KEY_BRACKETLEFT ] = "[";
1072 aKeyMap[ KEY_BRACKETRIGHT ] = "]";
1073 aKeyMap[ KEY_SEMICOLON ] = ";";
1074 aKeyMap[ KEY_QUOTERIGHT ] = "'";
1075
1076 /* yet unmapped KEYCODES:
1077 aKeyMap[ KEY_INSERT ] = OUString( sal_Unicode( ) );
1078 aKeyMap[ KEY_CUT ] = OUString( sal_Unicode( ) );
1079 aKeyMap[ KEY_COPY ] = OUString( sal_Unicode( ) );
1080 aKeyMap[ KEY_PASTE ] = OUString( sal_Unicode( ) );
1081 aKeyMap[ KEY_UNDO ] = OUString( sal_Unicode( ) );
1082 aKeyMap[ KEY_REPEAT ] = OUString( sal_Unicode( ) );
1083 aKeyMap[ KEY_FIND ] = OUString( sal_Unicode( ) );
1084 aKeyMap[ KEY_PROPERTIES ] = OUString( sal_Unicode( ) );
1085 aKeyMap[ KEY_FRONT ] = OUString( sal_Unicode( ) );
1086 aKeyMap[ KEY_CONTEXTMENU ] = OUString( sal_Unicode( ) );
1087 aKeyMap[ KEY_MENU ] = OUString( sal_Unicode( ) );
1088 aKeyMap[ KEY_HELP ] = OUString( sal_Unicode( ) );
1089 aKeyMap[ KEY_HANGUL_HANJA ] = OUString( sal_Unicode( ) );
1090 aKeyMap[ KEY_DECIMAL ] = OUString( sal_Unicode( ) );
1091 aKeyMap[ KEY_QUOTELEFT ]= OUString( sal_Unicode( ) );
1092 aKeyMap[ KEY_CAPSLOCK ]= OUString( sal_Unicode( ) );
1093 aKeyMap[ KEY_NUMLOCK ]= OUString( sal_Unicode( ) );
1094 aKeyMap[ KEY_SCROLLLOCK ]= OUString( sal_Unicode( ) );
1095 */
1096
1097 }
1098
1099 OUStringBuffer aResult( 16 );
1100
1101 sal_uInt16 nUnmodifiedCode = (nKeyCode & KEY_CODE_MASK);
1102 std::map< sal_uInt16, OUString >::const_iterator it = aKeyMap.find( nUnmodifiedCode );
1103 if( it != aKeyMap.end() )
1104 {
1105 if( (nKeyCode & KEY_SHIFT) != 0 )
1106 aResult.append( u'\x21e7' ); //⇧
1107 if( (nKeyCode & KEY_MOD1) != 0 )
1108 aResult.append( u'\x2318' ); //⌘
1109 if( (nKeyCode & KEY_MOD2) != 0 )
1110 aResult.append( u'\x2325' ); //⌥
1111 if( (nKeyCode & KEY_MOD3) != 0 )
1112 aResult.append( u'\x2303' ); //⌃
1113
1114 aResult.append( it->second );
1115 }
1116
1117 return aResult.makeStringAndClear();
1118 }
1119
getAppleScrollBarVariant(StyleSettings & rSettings)1120 static void getAppleScrollBarVariant(StyleSettings &rSettings)
1121 {
1122 bool bIsScrollbarDoubleMax = true; // default is DoubleMax
1123
1124 CFStringRef AppleScrollBarType = CFSTR("AppleScrollBarVariant");
1125 if( AppleScrollBarType )
1126 {
1127 CFStringRef ScrollBarVariant = static_cast<CFStringRef>(CFPreferencesCopyAppValue( AppleScrollBarType, kCFPreferencesCurrentApplication ));
1128 if( ScrollBarVariant )
1129 {
1130 if( CFGetTypeID( ScrollBarVariant ) == CFStringGetTypeID() )
1131 {
1132 // TODO: check for the less important variants "DoubleMin" and "DoubleBoth" too
1133 CFStringRef DoubleMax = CFSTR("DoubleMax");
1134 if (DoubleMax)
1135 {
1136 if ( !CFStringCompare(ScrollBarVariant, DoubleMax, kCFCompareCaseInsensitive) )
1137 bIsScrollbarDoubleMax = true;
1138 else
1139 bIsScrollbarDoubleMax = false;
1140 CFRelease(DoubleMax);
1141 }
1142 }
1143 CFRelease( ScrollBarVariant );
1144 }
1145 CFRelease(AppleScrollBarType);
1146 }
1147
1148 GetSalData()->mbIsScrollbarDoubleMax = bIsScrollbarDoubleMax;
1149
1150 CFStringRef jumpScroll = CFSTR("AppleScrollerPagingBehavior");
1151 if( jumpScroll )
1152 {
1153 CFBooleanRef jumpStr = static_cast<CFBooleanRef>(CFPreferencesCopyAppValue( jumpScroll, kCFPreferencesCurrentApplication ));
1154 if( jumpStr )
1155 {
1156 if( CFGetTypeID( jumpStr ) == CFBooleanGetTypeID() )
1157 rSettings.SetPrimaryButtonWarpsSlider(jumpStr == kCFBooleanTrue);
1158 CFRelease( jumpStr );
1159 }
1160 CFRelease( jumpScroll );
1161 }
1162 }
1163
getColor(NSColor * pSysColor,const Color & rDefault,NSWindow * pWin)1164 static Color getColor( NSColor* pSysColor, const Color& rDefault, NSWindow* pWin )
1165 {
1166 Color aRet( rDefault );
1167 if( pSysColor )
1168 {
1169 // transform to RGB
1170 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1171 // "'colorUsingColorSpaceName:device:' is deprecated: first deprecated in macOS 10.14 -
1172 // Use -colorUsingType: or -colorUsingColorSpace: instead"
1173 NSColor* pRBGColor = [pSysColor colorUsingColorSpaceName: NSDeviceRGBColorSpace device: [pWin deviceDescription]];
1174 SAL_WNODEPRECATED_DECLARATIONS_POP
1175 if( pRBGColor )
1176 {
1177 CGFloat r = 0, g = 0, b = 0, a = 0;
1178 [pRBGColor getRed: &r green: &g blue: &b alpha: &a];
1179 aRet = Color( int(r*255.999), int(g*255.999), int(b*255.999) );
1180 /*
1181 do not release here; leads to duplicate free in yield
1182 it seems the converted color comes out autoreleased, although this
1183 is not documented
1184 [pRBGColor release];
1185 */
1186 }
1187 }
1188 return aRet;
1189 }
1190
getFont(NSFont * pFont,long nDPIY,const vcl::Font & rDefault)1191 static vcl::Font getFont( NSFont* pFont, long nDPIY, const vcl::Font& rDefault )
1192 {
1193 vcl::Font aResult( rDefault );
1194 if( pFont )
1195 {
1196 aResult.SetFamilyName( GetOUString( [pFont familyName] ) );
1197 aResult.SetFontHeight( static_cast<int>(([pFont pointSize] * 72.0 / static_cast<float>(nDPIY))+0.5) );
1198 aResult.SetItalic( ([pFont italicAngle] != 0.0) ? ITALIC_NORMAL : ITALIC_NONE );
1199 // FIMXE: bold ?
1200 }
1201
1202 return aResult;
1203 }
1204
getResolution(sal_Int32 & o_rDPIX,sal_Int32 & o_rDPIY)1205 void AquaSalFrame::getResolution( sal_Int32& o_rDPIX, sal_Int32& o_rDPIY )
1206 {
1207 OSX_SALDATA_RUNINMAIN( getResolution( o_rDPIX, o_rDPIY ) )
1208
1209 if( ! mpGraphics )
1210 {
1211 AcquireGraphics();
1212 ReleaseGraphics( mpGraphics );
1213 }
1214 mpGraphics->GetResolution( o_rDPIX, o_rDPIY );
1215 }
1216
1217 // on OSX-Aqua the style settings are independent of the frame, so it does
1218 // not really belong here. Since the connection to the Appearance_Manager
1219 // is currently done in salnativewidgets.cxx this would be a good place.
1220 // On the other hand VCL's platform independent code currently only asks
1221 // SalFrames for system settings anyway, so moving the code somewhere else
1222 // doesn't make the anything cleaner for now
UpdateSettings(AllSettings & rSettings)1223 void AquaSalFrame::UpdateSettings( AllSettings& rSettings )
1224 {
1225 if ( !mpNSWindow )
1226 return;
1227
1228 OSX_SALDATA_RUNINMAIN( UpdateSettings( rSettings ) )
1229
1230 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1231 // "'lockFocus' is deprecated: first deprecated in macOS 10.14 - To draw, subclass NSView
1232 // and implement -drawRect:; AppKit's automatic deferred display mechanism will call
1233 // -drawRect: as necessary to display the view."
1234 if (![mpNSView lockFocusIfCanDraw])
1235 return;
1236 SAL_WNODEPRECATED_DECLARATIONS_POP
1237
1238 StyleSettings aStyleSettings = rSettings.GetStyleSettings();
1239
1240 // Background Color
1241 Color aBackgroundColor( 0xEC, 0xEC, 0xEC );
1242 aStyleSettings.BatchSetBackgrounds( aBackgroundColor, false );
1243 aStyleSettings.SetLightBorderColor( aBackgroundColor );
1244
1245 Color aInactiveTabColor( aBackgroundColor );
1246 aInactiveTabColor.DecreaseLuminance( 32 );
1247 aStyleSettings.SetInactiveTabColor( aInactiveTabColor );
1248
1249 Color aShadowColor( aStyleSettings.GetShadowColor() );
1250 aShadowColor.IncreaseLuminance( 32 );
1251 aStyleSettings.SetShadowColor( aShadowColor );
1252
1253 // get the system font settings
1254 vcl::Font aAppFont = aStyleSettings.GetAppFont();
1255 sal_Int32 nDPIX = 72, nDPIY = 72;
1256 getResolution( nDPIX, nDPIY );
1257 aAppFont = getFont( [NSFont systemFontOfSize: 0], nDPIY, aAppFont );
1258
1259 aStyleSettings.SetToolbarIconSize( ToolbarIconSize::Large );
1260
1261 // TODO: better mapping of macOS<->LibreOffice font settings
1262 vcl::Font aLabelFont( getFont( [NSFont labelFontOfSize: 0], nDPIY, aAppFont ) );
1263 aStyleSettings.BatchSetFonts( aAppFont, aLabelFont );
1264 vcl::Font aMenuFont( getFont( [NSFont menuFontOfSize: 0], nDPIY, aAppFont ) );
1265 aStyleSettings.SetMenuFont( aMenuFont );
1266
1267 vcl::Font aTitleFont( getFont( [NSFont titleBarFontOfSize: 0], nDPIY, aAppFont ) );
1268 aStyleSettings.SetTitleFont( aTitleFont );
1269 aStyleSettings.SetFloatTitleFont( aTitleFont );
1270
1271 vcl::Font aTooltipFont(getFont([NSFont toolTipsFontOfSize: 0], nDPIY, aAppFont));
1272 aStyleSettings.SetHelpFont(aTooltipFont);
1273
1274 Color aHighlightColor( getColor( [NSColor selectedTextBackgroundColor],
1275 aStyleSettings.GetHighlightColor(), mpNSWindow ) );
1276 aStyleSettings.SetHighlightColor( aHighlightColor );
1277 Color aHighlightTextColor( getColor( [NSColor selectedTextColor],
1278 aStyleSettings.GetHighlightTextColor(), mpNSWindow ) );
1279 aStyleSettings.SetHighlightTextColor( aHighlightTextColor );
1280
1281 Color aMenuHighlightColor( getColor( [NSColor selectedMenuItemColor],
1282 aStyleSettings.GetMenuHighlightColor(), mpNSWindow ) );
1283 aStyleSettings.SetMenuHighlightColor( aMenuHighlightColor );
1284 Color aMenuHighlightTextColor( getColor( [NSColor selectedMenuItemTextColor],
1285 aStyleSettings.GetMenuHighlightTextColor(), mpNSWindow ) );
1286 aStyleSettings.SetMenuHighlightTextColor( aMenuHighlightTextColor );
1287
1288 aStyleSettings.SetMenuColor( aBackgroundColor );
1289 Color aMenuTextColor( getColor( [NSColor textColor],
1290 aStyleSettings.GetMenuTextColor(), mpNSWindow ) );
1291 aStyleSettings.SetMenuTextColor( aMenuTextColor );
1292 aStyleSettings.SetMenuBarTextColor( aMenuTextColor );
1293 aStyleSettings.SetMenuBarRolloverTextColor( aMenuTextColor );
1294 aStyleSettings.SetMenuBarHighlightTextColor(aStyleSettings.GetMenuHighlightTextColor());
1295
1296 aStyleSettings.SetCursorBlinkTime( mnBlinkCursorDelay );
1297
1298 // no mnemonics on macOS
1299 aStyleSettings.SetOptions( aStyleSettings.GetOptions() | StyleSettingsOptions::NoMnemonics );
1300
1301 getAppleScrollBarVariant(aStyleSettings);
1302
1303 // set scrollbar size
1304 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1305 // 'NSRegularControlSize' is deprecated: first deprecated in macOS 10.12
1306 aStyleSettings.SetScrollBarSize( static_cast<long int>([NSScroller scrollerWidthForControlSize:NSRegularControlSize scrollerStyle:NSScrollerStyleLegacy]) );
1307 SAL_WNODEPRECATED_DECLARATIONS_POP
1308 // images in menus false for MacOSX
1309 aStyleSettings.SetPreferredUseImagesInMenus( false );
1310 aStyleSettings.SetHideDisabledMenuItems( true );
1311 aStyleSettings.SetPreferredContextMenuShortcuts( false );
1312
1313 rSettings.SetStyleSettings( aStyleSettings );
1314
1315 // don't draw frame around each and every toolbar
1316 ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames = true;
1317
1318 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1319 // "'unlockFocus' is deprecated: first deprecated in macOS 10.14 - To draw, subclass NSView
1320 // and implement -drawRect:; AppKit's automatic deferred display mechanism will call
1321 // -drawRect: as necessary to display the view."
1322 [mpNSView unlockFocus];
1323 SAL_WNODEPRECATED_DECLARATIONS_POP
1324 }
1325
GetSystemData() const1326 const SystemEnvData* AquaSalFrame::GetSystemData() const
1327 {
1328 return &maSysData;
1329 }
1330
Beep()1331 void AquaSalFrame::Beep()
1332 {
1333 OSX_SALDATA_RUNINMAIN( Beep() )
1334 NSBeep();
1335 }
1336
SetPosSize(long nX,long nY,long nWidth,long nHeight,sal_uInt16 nFlags)1337 void AquaSalFrame::SetPosSize(long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags)
1338 {
1339 if (!mpNSWindow && !Application::IsBitmapRendering())
1340 return;
1341
1342 OSX_SALDATA_RUNINMAIN( SetPosSize( nX, nY, nWidth, nHeight, nFlags ) )
1343
1344 SalEvent nEvent = PreparePosSize(nX, nY, nWidth, nHeight, nFlags);
1345 if (Application::IsBitmapRendering())
1346 return;
1347
1348 if( [mpNSWindow isMiniaturized] )
1349 [mpNSWindow deminiaturize: NSApp]; // expand the window
1350
1351 NSRect aFrameRect = [mpNSWindow frame];
1352 NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask];
1353
1354 // position is always relative to parent frame
1355 NSRect aParentContentRect;
1356
1357 if( mpParent )
1358 {
1359 if( AllSettings::GetLayoutRTL() )
1360 {
1361 if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
1362 nX = mpParent->maGeometry.nWidth - nWidth-1 - nX;
1363 else
1364 nX = mpParent->maGeometry.nWidth - static_cast<long int>( aContentRect.size.width-1) - nX;
1365 }
1366 NSRect aParentFrameRect = [mpParent->mpNSWindow frame];
1367 aParentContentRect = [NSWindow contentRectForFrameRect: aParentFrameRect styleMask: mpParent->mnStyleMask];
1368 }
1369 else
1370 aParentContentRect = maScreenRect; // use screen if no parent
1371
1372 CocoaToVCL( aContentRect );
1373 CocoaToVCL( aParentContentRect );
1374
1375 bool bPaint = false;
1376 if( (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) != 0 )
1377 {
1378 if( nWidth != aContentRect.size.width || nHeight != aContentRect.size.height )
1379 bPaint = true;
1380 }
1381
1382 // use old window pos if no new pos requested
1383 if( (nFlags & SAL_FRAME_POSSIZE_X) != 0 )
1384 aContentRect.origin.x = nX + aParentContentRect.origin.x;
1385 if( (nFlags & SAL_FRAME_POSSIZE_Y) != 0)
1386 aContentRect.origin.y = nY + aParentContentRect.origin.y;
1387
1388 // use old size if no new size requested
1389 if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
1390 aContentRect.size.width = nWidth;
1391 if( (nFlags & SAL_FRAME_POSSIZE_HEIGHT) != 0)
1392 aContentRect.size.height = nHeight;
1393
1394 VCLToCocoa( aContentRect );
1395
1396 // do not display yet, we need to update our backbuffer
1397 {
1398 [mpNSWindow setFrame: [NSWindow frameRectForContentRect: aContentRect styleMask: mnStyleMask] display: NO];
1399 }
1400
1401 UpdateFrameGeometry();
1402
1403 if (nEvent != SalEvent::NONE)
1404 CallCallback(nEvent, nullptr);
1405
1406 if( mbShown && bPaint )
1407 {
1408 // trigger filling our backbuffer
1409 SendPaintEvent();
1410
1411 // now inform the system that the views need to be drawn
1412 [mpNSWindow display];
1413 }
1414 }
1415
GetWorkArea(tools::Rectangle & rRect)1416 void AquaSalFrame::GetWorkArea( tools::Rectangle& rRect )
1417 {
1418 if (!mpNSWindow)
1419 {
1420 if (Application::IsBitmapRendering())
1421 rRect = tools::Rectangle(Point(0, 0), Size(1024, 768));
1422 return;
1423 }
1424
1425 OSX_SALDATA_RUNINMAIN( GetWorkArea( rRect ) )
1426
1427 NSScreen* pScreen = [mpNSWindow screen];
1428 if( pScreen == nil )
1429 pScreen = [NSScreen mainScreen];
1430 NSRect aRect = [pScreen visibleFrame];
1431 CocoaToVCL( aRect );
1432 rRect.SetLeft( static_cast<long>(aRect.origin.x) );
1433 rRect.SetTop( static_cast<long>(aRect.origin.y) );
1434 rRect.SetRight( static_cast<long>(aRect.origin.x + aRect.size.width - 1) );
1435 rRect.SetBottom( static_cast<long>(aRect.origin.y + aRect.size.height - 1) );
1436 }
1437
GetPointerState()1438 SalFrame::SalPointerState AquaSalFrame::GetPointerState()
1439 {
1440 OSX_SALDATA_RUNINMAIN_UNION( GetPointerState(), state )
1441
1442 SalPointerState state;
1443 state.mnState = 0;
1444
1445 // get position
1446 NSPoint aPt = [mpNSWindow mouseLocationOutsideOfEventStream];
1447 CocoaToVCL( aPt, false );
1448 state.maPos = Point(static_cast<long>(aPt.x), static_cast<long>(aPt.y));
1449
1450 NSEvent* pCur = [NSApp currentEvent];
1451 bool bMouseEvent = false;
1452 if( pCur )
1453 {
1454 bMouseEvent = true;
1455 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1456 // 'NSLeftMouseDown' is deprecated: first deprecated in macOS 10.12
1457 // 'NSLeftMouseDragged' is deprecated: first deprecated in macOS 10.12
1458 // 'NSLeftMouseUp' is deprecated: first deprecated in macOS 10.12
1459 // 'NSMouseMoved' is deprecated: first deprecated in macOS 10.12
1460 // 'NSOtherMouseDown' is deprecated: first deprecated in macOS 10.12
1461 // 'NSOtherMouseDragged' is deprecated: first deprecated in macOS 10.12
1462 // 'NSOtherMouseUp' is deprecated: first deprecated in macOS 10.12
1463 // 'NSRightMouseDown' is deprecated: first deprecated in macOS 10.12
1464 // 'NSRightMouseDragged' is deprecated: first deprecated in macOS 10.12
1465 // 'NSRightMouseUp' is deprecated: first deprecated in macOS 10.12
1466 switch( [pCur type] )
1467 {
1468 case NSLeftMouseDown: state.mnState |= MOUSE_LEFT; break;
1469 case NSLeftMouseUp: break;
1470 case NSRightMouseDown: state.mnState |= MOUSE_RIGHT; break;
1471 case NSRightMouseUp: break;
1472 case NSOtherMouseDown: state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0; break;
1473 case NSOtherMouseUp: break;
1474 case NSMouseMoved: break;
1475 case NSLeftMouseDragged: state.mnState |= MOUSE_LEFT; break;
1476 case NSRightMouseDragged: state.mnState |= MOUSE_RIGHT; break;
1477 case NSOtherMouseDragged: state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0; break;
1478 break;
1479 default:
1480 bMouseEvent = false;
1481 break;
1482 }
1483 SAL_WNODEPRECATED_DECLARATIONS_POP
1484 }
1485 if( bMouseEvent )
1486 {
1487 unsigned int nMask = static_cast<unsigned int>([pCur modifierFlags]);
1488 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1489 // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12
1490 // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12
1491 // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12
1492 // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12
1493 if( (nMask & NSShiftKeyMask) != 0 )
1494 state.mnState |= KEY_SHIFT;
1495 if( (nMask & NSControlKeyMask) != 0 )
1496 state.mnState |= KEY_MOD3;
1497 if( (nMask & NSAlternateKeyMask) != 0 )
1498 state.mnState |= KEY_MOD2;
1499 if( (nMask & NSCommandKeyMask) != 0 )
1500 state.mnState |= KEY_MOD1;
1501 SAL_WNODEPRECATED_DECLARATIONS_POP
1502
1503 }
1504 else
1505 {
1506 // FIXME: replace Carbon by Cocoa
1507 // Cocoa does not have an equivalent for GetCurrentEventButtonState
1508 // and GetCurrentEventKeyModifiers.
1509 // we could try to get away with tracking all events for modifierKeys
1510 // and all mouse events for button state in VCL_NSApplication::sendEvent,
1511 // but it is unclear whether this will get us the same result.
1512 // leave in GetCurrentEventButtonState and GetCurrentEventKeyModifiers for now
1513
1514 // fill in button state
1515 UInt32 nState = GetCurrentEventButtonState();
1516 state.mnState = 0;
1517 if( nState & 1 )
1518 state.mnState |= MOUSE_LEFT; // primary button
1519 if( nState & 2 )
1520 state.mnState |= MOUSE_RIGHT; // secondary button
1521 if( nState & 4 )
1522 state.mnState |= MOUSE_MIDDLE; // tertiary button
1523
1524 // fill in modifier state
1525 nState = GetCurrentEventKeyModifiers();
1526 if( nState & shiftKey )
1527 state.mnState |= KEY_SHIFT;
1528 if( nState & controlKey )
1529 state.mnState |= KEY_MOD3;
1530 if( nState & optionKey )
1531 state.mnState |= KEY_MOD2;
1532 if( nState & cmdKey )
1533 state.mnState |= KEY_MOD1;
1534 }
1535
1536 return state;
1537 }
1538
GetIndicatorState()1539 KeyIndicatorState AquaSalFrame::GetIndicatorState()
1540 {
1541 return KeyIndicatorState::NONE;
1542 }
1543
SimulateKeyPress(sal_uInt16)1544 void AquaSalFrame::SimulateKeyPress( sal_uInt16 /*nKeyCode*/ )
1545 {
1546 }
1547
SetPluginParent(SystemParentData *)1548 bool AquaSalFrame::SetPluginParent( SystemParentData* )
1549 {
1550 // plugin parent may be killed unexpectedly by
1551 // plugging process;
1552
1553 //TODO: implement
1554 return false;
1555 }
1556
MapUnicodeToKeyCode(sal_Unicode,LanguageType,vcl::KeyCode &)1557 bool AquaSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , vcl::KeyCode& )
1558 {
1559 // not supported yet
1560 return FALSE;
1561 }
1562
GetInputLanguage()1563 LanguageType AquaSalFrame::GetInputLanguage()
1564 {
1565 //TODO: implement
1566 return LANGUAGE_DONTKNOW;
1567 }
1568
DrawMenuBar()1569 void AquaSalFrame::DrawMenuBar()
1570 {
1571 }
1572
SetMenu(SalMenu * pSalMenu)1573 void AquaSalFrame::SetMenu( SalMenu* pSalMenu )
1574 {
1575 OSX_SALDATA_RUNINMAIN( SetMenu( pSalMenu ) )
1576
1577 AquaSalMenu* pMenu = static_cast<AquaSalMenu*>(pSalMenu);
1578 SAL_WARN_IF( pMenu && !pMenu->mbMenuBar, "vcl", "setting non menubar on frame" );
1579 mpMenu = pMenu;
1580 if( mpMenu )
1581 mpMenu->setMainMenu();
1582 }
1583
SetExtendedFrameStyle(SalExtStyle nStyle)1584 void AquaSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
1585 {
1586 if ( !mpNSWindow )
1587 {
1588 mnExtStyle = nStyle;
1589 return;
1590 }
1591
1592 OSX_SALDATA_RUNINMAIN( SetExtendedFrameStyle( nStyle ) )
1593
1594 if( (mnExtStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) != (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) )
1595 [mpNSWindow setDocumentEdited: (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) ? YES : NO];
1596
1597 mnExtStyle = nStyle;
1598 }
1599
GetParent() const1600 SalFrame* AquaSalFrame::GetParent() const
1601 {
1602 return mpParent;
1603 }
1604
SetParent(SalFrame * pNewParent)1605 void AquaSalFrame::SetParent( SalFrame* pNewParent )
1606 {
1607 bool bShown = mbShown;
1608 // remove from child list
1609 if (bShown)
1610 Show(FALSE);
1611 mpParent = static_cast<AquaSalFrame*>(pNewParent);
1612 // insert to correct parent and paint
1613 Show( bShown );
1614 }
1615
UpdateFrameGeometry()1616 void AquaSalFrame::UpdateFrameGeometry()
1617 {
1618 bool bFirstTime = (mnTrackingRectTag == 0);
1619 mbGeometryDidChange = false;
1620
1621 if ( !mpNSWindow )
1622 return;
1623
1624 OSX_SALDATA_RUNINMAIN( UpdateFrameGeometry() )
1625
1626 // keep in mind that view and window coordinates are lower left
1627 // whereas vcl's are upper left
1628
1629 // update screen rect
1630 NSScreen * pScreen = [mpNSWindow screen];
1631 if( pScreen )
1632 {
1633 NSRect aNewScreenRect = [pScreen frame];
1634 if (bFirstTime || !NSEqualRects(maScreenRect, aNewScreenRect))
1635 {
1636 mbGeometryDidChange = true;
1637 maScreenRect = aNewScreenRect;
1638 }
1639 NSArray* pScreens = [NSScreen screens];
1640 if( pScreens )
1641 {
1642 unsigned int nNewDisplayScreenNumber = [pScreens indexOfObject: pScreen];
1643 if (bFirstTime || maGeometry.nDisplayScreenNumber != nNewDisplayScreenNumber)
1644 {
1645 mbGeometryDidChange = true;
1646 maGeometry.nDisplayScreenNumber = nNewDisplayScreenNumber;
1647 }
1648 }
1649 }
1650
1651 NSRect aFrameRect = [mpNSWindow frame];
1652 NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask];
1653
1654 NSRect aTrackRect = { NSZeroPoint, aContentRect.size };
1655
1656 if (bFirstTime || !NSEqualRects(maTrackingRect, aTrackRect))
1657 {
1658 mbGeometryDidChange = true;
1659 maTrackingRect = aTrackRect;
1660
1661 // release old track rect
1662 [mpNSView removeTrackingRect: mnTrackingRectTag];
1663 // install the new track rect
1664 mnTrackingRectTag = [mpNSView addTrackingRect: aTrackRect owner: mpNSView userData: nil assumeInside: NO];
1665 }
1666
1667 // convert to vcl convention
1668 CocoaToVCL( aFrameRect );
1669 CocoaToVCL( aContentRect );
1670
1671 if (bFirstTime || !NSEqualRects(maContentRect, aContentRect) || !NSEqualRects(maFrameRect, aFrameRect))
1672 {
1673 mbGeometryDidChange = true;
1674
1675 maContentRect = aContentRect;
1676 maFrameRect = aFrameRect;
1677
1678 maGeometry.nX = static_cast<int>(aContentRect.origin.x);
1679 maGeometry.nY = static_cast<int>(aContentRect.origin.y);
1680
1681 maGeometry.nLeftDecoration = static_cast<unsigned int>(aContentRect.origin.x - aFrameRect.origin.x);
1682 maGeometry.nRightDecoration = static_cast<unsigned int>((aFrameRect.origin.x + aFrameRect.size.width) -
1683 (aContentRect.origin.x + aContentRect.size.width));
1684
1685 maGeometry.nTopDecoration = static_cast<unsigned int>(aContentRect.origin.y - aFrameRect.origin.y);
1686 maGeometry.nBottomDecoration = static_cast<unsigned int>((aFrameRect.origin.y + aFrameRect.size.height) -
1687 (aContentRect.origin.y + aContentRect.size.height));
1688
1689 maGeometry.nWidth = static_cast<unsigned int>(aContentRect.size.width);
1690 maGeometry.nHeight = static_cast<unsigned int>(aContentRect.size.height);
1691 }
1692 }
1693
CaptureMouse(bool bCapture)1694 void AquaSalFrame::CaptureMouse( bool bCapture )
1695 {
1696 /* Remark:
1697 we'll try to use a pidgin version of capture mouse
1698 on MacOSX (neither carbon nor cocoa) there is a
1699 CaptureMouse equivalent (in Carbon there is TrackMouseLocation
1700 but this is useless to use since it is blocking)
1701
1702 However on cocoa the active frame seems to get mouse events
1703 also outside the window, so we'll try to forward mouse events
1704 to the capture frame in the hope that one of our frames
1705 gets a mouse event.
1706
1707 This will break as soon as the user activates another app, but
1708 a mouse click will normally lead to a release of the mouse anyway.
1709
1710 Let's see how far we get this way. Alternatively we could use one
1711 large overlay window like we did for the carbon implementation,
1712 however that is resource intensive.
1713 */
1714
1715 if( bCapture )
1716 s_pCaptureFrame = this;
1717 else if( ! bCapture && s_pCaptureFrame == this )
1718 s_pCaptureFrame = nullptr;
1719 }
1720
ResetClipRegion()1721 void AquaSalFrame::ResetClipRegion()
1722 {
1723 doResetClipRegion();
1724 }
1725
doResetClipRegion()1726 void AquaSalFrame::doResetClipRegion()
1727 {
1728 if ( !mpNSWindow )
1729 return;
1730
1731 OSX_SALDATA_RUNINMAIN( ResetClipRegion() )
1732
1733 // release old path and indicate no clipping
1734 CGPathRelease( mrClippingPath );
1735 mrClippingPath = nullptr;
1736
1737 if( mpNSView && mbShown )
1738 [mpNSView setNeedsDisplay: YES];
1739 [mpNSWindow setOpaque: YES];
1740 [mpNSWindow invalidateShadow];
1741 }
1742
BeginSetClipRegion(sal_uInt32 nRects)1743 void AquaSalFrame::BeginSetClipRegion( sal_uInt32 nRects )
1744 {
1745 if ( !mpNSWindow )
1746 return;
1747
1748 OSX_SALDATA_RUNINMAIN( BeginSetClipRegion( nRects ) )
1749
1750 // release old path
1751 if( mrClippingPath )
1752 {
1753 CGPathRelease( mrClippingPath );
1754 mrClippingPath = nullptr;
1755 }
1756
1757 if( maClippingRects.size() > SAL_CLIPRECT_COUNT && nRects < maClippingRects.size() )
1758 {
1759 std::vector<CGRect> aEmptyVec;
1760 maClippingRects.swap( aEmptyVec );
1761 }
1762 maClippingRects.clear();
1763 maClippingRects.reserve( nRects );
1764 }
1765
UnionClipRegion(long nX,long nY,long nWidth,long nHeight)1766 void AquaSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
1767 {
1768 // #i113170# may not be the main thread if called from UNO API
1769 SalData::ensureThreadAutoreleasePool();
1770
1771 if( nWidth && nHeight )
1772 {
1773 NSRect aRect = { { static_cast<CGFloat>(nX), static_cast<CGFloat>(nY) }, { static_cast<CGFloat>(nWidth), static_cast<CGFloat>(nHeight) } };
1774 VCLToCocoa( aRect, false );
1775 maClippingRects.push_back( CGRectMake(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height) );
1776 }
1777 }
1778
EndSetClipRegion()1779 void AquaSalFrame::EndSetClipRegion()
1780 {
1781 if ( !mpNSWindow )
1782 return;
1783
1784 OSX_SALDATA_RUNINMAIN( EndSetClipRegion() )
1785
1786 if( ! maClippingRects.empty() )
1787 {
1788 mrClippingPath = CGPathCreateMutable();
1789 CGPathAddRects( mrClippingPath, nullptr, maClippingRects.data(), maClippingRects.size() );
1790 }
1791 if( mpNSView && mbShown )
1792 [mpNSView setNeedsDisplay: YES];
1793 [mpNSWindow setOpaque: (mrClippingPath != nullptr) ? NO : YES];
1794 [mpNSWindow setBackgroundColor: [NSColor clearColor]];
1795 // shadow is invalidated when view gets drawn again
1796 }
1797
1798 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1799