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