bump product version to 6.4.0.3
[LibreOffice.git] / vcl / osx / salframeview.mm
blobc2c9169a40dfaedf57232b589e7ce5a4a5d6ce6b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
20 #include <sal/config.h>
22 #include <sal/macros.h>
23 #include <tools/helpers.hxx>
25 #include <vcl/event.hxx>
26 #include <vcl/inputctx.hxx>
27 #include <vcl/settings.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/window.hxx>
30 #include <vcl/commandevent.hxx>
32 #include <osx/a11yfactory.h>
33 #include <osx/salframe.h>
34 #include <osx/salframeview.h>
35 #include <osx/salinst.h>
36 #include <quartz/salgdi.h>
37 #include <quartz/utils.h>
39 #define WHEEL_EVENT_FACTOR 1.5
41 static sal_uInt16 ImplGetModifierMask( unsigned int nMask )
43     sal_uInt16 nRet = 0;
44 SAL_WNODEPRECATED_DECLARATIONS_PUSH
45         // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12
46         // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12
47         // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12
48         // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12
49     if( (nMask & NSShiftKeyMask) != 0 )
50         nRet |= KEY_SHIFT;
51     if( (nMask & NSControlKeyMask) != 0 )
52         nRet |= KEY_MOD3;
53     if( (nMask & NSAlternateKeyMask) != 0 )
54         nRet |= KEY_MOD2;
55     if( (nMask & NSCommandKeyMask) != 0 )
56         nRet |= KEY_MOD1;
57 SAL_WNODEPRECATED_DECLARATIONS_POP
58     return nRet;
61 static sal_uInt16 ImplMapCharCode( sal_Unicode aCode )
63     static sal_uInt16 aKeyCodeMap[ 128 ] =
64     {
65                     0,                0,                0,                0,                0,                0,                0,                0,
66         KEY_BACKSPACE,          KEY_TAB,       KEY_RETURN,                0,                0,       KEY_RETURN,                0,                0,
67                     0,                0,                0,                0,                0,                0,                0,                0,
68                     0,          KEY_TAB,                0,       KEY_ESCAPE,                0,                0,                0,                0,
69             KEY_SPACE,                0,                0,                0,                0,                0,                0,                0,
70                     0,                0,     KEY_MULTIPLY,          KEY_ADD,        KEY_COMMA,     KEY_SUBTRACT,        KEY_POINT,       KEY_DIVIDE,
71                 KEY_0,            KEY_1,            KEY_2,            KEY_3,            KEY_4,            KEY_5,            KEY_6,            KEY_7,
72                 KEY_8,            KEY_9,                0,                0,         KEY_LESS,        KEY_EQUAL,      KEY_GREATER,                0,
73                     0,            KEY_A,            KEY_B,            KEY_C,            KEY_D,            KEY_E,            KEY_F,            KEY_G,
74                 KEY_H,            KEY_I,            KEY_J,            KEY_K,            KEY_L,            KEY_M,            KEY_N,            KEY_O,
75                 KEY_P,            KEY_Q,            KEY_R,            KEY_S,            KEY_T,            KEY_U,            KEY_V,            KEY_W,
76                 KEY_X,            KEY_Y,            KEY_Z,                0,                0,                0,                0,                0,
77         KEY_QUOTELEFT,            KEY_A,            KEY_B,            KEY_C,            KEY_D,            KEY_E,            KEY_F,            KEY_G,
78                 KEY_H,            KEY_I,            KEY_J,            KEY_K,            KEY_L,            KEY_M,            KEY_N,            KEY_O,
79                 KEY_P,            KEY_Q,            KEY_R,            KEY_S,            KEY_T,            KEY_U,            KEY_V,            KEY_W,
80                 KEY_X,            KEY_Y,            KEY_Z,                0,                0,                0,        KEY_TILDE,    KEY_BACKSPACE
81     };
83     // Note: the mapping 0x7f should by rights be KEY_DELETE
84     // however if you press "backspace" 0x7f is reported
85     // whereas for "delete" 0xf728 gets reported
87     // Note: the mapping of 0x19 to KEY_TAB is because for unknown reasons
88     // tab alone is reported as 0x09 (as expected) but shift-tab is
89     // reported as 0x19 (end of medium)
91     static sal_uInt16 aFunctionKeyCodeMap[ 128 ] =
92     {
93             KEY_UP,         KEY_DOWN,         KEY_LEFT,        KEY_RIGHT,           KEY_F1,           KEY_F2,           KEY_F3,           KEY_F4,
94             KEY_F5,           KEY_F6,           KEY_F7,           KEY_F8,           KEY_F9,          KEY_F10,          KEY_F11,          KEY_F12,
95            KEY_F13,          KEY_F14,          KEY_F15,          KEY_F16,          KEY_F17,          KEY_F18,          KEY_F19,          KEY_F20,
96            KEY_F21,          KEY_F22,          KEY_F23,          KEY_F24,          KEY_F25,          KEY_F26,                0,                0,
97                  0,                0,                0,                0,                0,                0,                0,       KEY_INSERT,
98         KEY_DELETE,         KEY_HOME,                0,          KEY_END,        KEY_PAGEUP,    KEY_PAGEDOWN,                0,                0,
99                  0,                0,                0,                0,                 0,        KEY_MENU,                0,                0,
100                  0,                0,                0,                0,                 0,               0,                0,                0,
101                  0,                0,                0,         KEY_UNDO,        KEY_REPEAT,        KEY_FIND,         KEY_HELP,                0,
102                  0,                0,                0,                0,                 0,               0,                0,                0,
103                  0,                0,                0,                0,                 0,               0,                0,                0,
104                  0,                0,                0,                0,                 0,               0,                0,                0,
105                  0,                0,                0,                0,                 0,               0,                0,                0,
106                  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     };
111     sal_uInt16 nKeyCode = 0;
112     if( aCode < SAL_N_ELEMENTS( aKeyCodeMap)  )
113         nKeyCode = aKeyCodeMap[ aCode ];
114     else if( aCode >= 0xf700 && aCode < 0xf780 )
115         nKeyCode = aFunctionKeyCodeMap[ aCode - 0xf700 ];
116     return nKeyCode;
119 static sal_uInt16 ImplMapKeyCode(sal_uInt16 nKeyCode)
121     /*
122       http://stackoverflow.com/questions/2080312/where-can-i-find-a-list-of-key-codes-for-use-with-cocoas-nsevent-class/2080324#2080324
123       /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h
124      */
126     static sal_uInt16 aKeyCodeMap[ 0x80 ] =
127     {
128             KEY_A,            KEY_S,            KEY_D,            KEY_F,            KEY_H,            KEY_G,            KEY_Z,            KEY_X,
129             KEY_C,            KEY_V,                0,            KEY_B,            KEY_Q,            KEY_W,            KEY_E,            KEY_R,
130             KEY_Y,            KEY_T,            KEY_1,            KEY_2,            KEY_3,            KEY_4,            KEY_6,            KEY_5,
131         KEY_EQUAL,            KEY_9,            KEY_7,     KEY_SUBTRACT,            KEY_8,            KEY_0, KEY_BRACKETRIGHT,            KEY_0,
132             KEY_U,  KEY_BRACKETLEFT,            KEY_I,            KEY_P,       KEY_RETURN,            KEY_L,            KEY_J,   KEY_QUOTERIGHT,
133             KEY_K,    KEY_SEMICOLON,                0,        KEY_COMMA,       KEY_DIVIDE,            KEY_N,            KEY_M,        KEY_POINT,
134           KEY_TAB,        KEY_SPACE,    KEY_QUOTELEFT,       KEY_DELETE,                0,       KEY_ESCAPE,                0,                0,
135                 0,     KEY_CAPSLOCK,                0,                0,                0,                0,                0,                0,
136           KEY_F17,      KEY_DECIMAL,                0,     KEY_MULTIPLY,                0,          KEY_ADD,                0,                0,
137                 0,                0,                0,       KEY_DIVIDE,       KEY_RETURN,                0,     KEY_SUBTRACT,          KEY_F18,
138           KEY_F19,        KEY_EQUAL,                0,                0,                0,                0,                0,                0,
139                 0,                0,          KEY_F20,                0,                0,                0,                0,                0,
140            KEY_F5,           KEY_F6,           KEY_F7,           KEY_F3,           KEY_F8,           KEY_F9,                0,          KEY_F11,
141                 0,          KEY_F13,          KEY_F16,          KEY_F14,                0,          KEY_F10,                0,          KEY_F12,
142                 0,          KEY_F15,         KEY_HELP,         KEY_HOME,       KEY_PAGEUP,       KEY_DELETE,           KEY_F4,          KEY_END,
143            KEY_F2,     KEY_PAGEDOWN,           KEY_F1,         KEY_LEFT,        KEY_RIGHT,         KEY_DOWN,           KEY_UP,                0
144     };
146     if (nKeyCode < SAL_N_ELEMENTS(aKeyCodeMap))
147         return aKeyCodeMap[nKeyCode];
148     return 0;
151 // store the frame the mouse last entered
152 static AquaSalFrame* s_pMouseFrame = nullptr;
153 // store the last pressed button for enter/exit events
154 // which lack that information
155 static sal_uInt16 s_nLastButton = 0;
157 static AquaSalFrame* getMouseContainerFrame()
159     AquaSalFrame* pDispatchFrame = nullptr;
160     NSArray* aWindows = [NSWindow windowNumbersWithOptions:0];
161     for(NSUInteger i = 0; i < [aWindows count] && ! pDispatchFrame; i++ )
162     {
163         NSWindow* pWin = [NSApp windowWithWindowNumber:[[aWindows objectAtIndex:i] integerValue]];
164         if( pWin && [pWin isMemberOfClass: [SalFrameWindow class]] && [static_cast<SalFrameWindow*>(pWin) containsMouse] )
165             pDispatchFrame = [static_cast<SalFrameWindow*>(pWin) getSalFrame];
166     }
167     return pDispatchFrame;
170 @implementation SalFrameWindow
171 -(id)initWithSalFrame: (AquaSalFrame*)pFrame
173     mDraggingDestinationHandler = nil;
174     mpFrame = pFrame;
175     NSRect aRect = { { static_cast<CGFloat>(pFrame->maGeometry.nX), static_cast<CGFloat>(pFrame->maGeometry.nY) },
176                      { static_cast<CGFloat>(pFrame->maGeometry.nWidth), static_cast<CGFloat>(pFrame->maGeometry.nHeight) } };
177     pFrame->VCLToCocoa( aRect );
178     NSWindow* pNSWindow = [super initWithContentRect: aRect
179                                  styleMask: mpFrame->getStyleMask()
180                                  backing: NSBackingStoreBuffered
181                                  defer: Application::IsHeadlessModeEnabled()];
183     // Disallow full-screen mode on macOS >= 10.11 where it is enabled by default. We don't want it
184     // for now as it will just be confused with LibreOffice's home-grown full-screen concept, with
185     // which it has nothing to do, and one can get into all kinds of weird states by using them
186     // intermixedly.
188     // Ideally we should use the system full-screen mode and adapt the code for the home-grown thing
189     // to be in sync with that instead. (And we would then not need the button to get out of
190     // full-screen mode, as the normal way to get out of it is to either click on the green bubble
191     // again, or invoke the keyboard command again.)
193     // (Confusingly, at the moment the home-grown full-screen mode is bound to Cmd+Shift+F, which is
194     // the keyboard command normally used in apps to get in and out of the system full-screen mode.)
196     // Disabling system full-screen mode makes the green button on the title bar (on macOS >= 10.11)
197     // show a plus sign instead, and clicking it becomes identical to double-clicking the title bar,
198     // i.e. it maximizes / unmaximises the window. Sure, that state can also be confused with LO's
199     // home-grown full-screen mode. Oh well.
201     [pNSWindow setCollectionBehavior: NSWindowCollectionBehaviorFullScreenNone];
203     // Disable window restoration until we support it directly
204     [pNSWindow setRestorable: NO];
206     return static_cast<SalFrameWindow *>(pNSWindow);
209 -(AquaSalFrame*)getSalFrame
211     return mpFrame;
214 -(void)displayIfNeeded
216     if( GetSalData() && GetSalData()->mpInstance )
217     {
218         SolarMutexGuard aGuard;
219         [super displayIfNeeded];
220     }
223 -(BOOL)containsMouse
225     // is this event actually inside that NSWindow ?
226     NSPoint aPt = [NSEvent mouseLocation];
227     NSRect aFrameRect = [self frame];
228     BOOL bInRect = NSPointInRect( aPt, aFrameRect );
229     return bInRect;
232 -(BOOL)canBecomeKeyWindow
234     if( (mpFrame->mnStyle &
235             ( SalFrameStyleFlags::FLOAT                 |
236               SalFrameStyleFlags::TOOLTIP               |
237               SalFrameStyleFlags::INTRO
238             )) == SalFrameStyleFlags::NONE )
239         return YES;
240     if( mpFrame->mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION )
241         return YES;
242     if( mpFrame->mbFullScreen )
243         return YES;
244     return [super canBecomeKeyWindow];
247 -(void)windowDidBecomeKey: (NSNotification*)pNotification
249     (void)pNotification;
250     SolarMutexGuard aGuard;
252     if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
253     {
254         static const SalFrameStyleFlags nGuessDocument = SalFrameStyleFlags::MOVEABLE|
255                                             SalFrameStyleFlags::SIZEABLE|
256                                             SalFrameStyleFlags::CLOSEABLE;
258         if( mpFrame->mpMenu )
259             mpFrame->mpMenu->setMainMenu();
260         else if( ! mpFrame->mpParent &&
261                  ( (mpFrame->mnStyle & nGuessDocument) == nGuessDocument || // set default menu for e.g. help
262                     mpFrame->mbFullScreen ) )                               // set default menu for e.g. presentation
263         {
264             AquaSalMenu::setDefaultMenu();
265         }
266         #if 0
267         // FIXME: we should disable menus while in modal mode
268         // however from down here there is currently no reliable way to
269         // find out when to do this
270         if( (mpFrame->mpParent && mpFrame->mpParent->GetWindow()->IsInModalMode()) )
271             AquaSalMenu::enableMainMenu( false );
272         #endif
273         mpFrame->CallCallback( SalEvent::GetFocus, nullptr );
274         mpFrame->SendPaintEvent(); // repaint controls as active
275     }
278 -(void)windowDidResignKey: (NSNotification*)pNotification
280     (void)pNotification;
281     SolarMutexGuard aGuard;
283     if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
284     {
285         mpFrame->CallCallback(SalEvent::LoseFocus, nullptr);
286         mpFrame->SendPaintEvent(); // repaint controls as inactive
287     }
290 -(void)windowDidChangeScreen: (NSNotification*)pNotification
292     (void)pNotification;
293     SolarMutexGuard aGuard;
295     if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
296         mpFrame->screenParametersChanged();
299 -(void)windowDidMove: (NSNotification*)pNotification
301     (void)pNotification;
302     SolarMutexGuard aGuard;
304     if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
305     {
306         mpFrame->UpdateFrameGeometry();
307         mpFrame->CallCallback( SalEvent::Move, nullptr );
308     }
311 -(void)windowDidResize: (NSNotification*)pNotification
313     (void)pNotification;
314     SolarMutexGuard aGuard;
316     if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
317     {
318         mpFrame->UpdateFrameGeometry();
319         mpFrame->CallCallback( SalEvent::Resize, nullptr );
320         mpFrame->SendPaintEvent();
321     }
324 -(void)windowDidMiniaturize: (NSNotification*)pNotification
326     (void)pNotification;
327     SolarMutexGuard aGuard;
329     if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
330     {
331         mpFrame->mbShown = false;
332         mpFrame->UpdateFrameGeometry();
333         mpFrame->CallCallback( SalEvent::Resize, nullptr );
334     }
337 -(void)windowDidDeminiaturize: (NSNotification*)pNotification
339     (void)pNotification;
340     SolarMutexGuard aGuard;
342     if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
343     {
344         mpFrame->mbShown = true;
345         mpFrame->UpdateFrameGeometry();
346         mpFrame->CallCallback( SalEvent::Resize, nullptr );
347     }
350 -(BOOL)windowShouldClose: (NSNotification*)pNotification
352     (void)pNotification;
353     SolarMutexGuard aGuard;
355     BOOL bRet = YES;
356     if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
357     {
358         // #i84461# end possible input
359         mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
360         if( AquaSalFrame::isAlive( mpFrame ) )
361         {
362             mpFrame->CallCallback( SalEvent::Close, nullptr );
363             bRet = NO; // application will close the window or not, AppKit shouldn't
364             AquaSalTimer *pTimer = static_cast<AquaSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer );
365             assert( pTimer );
366             pTimer->handleWindowShouldClose();
367         }
368     }
370     return bRet;
373 -(void)windowDidEnterFullScreen: (NSNotification*)pNotification
375     SolarMutexGuard aGuard;
377     if( !mpFrame || !AquaSalFrame::isAlive( mpFrame))
378         return;
379     mpFrame->mbFullScreen = true;
380     (void)pNotification;
383 -(void)windowDidExitFullScreen: (NSNotification*)pNotification
385     SolarMutexGuard aGuard;
387     if( !mpFrame || !AquaSalFrame::isAlive( mpFrame))
388         return;
389     mpFrame->mbFullScreen = false;
390     (void)pNotification;
393 -(void)dockMenuItemTriggered: (id)sender
395     (void)sender;
396     SolarMutexGuard aGuard;
398     if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
399         mpFrame->ToTop( SalFrameToTop::RestoreWhenMin | SalFrameToTop::GrabFocus );
402 -(css::uno::Reference < css::accessibility::XAccessibleContext >)accessibleContext
404     return mpFrame -> GetWindow() -> GetAccessible() -> getAccessibleContext();
407 -(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
409   return [mDraggingDestinationHandler draggingEntered: sender];
412 -(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
414   return [mDraggingDestinationHandler draggingUpdated: sender];
417 -(void)draggingExited:(id <NSDraggingInfo>)sender
419   [mDraggingDestinationHandler draggingExited: sender];
422 -(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
424   return [mDraggingDestinationHandler prepareForDragOperation: sender];
427 -(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
429   return [mDraggingDestinationHandler performDragOperation: sender];
432 -(void)concludeDragOperation:(id <NSDraggingInfo>)sender
434   [mDraggingDestinationHandler concludeDragOperation: sender];
437 -(void)registerDraggingDestinationHandler:(id)theHandler
439   mDraggingDestinationHandler = theHandler;
442 -(void)unregisterDraggingDestinationHandler:(id)theHandler
444     (void)theHandler;
445     mDraggingDestinationHandler = nil;
448 @end
450 @implementation SalFrameView
451 +(void)unsetMouseFrame: (AquaSalFrame*)pFrame
453     if( pFrame == s_pMouseFrame )
454         s_pMouseFrame = nullptr;
457 -(id)initWithSalFrame: (AquaSalFrame*)pFrame
459     if ((self = [super initWithFrame: [NSWindow contentRectForFrameRect: [pFrame->getNSWindow() frame] styleMask: pFrame->mnStyleMask]]) != nil)
460     {
461         mDraggingDestinationHandler = nil;
462         mpFrame = pFrame;
463         mMarkedRange = NSMakeRange(NSNotFound, 0);
464         mSelectedRange = NSMakeRange(NSNotFound, 0);
465         mpReferenceWrapper = nil;
466         mpMouseEventListener = nil;
467         mpLastSuperEvent = nil;
468     }
470     mfLastMagnifyTime = 0.0;
471     return self;
474 -(AquaSalFrame*)getSalFrame
476     return mpFrame;
479 -(void)resetCursorRects
481     if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
482     {
483         // FIXME: does this leak the returned NSCursor of getCurrentCursor ?
484         const NSRect aRect = { NSZeroPoint, NSMakeSize( mpFrame->maGeometry.nWidth, mpFrame->maGeometry.nHeight) };
485         [self addCursorRect: aRect cursor: mpFrame->getCurrentCursor()];
486     }
489 -(BOOL)acceptsFirstResponder
491     return YES;
494 -(BOOL)acceptsFirstMouse: (NSEvent*)pEvent
496     (void)pEvent;
497     return YES;
500 -(BOOL)isOpaque
502     if( !mpFrame)
503         return YES;
504     if( !AquaSalFrame::isAlive( mpFrame))
505         return YES;
506     if( !mpFrame->getClipPath())
507         return YES;
508     return NO;
511 -(void)drawRect: (NSRect)aRect
513     AquaSalInstance *pInstance = GetSalData()->mpInstance;
514     assert(pInstance);
515     if (!pInstance)
516         return;
518     SolarMutexGuard aGuard;
519     if (!mpFrame || !AquaSalFrame::isAlive(mpFrame))
520         return;
522     const bool bIsLiveResize = [self inLiveResize];
523     const bool bWasLiveResize = pInstance->mbIsLiveResize;
524     if (bWasLiveResize != bIsLiveResize)
525     {
526         pInstance->mbIsLiveResize = bIsLiveResize;
527         Scheduler::ProcessTaskScheduling();
528     }
530     AquaSalGraphics* pGraphics = mpFrame->mpGraphics;
531     if (pGraphics)
532     {
533         pGraphics->UpdateWindow(aRect);
534         if (mpFrame->getClipPath())
535             [mpFrame->getNSWindow() invalidateShadow];
536     }
539 -(void)sendMouseEventToFrame: (NSEvent*)pEvent button:(sal_uInt16)nButton eventtype:(SalEvent)nEvent
541     SolarMutexGuard aGuard;
543     AquaSalFrame* pDispatchFrame = AquaSalFrame::GetCaptureFrame();
544     bool bIsCaptured = false;
545     if( pDispatchFrame )
546     {
547         bIsCaptured = true;
548         if( nEvent == SalEvent::MouseLeave ) // no leave events if mouse is captured
549             nEvent = SalEvent::MouseMove;
550     }
551     else if( s_pMouseFrame )
552         pDispatchFrame = s_pMouseFrame;
553     else
554         pDispatchFrame = mpFrame;
556     /* #i81645# Cocoa reports mouse events while a button is pressed
557        to the window in which it was first pressed. This is reasonable and fine and
558        gets one around most cases where on other platforms one uses CaptureMouse or XGrabPointer,
559        however vcl expects mouse events to occur in the window the mouse is over, unless the
560        mouse is explicitly captured. So we need to find the window the mouse is actually
561        over for conformance with other platforms.
562     */
563     if( ! bIsCaptured && nButton && pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
564     {
565         // is this event actually inside that NSWindow ?
566         NSPoint aPt = [NSEvent mouseLocation];
567         NSRect aFrameRect = [pDispatchFrame->getNSWindow() frame];
569         if ( ! NSPointInRect( aPt, aFrameRect ) )
570         {
571             // no, it is not
572             // now we need to find the one it may be in
573             /* #i93756# we ant to get enumerate the application windows in z-order
574                to check if any contains the mouse. This could be elegantly done with this
575                code:
577                // use NSApp to check windows in ZOrder whether they contain the mouse pointer
578                NSWindow* pWindow = [NSApp makeWindowsPerform: @selector(containsMouse) inOrder: YES];
579                if( pWindow && [pWindow isMemberOfClass: [SalFrameWindow class]] )
580                    pDispatchFrame = [(SalFrameWindow*)pWindow getSalFrame];
582                However if a non SalFrameWindow is on screen (like e.g. the file dialog)
583                it can be hit with the containsMouse selector, which it doesn't support.
584                Sadly NSApplication:makeWindowsPerform does not check (for performance reasons
585                I assume) whether a window supports a selector before sending it.
586             */
587             AquaSalFrame* pMouseFrame = getMouseContainerFrame();
588             if( pMouseFrame )
589                 pDispatchFrame = pMouseFrame;
590         }
591     }
593     if( pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
594     {
595         pDispatchFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
596         pDispatchFrame->mnLastModifierFlags = [pEvent modifierFlags];
598         NSPoint aPt = [NSEvent mouseLocation];
599         pDispatchFrame->CocoaToVCL( aPt );
601         sal_uInt16 nModMask = ImplGetModifierMask( [pEvent modifierFlags] );
602         // #i82284# emulate ctrl left
603         if( nModMask == KEY_MOD3 && nButton == MOUSE_LEFT )
604         {
605             nModMask    = 0;
606             nButton     = MOUSE_RIGHT;
607         }
609         SalMouseEvent aEvent;
610         aEvent.mnTime   = pDispatchFrame->mnLastEventTime;
611         aEvent.mnX      = static_cast<long>(aPt.x) - pDispatchFrame->maGeometry.nX;
612         aEvent.mnY      = static_cast<long>(aPt.y) - pDispatchFrame->maGeometry.nY;
613         aEvent.mnButton = nButton;
614         aEvent.mnCode   =  aEvent.mnButton | nModMask;
616         if( AllSettings::GetLayoutRTL() )
617             aEvent.mnX = pDispatchFrame->maGeometry.nWidth-1-aEvent.mnX;
619         pDispatchFrame->CallCallback( nEvent, &aEvent );
620     }
623 -(void)mouseDown: (NSEvent*)pEvent
625     if ( mpMouseEventListener != nil &&
626         [mpMouseEventListener respondsToSelector: @selector(mouseDown:)])
627     {
628         [mpMouseEventListener mouseDown: [pEvent copyWithZone: nullptr]];
629     }
631     s_nLastButton = MOUSE_LEFT;
632     [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SalEvent::MouseButtonDown];
635 -(void)mouseDragged: (NSEvent*)pEvent
637     if ( mpMouseEventListener != nil &&
638          [mpMouseEventListener respondsToSelector: @selector(mouseDragged:)])
639     {
640         [mpMouseEventListener mouseDragged: [pEvent copyWithZone: nullptr]];
641     }
642     s_nLastButton = MOUSE_LEFT;
643     [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SalEvent::MouseMove];
646 -(void)mouseUp: (NSEvent*)pEvent
648     s_nLastButton = 0;
649     [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SalEvent::MouseButtonUp];
652 -(void)mouseMoved: (NSEvent*)pEvent
654     s_nLastButton = 0;
655     [self sendMouseEventToFrame:pEvent button:0 eventtype:SalEvent::MouseMove];
658 -(void)mouseEntered: (NSEvent*)pEvent
660     s_pMouseFrame = mpFrame;
662     // #i107215# the only mouse events we get when inactive are enter/exit
663     // actually we would like to have all of them, but better none than some
664     if( [NSApp isActive] )
665         [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SalEvent::MouseMove];
668 -(void)mouseExited: (NSEvent*)pEvent
670     if( s_pMouseFrame == mpFrame )
671         s_pMouseFrame = nullptr;
673     // #i107215# the only mouse events we get when inactive are enter/exit
674     // actually we would like to have all of them, but better none than some
675     if( [NSApp isActive] )
676         [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SalEvent::MouseLeave];
679 -(void)rightMouseDown: (NSEvent*)pEvent
681     s_nLastButton = MOUSE_RIGHT;
682     [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SalEvent::MouseButtonDown];
685 -(void)rightMouseDragged: (NSEvent*)pEvent
687     s_nLastButton = MOUSE_RIGHT;
688     [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SalEvent::MouseMove];
691 -(void)rightMouseUp: (NSEvent*)pEvent
693     s_nLastButton = 0;
694     [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SalEvent::MouseButtonUp];
697 -(void)otherMouseDown: (NSEvent*)pEvent
699     if( [pEvent buttonNumber] == 2 )
700     {
701         s_nLastButton = MOUSE_MIDDLE;
702         [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SalEvent::MouseButtonDown];
703     }
704     else
705         s_nLastButton = 0;
708 -(void)otherMouseDragged: (NSEvent*)pEvent
710     if( [pEvent buttonNumber] == 2 )
711     {
712         s_nLastButton = MOUSE_MIDDLE;
713         [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SalEvent::MouseMove];
714     }
715     else
716         s_nLastButton = 0;
719 -(void)otherMouseUp: (NSEvent*)pEvent
721     s_nLastButton = 0;
722     if( [pEvent buttonNumber] == 2 )
723         [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SalEvent::MouseButtonUp];
726 - (void)magnifyWithEvent: (NSEvent*)pEvent
728     SolarMutexGuard aGuard;
730     // TODO: ??  -(float)magnification;
731     if( AquaSalFrame::isAlive( mpFrame ) )
732     {
733         const NSTimeInterval fMagnifyTime = [pEvent timestamp];
734         mpFrame->mnLastEventTime = static_cast<sal_uInt64>( fMagnifyTime * 1000.0 );
735         mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
737         // check if this is a new series of magnify events
738         static const NSTimeInterval fMaxDiffTime = 0.3;
739         const bool bNewSeries = (fMagnifyTime - mfLastMagnifyTime > fMaxDiffTime);
741         if( bNewSeries )
742             mfMagnifyDeltaSum = 0.0;
743         mfMagnifyDeltaSum += [pEvent magnification];
745         mfLastMagnifyTime = [pEvent timestamp];
746 // TODO: change to 0.1 when CommandWheelMode::ZOOM handlers allow finer zooming control
747         static const float fMagnifyFactor = 0.25*500; // steps are 500 times smaller for -magnification
748         static const float fMinMagnifyStep = 15.0 / fMagnifyFactor;
749         if( fabs(mfMagnifyDeltaSum) <= fMinMagnifyStep )
750             return;
752         // adapt NSEvent-sensitivity to application expectations
753         // TODO: rather make CommandWheelMode::ZOOM handlers smarter
754         const float fDeltaZ = mfMagnifyDeltaSum * fMagnifyFactor;
755         int nDeltaZ = FRound( fDeltaZ );
756         if( !nDeltaZ )
757         {
758             // handle new series immediately
759             if( !bNewSeries )
760                 return;
761             nDeltaZ = (fDeltaZ >= 0.0) ? +1 : -1;
762         }
763         // eventually give credit for delta sum
764         mfMagnifyDeltaSum -= nDeltaZ / fMagnifyFactor;
766         NSPoint aPt = [NSEvent mouseLocation];
767         mpFrame->CocoaToVCL( aPt );
769         SalWheelMouseEvent aEvent;
770         aEvent.mnTime           = mpFrame->mnLastEventTime;
771         aEvent.mnX              = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
772         aEvent.mnY              = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
773         aEvent.mnCode           = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
774         aEvent.mnCode           |= KEY_MOD1; // we want zooming, no scrolling
775         aEvent.mbDeltaIsPixel   = TRUE;
777         if( AllSettings::GetLayoutRTL() )
778             aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
780         aEvent.mnDelta = nDeltaZ;
781         aEvent.mnNotchDelta = (nDeltaZ >= 0) ? +1 : -1;
782         if( aEvent.mnDelta == 0 )
783             aEvent.mnDelta = aEvent.mnNotchDelta;
784         aEvent.mbHorz = FALSE;
785         sal_uInt32 nScrollLines = nDeltaZ;
786         if (nScrollLines == 0)
787             nScrollLines = 1;
788         aEvent.mnScrollLines = nScrollLines;
789         mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
790     }
793 - (void)rotateWithEvent: (NSEvent*)pEvent
795     //Rotation : -(float)rotation;
796     // TODO: create new CommandType so rotation is available to the applications
797     (void)pEvent;
800 - (void)swipeWithEvent: (NSEvent*)pEvent
802     SolarMutexGuard aGuard;
804     if( AquaSalFrame::isAlive( mpFrame ) )
805     {
806         mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
807         mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
809         // merge pending scroll wheel events
810         CGFloat dX = 0.0;
811         CGFloat dY = 0.0;
812         for(;;)
813         {
814             dX += [pEvent deltaX];
815             dY += [pEvent deltaY];
816 SAL_WNODEPRECATED_DECLARATIONS_PUSH
817     // 'NSScrollWheelMask' is deprecated: first deprecated in macOS 10.12
818             NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
819 SAL_WNODEPRECATED_DECLARATIONS_POP
820             untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
821             if( !pNextEvent )
822                 break;
823             pEvent = pNextEvent;
824         }
826         NSPoint aPt = [NSEvent mouseLocation];
827         mpFrame->CocoaToVCL( aPt );
829         SalWheelMouseEvent aEvent;
830         aEvent.mnTime           = mpFrame->mnLastEventTime;
831         aEvent.mnX              = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
832         aEvent.mnY              = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
833         aEvent.mnCode           = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
834         aEvent.mbDeltaIsPixel   = TRUE;
836         if( AllSettings::GetLayoutRTL() )
837             aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
839         if( dX != 0.0 )
840         {
841             aEvent.mnDelta = static_cast<long>(floor(dX));
842             aEvent.mnNotchDelta = (dX < 0) ? -1 : +1;
843             if( aEvent.mnDelta == 0 )
844                 aEvent.mnDelta = aEvent.mnNotchDelta;
845             aEvent.mbHorz = TRUE;
846             aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
847             mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
848         }
849         if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ))
850         {
851             aEvent.mnDelta = static_cast<long>(floor(dY));
852             aEvent.mnNotchDelta = (dY < 0) ? -1 : +1;
853             if( aEvent.mnDelta == 0 )
854                 aEvent.mnDelta = aEvent.mnNotchDelta;
855             aEvent.mbHorz = FALSE;
856             aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
857             mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
858         }
859     }
862 -(void)scrollWheel: (NSEvent*)pEvent
864     SolarMutexGuard aGuard;
866     if( AquaSalFrame::isAlive( mpFrame ) )
867     {
868         mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
869         mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
871         // merge pending scroll wheel events
872         CGFloat dX = 0.0;
873         CGFloat dY = 0.0;
874         for(;;)
875         {
876             dX += [pEvent deltaX];
877             dY += [pEvent deltaY];
878 SAL_WNODEPRECATED_DECLARATIONS_PUSH
879     // 'NSScrollWheelMask' is deprecated: first deprecated in macOS 10.12
880             NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
881 SAL_WNODEPRECATED_DECLARATIONS_POP
882                 untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
883             if( !pNextEvent )
884                 break;
885             pEvent = pNextEvent;
886         }
888         NSPoint aPt = [NSEvent mouseLocation];
889         mpFrame->CocoaToVCL( aPt );
891         SalWheelMouseEvent aEvent;
892         aEvent.mnTime         = mpFrame->mnLastEventTime;
893         aEvent.mnX            = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
894         aEvent.mnY            = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
895         aEvent.mnCode         = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
896         aEvent.mbDeltaIsPixel = FALSE;
898         if( AllSettings::GetLayoutRTL() )
899             aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
901         if( dX != 0.0 )
902         {
903             aEvent.mnDelta = static_cast<long>(floor(dX));
904             aEvent.mnNotchDelta = (dX < 0) ? -1 : +1;
905             if( aEvent.mnDelta == 0 )
906                 aEvent.mnDelta = aEvent.mnNotchDelta;
907             aEvent.mbHorz = TRUE;
908             sal_uInt32 nScrollLines = fabs(dX) / WHEEL_EVENT_FACTOR;
909             if (nScrollLines == 0)
910                 nScrollLines = 1;
911             aEvent.mnScrollLines = nScrollLines;
913             mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
914         }
915         if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ) )
916         {
917             aEvent.mnDelta = static_cast<long>(floor(dY));
918             aEvent.mnNotchDelta = (dY < 0) ? -1 : +1;
919             if( aEvent.mnDelta == 0 )
920                 aEvent.mnDelta = aEvent.mnNotchDelta;
921             aEvent.mbHorz = FALSE;
922             sal_uInt32 nScrollLines = fabs(dY) / WHEEL_EVENT_FACTOR;
923             if (nScrollLines == 0)
924                 nScrollLines = 1;
925             aEvent.mnScrollLines = nScrollLines;
927             mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent );
928         }
929     }
933 -(void)keyDown: (NSEvent*)pEvent
935     SolarMutexGuard aGuard;
937     if( AquaSalFrame::isAlive( mpFrame ) )
938     {
939         mpLastEvent = pEvent;
940         mbInKeyInput = true;
941         mbNeedSpecialKeyHandle = false;
942         mbKeyHandled = false;
944         mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
945         mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
947         if( ! [self handleKeyDownException: pEvent] )
948         {
949             NSArray* pArray = [NSArray arrayWithObject: pEvent];
950             [self interpretKeyEvents: pArray];
951         }
953         mbInKeyInput = false;
954     }
957 -(BOOL)handleKeyDownException:(NSEvent*)pEvent
959     // check for a very special set of modified characters
960     NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
962     if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
963     {
964         /* #i103102# key events with command and alternate don't make it through
965            interpretKeyEvents (why?). Try to dispatch them here first,
966            if not successful continue normally
967         */
968 SAL_WNODEPRECATED_DECLARATIONS_PUSH
969     // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12
970     // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12
971         if( (mpFrame->mnLastModifierFlags & (NSAlternateKeyMask | NSCommandKeyMask))
972                     == (NSAlternateKeyMask | NSCommandKeyMask) )
973 SAL_WNODEPRECATED_DECLARATIONS_POP
974         {
975             if( [self sendSingleCharacter: mpLastEvent] )
976                 return YES;
977         }
978     }
979     return NO;
982 -(void)flagsChanged: (NSEvent*)pEvent
984     SolarMutexGuard aGuard;
986     if( AquaSalFrame::isAlive( mpFrame ) )
987     {
988         mpFrame->mnLastEventTime = static_cast<sal_uInt64>( [pEvent timestamp] * 1000.0 );
989         mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
990     }
993 -(void)insertText:(id)aString replacementRange:(NSRange)replacementRange
995     (void) replacementRange; // FIXME: surely it must be used
997     SolarMutexGuard aGuard;
999     if( AquaSalFrame::isAlive( mpFrame ) )
1000     {
1001         NSString* pInsert = nil;
1002         if( [aString isMemberOfClass: [NSAttributedString class]] )
1003             pInsert = [aString string];
1004         else
1005             pInsert = aString;
1007         int nLen = 0;
1008         if( pInsert && ( nLen = [pInsert length] ) > 0 )
1009         {
1010             OUString aInsertString( GetOUString( pInsert ) );
1011              // aCharCode initializer is safe since aInsertString will at least contain '\0'
1012             sal_Unicode aCharCode = *aInsertString.getStr();
1014             if( nLen == 1 &&
1015                 aCharCode < 0x80 &&
1016                 aCharCode > 0x1f &&
1017                 ! [self hasMarkedText ]
1018                 )
1019             {
1020                 sal_uInt16 nKeyCode = ImplMapCharCode( aCharCode );
1021                 unsigned int nLastModifiers = mpFrame->mnLastModifierFlags;
1023                 // #i99567#
1024                 // find out the unmodified key code
1026 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1027     // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12
1028     // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12
1029     // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12
1030     // 'NSKeyDown' is deprecated: first deprecated in macOS 10.12
1031     // 'NSKeyUp' is deprecated: first deprecated in macOS 10.12
1032                 // sanity check
1033                 if( mpLastEvent && ( [mpLastEvent type] == NSKeyDown || [mpLastEvent type] == NSKeyUp ) )
1034                 {
1035                     // get unmodified string
1036                     NSString* pUnmodifiedString = [mpLastEvent charactersIgnoringModifiers];
1037                     if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
1038                     {
1039                         // map the unmodified key code
1040                         unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
1041                         nKeyCode = ImplMapCharCode( keyChar );
1042                     }
1043                     nLastModifiers = [mpLastEvent modifierFlags];
1045                 }
1046                 // #i99567#
1047                 // applications and vcl's edit fields ignore key events with ALT
1048                 // however we're at a place where we know text should be inserted
1049                 // so it seems we need to strip the Alt modifier here
1050                 if( (nLastModifiers & (NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask))
1051                     == NSAlternateKeyMask )
1052                 {
1053                     nLastModifiers = 0;
1054                 }
1055 SAL_WNODEPRECATED_DECLARATIONS_POP
1056                 [self sendKeyInputAndReleaseToFrame: nKeyCode character: aCharCode modifiers: nLastModifiers];
1057             }
1058             else
1059             {
1060                 SalExtTextInputEvent aEvent;
1061                 aEvent.maText           = aInsertString;
1062                 aEvent.mpTextAttr       = nullptr;
1063                 aEvent.mnCursorPos      = aInsertString.getLength();
1064                 aEvent.mnCursorFlags    = 0;
1065                 mpFrame->CallCallback( SalEvent::ExtTextInput, &aEvent );
1066                 if( AquaSalFrame::isAlive( mpFrame ) )
1067                     mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
1068             }
1069         }
1070         else
1071         {
1072             SalExtTextInputEvent aEvent;
1073             aEvent.maText.clear();
1074             aEvent.mpTextAttr       = nullptr;
1075             aEvent.mnCursorPos      = 0;
1076             aEvent.mnCursorFlags    = 0;
1077             mpFrame->CallCallback( SalEvent::ExtTextInput, &aEvent );
1078             if( AquaSalFrame::isAlive( mpFrame ) )
1079                 mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
1081         }
1082         mbKeyHandled = true;
1083         [self unmarkText];
1084     }
1087 -(void)insertTab: (id)aSender
1089     (void)aSender;
1090     [self sendKeyInputAndReleaseToFrame: KEY_TAB character: '\t' modifiers: 0];
1093 -(void)insertBacktab: (id)aSender
1095     (void)aSender;
1096     [self sendKeyInputAndReleaseToFrame: (KEY_TAB | KEY_SHIFT) character: '\t' modifiers: 0];
1099 -(void)moveLeft: (id)aSender
1101     (void)aSender;
1102     [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: 0];
1105 -(void)moveLeftAndModifySelection: (id)aSender
1107     (void)aSender;
1108 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1109         // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12
1110     [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: NSShiftKeyMask];
1111 SAL_WNODEPRECATED_DECLARATIONS_POP
1114 -(void)moveBackwardAndModifySelection: (id)aSender
1116     (void)aSender;
1117     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_BACKWARD character: 0  modifiers: 0];
1120 -(void)moveRight: (id)aSender
1122     (void)aSender;
1123     [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: 0];
1126 -(void)moveRightAndModifySelection: (id)aSender
1128     (void)aSender;
1129 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1130         // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12
1131     [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: NSShiftKeyMask];
1132 SAL_WNODEPRECATED_DECLARATIONS_POP
1135 -(void)moveForwardAndModifySelection: (id)aSender
1137     (void)aSender;
1138     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_FORWARD character: 0  modifiers: 0];
1141 -(void)moveWordLeft: (id)aSender
1143     (void)aSender;
1144     [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_BACKWARD character: 0  modifiers: 0];
1147 -(void)moveWordBackward: (id)aSender
1149     (void)aSender;
1150     [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_BACKWARD character: 0  modifiers: 0];
1153 -(void)moveWordBackwardAndModifySelection: (id)aSender
1155     (void)aSender;
1156     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_BACKWARD character: 0  modifiers: 0];
1159 -(void)moveWordLeftAndModifySelection: (id)aSender
1161     (void)aSender;
1162     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_BACKWARD character: 0  modifiers: 0];
1165 -(void)moveWordRight: (id)aSender
1167     (void)aSender;
1168     [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_FORWARD character: 0  modifiers: 0];
1171 -(void)moveWordForward: (id)aSender
1173     (void)aSender;
1174     [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_FORWARD character: 0  modifiers: 0];
1177 -(void)moveWordForwardAndModifySelection: (id)aSender
1179     (void)aSender;
1180     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_FORWARD character: 0  modifiers: 0];
1183 -(void)moveWordRightAndModifySelection: (id)aSender
1185     (void)aSender;
1186     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_FORWARD character: 0  modifiers: 0];
1189 -(void)moveToEndOfLine: (id)aSender
1191     (void)aSender;
1192     [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_LINE character: 0  modifiers: 0];
1195 -(void)moveToRightEndOfLine: (id)aSender
1197     (void)aSender;
1198     [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_LINE character: 0  modifiers: 0];
1201 -(void)moveToEndOfLineAndModifySelection: (id)aSender
1203     (void)aSender;
1204     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_LINE character: 0  modifiers: 0];
1207 -(void)moveToRightEndOfLineAndModifySelection: (id)aSender
1209     (void)aSender;
1210     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_LINE character: 0  modifiers: 0];
1213 -(void)moveToBeginningOfLine: (id)aSender
1215     (void)aSender;
1216     [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0  modifiers: 0];
1219 -(void)moveToLeftEndOfLine: (id)aSender
1221     (void)aSender;
1222     [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0  modifiers: 0];
1225 -(void)moveToBeginningOfLineAndModifySelection: (id)aSender
1227     (void)aSender;
1228     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0  modifiers: 0];
1231 -(void)moveToLeftEndOfLineAndModifySelection: (id)aSender
1233     (void)aSender;
1234     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0  modifiers: 0];
1237 -(void)moveToEndOfParagraph: (id)aSender
1239     (void)aSender;
1240     [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0  modifiers: 0];
1243 -(void)moveToEndOfParagraphAndModifySelection: (id)aSender
1245     (void)aSender;
1246     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0  modifiers: 0];
1249 -(void)moveParagraphForward: (id)aSender
1251     (void)aSender;
1252     [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0  modifiers: 0];
1255 -(void)moveParagraphForwardAndModifySelection: (id)aSender
1257     (void)aSender;
1258     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0  modifiers: 0];
1261 -(void)moveToBeginningOfParagraph: (id)aSender
1263     (void)aSender;
1264     [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0  modifiers: 0];
1267 -(void)moveParagraphBackward: (id)aSender
1269     (void)aSender;
1270     [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0  modifiers: 0];
1273 -(void)moveToBeginningOfParagraphAndModifySelection: (id)aSender
1275     (void)aSender;
1276     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0  modifiers: 0];
1279 -(void)moveParagraphBackwardAndModifySelection: (id)aSender
1281     (void)aSender;
1282     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0  modifiers: 0];
1285 -(void)moveToEndOfDocument: (id)aSender
1287     (void)aSender;
1288     [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0  modifiers: 0];
1291 -(void)scrollToEndOfDocument: (id)aSender
1293     (void)aSender;
1294     // this is not exactly what we should do, but it makes "End" and "Shift-End" behave consistent
1295     [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0  modifiers: 0];
1298 -(void)moveToEndOfDocumentAndModifySelection: (id)aSender
1300     (void)aSender;
1301     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_DOCUMENT character: 0  modifiers: 0];
1304 -(void)moveToBeginningOfDocument: (id)aSender
1306     (void)aSender;
1307     [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0  modifiers: 0];
1310 -(void)scrollToBeginningOfDocument: (id)aSender
1312     (void)aSender;
1313     // this is not exactly what we should do, but it makes "Home" and "Shift-Home" behave consistent
1314     [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0  modifiers: 0];
1317 -(void)moveToBeginningOfDocumentAndModifySelection: (id)aSender
1319     (void)aSender;
1320     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT character: 0  modifiers: 0];
1323 -(void)moveUp: (id)aSender
1325     (void)aSender;
1326     [self sendKeyInputAndReleaseToFrame: KEY_UP character: 0 modifiers: 0];
1329 -(void)moveDown: (id)aSender
1331     (void)aSender;
1332     [self sendKeyInputAndReleaseToFrame: KEY_DOWN character: 0 modifiers: 0];
1335 -(void)insertNewline: (id)aSender
1337     (void)aSender;
1338     // #i91267# make enter and shift-enter work by evaluating the modifiers
1339     [self sendKeyInputAndReleaseToFrame: KEY_RETURN character: '\n' modifiers: mpFrame->mnLastModifierFlags];
1342 -(void)deleteBackward: (id)aSender
1344     (void)aSender;
1345     [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
1348 -(void)deleteForward: (id)aSender
1350     (void)aSender;
1351     [self sendKeyInputAndReleaseToFrame: KEY_DELETE character: 0x7f modifiers: 0];
1354 -(void)deleteBackwardByDecomposingPreviousCharacter: (id)aSender
1356     (void)aSender;
1357     [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
1360 -(void)deleteWordBackward: (id)aSender
1362     (void)aSender;
1363     [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_WORD_BACKWARD character: 0  modifiers: 0];
1366 -(void)deleteWordForward: (id)aSender
1368     (void)aSender;
1369     [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_WORD_FORWARD character: 0  modifiers: 0];
1372 -(void)deleteToBeginningOfLine: (id)aSender
1374     (void)aSender;
1375     [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_BEGIN_OF_LINE character: 0  modifiers: 0];
1378 -(void)deleteToEndOfLine: (id)aSender
1380     (void)aSender;
1381     [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_END_OF_LINE character: 0  modifiers: 0];
1384 -(void)deleteToBeginningOfParagraph: (id)aSender
1386     (void)aSender;
1387     [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH character: 0  modifiers: 0];
1390 -(void)deleteToEndOfParagraph: (id)aSender
1392     (void)aSender;
1393     [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_END_OF_PARAGRAPH character: 0  modifiers: 0];
1396 -(void)insertLineBreak: (id)aSender
1398     (void)aSender;
1399     [self sendKeyInputAndReleaseToFrame: css::awt::Key::INSERT_LINEBREAK character: 0  modifiers: 0];
1402 -(void)insertParagraphSeparator: (id)aSender
1404     (void)aSender;
1405     [self sendKeyInputAndReleaseToFrame: css::awt::Key::INSERT_PARAGRAPH character: 0  modifiers: 0];
1408 -(void)selectWord: (id)aSender
1410     (void)aSender;
1411     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD character: 0  modifiers: 0];
1414 -(void)selectLine: (id)aSender
1416     (void)aSender;
1417     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_LINE character: 0  modifiers: 0];
1420 -(void)selectParagraph: (id)aSender
1422     (void)aSender;
1423     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_PARAGRAPH character: 0  modifiers: 0];
1426 -(void)selectAll: (id)aSender
1428     (void)aSender;
1429     [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_ALL character: 0  modifiers: 0];
1432 -(void)cancelOperation: (id)aSender
1434     (void)aSender;
1435     [self sendKeyInputAndReleaseToFrame: KEY_ESCAPE character: 0x1b modifiers: 0];
1438 -(void)noop: (id)aSender
1440     (void)aSender;
1441     if( ! mbKeyHandled )
1442     {
1443         if( ! [self sendSingleCharacter:mpLastEvent] )
1444         {
1445             /* prevent recursion */
1446             if( mpLastEvent != mpLastSuperEvent && [NSApp respondsToSelector: @selector(sendSuperEvent:)] )
1447             {
1448                 id pLastSuperEvent = mpLastSuperEvent;
1449                 mpLastSuperEvent = mpLastEvent;
1450                 [NSApp performSelector:@selector(sendSuperEvent:) withObject: mpLastEvent];
1451                 mpLastSuperEvent = pLastSuperEvent;
1453                 std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
1454                 if( it != GetSalData()->maKeyEventAnswer.end() )
1455                     it->second = true;
1456             }
1457         }
1458     }
1461 -(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar
1463     return [self sendKeyInputAndReleaseToFrame: nKeyCode character: aChar modifiers: mpFrame->mnLastModifierFlags];
1466 -(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
1468     return [self sendKeyToFrameDirect: nKeyCode character: aChar modifiers: nMod] ||
1469            [self sendSingleCharacter: mpLastEvent];
1472 -(BOOL)sendKeyToFrameDirect: (sal_uInt16)nKeyCode  character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
1474     SolarMutexGuard aGuard;
1476     bool nRet = false;
1477     if( AquaSalFrame::isAlive( mpFrame ) )
1478     {
1479         SalKeyEvent aEvent;
1480         aEvent.mnCode           = nKeyCode | ImplGetModifierMask( nMod );
1481         aEvent.mnCharCode       = aChar;
1482         aEvent.mnRepeat         = FALSE;
1483         nRet = mpFrame->CallCallback( SalEvent::KeyInput, &aEvent );
1484         std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
1485         if( it != GetSalData()->maKeyEventAnswer.end() )
1486             it->second = nRet;
1487         if( AquaSalFrame::isAlive( mpFrame ) )
1488             mpFrame->CallCallback( SalEvent::KeyUp, &aEvent );
1489     }
1490     return nRet;
1494 -(BOOL)sendSingleCharacter: (NSEvent *)pEvent
1496     NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
1498     if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
1499     {
1500         unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
1501         sal_uInt16 nKeyCode = ImplMapCharCode( keyChar );
1502         if (nKeyCode == 0)
1503         {
1504             sal_uInt16 nOtherKeyCode = [pEvent keyCode];
1505             nKeyCode = ImplMapKeyCode(nOtherKeyCode);
1506         }
1507         if( nKeyCode != 0 )
1508         {
1509             // don't send code points in the private use area
1510             if( keyChar >= 0xf700 && keyChar < 0xf780 )
1511                 keyChar = 0;
1512             BOOL bRet = [self sendKeyToFrameDirect: nKeyCode character: keyChar modifiers: mpFrame->mnLastModifierFlags];
1513             mbInKeyInput = false;
1515             return bRet;
1516         }
1517     }
1518     return NO;
1522 // NSTextInput/NSTextInputClient protocol
1523 - (NSArray *)validAttributesForMarkedText
1525     return [NSArray arrayWithObjects:NSUnderlineStyleAttributeName, nil];
1528 - (BOOL)hasMarkedText
1530     BOOL bHasMarkedText;
1532     bHasMarkedText = ( mMarkedRange.location != NSNotFound ) &&
1533                      ( mMarkedRange.length != 0 );
1534     // hack to check keys like "Control-j"
1535     if( mbInKeyInput )
1536     {
1537         mbNeedSpecialKeyHandle = true;
1538     }
1540     // FIXME:
1541     // #i106901#
1542     // if we come here outside of mbInKeyInput, this is likely to be because
1543     // of the keyboard viewer. For unknown reasons having no marked range
1544     // in this case causes a crash. So we say we have a marked range anyway
1545     // This is a hack, since it is not understood what a) causes that crash
1546     // and b) why we should have a marked range at this point.
1547     if( ! mbInKeyInput )
1548         bHasMarkedText = YES;
1550     return bHasMarkedText;
1553 - (NSRange)markedRange
1555     // FIXME:
1556     // #i106901#
1557     // if we come here outside of mbInKeyInput, this is likely to be because
1558     // of the keyboard viewer. For unknown reasons having no marked range
1559     // in this case causes a crash. So we say we have a marked range anyway
1560     // This is a hack, since it is not understood what a) causes that crash
1561     // and b) why we should have a marked range at this point.
1562     if( ! mbInKeyInput )
1563         return NSMakeRange( 0, 0 );
1565     return [self hasMarkedText] ? mMarkedRange : NSMakeRange( NSNotFound, 0 );
1568 - (NSRange)selectedRange
1570     return mSelectedRange;
1573 - (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange replacementRange:(NSRange)replacementRange
1575     (void) replacementRange; // FIXME - use it!
1577     SolarMutexGuard aGuard;
1579     if( ![aString isKindOfClass:[NSAttributedString class]] )
1580         aString = [[[NSAttributedString alloc] initWithString:aString] autorelease];
1581     NSRange rangeToReplace = [self hasMarkedText] ? [self markedRange] : [self selectedRange];
1582     if( rangeToReplace.location == NSNotFound )
1583     {
1584         mMarkedRange = NSMakeRange( selRange.location, [aString length] );
1585         mSelectedRange = NSMakeRange( selRange.location, selRange.length );
1586     }
1587     else
1588     {
1589         mMarkedRange = NSMakeRange( rangeToReplace.location, [aString length] );
1590         mSelectedRange = NSMakeRange( rangeToReplace.location + selRange.location, selRange.length );
1591     }
1593     int len = [aString length];
1594     SalExtTextInputEvent aInputEvent;
1595     if( len > 0 ) {
1596         NSString *pString = [aString string];
1597         OUString aInsertString( GetOUString( pString ) );
1598         std::vector<ExtTextInputAttr> aInputFlags( std::max( 1, len ), ExtTextInputAttr::NONE );
1599         for ( int i = 0; i < len; i++ )
1600         {
1601             unsigned int nUnderlineValue;
1602             NSRange effectiveRange;
1604             effectiveRange = NSMakeRange(i, 1);
1605             nUnderlineValue = [[aString attribute:NSUnderlineStyleAttributeName atIndex:i effectiveRange:&effectiveRange] unsignedIntValue];
1607             switch (nUnderlineValue & 0xff) {
1608             case NSUnderlineStyleSingle:
1609                 aInputFlags[i] = ExtTextInputAttr::Underline;
1610                 break;
1611             case NSUnderlineStyleThick:
1612                 aInputFlags[i] = ExtTextInputAttr::Underline | ExtTextInputAttr::Highlight;
1613                 break;
1614             case NSUnderlineStyleDouble:
1615                 aInputFlags[i] = ExtTextInputAttr::BoldUnderline;
1616                 break;
1617             default:
1618                 aInputFlags[i] = ExtTextInputAttr::Highlight;
1619                 break;
1620             }
1621         }
1623         aInputEvent.maText = aInsertString;
1624         aInputEvent.mnCursorPos = selRange.location;
1625         aInputEvent.mpTextAttr = aInputFlags.data();
1626         mpFrame->CallCallback( SalEvent::ExtTextInput, static_cast<void *>(&aInputEvent) );
1627     } else {
1628         aInputEvent.maText.clear();
1629         aInputEvent.mnCursorPos = 0;
1630         aInputEvent.mnCursorFlags = 0;
1631         aInputEvent.mpTextAttr = nullptr;
1632         mpFrame->CallCallback( SalEvent::ExtTextInput, static_cast<void *>(&aInputEvent) );
1633         mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
1634     }
1635     mbKeyHandled= true;
1638 - (void)unmarkText
1640     mSelectedRange = mMarkedRange = NSMakeRange(NSNotFound, 0);
1643 - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
1645     (void) aRange;
1646     (void) actualRange;
1648     // FIXME - Implement
1649     return nil;
1652 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
1654     (void)thePoint;
1655     // FIXME
1656     return 0;
1659 - (NSInteger)conversationIdentifier
1661     return reinterpret_cast<long>(self);
1664 - (void)doCommandBySelector:(SEL)aSelector
1666     if( AquaSalFrame::isAlive( mpFrame ) )
1667     {
1668         if( (mpFrame->mnICOptions & InputContextFlags::Text) &&
1669             aSelector != nullptr && [self respondsToSelector: aSelector] )
1670         {
1671             [self performSelector: aSelector];
1672         }
1673         else
1674         {
1675             [self sendSingleCharacter:mpLastEvent];
1676         }
1677     }
1679     mbKeyHandled = true;
1682 -(void)clearLastEvent
1684     mpLastEvent = nil;
1687 - (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
1689      // FIXME - These should probably be used?
1690     (void) aRange;
1691     (void) actualRange;
1693     SolarMutexGuard aGuard;
1695     SalExtTextInputPosEvent aPosEvent;
1696     mpFrame->CallCallback( SalEvent::ExtTextInputPos, static_cast<void *>(&aPosEvent) );
1698     NSRect rect;
1700     rect.origin.x = aPosEvent.mnX + mpFrame->maGeometry.nX;
1701     rect.origin.y =   aPosEvent.mnY + mpFrame->maGeometry.nY + 4; // add some space for underlines
1702     rect.size.width = aPosEvent.mnWidth;
1703     rect.size.height = aPosEvent.mnHeight;
1705     mpFrame->VCLToCocoa( rect );
1706     return rect;
1709 -(id)parentAttribute {
1710     return reinterpret_cast<NSView*>(mpFrame->getNSWindow());
1711         //TODO: odd cast really needed for fdo#74121?
1714 -(css::accessibility::XAccessibleContext *)accessibleContext
1716     if ( !mpReferenceWrapper ) {
1717         // some frames never become visible ..
1718         vcl::Window *pWindow = mpFrame -> GetWindow();
1719         if ( ! pWindow )
1720             return nil;
1722         mpReferenceWrapper = new ReferenceWrapper;
1723         mpReferenceWrapper -> rAccessibleContext =  pWindow -> /*GetAccessibleChildWindow( 0 ) ->*/ GetAccessible() -> getAccessibleContext();
1724         [ AquaA11yFactory insertIntoWrapperRepository: self forAccessibleContext: mpReferenceWrapper -> rAccessibleContext ];
1725     }
1726     return [ super accessibleContext ];
1729 -(NSWindow*)windowForParent
1731     return mpFrame->getNSWindow();
1734 -(void)registerMouseEventListener: (id)theListener
1736   mpMouseEventListener = theListener;
1739 -(void)unregisterMouseEventListener: (id)theListener
1741     (void)theListener;
1742     mpMouseEventListener = nil;
1745 -(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
1747   return [mDraggingDestinationHandler draggingEntered: sender];
1750 -(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
1752   return [mDraggingDestinationHandler draggingUpdated: sender];
1755 -(void)draggingExited:(id <NSDraggingInfo>)sender
1757   [mDraggingDestinationHandler draggingExited: sender];
1760 -(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
1762   return [mDraggingDestinationHandler prepareForDragOperation: sender];
1765 -(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
1767   return [mDraggingDestinationHandler performDragOperation: sender];
1770 -(void)concludeDragOperation:(id <NSDraggingInfo>)sender
1772   [mDraggingDestinationHandler concludeDragOperation: sender];
1775 -(void)registerDraggingDestinationHandler:(id)theHandler
1777   mDraggingDestinationHandler = theHandler;
1780 -(void)unregisterDraggingDestinationHandler:(id)theHandler
1782     (void)theHandler;
1783     mDraggingDestinationHandler = nil;
1786 @end
1788 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */