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