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