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