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