1/*n***********************************************************************
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 <sal/alloca.h>
32
33#include "vcl/window.hxx"
34#include "vcl/svapp.hxx"
35
36#include "aqua/salinst.h"
37#include "aqua/salgdi.h"
38#include "aqua/salframe.h"
39#include "aqua/salframeview.h"
40#include "aqua/aqua11yfactory.h"
41
42#define WHEEL_EVENT_FACTOR 1.5
43
44static sal_uInt16 ImplGetModifierMask( unsigned int nMask )
45{
46    sal_uInt16 nRet = 0;
47    if( (nMask & NSShiftKeyMask) != 0 )
48        nRet |= KEY_SHIFT;
49    if( (nMask & NSControlKeyMask) != 0 )
50        nRet |= KEY_MOD3;
51    if( (nMask & NSAlternateKeyMask) != 0 )
52        nRet |= KEY_MOD2;
53    if( (nMask & NSCommandKeyMask) != 0 )
54        nRet |= KEY_MOD1;
55    return nRet;
56}
57
58static sal_uInt16 ImplMapCharCode( sal_Unicode aCode )
59{
60    static sal_uInt16 aKeyCodeMap[ 128 ] =
61    {
62        0, 0, 0, 0, 0, 0, 0, 0,
63        KEY_BACKSPACE, KEY_TAB, KEY_RETURN, 0, 0, KEY_RETURN, 0, 0,
64        0, 0, 0, 0, 0, 0, 0, 0,
65        0, KEY_TAB, 0, KEY_ESCAPE, 0, 0, 0, 0,
66        KEY_SPACE, 0, 0, 0, 0, 0, 0, 0,
67        0, 0, KEY_MULTIPLY, KEY_ADD, KEY_COMMA, KEY_SUBTRACT, KEY_POINT, KEY_DIVIDE,
68        KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
69        KEY_8, KEY_9, 0, 0, KEY_LESS, KEY_EQUAL, KEY_GREATER, 0,
70        0, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G,
71        KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
72        KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W,
73        KEY_X, KEY_Y, KEY_Z, 0, 0, 0, 0, 0,
74        KEY_QUOTELEFT, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G,
75        KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
76        KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W,
77        KEY_X, KEY_Y, KEY_Z, 0, 0, 0, KEY_TILDE, KEY_BACKSPACE
78    };
79
80    // Note: the mapping 0x7f should by rights be KEY_DELETE
81    // however if you press "backspace" 0x7f is reported
82    // whereas for "delete" 0xf728 gets reported
83
84    // Note: the mapping of 0x19 to KEY_TAB is because for unknown reasons
85    // tab alone is reported as 0x09 (as expected) but shift-tab is
86    // reported as 0x19 (end of medium)
87
88    static sal_uInt16 aFunctionKeyCodeMap[ 128 ] =
89    {
90        KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_F1, KEY_F2, KEY_F3, KEY_F4,
91        KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12,
92        KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20,
93        KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_F25, KEY_F26, 0, 0,
94        0, 0, 0, 0, 0, 0, 0, KEY_INSERT,
95        KEY_DELETE, KEY_HOME, 0, KEY_END, KEY_PAGEUP, KEY_PAGEDOWN, 0, 0,
96        0, 0, 0, 0, 0, KEY_MENU, 0, 0,
97        0, 0, 0, 0, 0, 0, 0, 0,
98        0, 0, 0, KEY_UNDO, KEY_REPEAT, KEY_FIND, KEY_HELP, 0,
99        0, 0, 0, 0, 0, 0, 0, 0,
100        0, 0, 0, 0, 0, 0, 0, 0,
101        0, 0, 0, 0, 0, 0, 0, 0,
102        0, 0, 0, 0, 0, 0, 0, 0,
103        0, 0, 0, 0, 0, 0, 0, 0,
104        0, 0, 0, 0, 0, 0, 0, 0,
105        0, 0, 0, 0, 0, 0, 0, 0
106    };
107
108    sal_uInt16 nKeyCode = 0;
109    if( aCode < sizeof( aKeyCodeMap) / sizeof( aKeyCodeMap[0] ) )
110        nKeyCode = aKeyCodeMap[ aCode ];
111    else if( aCode >= 0xf700 && aCode < 0xf780 )
112        nKeyCode = aFunctionKeyCodeMap[ aCode - 0xf700 ];
113    return nKeyCode;
114}
115
116// store the frame the mouse last entered
117static AquaSalFrame* s_pMouseFrame = NULL;
118// store the last pressed button for enter/exit events
119// which lack that information
120static sal_uInt16 s_nLastButton = 0;
121
122// combinations of keys we need to handle ourselves
123static const struct ExceptionalKey
124{
125    const sal_uInt16        nKeyCode;
126    const unsigned int  nModifierMask;
127} aExceptionalKeys[] =
128{
129    { KEY_D, NSControlKeyMask | NSShiftKeyMask | NSAlternateKeyMask },
130    { KEY_D, NSCommandKeyMask | NSShiftKeyMask | NSAlternateKeyMask }
131};
132
133static AquaSalFrame* getMouseContainerFrame()
134{
135    int nWindows = 0;
136    NSCountWindows( &nWindows );
137    int* pWindows = (int*)alloca( nWindows * sizeof(int) );
138    // note: NSWindowList is supposed to be in z-order front to back
139    NSWindowList( nWindows, pWindows );
140    AquaSalFrame* pDispatchFrame = NULL;
141    for(int i = 0; i < nWindows && ! pDispatchFrame; i++ )
142    {
143        NSWindow* pWin = [NSApp windowWithWindowNumber: pWindows[i]];
144        if( pWin && [pWin isMemberOfClass: [SalFrameWindow class]] && [(SalFrameWindow*)pWin containsMouse] )
145            pDispatchFrame = [(SalFrameWindow*)pWin getSalFrame];
146    }
147    return pDispatchFrame;
148}
149
150@implementation SalFrameWindow
151-(id)initWithSalFrame: (AquaSalFrame*)pFrame
152{
153	mDraggingDestinationHandler = nil;
154    mpFrame = pFrame;
155    NSRect aRect = { { pFrame->maGeometry.nX, pFrame->maGeometry.nY },
156                     { pFrame->maGeometry.nWidth, pFrame->maGeometry.nHeight } };
157    pFrame->VCLToCocoa( aRect );
158    NSWindow* pNSWindow = [super initWithContentRect: aRect styleMask: mpFrame->getStyleMask() backing: NSBackingStoreBuffered defer: NO ];
159    [pNSWindow useOptimizedDrawing: YES]; // OSX recommendation when there are no overlapping subviews within the receiver
160    return pNSWindow;
161}
162
163-(AquaSalFrame*)getSalFrame
164{
165    return mpFrame;
166}
167
168-(void)displayIfNeeded
169{
170    if( GetSalData() && GetSalData()->mpFirstInstance )
171    {
172        vos::IMutex* pMutex = GetSalData()->mpFirstInstance->GetYieldMutex();
173        if( pMutex )
174        {
175            pMutex->acquire();
176            [super displayIfNeeded];
177            pMutex->release();
178        }
179    }
180}
181
182-(BOOL)containsMouse
183{
184    // is this event actually inside that NSWindow ?
185    NSPoint aPt = [NSEvent mouseLocation];
186    NSRect aFrameRect = [self frame];
187    BOOL bInRect = NSPointInRect( aPt, aFrameRect );
188    return bInRect;
189}
190
191-(BOOL)canBecomeKeyWindow
192{
193    if( (mpFrame->mnStyle &
194            ( SAL_FRAME_STYLE_FLOAT                 |
195              SAL_FRAME_STYLE_TOOLTIP               |
196              SAL_FRAME_STYLE_INTRO
197            )) == 0 )
198        return YES;
199    if( (mpFrame->mnStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) != 0 )
200        return YES;
201    if( mpFrame->mbFullScreen )
202        return YES;
203    if( (mpFrame->mnStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) )
204        return YES;
205    return [super canBecomeKeyWindow];
206}
207
208-(void)windowDidBecomeKey: (NSNotification*)pNotification
209{
210    (void)pNotification;
211    YIELD_GUARD;
212
213    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
214    {
215        static const sal_uLong nGuessDocument = SAL_FRAME_STYLE_MOVEABLE|
216                                            SAL_FRAME_STYLE_SIZEABLE|
217                                            SAL_FRAME_STYLE_CLOSEABLE;
218
219        if( mpFrame->mpMenu )
220            mpFrame->mpMenu->setMainMenu();
221        else if( ! mpFrame->mpParent &&
222                 ( (mpFrame->mnStyle & nGuessDocument) == nGuessDocument || // set default menu for e.g. help
223                    mpFrame->mbFullScreen ) )                               // ser default menu for e.g. presentation
224        {
225            AquaSalMenu::setDefaultMenu();
226        }
227        #if 0
228        // FIXME: we should disable menus while in modal mode
229        // however from down here there is currently no reliable way to
230        // find out when to do this
231        if( (mpFrame->mpParent && mpFrame->mpParent->GetWindow()->IsInModalMode()) )
232            AquaSalMenu::enableMainMenu( false );
233        #endif
234        mpFrame->CallCallback( SALEVENT_GETFOCUS, 0 );
235        mpFrame->SendPaintEvent(); // repaint controls as active
236    }
237}
238
239-(void)windowDidResignKey: (NSNotification*)pNotification
240{
241    (void)pNotification;
242    YIELD_GUARD;
243
244    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
245    {
246        mpFrame->CallCallback(SALEVENT_LOSEFOCUS, 0);
247        mpFrame->SendPaintEvent(); // repaint controls as inactive
248    }
249}
250
251-(void)windowDidChangeScreen: (NSNotification*)pNotification
252{
253    (void)pNotification;
254    YIELD_GUARD;
255
256    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
257        mpFrame->screenParametersChanged();
258}
259
260-(void)windowDidMove: (NSNotification*)pNotification
261{
262    (void)pNotification;
263    YIELD_GUARD;
264
265    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
266    {
267        mpFrame->UpdateFrameGeometry();
268        mpFrame->CallCallback( SALEVENT_MOVE, 0 );
269    }
270}
271
272-(void)windowDidResize: (NSNotification*)pNotification
273{
274    (void)pNotification;
275    YIELD_GUARD;
276
277    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
278    {
279        mpFrame->UpdateFrameGeometry();
280        mpFrame->CallCallback( SALEVENT_RESIZE, 0 );
281        mpFrame->SendPaintEvent();
282    }
283}
284
285-(void)windowDidMiniaturize: (NSNotification*)pNotification
286{
287    (void)pNotification;
288    YIELD_GUARD;
289
290    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
291    {
292        mpFrame->mbShown = false;
293        mpFrame->UpdateFrameGeometry();
294        mpFrame->CallCallback( SALEVENT_RESIZE, 0 );
295    }
296}
297
298-(void)windowDidDeminiaturize: (NSNotification*)pNotification
299{
300    (void)pNotification;
301    YIELD_GUARD;
302
303    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
304    {
305        mpFrame->mbShown = true;
306        mpFrame->UpdateFrameGeometry();
307        mpFrame->CallCallback( SALEVENT_RESIZE, 0 );
308    }
309}
310
311-(BOOL)windowShouldClose: (NSNotification*)pNotification
312{
313    (void)pNotification;
314    YIELD_GUARD;
315
316    BOOL bRet = YES;
317    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
318    {
319        // #i84461# end possible input
320        mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
321        if( AquaSalFrame::isAlive( mpFrame ) )
322        {
323            mpFrame->CallCallback( SALEVENT_CLOSE, 0 );
324            bRet = NO; // application will close the window or not, AppKit shouldn't
325        }
326    }
327
328    return bRet;
329}
330
331-(void)dockMenuItemTriggered: (id)sender
332{
333    (void)sender;
334    YIELD_GUARD;
335
336    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
337        mpFrame->ToTop( SAL_FRAME_TOTOP_RESTOREWHENMIN | SAL_FRAME_TOTOP_GRABFOCUS );
338}
339
340-(::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >)accessibleContext
341{
342    return mpFrame -> GetWindow() -> GetAccessible() -> getAccessibleContext();
343}
344
345-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
346{
347  return [mDraggingDestinationHandler draggingEntered: sender];
348}
349
350-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
351{
352  return [mDraggingDestinationHandler draggingUpdated: sender];
353}
354
355-(void)draggingExited:(id <NSDraggingInfo>)sender
356{
357  [mDraggingDestinationHandler draggingExited: sender];
358}
359
360-(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
361{
362  return [mDraggingDestinationHandler prepareForDragOperation: sender];
363}
364
365-(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
366{
367  return [mDraggingDestinationHandler performDragOperation: sender];
368}
369
370-(void)concludeDragOperation:(id <NSDraggingInfo>)sender
371{
372  [mDraggingDestinationHandler concludeDragOperation: sender];
373}
374
375-(void)registerDraggingDestinationHandler:(id)theHandler
376{
377  mDraggingDestinationHandler = theHandler;
378}
379
380-(void)unregisterDraggingDestinationHandler:(id)theHandler
381{
382    (void)theHandler;
383    mDraggingDestinationHandler = nil;
384}
385
386@end
387
388@implementation SalFrameView
389+(void)unsetMouseFrame: (AquaSalFrame*)pFrame
390{
391    if( pFrame == s_pMouseFrame )
392        s_pMouseFrame = NULL;
393}
394
395-(id)initWithSalFrame: (AquaSalFrame*)pFrame
396{
397    if ((self = [super initWithFrame: [NSWindow contentRectForFrameRect: [pFrame->getWindow() frame] styleMask: pFrame->mnStyleMask]]) != nil)
398    {
399        mDraggingDestinationHandler = nil;
400        mpFrame = pFrame;
401        mMarkedRange = NSMakeRange(NSNotFound, 0);
402        mSelectedRange = NSMakeRange(NSNotFound, 0);
403        mpReferenceWrapper = nil;
404		mpMouseEventListener = nil;
405        mpLastSuperEvent = nil;
406    }
407
408    mfLastMagnifyTime = 0.0;
409    return self;
410}
411
412-(AquaSalFrame*)getSalFrame
413{
414    return mpFrame;
415}
416
417-(void)resetCursorRects
418{
419    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
420    {
421        // FIXME: does this leak the returned NSCursor of getCurrentCursor ?
422        NSRect aRect = { { 0, 0 }, { mpFrame->maGeometry.nWidth, mpFrame->maGeometry.nHeight } };
423        [self addCursorRect: aRect cursor: mpFrame->getCurrentCursor()];
424    }
425}
426
427-(BOOL)acceptsFirstResponder
428{
429    return YES;
430}
431
432-(BOOL)acceptsFirstMouse: (NSEvent*)pEvent
433{
434    (void)pEvent;
435    return YES;
436}
437
438-(BOOL)isOpaque
439{
440    return mpFrame ? (mpFrame->getClipPath() != 0 ? NO : YES) : YES;
441}
442
443// helper class similar to a vos::OGuard for the SalYieldMutex
444// the difference is that it only does tryToAcquire instead of aquire
445// so dreaded deadlocks like #i93512# are prevented
446class TryGuard
447{
448public:
449			TryGuard()  { mbGuarded = ImplSalYieldMutexTryToAcquire(); }
450			~TryGuard() { if( mbGuarded ) ImplSalYieldMutexRelease(); }
451	bool	IsGuarded() { return mbGuarded; }
452private:
453	bool	mbGuarded;
454};
455
456-(void)drawRect: (NSRect)aRect
457{
458	// HOTFIX: #i93512# prevent deadlocks if any other thread already has the SalYieldMutex
459	TryGuard aTryGuard;
460	if( !aTryGuard.IsGuarded() )
461	{
462		// NOTE: the mpFrame access below is not guarded yet!
463		// TODO: mpFrame et al need to be guarded by an independent mutex
464		AquaSalGraphics* pGraphics = (mpFrame && AquaSalFrame::isAlive(mpFrame)) ? mpFrame->mpGraphics : NULL;
465		if( pGraphics )
466		{
467			// we did not get the mutex so we cannot draw now => request to redraw later
468			// convert the NSRect to a CGRect for Refreshrect()
469			const CGRect aCGRect = {{aRect.origin.x,aRect.origin.y},{aRect.size.width,aRect.size.height}};
470			pGraphics->RefreshRect( aCGRect );
471		}
472		return;
473	}
474
475    if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
476    {
477        if( mpFrame->mpGraphics )
478        {
479            mpFrame->mpGraphics->UpdateWindow( aRect );
480            if( mpFrame->getClipPath() )
481                [mpFrame->getWindow() invalidateShadow];
482        }
483    }
484}
485
486-(void)sendMouseEventToFrame: (NSEvent*)pEvent button:(sal_uInt16)nButton eventtype:(sal_uInt16)nEvent
487{
488    YIELD_GUARD;
489
490    AquaSalFrame* pDispatchFrame = AquaSalFrame::GetCaptureFrame();
491    bool bIsCaptured = false;
492    if( pDispatchFrame )
493    {
494        bIsCaptured = true;
495        if( nEvent == SALEVENT_MOUSELEAVE ) // no leave events if mouse is captured
496            nEvent = SALEVENT_MOUSEMOVE;
497    }
498    else if( s_pMouseFrame )
499        pDispatchFrame = s_pMouseFrame;
500    else
501        pDispatchFrame = mpFrame;
502
503    /* #i81645# Cocoa reports mouse events while a button is pressed
504       to the window in which it was first pressed. This is reasonable and fine and
505       gets one around most cases where on other platforms one uses CaptureMouse or XGrabPointer,
506       however vcl expects mouse events to occur in the window the mouse is over, unless the
507       mouse is explicitly captured. So we need to find the window the mouse is actually
508       over for conformance with other platforms.
509    */
510    if( ! bIsCaptured && nButton && pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
511    {
512        // is this event actually inside that NSWindow ?
513        NSPoint aPt = [NSEvent mouseLocation];
514        NSRect aFrameRect = [pDispatchFrame->getWindow() frame];
515
516	if ( ! NSPointInRect( aPt, aFrameRect ) )
517        {
518            // no, it is not
519            // now we need to find the one it may be in
520            /* #i93756# we ant to get enumerate the application windows in z-order
521               to check if any contains the mouse. This could be elegantly done with this
522               code:
523
524               // use NSApp to check windows in ZOrder whether they contain the mouse pointer
525               NSWindow* pWindow = [NSApp makeWindowsPerform: @selector(containsMouse) inOrder: YES];
526               if( pWindow && [pWindow isMemberOfClass: [SalFrameWindow class]] )
527                   pDispatchFrame = [(SalFrameWindow*)pWindow getSalFrame];
528
529               However if a non SalFrameWindow is on screen (like e.g. the file dialog)
530               it can be hit with the containsMouse selector, which it doesn't support.
531               Sadly NSApplication:makeWindowsPerform does not check (for performance reasons
532               I assume) whether a window supports a selector before sending it.
533            */
534            AquaSalFrame* pMouseFrame = getMouseContainerFrame();
535            if( pMouseFrame )
536                pDispatchFrame = pMouseFrame;
537        }
538    }
539
540    if( pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
541    {
542        pDispatchFrame->mnLastEventTime = static_cast<sal_uLong>( [pEvent timestamp] * 1000.0 );
543        pDispatchFrame->mnLastModifierFlags = [pEvent modifierFlags];
544
545        NSPoint aPt = [NSEvent mouseLocation];
546        pDispatchFrame->CocoaToVCL( aPt );
547
548        sal_uInt16 nModMask = ImplGetModifierMask( [pEvent modifierFlags] );
549        // #i82284# emulate ctrl left
550        if( nModMask == KEY_MOD3 && nButton == MOUSE_LEFT )
551        {
552            nModMask    = 0;
553            nButton     = MOUSE_RIGHT;
554        }
555
556        SalMouseEvent aEvent;
557        aEvent.mnTime   = pDispatchFrame->mnLastEventTime;
558        aEvent.mnX      = static_cast<long>(aPt.x) - pDispatchFrame->maGeometry.nX;
559        aEvent.mnY      = static_cast<long>(aPt.y) - pDispatchFrame->maGeometry.nY;
560        aEvent.mnButton = nButton;
561        aEvent.mnCode   =  aEvent.mnButton | nModMask;
562
563        // --- RTL --- (mirror mouse pos)
564        if( Application::GetSettings().GetLayoutRTL() )
565            aEvent.mnX = pDispatchFrame->maGeometry.nWidth-1-aEvent.mnX;
566
567        pDispatchFrame->CallCallback( nEvent, &aEvent );
568    }
569}
570
571-(void)mouseDown: (NSEvent*)pEvent
572{
573    if ( mpMouseEventListener != nil &&
574	    [mpMouseEventListener respondsToSelector: @selector(mouseDown:)])
575	{
576	    [mpMouseEventListener mouseDown: [pEvent copyWithZone: NULL]];
577	}
578
579    s_nLastButton = MOUSE_LEFT;
580    [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SALEVENT_MOUSEBUTTONDOWN];
581}
582
583-(void)mouseDragged: (NSEvent*)pEvent
584{
585    if ( mpMouseEventListener != nil &&
586	     [mpMouseEventListener respondsToSelector: @selector(mouseDragged:)])
587	{
588	    [mpMouseEventListener mouseDragged: [pEvent copyWithZone: NULL]];
589	}
590    s_nLastButton = MOUSE_LEFT;
591    [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SALEVENT_MOUSEMOVE];
592}
593
594-(void)mouseUp: (NSEvent*)pEvent
595{
596    s_nLastButton = 0;
597    [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SALEVENT_MOUSEBUTTONUP];
598}
599
600-(void)mouseMoved: (NSEvent*)pEvent
601{
602    s_nLastButton = 0;
603    [self sendMouseEventToFrame:pEvent button:0 eventtype:SALEVENT_MOUSEMOVE];
604}
605
606-(void)mouseEntered: (NSEvent*)pEvent
607{
608    s_pMouseFrame = mpFrame;
609
610    // #i107215# the only mouse events we get when inactive are enter/exit
611    // actually we would like to have all of them, but better none than some
612    if( [NSApp isActive] )
613        [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SALEVENT_MOUSEMOVE];
614}
615
616-(void)mouseExited: (NSEvent*)pEvent
617{
618    if( s_pMouseFrame == mpFrame )
619        s_pMouseFrame = NULL;
620
621    // #i107215# the only mouse events we get when inactive are enter/exit
622    // actually we would like to have all of them, but better none than some
623    if( [NSApp isActive] )
624        [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SALEVENT_MOUSELEAVE];
625}
626
627-(void)rightMouseDown: (NSEvent*)pEvent
628{
629    s_nLastButton = MOUSE_RIGHT;
630    [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SALEVENT_MOUSEBUTTONDOWN];
631}
632
633-(void)rightMouseDragged: (NSEvent*)pEvent
634{
635    s_nLastButton = MOUSE_RIGHT;
636    [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SALEVENT_MOUSEMOVE];
637}
638
639-(void)rightMouseUp: (NSEvent*)pEvent
640{
641    s_nLastButton = 0;
642    [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SALEVENT_MOUSEBUTTONUP];
643}
644
645-(void)otherMouseDown: (NSEvent*)pEvent
646{
647    if( [pEvent buttonNumber] == 2 )
648    {
649        s_nLastButton = MOUSE_MIDDLE;
650        [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SALEVENT_MOUSEBUTTONDOWN];
651    }
652    else
653        s_nLastButton = 0;
654}
655
656-(void)otherMouseDragged: (NSEvent*)pEvent
657{
658    if( [pEvent buttonNumber] == 2 )
659    {
660        s_nLastButton = MOUSE_MIDDLE;
661        [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SALEVENT_MOUSEMOVE];
662    }
663    else
664        s_nLastButton = 0;
665}
666
667-(void)otherMouseUp: (NSEvent*)pEvent
668{
669    s_nLastButton = 0;
670    if( [pEvent buttonNumber] == 2 )
671        [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SALEVENT_MOUSEBUTTONUP];
672}
673
674- (void)magnifyWithEvent: (NSEvent*)pEvent
675{
676    YIELD_GUARD;
677
678    // TODO: ??  -(float)magnification;
679    if( AquaSalFrame::isAlive( mpFrame ) )
680	{
681		const NSTimeInterval fMagnifyTime = [pEvent timestamp];
682        mpFrame->mnLastEventTime = static_cast<sal_uLong>( fMagnifyTime * 1000.0 );
683        mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
684
685        // check if this is a new series of magnify events
686        static const NSTimeInterval fMaxDiffTime = 0.3;
687        const bool bNewSeries = (fMagnifyTime - mfLastMagnifyTime > fMaxDiffTime);
688
689        if( bNewSeries )
690            mfMagnifyDeltaSum = 0.0;
691        mfMagnifyDeltaSum += [pEvent deltaZ];
692
693		mfLastMagnifyTime = [pEvent timestamp];
694		// TODO: change to 0.1 when COMMAND_WHEEL_ZOOM handlers allow finer zooming control
695		static const float fMagnifyFactor = 0.25;
696        static const float fMinMagnifyStep = 15.0 / fMagnifyFactor;
697        if( fabs(mfMagnifyDeltaSum) <= fMinMagnifyStep )
698            return;
699
700        // adapt NSEvent-sensitivity to application expectations
701        // TODO: rather make COMMAND_WHEEL_ZOOM handlers smarter
702        const float fDeltaZ = mfMagnifyDeltaSum * fMagnifyFactor;
703        int nDeltaZ = FRound( fDeltaZ );
704        if( !nDeltaZ )
705        {
706            // handle new series immediately
707            if( !bNewSeries )
708                return;
709            nDeltaZ = (fDeltaZ >= 0.0) ? +1 : -1;
710        }
711        // eventually give credit for delta sum
712        mfMagnifyDeltaSum -= nDeltaZ / fMagnifyFactor;
713
714        NSPoint aPt = [NSEvent mouseLocation];
715        mpFrame->CocoaToVCL( aPt );
716
717        SalWheelMouseEvent aEvent;
718        aEvent.mnTime           = mpFrame->mnLastEventTime;
719        aEvent.mnX              = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
720        aEvent.mnY              = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
721        aEvent.mnCode           = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
722        aEvent.mnCode           |= KEY_MOD1; // we want zooming, no scrolling
723        aEvent.mbDeltaIsPixel   = TRUE;
724
725        // --- RTL --- (mirror mouse pos)
726        if( Application::GetSettings().GetLayoutRTL() )
727            aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
728
729        aEvent.mnDelta = nDeltaZ;
730        aEvent.mnNotchDelta = (nDeltaZ >= 0) ? +1 : -1;
731        if( aEvent.mnDelta == 0 )
732            aEvent.mnDelta = aEvent.mnNotchDelta;
733        aEvent.mbHorz = FALSE;
734        aEvent.mnScrollLines = nDeltaZ;
735        if( aEvent.mnScrollLines == 0 )
736            aEvent.mnScrollLines = 1;
737        mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
738    }
739}
740
741- (void)rotateWithEvent: (NSEvent*)pEvent
742{
743    //Rotation : -(float)rotation;
744    // TODO: create new CommandType so rotation is available to the applications
745    (void)pEvent;
746}
747
748- (void)swipeWithEvent: (NSEvent*)pEvent
749{
750    YIELD_GUARD;
751
752    if( AquaSalFrame::isAlive( mpFrame ) )
753    {
754        mpFrame->mnLastEventTime = static_cast<sal_uLong>( [pEvent timestamp] * 1000.0 );
755        mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
756
757        // merge pending scroll wheel events
758        float dX = 0.0;
759        float dY = 0.0;
760        for(;;)
761        {
762            dX += [pEvent deltaX];
763            dY += [pEvent deltaY];
764            NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
765            untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
766            if( !pNextEvent )
767                break;
768            pEvent = pNextEvent;
769        }
770
771        NSPoint aPt = [NSEvent mouseLocation];
772        mpFrame->CocoaToVCL( aPt );
773
774        SalWheelMouseEvent aEvent;
775        aEvent.mnTime           = mpFrame->mnLastEventTime;
776        aEvent.mnX              = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
777        aEvent.mnY              = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
778        aEvent.mnCode           = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
779        aEvent.mbDeltaIsPixel   = TRUE;
780
781        // --- RTL --- (mirror mouse pos)
782        if( Application::GetSettings().GetLayoutRTL() )
783            aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
784
785        if( dX != 0.0 )
786        {
787            aEvent.mnDelta = static_cast<long>(floor(dX));
788            aEvent.mnNotchDelta = dX < 0 ? -1 : 1;
789            if( aEvent.mnDelta == 0 )
790                aEvent.mnDelta = aEvent.mnNotchDelta;
791            aEvent.mbHorz = TRUE;
792            aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
793            mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
794        }
795        if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ))
796        {
797            aEvent.mnDelta = static_cast<long>(floor(dY));
798            aEvent.mnNotchDelta = dY < 0 ? -1 : 1;
799            if( aEvent.mnDelta == 0 )
800                aEvent.mnDelta = aEvent.mnNotchDelta;
801            aEvent.mbHorz = FALSE;
802            aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
803            mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
804        }
805    }
806}
807
808-(void)scrollWheel: (NSEvent*)pEvent
809{
810    YIELD_GUARD;
811
812    if( AquaSalFrame::isAlive( mpFrame ) )
813    {
814        mpFrame->mnLastEventTime = static_cast<sal_uLong>( [pEvent timestamp] * 1000.0 );
815        mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
816
817        // merge pending scroll wheel events
818        float dX = 0.0;
819        float dY = 0.0;
820        for(;;)
821        {
822            dX += [pEvent deltaX];
823    	    dY += [pEvent deltaY];
824            NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
825                untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
826            if( !pNextEvent )
827                break;
828            pEvent = pNextEvent;
829        }
830
831        NSPoint aPt = [NSEvent mouseLocation];
832        mpFrame->CocoaToVCL( aPt );
833
834        SalWheelMouseEvent aEvent;
835        aEvent.mnTime         = mpFrame->mnLastEventTime;
836        aEvent.mnX            = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
837        aEvent.mnY            = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
838        aEvent.mnCode         = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
839        aEvent.mbDeltaIsPixel = TRUE;
840
841        // --- RTL --- (mirror mouse pos)
842        if( Application::GetSettings().GetLayoutRTL() )
843            aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
844
845        if( dX != 0.0 )
846        {
847            aEvent.mnDelta = static_cast<long>(floor(dX));
848            aEvent.mnNotchDelta = dX < 0 ? -1 : 1;
849            if( aEvent.mnDelta == 0 )
850                aEvent.mnDelta = aEvent.mnNotchDelta;
851            aEvent.mbHorz = TRUE;
852            aEvent.mnScrollLines = dY > 0 ? dX/WHEEL_EVENT_FACTOR : -dX/WHEEL_EVENT_FACTOR;
853            if( aEvent.mnScrollLines == 0 )
854                aEvent.mnScrollLines = 1;
855
856            mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
857        }
858        if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ) )
859        {
860            aEvent.mnDelta = static_cast<long>(floor(dY));
861            aEvent.mnNotchDelta = dY < 0 ? -1 : 1;
862            if( aEvent.mnDelta == 0 )
863                aEvent.mnDelta = aEvent.mnNotchDelta;
864            aEvent.mbHorz = FALSE;
865            aEvent.mnScrollLines = dY > 0 ? dY/WHEEL_EVENT_FACTOR : -dY/WHEEL_EVENT_FACTOR;
866            if( aEvent.mnScrollLines < 1 )
867                aEvent.mnScrollLines = 1;
868
869            mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
870        }
871    }
872}
873
874
875-(void)keyDown: (NSEvent*)pEvent
876{
877    YIELD_GUARD;
878
879    if( AquaSalFrame::isAlive( mpFrame ) )
880    {
881        mpLastEvent = pEvent;
882        mbInKeyInput = true;
883        mbNeedSpecialKeyHandle = false;
884        mbKeyHandled = false;
885
886        mpFrame->mnLastEventTime = static_cast<sal_uLong>( [pEvent timestamp] * 1000.0 );
887        mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
888
889        if( ! [self handleKeyDownException: pEvent] )
890        {
891            NSArray* pArray = [NSArray arrayWithObject: pEvent];
892            [self interpretKeyEvents: pArray];
893        }
894
895        mbInKeyInput = false;
896    }
897}
898
899-(BOOL)handleKeyDownException:(NSEvent*)pEvent
900{
901    // check for a very special set of modified characters
902    NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
903
904    if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
905    {
906        /* #i103102# key events with command and alternate don't make it through
907           interpretKeyEvents (why ?). Try to dispatch them here first,
908           if not successful continue normally
909        */
910        if( (mpFrame->mnLastModifierFlags & (NSAlternateKeyMask | NSCommandKeyMask))
911                    == (NSAlternateKeyMask | NSCommandKeyMask) )
912        {
913            if( [self sendSingleCharacter: mpLastEvent] )
914                return YES;
915        }
916        unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
917        sal_uInt16 nKeyCode = ImplMapCharCode( keyChar );
918
919        // Caution: should the table grow to more than 5 or 6 entries,
920        // we must consider moving it to a kind of hash map
921        const unsigned int nExceptions = sizeof( aExceptionalKeys ) / sizeof( aExceptionalKeys[0] );
922        for( unsigned int i = 0; i < nExceptions; i++ )
923        {
924            if( nKeyCode == aExceptionalKeys[i].nKeyCode &&
925                (mpFrame->mnLastModifierFlags & aExceptionalKeys[i].nModifierMask)
926                == aExceptionalKeys[i].nModifierMask )
927            {
928                [self sendKeyInputAndReleaseToFrame: nKeyCode character: 0];
929
930                return YES;
931            }
932        }
933    }
934    return NO;
935}
936
937-(void)flagsChanged: (NSEvent*)pEvent
938{
939    YIELD_GUARD;
940
941    if( AquaSalFrame::isAlive( mpFrame ) )
942    {
943        mpFrame->mnLastEventTime = static_cast<sal_uLong>( [pEvent timestamp] * 1000.0 );
944        mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
945    }
946}
947
948-(void)insertText:(id)aString
949{
950    YIELD_GUARD;
951
952    if( AquaSalFrame::isAlive( mpFrame ) )
953    {
954        NSString* pInsert = nil;
955        if( [aString isMemberOfClass: [NSAttributedString class]] )
956            pInsert = [aString string];
957        else
958            pInsert = aString;
959
960        int nLen = 0;
961        if( pInsert && ( nLen = [pInsert length] ) > 0 )
962        {
963            OUString aInsertString( GetOUString( pInsert ) );
964             // aCharCode initializer is safe since aInsertString will at least contain '\0'
965            sal_Unicode aCharCode = *aInsertString.getStr();
966
967            if( nLen == 1 &&
968                aCharCode < 0x80 &&
969                aCharCode > 0x1f &&
970				! [self hasMarkedText ]
971                )
972            {
973                sal_uInt16 nKeyCode = ImplMapCharCode( aCharCode );
974                unsigned int nLastModifiers = mpFrame->mnLastModifierFlags;
975
976                // #i99567#
977                // find out the unmodified key code
978
979                // sanity check
980                if( mpLastEvent && ( [mpLastEvent type] == NSKeyDown || [mpLastEvent type] == NSKeyUp ) )
981                {
982                    // get unmodified string
983                    NSString* pUnmodifiedString = [mpLastEvent charactersIgnoringModifiers];
984                    if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
985                    {
986                        // map the unmodified key code
987                        unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
988                        nKeyCode = ImplMapCharCode( keyChar );
989                    }
990                    nLastModifiers = [mpLastEvent modifierFlags];
991
992                }
993                // #i99567#
994                // applications and vcl's edit fields ignore key events with ALT
995                // however we're at a place where we know text should be inserted
996                // so it seems we need to strip the Alt modifier here
997                if( (nLastModifiers & (NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask))
998                    == NSAlternateKeyMask )
999                {
1000                    nLastModifiers = 0;
1001                }
1002                [self sendKeyInputAndReleaseToFrame: nKeyCode character: aCharCode modifiers: nLastModifiers];
1003            }
1004            else
1005            {
1006                SalExtTextInputEvent aEvent;
1007                aEvent.mnTime           = mpFrame->mnLastEventTime;
1008                aEvent.maText           = aInsertString;
1009                aEvent.mpTextAttr       = NULL;
1010                aEvent.mnCursorPos      = aInsertString.getLength();
1011                aEvent.mnDeltaStart     = 0;
1012                aEvent.mnCursorFlags    = 0;
1013                aEvent.mbOnlyCursor     = FALSE;
1014                mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, &aEvent );
1015                if( AquaSalFrame::isAlive( mpFrame ) )
1016                    mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
1017            }
1018        }
1019        else
1020        {
1021            SalExtTextInputEvent aEvent;
1022            aEvent.mnTime           = mpFrame->mnLastEventTime;
1023            aEvent.maText           = String();
1024            aEvent.mpTextAttr       = NULL;
1025            aEvent.mnCursorPos      = 0;
1026            aEvent.mnDeltaStart     = 0;
1027            aEvent.mnCursorFlags    = 0;
1028            aEvent.mbOnlyCursor     = FALSE;
1029            mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, &aEvent );
1030            if( AquaSalFrame::isAlive( mpFrame ) )
1031                mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
1032
1033        }
1034        mbKeyHandled = true;
1035        [self unmarkText];
1036    }
1037}
1038
1039-(void)insertTab: (id)aSender
1040{
1041    (void)aSender;
1042    [self sendKeyInputAndReleaseToFrame: KEY_TAB character: '\t' modifiers: 0];
1043}
1044
1045-(void)insertBacktab: (id)aSender
1046{
1047    (void)aSender;
1048    [self sendKeyInputAndReleaseToFrame: (KEY_TAB | KEY_SHIFT) character: '\t' modifiers: 0];
1049}
1050
1051-(void)moveLeft: (id)aSender
1052{
1053    (void)aSender;
1054    [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: 0];
1055}
1056
1057-(void)moveLeftAndModifySelection: (id)aSender
1058{
1059    (void)aSender;
1060    [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: NSShiftKeyMask];
1061}
1062
1063-(void)moveBackwardAndModifySelection: (id)aSender
1064{
1065    (void)aSender;
1066    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_BACKWARD character: 0  modifiers: 0];
1067}
1068
1069-(void)moveRight: (id)aSender
1070{
1071    (void)aSender;
1072    [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: 0];
1073}
1074
1075-(void)moveRightAndModifySelection: (id)aSender
1076{
1077    (void)aSender;
1078    [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: NSShiftKeyMask];
1079}
1080
1081-(void)moveForwardAndModifySelection: (id)aSender
1082{
1083    (void)aSender;
1084    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_FORWARD character: 0  modifiers: 0];
1085}
1086
1087-(void)moveWordLeft: (id)aSender
1088{
1089    (void)aSender;
1090    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_BACKWARD character: 0  modifiers: 0];
1091}
1092
1093-(void)moveWordBackward: (id)aSender
1094{
1095    (void)aSender;
1096    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_BACKWARD character: 0  modifiers: 0];
1097}
1098
1099-(void)moveWordBackwardAndModifySelection: (id)aSender
1100{
1101    (void)aSender;
1102    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_BACKWARD character: 0  modifiers: 0];
1103}
1104
1105-(void)moveWordLeftAndModifySelection: (id)aSender
1106{
1107    (void)aSender;
1108    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_BACKWARD character: 0  modifiers: 0];
1109}
1110
1111-(void)moveWordRight: (id)aSender
1112{
1113    (void)aSender;
1114    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_FORWARD character: 0  modifiers: 0];
1115}
1116
1117-(void)moveWordForward: (id)aSender
1118{
1119    (void)aSender;
1120    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_FORWARD character: 0  modifiers: 0];
1121}
1122
1123-(void)moveWordForwardAndModifySelection: (id)aSender
1124{
1125    (void)aSender;
1126    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_FORWARD character: 0  modifiers: 0];
1127}
1128
1129-(void)moveWordRightAndModifySelection: (id)aSender
1130{
1131    (void)aSender;
1132    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_FORWARD character: 0  modifiers: 0];
1133}
1134
1135-(void)moveToEndOfLine: (id)aSender
1136{
1137    (void)aSender;
1138    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_LINE character: 0  modifiers: 0];
1139}
1140
1141-(void)moveToRightEndOfLine: (id)aSender
1142{
1143    (void)aSender;
1144    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_LINE character: 0  modifiers: 0];
1145}
1146
1147-(void)moveToEndOfLineAndModifySelection: (id)aSender
1148{
1149    (void)aSender;
1150    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_LINE character: 0  modifiers: 0];
1151}
1152
1153-(void)moveToRightEndOfLineAndModifySelection: (id)aSender
1154{
1155    (void)aSender;
1156    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_LINE character: 0  modifiers: 0];
1157}
1158
1159-(void)moveToBeginningOfLine: (id)aSender
1160{
1161    (void)aSender;
1162    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0  modifiers: 0];
1163}
1164
1165-(void)moveToLeftEndOfLine: (id)aSender
1166{
1167    (void)aSender;
1168    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0  modifiers: 0];
1169}
1170
1171-(void)moveToBeginningOfLineAndModifySelection: (id)aSender
1172{
1173    (void)aSender;
1174    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0  modifiers: 0];
1175}
1176
1177-(void)moveToLeftEndOfLineAndModifySelection: (id)aSender
1178{
1179    (void)aSender;
1180    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0  modifiers: 0];
1181}
1182
1183-(void)moveToEndOfParagraph: (id)aSender
1184{
1185    (void)aSender;
1186    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0  modifiers: 0];
1187}
1188
1189-(void)moveToEndOfParagraphAndModifySelection: (id)aSender
1190{
1191    (void)aSender;
1192    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0  modifiers: 0];
1193}
1194
1195-(void)moveParagraphForward: (id)aSender
1196{
1197    (void)aSender;
1198    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0  modifiers: 0];
1199}
1200
1201-(void)moveParagraphForwardAndModifySelection: (id)aSender
1202{
1203    (void)aSender;
1204    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0  modifiers: 0];
1205}
1206
1207-(void)moveToBeginningOfParagraph: (id)aSender
1208{
1209    (void)aSender;
1210    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0  modifiers: 0];
1211}
1212
1213-(void)moveParagraphBackward: (id)aSender
1214{
1215    (void)aSender;
1216    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0  modifiers: 0];
1217}
1218
1219-(void)moveToBeginningOfParagraphAndModifySelection: (id)aSender
1220{
1221    (void)aSender;
1222    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0  modifiers: 0];
1223}
1224
1225-(void)moveParagraphBackwardAndModifySelection: (id)aSender
1226{
1227    (void)aSender;
1228    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0  modifiers: 0];
1229}
1230
1231-(void)moveToEndOfDocument: (id)aSender
1232{
1233    (void)aSender;
1234    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0  modifiers: 0];
1235}
1236
1237-(void)scrollToEndOfDocument: (id)aSender
1238{
1239    (void)aSender;
1240    // this is not exactly what we should do, but it makes "End" and "Shift-End" behave consistent
1241    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0  modifiers: 0];
1242}
1243
1244-(void)moveToEndOfDocumentAndModifySelection: (id)aSender
1245{
1246    (void)aSender;
1247    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT character: 0  modifiers: 0];
1248}
1249
1250-(void)moveToBeginningOfDocument: (id)aSender
1251{
1252    (void)aSender;
1253    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0  modifiers: 0];
1254}
1255
1256-(void)scrollToBeginningOfDocument: (id)aSender
1257{
1258    (void)aSender;
1259    // this is not exactly what we should do, but it makes "Home" and "Shift-Home" behave consistent
1260    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0  modifiers: 0];
1261}
1262
1263-(void)moveToBeginningOfDocumentAndModifySelection: (id)aSender
1264{
1265    (void)aSender;
1266    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT character: 0  modifiers: 0];
1267}
1268
1269-(void)moveUp: (id)aSender
1270{
1271    (void)aSender;
1272    [self sendKeyInputAndReleaseToFrame: KEY_UP character: 0 modifiers: 0];
1273}
1274
1275-(void)moveDown: (id)aSender
1276{
1277    (void)aSender;
1278    [self sendKeyInputAndReleaseToFrame: KEY_DOWN character: 0 modifiers: 0];
1279}
1280
1281-(void)insertNewline: (id)aSender
1282{
1283    (void)aSender;
1284    // #i91267# make enter and shift-enter work by evaluating the modifiers
1285    [self sendKeyInputAndReleaseToFrame: KEY_RETURN character: '\n' modifiers: mpFrame->mnLastModifierFlags];
1286}
1287
1288-(void)deleteBackward: (id)aSender
1289{
1290    (void)aSender;
1291    [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
1292}
1293
1294-(void)deleteForward: (id)aSender
1295{
1296    (void)aSender;
1297    [self sendKeyInputAndReleaseToFrame: KEY_DELETE character: 0x7f modifiers: 0];
1298}
1299
1300-(void)deleteBackwardByDecomposingPreviousCharacter: (id)aSender
1301{
1302    (void)aSender;
1303    [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
1304}
1305
1306-(void)deleteWordBackward: (id)aSender
1307{
1308    (void)aSender;
1309    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_WORD_BACKWARD character: 0  modifiers: 0];
1310}
1311
1312-(void)deleteWordForward: (id)aSender
1313{
1314    (void)aSender;
1315    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_WORD_FORWARD character: 0  modifiers: 0];
1316}
1317
1318-(void)deleteToBeginningOfLine: (id)aSender
1319{
1320    (void)aSender;
1321    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE character: 0  modifiers: 0];
1322}
1323
1324-(void)deleteToEndOfLine: (id)aSender
1325{
1326    (void)aSender;
1327    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_END_OF_LINE character: 0  modifiers: 0];
1328}
1329
1330-(void)deleteToBeginningOfParagraph: (id)aSender
1331{
1332    (void)aSender;
1333    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH character: 0  modifiers: 0];
1334}
1335
1336-(void)deleteToEndOfParagraph: (id)aSender
1337{
1338    (void)aSender;
1339    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_END_OF_PARAGRAPH character: 0  modifiers: 0];
1340}
1341
1342-(void)insertLineBreak: (id)aSender
1343{
1344    (void)aSender;
1345    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::INSERT_LINEBREAK character: 0  modifiers: 0];
1346}
1347
1348-(void)insertParagraphSeparator: (id)aSender
1349{
1350    (void)aSender;
1351    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::INSERT_PARAGRAPH character: 0  modifiers: 0];
1352}
1353
1354-(void)selectWord: (id)aSender
1355{
1356    (void)aSender;
1357    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD character: 0  modifiers: 0];
1358}
1359
1360-(void)selectLine: (id)aSender
1361{
1362    (void)aSender;
1363    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_LINE character: 0  modifiers: 0];
1364}
1365
1366-(void)selectParagraph: (id)aSender
1367{
1368    (void)aSender;
1369    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_PARAGRAPH character: 0  modifiers: 0];
1370}
1371
1372-(void)selectAll: (id)aSender
1373{
1374    (void)aSender;
1375    [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_ALL character: 0  modifiers: 0];
1376}
1377
1378-(void)cancelOperation: (id)aSender
1379{
1380    (void)aSender;
1381    [self sendKeyInputAndReleaseToFrame: KEY_ESCAPE character: 0x1b modifiers: 0];
1382}
1383
1384-(void)noop: (id)aSender
1385{
1386    (void)aSender;
1387    if( ! mbKeyHandled )
1388    {
1389        if( ! [self sendSingleCharacter:mpLastEvent] )
1390        {
1391            /* prevent recursion */
1392            if( mpLastEvent != mpLastSuperEvent && [NSApp respondsToSelector: @selector(sendSuperEvent:)] )
1393            {
1394                id pLastSuperEvent = mpLastSuperEvent;
1395                mpLastSuperEvent = mpLastEvent;
1396                [NSApp performSelector:@selector(sendSuperEvent:) withObject: mpLastEvent];
1397                mpLastSuperEvent = pLastSuperEvent;
1398
1399                std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
1400                if( it != GetSalData()->maKeyEventAnswer.end() )
1401                    it->second = true;
1402            }
1403        }
1404    }
1405}
1406
1407-(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar
1408{
1409    return [self sendKeyInputAndReleaseToFrame: nKeyCode character: aChar modifiers: mpFrame->mnLastModifierFlags];
1410}
1411
1412-(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
1413{
1414    return [self sendKeyToFrameDirect: nKeyCode character: aChar modifiers: nMod] ||
1415           [self sendSingleCharacter: mpLastEvent];
1416}
1417
1418-(BOOL)sendKeyToFrameDirect: (sal_uInt16)nKeyCode  character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
1419{
1420    YIELD_GUARD;
1421
1422    long nRet = 0;
1423    if( AquaSalFrame::isAlive( mpFrame ) )
1424    {
1425        SalKeyEvent aEvent;
1426        aEvent.mnTime           = mpFrame->mnLastEventTime;
1427        aEvent.mnCode           = nKeyCode | ImplGetModifierMask( nMod );
1428        aEvent.mnCharCode       = aChar;
1429        aEvent.mnRepeat         = FALSE;
1430        nRet = mpFrame->CallCallback( SALEVENT_KEYINPUT, &aEvent );
1431        std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
1432        if( it != GetSalData()->maKeyEventAnswer.end() )
1433            it->second = nRet ? true : false;
1434        if( AquaSalFrame::isAlive( mpFrame ) )
1435            mpFrame->CallCallback( SALEVENT_KEYUP, &aEvent );
1436    }
1437    return nRet ? YES : NO;
1438}
1439
1440
1441-(BOOL)sendSingleCharacter: (NSEvent *)pEvent
1442{
1443    NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
1444
1445    if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
1446    {
1447        unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
1448        sal_uInt16 nKeyCode = ImplMapCharCode( keyChar );
1449        if( nKeyCode != 0 )
1450        {
1451            // don't send unicodes in the private use area
1452            if( keyChar >= 0xf700 && keyChar < 0xf780 )
1453                keyChar = 0;
1454            BOOL bRet = [self sendKeyToFrameDirect: nKeyCode character: keyChar modifiers: mpFrame->mnLastModifierFlags];
1455            mbInKeyInput = false;
1456
1457            return bRet;
1458        }
1459    }
1460    return NO;
1461}
1462
1463
1464// NSTextInput protocol
1465- (NSArray *)validAttributesForMarkedText
1466{
1467    return [NSArray arrayWithObjects:NSUnderlineStyleAttributeName, nil];
1468}
1469
1470- (BOOL)hasMarkedText
1471{
1472    BOOL bHasMarkedText;
1473
1474    bHasMarkedText = ( mMarkedRange.location != NSNotFound ) &&
1475                     ( mMarkedRange.length != 0 );
1476    // hack to check keys like "Control-j"
1477    if( mbInKeyInput )
1478    {
1479        mbNeedSpecialKeyHandle = true;
1480    }
1481
1482    // FIXME:
1483    // #i106901#
1484    // if we come here outside of mbInKeyInput, this is likely to be because
1485    // of the keyboard viewer. For unknown reasons having no marked range
1486    // in this case causes a crash. So we say we have a marked range anyway
1487    // This is a hack, since it is not understood what a) causes that crash
1488    // and b) why we should have a marked range at this point.
1489    if( ! mbInKeyInput )
1490        bHasMarkedText = YES;
1491
1492    return bHasMarkedText;
1493}
1494
1495- (NSRange)markedRange
1496{
1497    // FIXME:
1498    // #i106901#
1499    // if we come here outside of mbInKeyInput, this is likely to be because
1500    // of the keyboard viewer. For unknown reasons having no marked range
1501    // in this case causes a crash. So we say we have a marked range anyway
1502    // This is a hack, since it is not understood what a) causes that crash
1503    // and b) why we should have a marked range at this point.
1504    if( ! mbInKeyInput )
1505        return NSMakeRange( 0, 0 );
1506
1507    return [self hasMarkedText] ? mMarkedRange : NSMakeRange( NSNotFound, 0 );
1508}
1509
1510- (NSRange)selectedRange
1511{
1512    return mSelectedRange;
1513}
1514
1515- (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange
1516{
1517    if( ![aString isKindOfClass:[NSAttributedString class]] )
1518        aString = [[[NSAttributedString alloc] initWithString:aString] autorelease];
1519    NSRange rangeToReplace = [self hasMarkedText] ? [self markedRange] : [self selectedRange];
1520    if( rangeToReplace.location == NSNotFound )
1521    {
1522        mMarkedRange = NSMakeRange( selRange.location, [aString length] );
1523        mSelectedRange = NSMakeRange( selRange.location, selRange.length );
1524    }
1525    else
1526    {
1527        mMarkedRange = NSMakeRange( rangeToReplace.location, [aString length] );
1528        mSelectedRange = NSMakeRange( rangeToReplace.location + selRange.location, selRange.length );
1529    }
1530
1531    int len = [aString length];
1532    SalExtTextInputEvent aInputEvent;
1533    aInputEvent.mnTime = mpFrame->mnLastEventTime;
1534    aInputEvent.mnDeltaStart = 0;
1535    aInputEvent.mbOnlyCursor = FALSE;
1536    if( len > 0 ) {
1537        NSString *pString = [aString string];
1538        OUString aInsertString( GetOUString( pString ) );
1539        std::vector<sal_uInt16> aInputFlags = std::vector<sal_uInt16>( std::max( 1, len ), 0 );
1540        for ( int i = 0; i < len; i++ )
1541        {
1542            unsigned int nUnderlineValue;
1543            NSRange effectiveRange;
1544
1545            effectiveRange = NSMakeRange(i, 1);
1546            nUnderlineValue = [[aString attribute:NSUnderlineStyleAttributeName atIndex:i effectiveRange:&effectiveRange] unsignedIntValue];
1547
1548            switch (nUnderlineValue & 0xff) {
1549            case NSUnderlineStyleSingle:
1550                aInputFlags[i] = SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
1551                break;
1552            case NSUnderlineStyleThick:
1553                aInputFlags[i] = SAL_EXTTEXTINPUT_ATTR_UNDERLINE | SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT;
1554                break;
1555            case NSUnderlineStyleDouble:
1556                aInputFlags[i] = SAL_EXTTEXTINPUT_ATTR_BOLDUNDERLINE;
1557                break;
1558            default:
1559                aInputFlags[i] = SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT;
1560                break;
1561            }
1562        }
1563
1564        aInputEvent.maText = aInsertString;
1565        aInputEvent.mnCursorPos = selRange.location;
1566        aInputEvent.mpTextAttr = &aInputFlags[0];
1567        mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void *)&aInputEvent );
1568    } else {
1569        aInputEvent.maText = String();
1570        aInputEvent.mnCursorPos = 0;
1571        aInputEvent.mnCursorFlags = 0;
1572        aInputEvent.mpTextAttr = 0;
1573        mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void *)&aInputEvent );
1574        mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
1575    }
1576    mbKeyHandled= true;
1577}
1578
1579- (void)unmarkText
1580{
1581    mSelectedRange = mMarkedRange = NSMakeRange(NSNotFound, 0);
1582}
1583
1584- (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange
1585{
1586    (void)theRange;
1587    // FIXME
1588    return nil;
1589}
1590
1591- (unsigned int)characterIndexForPoint:(NSPoint)thePoint
1592{
1593    (void)thePoint;
1594    // FIXME
1595    return 0;
1596}
1597
1598#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
1599/* build target 10.5 or greater */
1600- (NSInteger)conversationIdentifier
1601#else
1602/* build target 10.4 */
1603- (long)conversationIdentifier
1604#endif
1605{
1606    return (long)self;
1607}
1608
1609- (void)doCommandBySelector:(SEL)aSelector
1610{
1611    if( AquaSalFrame::isAlive( mpFrame ) )
1612    {
1613        #if OSL_DEBUG_LEVEL > 1
1614        // fprintf( stderr, "SalFrameView: doCommandBySelector %s\n", (char*)aSelector );
1615        #endif
1616        if( (mpFrame->mnICOptions & SAL_INPUTCONTEXT_TEXT) != 0 &&
1617            aSelector != NULL && [self respondsToSelector: aSelector] )
1618        {
1619            [self performSelector: aSelector];
1620        }
1621        else
1622        {
1623            [self sendSingleCharacter:mpLastEvent];
1624        }
1625    }
1626
1627    mbKeyHandled = true;
1628}
1629
1630-(void)clearLastEvent
1631{
1632    mpLastEvent = nil;
1633}
1634
1635- (NSRect)firstRectForCharacterRange:(NSRange)theRange
1636{
1637    (void)theRange;
1638    SalExtTextInputPosEvent aPosEvent;
1639    mpFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void *)&aPosEvent );
1640
1641    NSRect rect;
1642
1643    rect.origin.x = aPosEvent.mnX + mpFrame->maGeometry.nX;
1644    rect.origin.y =   aPosEvent.mnY + mpFrame->maGeometry.nY + 4; // add some space for underlines
1645    rect.size.width = aPosEvent.mnWidth;
1646    rect.size.height = aPosEvent.mnHeight;
1647
1648    mpFrame->VCLToCocoa( rect );
1649    return rect;
1650}
1651
1652-(id)parentAttribute {
1653    return (NSView *) mpFrame -> mpWindow;
1654}
1655
1656-(::com::sun::star::accessibility::XAccessibleContext *)accessibleContext
1657{
1658    if ( mpReferenceWrapper == nil ) {
1659        // some frames never become visible ..
1660        Window *pWindow = mpFrame -> GetWindow();
1661        if ( ! pWindow )
1662            return nil;
1663
1664        mpReferenceWrapper = new ReferenceWrapper;
1665        mpReferenceWrapper -> rAccessibleContext =  pWindow -> /*GetAccessibleChildWindow( 0 ) ->*/ GetAccessible() -> getAccessibleContext();
1666        [ AquaA11yFactory insertIntoWrapperRepository: self forAccessibleContext: mpReferenceWrapper -> rAccessibleContext ];
1667    }
1668    return [ super accessibleContext ];
1669}
1670
1671-(NSView *)viewElementForParent
1672{
1673    return (NSView *) mpFrame -> mpWindow;
1674}
1675
1676-(void)registerMouseEventListener: (id)theListener
1677{
1678  mpMouseEventListener = theListener;
1679}
1680
1681-(void)unregisterMouseEventListener: (id)theListener
1682{
1683    (void)theListener;
1684    mpMouseEventListener = nil;
1685}
1686
1687-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
1688{
1689  return [mDraggingDestinationHandler draggingEntered: sender];
1690}
1691
1692-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
1693{
1694  return [mDraggingDestinationHandler draggingUpdated: sender];
1695}
1696
1697-(void)draggingExited:(id <NSDraggingInfo>)sender
1698{
1699  [mDraggingDestinationHandler draggingExited: sender];
1700}
1701
1702-(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
1703{
1704  return [mDraggingDestinationHandler prepareForDragOperation: sender];
1705}
1706
1707-(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
1708{
1709  return [mDraggingDestinationHandler performDragOperation: sender];
1710}
1711
1712-(void)concludeDragOperation:(id <NSDraggingInfo>)sender
1713{
1714  [mDraggingDestinationHandler concludeDragOperation: sender];
1715}
1716
1717-(void)registerDraggingDestinationHandler:(id)theHandler
1718{
1719  mDraggingDestinationHandler = theHandler;
1720}
1721
1722-(void)unregisterDraggingDestinationHandler:(id)theHandler
1723{
1724    (void)theHandler;
1725    mDraggingDestinationHandler = nil;
1726}
1727
1728@end
1729
1730