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