1 /************************************************************************ 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 <string> 32 33 #include "rtl/ustrbuf.hxx" 34 35 #include "osl/file.h" 36 37 #include "vcl/svapp.hxx" 38 #include "vcl/window.hxx" 39 #include "vcl/timer.hxx" 40 41 #include "aqua/saldata.hxx" 42 #include "aqua/salgdi.h" 43 #include "aqua/salframe.h" 44 #include "aqua/salmenu.h" 45 #include "aqua/saltimer.h" 46 #include "aqua/salinst.h" 47 #include "aqua/salframeview.h" 48 #include "aqua/aqua11yfactory.h" 49 50 #include "salwtype.hxx" 51 52 #include "premac.h" 53 // needed for theming 54 // FIXME: move theming code to salnativewidgets.cxx 55 #include <Carbon/Carbon.h> 56 #include "postmac.h" 57 58 59 using namespace std; 60 61 // ======================================================================= 62 63 AquaSalFrame* AquaSalFrame::s_pCaptureFrame = NULL; 64 65 // ======================================================================= 66 67 AquaSalFrame::AquaSalFrame( SalFrame* pParent, sal_uLong salFrameStyle ) : 68 mpWindow(nil), 69 mpView(nil), 70 mpDockMenuEntry(nil), 71 mpGraphics(NULL), 72 mpParent(NULL), 73 mnMinWidth(0), 74 mnMinHeight(0), 75 mnMaxWidth(0), 76 mnMaxHeight(0), 77 mbGraphics(false), 78 mbFullScreen( false ), 79 mbShown(false), 80 mbInitShow(true), 81 mbPositioned(false), 82 mbSized(false), 83 mbPresentation( false ), 84 mnStyle( salFrameStyle ), 85 mnStyleMask( 0 ), 86 mnLastEventTime( 0 ), 87 mnLastModifierFlags( 0 ), 88 mpMenu( NULL ), 89 mnExtStyle( 0 ), 90 mePointerStyle( POINTER_ARROW ), 91 mnTrackingRectTag( 0 ), 92 mrClippingPath( 0 ), 93 mnICOptions( 0 ) 94 { 95 maSysData.nSize = sizeof( SystemEnvData ); 96 97 mpParent = dynamic_cast<AquaSalFrame*>(pParent); 98 99 initWindowAndView(); 100 101 SalData* pSalData = GetSalData(); 102 pSalData->maFrames.push_front( this ); 103 pSalData->maFrameCheck.insert( this ); 104 } 105 106 // ----------------------------------------------------------------------- 107 108 AquaSalFrame::~AquaSalFrame() 109 { 110 // if the frame is destroyed and has the current menubar 111 // set the default menubar 112 if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu ) 113 AquaSalMenu::setDefaultMenu(); 114 115 // cleanup clipping stuff 116 ResetClipRegion(); 117 118 [SalFrameView unsetMouseFrame: this]; 119 120 SalData* pSalData = GetSalData(); 121 pSalData->maFrames.remove( this ); 122 pSalData->maFrameCheck.erase( this ); 123 pSalData->maPresentationFrames.remove( this ); 124 125 DBG_ASSERT( this != s_pCaptureFrame, "capture frame destroyed" ); 126 if( this == s_pCaptureFrame ) 127 s_pCaptureFrame = NULL; 128 129 if ( mpGraphics ) 130 delete mpGraphics; 131 132 if( mpDockMenuEntry ) 133 // life cycle comment: the menu has ownership of the item, so no release 134 [AquaSalInstance::GetDynamicDockMenu() removeItem: mpDockMenuEntry]; 135 if ( mpView ) { 136 [AquaA11yFactory revokeView: mpView]; 137 [mpView release]; 138 } 139 if ( mpWindow ) 140 [mpWindow release]; 141 } 142 143 // ----------------------------------------------------------------------- 144 145 void AquaSalFrame::initWindowAndView() 146 { 147 // initialize mirroring parameters 148 // FIXME: screens changing 149 NSScreen * pScreen = [mpWindow screen]; 150 if( pScreen == nil ) 151 pScreen = [NSScreen mainScreen]; 152 maScreenRect = [pScreen frame]; 153 154 // calculate some default geometry 155 NSRect aVisibleRect = [pScreen visibleFrame]; 156 CocoaToVCL( aVisibleRect ); 157 158 maGeometry.nX = static_cast<int>(aVisibleRect.origin.x + aVisibleRect.size.width / 10); 159 maGeometry.nY = static_cast<int>(aVisibleRect.origin.y + aVisibleRect.size.height / 10); 160 maGeometry.nWidth = static_cast<unsigned int>(aVisibleRect.size.width * 0.8); 161 maGeometry.nHeight = static_cast<unsigned int>(aVisibleRect.size.height * 0.8); 162 163 // calculate style mask 164 if( (mnStyle & SAL_FRAME_STYLE_FLOAT) || 165 (mnStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) 166 mnStyleMask = NSBorderlessWindowMask; 167 else if( mnStyle & SAL_FRAME_STYLE_DEFAULT ) 168 { 169 mnStyleMask = NSTitledWindowMask | 170 NSMiniaturizableWindowMask | 171 NSResizableWindowMask | 172 NSClosableWindowMask; 173 // make default window "maximized" 174 maGeometry.nX = static_cast<int>(aVisibleRect.origin.x); 175 maGeometry.nY = static_cast<int>(aVisibleRect.origin.y); 176 maGeometry.nWidth = static_cast<int>(aVisibleRect.size.width); 177 maGeometry.nHeight = static_cast<int>(aVisibleRect.size.height); 178 mbPositioned = mbSized = true; 179 } 180 else 181 { 182 if( (mnStyle & SAL_FRAME_STYLE_MOVEABLE) ) 183 { 184 mnStyleMask |= NSTitledWindowMask; 185 if( mpParent == NULL ) 186 mnStyleMask |= NSMiniaturizableWindowMask; 187 } 188 if( (mnStyle & SAL_FRAME_STYLE_SIZEABLE) ) 189 mnStyleMask |= NSResizableWindowMask; 190 if( (mnStyle & SAL_FRAME_STYLE_CLOSEABLE) ) 191 mnStyleMask |= NSClosableWindowMask; 192 // documentation says anything other than NSBorderlessWindowMask (=0) 193 // should also include NSTitledWindowMask; 194 if( mnStyleMask != 0 ) 195 mnStyleMask |= NSTitledWindowMask; 196 } 197 198 // #i91990# support GUI-less (daemon) execution 199 @try 200 { 201 mpWindow = [[SalFrameWindow alloc] initWithSalFrame: this]; 202 mpView = [[SalFrameView alloc] initWithSalFrame: this]; 203 } 204 @catch ( id exception ) 205 { 206 return; 207 } 208 209 if( (mnStyle & SAL_FRAME_STYLE_TOOLTIP) ) 210 [mpWindow setIgnoresMouseEvents: YES]; 211 else 212 [mpWindow setAcceptsMouseMovedEvents: YES]; 213 [mpWindow setHasShadow: YES]; 214 [mpWindow setDelegate: mpWindow]; 215 216 NSRect aRect = { { 0,0 }, { maGeometry.nWidth, maGeometry.nHeight } }; 217 mnTrackingRectTag = [mpView addTrackingRect: aRect owner: mpView userData: nil assumeInside: NO]; 218 219 maSysData.pView = mpView; 220 221 UpdateFrameGeometry(); 222 223 [mpWindow setContentView: mpView]; 224 } 225 226 // ----------------------------------------------------------------------- 227 228 void AquaSalFrame::CocoaToVCL( NSRect& io_rRect, bool bRelativeToScreen ) 229 { 230 if( bRelativeToScreen ) 231 io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height); 232 else 233 io_rRect.origin.y = maGeometry.nHeight - (io_rRect.origin.y+io_rRect.size.height); 234 } 235 236 void AquaSalFrame::VCLToCocoa( NSRect& io_rRect, bool bRelativeToScreen ) 237 { 238 if( bRelativeToScreen ) 239 io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height); 240 else 241 io_rRect.origin.y = maGeometry.nHeight - (io_rRect.origin.y+io_rRect.size.height); 242 } 243 244 void AquaSalFrame::CocoaToVCL( NSPoint& io_rPoint, bool bRelativeToScreen ) 245 { 246 if( bRelativeToScreen ) 247 io_rPoint.y = maScreenRect.size.height - io_rPoint.y; 248 else 249 io_rPoint.y = maGeometry.nHeight - io_rPoint.y; 250 } 251 252 void AquaSalFrame::VCLToCocoa( NSPoint& io_rPoint, bool bRelativeToScreen ) 253 { 254 if( bRelativeToScreen ) 255 io_rPoint.y = maScreenRect.size.height - io_rPoint.y; 256 else 257 io_rPoint.y = maGeometry.nHeight - io_rPoint.y; 258 } 259 260 // ----------------------------------------------------------------------- 261 262 void AquaSalFrame::screenParametersChanged() 263 { 264 UpdateFrameGeometry(); 265 266 if( mpGraphics ) 267 mpGraphics->updateResolution(); 268 CallCallback( SALEVENT_DISPLAYCHANGED, 0 ); 269 } 270 271 // ----------------------------------------------------------------------- 272 273 SalGraphics* AquaSalFrame::GetGraphics() 274 { 275 if ( mbGraphics ) 276 return NULL; 277 278 if ( !mpGraphics ) 279 { 280 mpGraphics = new AquaSalGraphics; 281 mpGraphics->SetWindowGraphics( this ); 282 } 283 284 mbGraphics = TRUE; 285 return mpGraphics; 286 } 287 288 // ----------------------------------------------------------------------- 289 290 void AquaSalFrame::ReleaseGraphics( SalGraphics *pGraphics ) 291 { 292 (void)pGraphics; 293 DBG_ASSERT( pGraphics == mpGraphics, "graphics released on wrong frame" ); 294 mbGraphics = FALSE; 295 } 296 297 // ----------------------------------------------------------------------- 298 299 sal_Bool AquaSalFrame::PostEvent( void *pData ) 300 { 301 GetSalData()->mpFirstInstance->PostUserEvent( this, SALEVENT_USEREVENT, pData ); 302 return TRUE; 303 } 304 305 // ----------------------------------------------------------------------- 306 void AquaSalFrame::SetTitle(const XubString& rTitle) 307 { 308 if ( !mpWindow ) 309 return; 310 311 // #i113170# may not be the main thread if called from UNO API 312 SalData::ensureThreadAutoreleasePool(); 313 314 NSString* pTitle = CreateNSString( rTitle ); 315 [mpWindow setTitle: pTitle]; 316 317 // create an entry in the dock menu 318 const sal_uLong nAppWindowStyle = (SAL_FRAME_STYLE_CLOSEABLE | SAL_FRAME_STYLE_MOVEABLE); 319 if( mpParent == NULL && 320 (mnStyle & nAppWindowStyle) == nAppWindowStyle ) 321 { 322 if( mpDockMenuEntry == NULL ) 323 { 324 NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu(); 325 mpDockMenuEntry = [pDock insertItemWithTitle: pTitle 326 action: @selector(dockMenuItemTriggered:) 327 keyEquivalent: @"" 328 atIndex: 0]; 329 [mpDockMenuEntry setTarget: mpWindow]; 330 331 // TODO: image (either the generic window image or an icon 332 // check mark (for "main" window ?) 333 } 334 else 335 [mpDockMenuEntry setTitle: pTitle]; 336 } 337 338 if (pTitle) 339 [pTitle release]; 340 } 341 342 // ----------------------------------------------------------------------- 343 344 void AquaSalFrame::SetIcon( sal_uInt16 ) 345 { 346 } 347 348 // ----------------------------------------------------------------------- 349 350 void AquaSalFrame::SetRepresentedURL( const rtl::OUString& i_rDocURL ) 351 { 352 // #i113170# may not be the main thread if called from UNO API 353 SalData::ensureThreadAutoreleasePool(); 354 355 if( i_rDocURL.indexOfAsciiL( "file:", 5 ) == 0 ) 356 { 357 rtl::OUString aSysPath; 358 osl_getSystemPathFromFileURL( i_rDocURL.pData, &aSysPath.pData ); 359 NSString* pStr = CreateNSString( aSysPath ); 360 if( pStr ) 361 { 362 [pStr autorelease]; 363 [mpWindow setRepresentedFilename: pStr]; 364 } 365 } 366 } 367 368 // ----------------------------------------------------------------------- 369 370 void AquaSalFrame::initShow() 371 { 372 mbInitShow = false; 373 if( ! mbPositioned && ! mbFullScreen ) 374 { 375 Rectangle aScreenRect; 376 GetWorkArea( aScreenRect ); 377 if( mpParent ) // center relative to parent 378 { 379 // center on parent 380 long nNewX = mpParent->maGeometry.nX + ((long)mpParent->maGeometry.nWidth - (long)maGeometry.nWidth)/2; 381 if( nNewX < aScreenRect.Left() ) 382 nNewX = aScreenRect.Left(); 383 if( long(nNewX + maGeometry.nWidth) > aScreenRect.Right() ) 384 nNewX = aScreenRect.Right() - maGeometry.nWidth-1; 385 long nNewY = mpParent->maGeometry.nY + ((long)mpParent->maGeometry.nHeight - (long)maGeometry.nHeight)/2; 386 if( nNewY < aScreenRect.Top() ) 387 nNewY = aScreenRect.Top(); 388 if( nNewY > aScreenRect.Bottom() ) 389 nNewY = aScreenRect.Bottom() - maGeometry.nHeight-1; 390 SetPosSize( nNewX - mpParent->maGeometry.nX, 391 nNewY - mpParent->maGeometry.nY, 392 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ); 393 } 394 else if( ! (mnStyle & SAL_FRAME_STYLE_SIZEABLE) ) 395 { 396 // center on screen 397 long nNewX = (aScreenRect.GetWidth() - maGeometry.nWidth)/2; 398 long nNewY = (aScreenRect.GetHeight() - maGeometry.nHeight)/2; 399 SetPosSize( nNewX, nNewY, 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ); 400 } 401 } 402 403 // make sure the view is present in the wrapper list before any children receive focus 404 [AquaA11yFactory registerView: mpView]; 405 } 406 407 void AquaSalFrame::SendPaintEvent( const Rectangle* pRect ) 408 { 409 SalPaintEvent aPaintEvt( 0, 0, maGeometry.nWidth, maGeometry.nHeight, true ); 410 if( pRect ) 411 { 412 aPaintEvt.mnBoundX = pRect->Left(); 413 aPaintEvt.mnBoundY = pRect->Top(); 414 aPaintEvt.mnBoundWidth = pRect->GetWidth(); 415 aPaintEvt.mnBoundHeight = pRect->GetHeight(); 416 } 417 418 CallCallback(SALEVENT_PAINT, &aPaintEvt); 419 } 420 421 // ----------------------------------------------------------------------- 422 423 void AquaSalFrame::Show(sal_Bool bVisible, sal_Bool bNoActivate) 424 { 425 if ( !mpWindow ) 426 return; 427 428 // #i113170# may not be the main thread if called from UNO API 429 SalData::ensureThreadAutoreleasePool(); 430 431 mbShown = bVisible; 432 if(bVisible) 433 { 434 if( mbInitShow ) 435 initShow(); 436 437 CallCallback(SALEVENT_RESIZE, 0); 438 // trigger filling our backbuffer 439 SendPaintEvent(); 440 441 if( bNoActivate || [mpWindow canBecomeKeyWindow] == NO ) 442 [mpWindow orderFront: NSApp]; 443 else 444 [mpWindow makeKeyAndOrderFront: NSApp]; 445 446 if( mpParent ) 447 { 448 /* #i92674# #i96433# we do not want an invisible parent to show up (which adding a visible 449 child implicitly does). However we also do not want a parentless toolbar. 450 451 HACK: try to decide when we should not insert a child to its parent 452 floaters and ownerdraw windows have not yet shown up in cases where 453 we don't want the parent to become visible 454 */ 455 if( mpParent->mbShown || (mnStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION | SAL_FRAME_STYLE_FLOAT) ) ) 456 { 457 [mpParent->mpWindow addChildWindow: mpWindow ordered: NSWindowAbove]; 458 } 459 } 460 461 if( mbPresentation ) 462 [mpWindow makeMainWindow]; 463 } 464 else 465 { 466 // if the frame holding the current menubar gets hidden 467 // show the default menubar 468 if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu ) 469 AquaSalMenu::setDefaultMenu(); 470 471 // #i90440# #i94443# work around the focus going back to some other window 472 // if a child gets hidden for a parent window 473 if( mpParent && mpParent->mbShown && [mpWindow isKeyWindow] ) 474 [mpParent->mpWindow makeKeyAndOrderFront: NSApp]; 475 476 [SalFrameView unsetMouseFrame: this]; 477 if( mpParent && [mpWindow parentWindow] == mpParent->mpWindow ) 478 [mpParent->mpWindow removeChildWindow: mpWindow]; 479 480 [mpWindow orderOut: NSApp]; 481 } 482 } 483 484 // ----------------------------------------------------------------------- 485 486 void AquaSalFrame::Enable( sal_Bool ) 487 { 488 } 489 490 // ----------------------------------------------------------------------- 491 492 void AquaSalFrame::SetMinClientSize( long nWidth, long nHeight ) 493 { 494 // #i113170# may not be the main thread if called from UNO API 495 SalData::ensureThreadAutoreleasePool(); 496 497 mnMinWidth = nWidth; 498 mnMinHeight = nHeight; 499 500 if( mpWindow ) 501 { 502 // Always add the decoration as the dimension concerns only 503 // the content rectangle 504 nWidth += maGeometry.nLeftDecoration + maGeometry.nRightDecoration; 505 nHeight += maGeometry.nTopDecoration + maGeometry.nBottomDecoration; 506 507 NSSize aSize = { nWidth, nHeight }; 508 509 // Size of full window (content+structure) although we only 510 // have the client size in arguments 511 [mpWindow setMinSize: aSize]; 512 } 513 } 514 515 // ----------------------------------------------------------------------- 516 517 void AquaSalFrame::SetMaxClientSize( long nWidth, long nHeight ) 518 { 519 // #i113170# may not be the main thread if called from UNO API 520 SalData::ensureThreadAutoreleasePool(); 521 522 mnMaxWidth = nWidth; 523 mnMaxHeight = nHeight; 524 525 if( mpWindow ) 526 { 527 // Always add the decoration as the dimension concerns only 528 // the content rectangle 529 nWidth += maGeometry.nLeftDecoration + maGeometry.nRightDecoration; 530 nHeight += maGeometry.nTopDecoration + maGeometry.nBottomDecoration; 531 532 // Carbon windows can't have a size greater than 32767x32767 533 if (nWidth>32767) nWidth=32767; 534 if (nHeight>32767) nHeight=32767; 535 536 NSSize aSize = { nWidth, nHeight }; 537 538 // Size of full window (content+structure) although we only 539 // have the client size in arguments 540 [mpWindow setMaxSize: aSize]; 541 } 542 } 543 544 // ----------------------------------------------------------------------- 545 546 void AquaSalFrame::SetClientSize( long nWidth, long nHeight ) 547 { 548 // #i113170# may not be the main thread if called from UNO API 549 SalData::ensureThreadAutoreleasePool(); 550 551 if( mpWindow ) 552 { 553 NSSize aSize = { nWidth, nHeight }; 554 555 [mpWindow setContentSize: aSize]; 556 UpdateFrameGeometry(); 557 if( mbShown ) 558 // trigger filling our backbuffer 559 SendPaintEvent(); 560 } 561 } 562 563 // ----------------------------------------------------------------------- 564 565 void AquaSalFrame::GetClientSize( long& rWidth, long& rHeight ) 566 { 567 if( mbShown || mbInitShow ) 568 { 569 rWidth = maGeometry.nWidth; 570 rHeight = maGeometry.nHeight; 571 } 572 else 573 { 574 rWidth = 0; 575 rHeight = 0; 576 } 577 } 578 579 // ----------------------------------------------------------------------- 580 581 void AquaSalFrame::SetWindowState( const SalFrameState* pState ) 582 { 583 // #i113170# may not be the main thread if called from UNO API 584 SalData::ensureThreadAutoreleasePool(); 585 586 if ( mpWindow ) 587 { 588 // set normal state 589 NSRect aStateRect = [mpWindow frame]; 590 aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask]; 591 CocoaToVCL( aStateRect ); 592 if( pState->mnMask & SAL_FRAMESTATE_MASK_X ) 593 aStateRect.origin.x = float(pState->mnX); 594 if( pState->mnMask & SAL_FRAMESTATE_MASK_Y ) 595 aStateRect.origin.y = float(pState->mnY); 596 if( pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH ) 597 aStateRect.size.width = float(pState->mnWidth); 598 if( pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT ) 599 aStateRect.size.height = float(pState->mnHeight); 600 VCLToCocoa( aStateRect ); 601 aStateRect = [NSWindow frameRectForContentRect: aStateRect styleMask: mnStyleMask]; 602 603 [mpWindow setFrame: aStateRect display: NO]; 604 if( pState->mnState == SAL_FRAMESTATE_MINIMIZED ) 605 [mpWindow miniaturize: NSApp]; 606 else if( [mpWindow isMiniaturized] ) 607 [mpWindow deminiaturize: NSApp]; 608 609 610 /* ZOOMED is not really maximized (actually it toggles between a user set size and 611 the program specified one), but comes closest since the default behavior is 612 "maximized" if the user did not intervene 613 */ 614 if( pState->mnState == SAL_FRAMESTATE_MAXIMIZED ) 615 { 616 if(! [mpWindow isZoomed]) 617 [mpWindow zoom: NSApp]; 618 } 619 else 620 { 621 if( [mpWindow isZoomed] ) 622 [mpWindow zoom: NSApp]; 623 } 624 } 625 626 // get new geometry 627 UpdateFrameGeometry(); 628 629 sal_uInt16 nEvent = 0; 630 if( pState->mnMask & (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_X) ) 631 { 632 mbPositioned = true; 633 nEvent = SALEVENT_MOVE; 634 } 635 636 if( pState->mnMask & (SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT) ) 637 { 638 mbSized = true; 639 nEvent = (nEvent == SALEVENT_MOVE) ? SALEVENT_MOVERESIZE : SALEVENT_RESIZE; 640 } 641 // send event that we were moved/sized 642 if( nEvent ) 643 CallCallback( nEvent, NULL ); 644 645 if( mbShown && mpWindow ) 646 { 647 // trigger filling our backbuffer 648 SendPaintEvent(); 649 650 // tell the system the views need to be updated 651 [mpWindow display]; 652 } 653 } 654 655 // ----------------------------------------------------------------------- 656 657 sal_Bool AquaSalFrame::GetWindowState( SalFrameState* pState ) 658 { 659 if ( !mpWindow ) 660 return FALSE; 661 662 // #i113170# may not be the main thread if called from UNO API 663 SalData::ensureThreadAutoreleasePool(); 664 665 pState->mnMask = SAL_FRAMESTATE_MASK_X | 666 SAL_FRAMESTATE_MASK_Y | 667 SAL_FRAMESTATE_MASK_WIDTH | 668 SAL_FRAMESTATE_MASK_HEIGHT | 669 #if 0 670 SAL_FRAMESTATE_MASK_MAXIMIZED_X | 671 SAL_FRAMESTATE_MASK_MAXIMIZED_Y | 672 SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH | 673 SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT | 674 #endif 675 SAL_FRAMESTATE_MASK_STATE; 676 677 NSRect aStateRect = [mpWindow frame]; 678 aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask]; 679 CocoaToVCL( aStateRect ); 680 pState->mnX = long(aStateRect.origin.x); 681 pState->mnY = long(aStateRect.origin.y); 682 pState->mnWidth = long(aStateRect.size.width); 683 pState->mnHeight = long(aStateRect.size.height); 684 685 if( [mpWindow isMiniaturized] ) 686 pState->mnState = SAL_FRAMESTATE_MINIMIZED; 687 else if( ! [mpWindow isZoomed] ) 688 pState->mnState = SAL_FRAMESTATE_NORMAL; 689 else 690 pState->mnState = SAL_FRAMESTATE_MAXIMIZED; 691 692 return TRUE; 693 } 694 695 // ----------------------------------------------------------------------- 696 697 void AquaSalFrame::SetScreenNumber(unsigned int nScreen) 698 { 699 if ( !mpWindow ) 700 return; 701 702 // #i113170# may not be the main thread if called from UNO API 703 SalData::ensureThreadAutoreleasePool(); 704 705 NSArray* pScreens = [NSScreen screens]; 706 Rectangle aRet; 707 NSScreen* pScreen = nil; 708 if( pScreens && nScreen < [pScreens count] ) 709 { 710 // get new screen frame 711 pScreen = [pScreens objectAtIndex: nScreen]; 712 NSRect aNewScreen = [pScreen frame]; 713 714 // get current screen frame 715 pScreen = [mpWindow screen]; 716 if( pScreen ) 717 { 718 NSRect aCurScreen = [pScreen frame]; 719 if( aCurScreen.origin.x != aNewScreen.origin.x || 720 aCurScreen.origin.y != aNewScreen.origin.y ) 721 { 722 NSRect aFrameRect = [mpWindow frame]; 723 aFrameRect.origin.x += aNewScreen.origin.x - aCurScreen.origin.x; 724 aFrameRect.origin.y += aNewScreen.origin.y - aCurScreen.origin.y; 725 [mpWindow setFrame: aFrameRect display: NO]; 726 UpdateFrameGeometry(); 727 } 728 } 729 } 730 } 731 732 // ----------------------------------------------------------------------- 733 734 void AquaSalFrame::ShowFullScreen( sal_Bool bFullScreen, sal_Int32 nDisplay ) 735 { 736 if ( !mpWindow ) 737 return; 738 739 // #i113170# may not be the main thread if called from UNO API 740 SalData::ensureThreadAutoreleasePool(); 741 742 if( mbFullScreen == bFullScreen ) 743 return; 744 745 mbFullScreen = bFullScreen; 746 if( bFullScreen ) 747 { 748 // hide the dock and the menubar if we are on the menu screen 749 // which is always on index 0 according to documentation 750 bool bHideMenu = (nDisplay == 0); 751 752 NSRect aNewContentRect = { { 0, 0 }, { 0, 0 } }; 753 // get correct screen 754 NSScreen* pScreen = nil; 755 NSArray* pScreens = [NSScreen screens]; 756 if( pScreens ) 757 { 758 if( nDisplay >= 0 && (unsigned int)nDisplay < [pScreens count] ) 759 pScreen = [pScreens objectAtIndex: nDisplay]; 760 else 761 { 762 // this means span all screens 763 bHideMenu = true; 764 NSEnumerator* pEnum = [pScreens objectEnumerator]; 765 while( (pScreen = [pEnum nextObject]) != nil ) 766 { 767 NSRect aScreenRect = [pScreen frame]; 768 if( aScreenRect.origin.x < aNewContentRect.origin.x ) 769 { 770 aNewContentRect.size.width += aNewContentRect.origin.x - aScreenRect.origin.x; 771 aNewContentRect.origin.x = aScreenRect.origin.x; 772 } 773 if( aScreenRect.origin.y < aNewContentRect.origin.y ) 774 { 775 aNewContentRect.size.height += aNewContentRect.origin.y - aScreenRect.origin.y; 776 aNewContentRect.origin.y = aScreenRect.origin.y; 777 } 778 if( aScreenRect.origin.x + aScreenRect.size.width > aNewContentRect.origin.x + aNewContentRect.size.width ) 779 aNewContentRect.size.width = aScreenRect.origin.x + aScreenRect.size.width - aNewContentRect.origin.x; 780 if( aScreenRect.origin.y + aScreenRect.size.height > aNewContentRect.origin.y + aNewContentRect.size.height ) 781 aNewContentRect.size.height = aScreenRect.origin.y + aScreenRect.size.height - aNewContentRect.origin.y; 782 } 783 } 784 } 785 if( aNewContentRect.size.width == 0 && aNewContentRect.size.height == 0 ) 786 { 787 if( pScreen == nil ) 788 pScreen = [mpWindow screen]; 789 if( pScreen == nil ) 790 pScreen = [NSScreen mainScreen]; 791 792 aNewContentRect = [pScreen frame]; 793 } 794 795 if( bHideMenu ) 796 [NSMenu setMenuBarVisible:NO]; 797 798 maFullScreenRect = [mpWindow frame]; 799 { 800 [mpWindow setFrame: [NSWindow frameRectForContentRect: aNewContentRect styleMask: mnStyleMask] display: mbShown ? YES : NO]; 801 } 802 803 UpdateFrameGeometry(); 804 805 if( mbShown ) 806 CallCallback( SALEVENT_MOVERESIZE, NULL ); 807 } 808 else 809 { 810 { 811 [mpWindow setFrame: maFullScreenRect display: mbShown ? YES : NO]; 812 } 813 UpdateFrameGeometry(); 814 815 if( mbShown ) 816 CallCallback( SALEVENT_MOVERESIZE, NULL ); 817 818 // show the dock and the menubar 819 [NSMenu setMenuBarVisible:YES]; 820 } 821 if( mbShown ) 822 // trigger filling our backbuffer 823 SendPaintEvent(); 824 } 825 826 // ----------------------------------------------------------------------- 827 828 class PreventSleepTimer : public AutoTimer 829 { 830 public: 831 PreventSleepTimer() 832 { 833 SetTimeout( 30000 ); 834 Start(); 835 } 836 837 virtual ~PreventSleepTimer() 838 { 839 } 840 841 virtual void Timeout() 842 { 843 UpdateSystemActivity(OverallAct); 844 } 845 }; 846 847 void AquaSalFrame::StartPresentation( sal_Bool bStart ) 848 { 849 if ( !mpWindow ) 850 return; 851 852 // #i113170# may not be the main thread if called from UNO API 853 SalData::ensureThreadAutoreleasePool(); 854 855 if( bStart ) 856 { 857 GetSalData()->maPresentationFrames.push_back( this ); 858 mpActivityTimer.reset( new PreventSleepTimer() ); 859 [mpWindow setLevel: NSPopUpMenuWindowLevel]; 860 if( mbShown ) 861 [mpWindow makeMainWindow]; 862 } 863 else 864 { 865 GetSalData()->maPresentationFrames.remove( this ); 866 mpActivityTimer.reset(); 867 [mpWindow setLevel: NSNormalWindowLevel]; 868 } 869 } 870 871 // ----------------------------------------------------------------------- 872 873 void AquaSalFrame::SetAlwaysOnTop( sal_Bool ) 874 { 875 } 876 877 // ----------------------------------------------------------------------- 878 879 void AquaSalFrame::ToTop(sal_uInt16 nFlags) 880 { 881 if ( !mpWindow ) 882 return; 883 884 // #i113170# may not be the main thread if called from UNO API 885 SalData::ensureThreadAutoreleasePool(); 886 887 // #i113170# may not be the main thread if called from UNO API 888 SalData::ensureThreadAutoreleasePool(); 889 890 if( ! (nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN) ) 891 { 892 if( ! [mpWindow isVisible] || [mpWindow isMiniaturized] ) 893 return; 894 } 895 if( nFlags & SAL_FRAME_TOTOP_GRABFOCUS ) 896 [mpWindow makeKeyAndOrderFront: NSApp]; 897 else 898 [mpWindow orderFront: NSApp]; 899 } 900 901 // ----------------------------------------------------------------------- 902 903 NSCursor* AquaSalFrame::getCurrentCursor() const 904 { 905 NSCursor* pCursor = nil; 906 switch( mePointerStyle ) 907 { 908 case POINTER_TEXT: pCursor = [NSCursor IBeamCursor]; break; 909 case POINTER_CROSS: pCursor = [NSCursor crosshairCursor]; break; 910 case POINTER_HAND: 911 case POINTER_MOVE: pCursor = [NSCursor openHandCursor]; break; 912 case POINTER_NSIZE: pCursor = [NSCursor resizeUpCursor]; break; 913 case POINTER_SSIZE: pCursor = [NSCursor resizeDownCursor]; break; 914 case POINTER_ESIZE: pCursor = [NSCursor resizeRightCursor]; break; 915 case POINTER_WSIZE: pCursor = [NSCursor resizeLeftCursor]; break; 916 case POINTER_ARROW: pCursor = [NSCursor arrowCursor]; break; 917 case POINTER_VSPLIT: 918 case POINTER_VSIZEBAR: 919 case POINTER_WINDOW_NSIZE: 920 case POINTER_WINDOW_SSIZE: 921 pCursor = [NSCursor resizeUpDownCursor]; break; 922 case POINTER_HSPLIT: 923 case POINTER_HSIZEBAR: 924 case POINTER_WINDOW_ESIZE: 925 case POINTER_WINDOW_WSIZE: 926 pCursor = [NSCursor resizeLeftRightCursor]; break; 927 case POINTER_REFHAND: pCursor = [NSCursor pointingHandCursor]; break; 928 929 default: 930 pCursor = GetSalData()->getCursor( mePointerStyle ); 931 if( pCursor == nil ) 932 { 933 DBG_ERROR( "unmapped cursor" ); 934 pCursor = [NSCursor arrowCursor]; 935 } 936 break; 937 } 938 return pCursor; 939 } 940 941 void AquaSalFrame::SetPointer( PointerStyle ePointerStyle ) 942 { 943 if ( !mpWindow ) 944 return; 945 946 // #i113170# may not be the main thread if called from UNO API 947 SalData::ensureThreadAutoreleasePool(); 948 949 if( ePointerStyle >= POINTER_COUNT || ePointerStyle == mePointerStyle ) 950 return; 951 mePointerStyle = ePointerStyle; 952 953 [mpWindow invalidateCursorRectsForView: mpView]; 954 } 955 956 // ----------------------------------------------------------------------- 957 958 void AquaSalFrame::SetPointerPos( long nX, long nY ) 959 { 960 // FIXME: use Cocoa functions 961 962 // FIXME: multiscreen support 963 CGPoint aPoint = { nX + maGeometry.nX, nY + maGeometry.nY }; 964 CGDirectDisplayID mainDisplayID = CGMainDisplayID(); 965 CGDisplayMoveCursorToPoint( mainDisplayID, aPoint ); 966 } 967 968 // ----------------------------------------------------------------------- 969 970 void AquaSalFrame::Flush( void ) 971 { 972 if( !(mbGraphics && mpGraphics && mpView && mbShown) ) 973 return; 974 975 // #i113170# may not be the main thread if called from UNO API 976 SalData::ensureThreadAutoreleasePool(); 977 978 979 [mpView setNeedsDisplay: YES]; 980 981 // outside of the application's event loop (e.g. IntroWindow) 982 // nothing would trigger paint event handling 983 // => fall back to synchronous painting 984 if( ImplGetSVData()->maAppData.mnDispatchLevel <= 0 ) 985 { 986 [mpView display]; 987 } 988 } 989 990 // ----------------------------------------------------------------------- 991 992 void AquaSalFrame::Flush( const Rectangle& rRect ) 993 { 994 if( !(mbGraphics && mpGraphics && mpView && mbShown) ) 995 return; 996 997 // #i113170# may not be the main thread if called from UNO API 998 SalData::ensureThreadAutoreleasePool(); 999 1000 NSRect aNSRect = { {rRect.Left(), rRect.Top()}, { rRect.GetWidth(), rRect.GetHeight() } }; 1001 VCLToCocoa( aNSRect, false ); 1002 [mpView setNeedsDisplayInRect: aNSRect]; 1003 1004 // outside of the application's event loop (e.g. IntroWindow) 1005 // nothing would trigger paint event handling 1006 // => fall back to synchronous painting 1007 if( ImplGetSVData()->maAppData.mnDispatchLevel <= 0 ) 1008 { 1009 [mpView display]; 1010 } 1011 } 1012 1013 // ----------------------------------------------------------------------- 1014 1015 void AquaSalFrame::Sync() 1016 { 1017 if( mbGraphics && mpGraphics && mpView && mbShown ) 1018 { 1019 // #i113170# may not be the main thread if called from UNO API 1020 SalData::ensureThreadAutoreleasePool(); 1021 1022 [mpView setNeedsDisplay: YES]; 1023 [mpView display]; 1024 } 1025 } 1026 1027 // ----------------------------------------------------------------------- 1028 1029 void AquaSalFrame::SetInputContext( SalInputContext* pContext ) 1030 { 1031 if (!pContext) 1032 { 1033 mnICOptions = 0; 1034 return; 1035 } 1036 1037 mnICOptions = pContext->mnOptions; 1038 1039 if(!(pContext->mnOptions & SAL_INPUTCONTEXT_TEXT)) 1040 return; 1041 } 1042 1043 // ----------------------------------------------------------------------- 1044 1045 void AquaSalFrame::EndExtTextInput( sal_uInt16 ) 1046 { 1047 } 1048 1049 // ----------------------------------------------------------------------- 1050 1051 XubString AquaSalFrame::GetKeyName( sal_uInt16 nKeyCode ) 1052 { 1053 static std::map< sal_uInt16, rtl::OUString > aKeyMap; 1054 if( aKeyMap.empty() ) 1055 { 1056 sal_uInt16 i; 1057 for( i = KEY_A; i <= KEY_Z; i++ ) 1058 aKeyMap[ i ] = rtl::OUString( sal_Unicode( 'A' + (i - KEY_A) ) ); 1059 for( i = KEY_0; i <= KEY_9; i++ ) 1060 aKeyMap[ i ] = rtl::OUString( sal_Unicode( '0' + (i - KEY_0) ) ); 1061 for( i = KEY_F1; i <= KEY_F26; i++ ) 1062 { 1063 rtl::OUStringBuffer aKey( 3 ); 1064 aKey.append( sal_Unicode( 'F' ) ); 1065 aKey.append( sal_Int32( i - KEY_F1 + 1 ) ); 1066 aKeyMap[ i ] = aKey.makeStringAndClear(); 1067 } 1068 1069 aKeyMap[ KEY_DOWN ] = rtl::OUString( sal_Unicode( 0x21e3 ) ); 1070 aKeyMap[ KEY_UP ] = rtl::OUString( sal_Unicode( 0x21e1 ) ); 1071 aKeyMap[ KEY_LEFT ] = rtl::OUString( sal_Unicode( 0x21e0 ) ); 1072 aKeyMap[ KEY_RIGHT ] = rtl::OUString( sal_Unicode( 0x21e2 ) ); 1073 aKeyMap[ KEY_HOME ] = rtl::OUString( sal_Unicode( 0x2196 ) ); 1074 aKeyMap[ KEY_END ] = rtl::OUString( sal_Unicode( 0x2198 ) ); 1075 aKeyMap[ KEY_PAGEUP ] = rtl::OUString( sal_Unicode( 0x21de ) ); 1076 aKeyMap[ KEY_PAGEDOWN ] = rtl::OUString( sal_Unicode( 0x21df ) ); 1077 aKeyMap[ KEY_RETURN ] = rtl::OUString( sal_Unicode( 0x21a9 ) ); 1078 aKeyMap[ KEY_ESCAPE ] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "esc" ) ); 1079 aKeyMap[ KEY_TAB ] = rtl::OUString( sal_Unicode( 0x21e5 ) ); 1080 aKeyMap[ KEY_BACKSPACE ]= rtl::OUString( sal_Unicode( 0x232b ) ); 1081 aKeyMap[ KEY_SPACE ] = rtl::OUString( sal_Unicode( 0x2423 ) ); 1082 aKeyMap[ KEY_DELETE ] = rtl::OUString( sal_Unicode( 0x2326 ) ); 1083 aKeyMap[ KEY_ADD ] = rtl::OUString( sal_Unicode( '+' ) ); 1084 aKeyMap[ KEY_SUBTRACT ] = rtl::OUString( sal_Unicode( '-' ) ); 1085 aKeyMap[ KEY_DIVIDE ] = rtl::OUString( sal_Unicode( '/' ) ); 1086 aKeyMap[ KEY_MULTIPLY ] = rtl::OUString( sal_Unicode( '*' ) ); 1087 aKeyMap[ KEY_POINT ] = rtl::OUString( sal_Unicode( '.' ) ); 1088 aKeyMap[ KEY_COMMA ] = rtl::OUString( sal_Unicode( ',' ) ); 1089 aKeyMap[ KEY_LESS ] = rtl::OUString( sal_Unicode( '<' ) ); 1090 aKeyMap[ KEY_GREATER ] = rtl::OUString( sal_Unicode( '>' ) ); 1091 aKeyMap[ KEY_EQUAL ] = rtl::OUString( sal_Unicode( '=' ) ); 1092 aKeyMap[ KEY_OPEN ] = rtl::OUString( sal_Unicode( 0x23cf ) ); 1093 1094 /* yet unmapped KEYCODES: 1095 aKeyMap[ KEY_INSERT ] = rtl::OUString( sal_Unicode( ) ); 1096 aKeyMap[ KEY_CUT ] = rtl::OUString( sal_Unicode( ) ); 1097 aKeyMap[ KEY_COPY ] = rtl::OUString( sal_Unicode( ) ); 1098 aKeyMap[ KEY_PASTE ] = rtl::OUString( sal_Unicode( ) ); 1099 aKeyMap[ KEY_UNDO ] = rtl::OUString( sal_Unicode( ) ); 1100 aKeyMap[ KEY_REPEAT ] = rtl::OUString( sal_Unicode( ) ); 1101 aKeyMap[ KEY_FIND ] = rtl::OUString( sal_Unicode( ) ); 1102 aKeyMap[ KEY_PROPERTIES ] = rtl::OUString( sal_Unicode( ) ); 1103 aKeyMap[ KEY_FRONT ] = rtl::OUString( sal_Unicode( ) ); 1104 aKeyMap[ KEY_CONTEXTMENU ] = rtl::OUString( sal_Unicode( ) ); 1105 aKeyMap[ KEY_MENU ] = rtl::OUString( sal_Unicode( ) ); 1106 aKeyMap[ KEY_HELP ] = rtl::OUString( sal_Unicode( ) ); 1107 aKeyMap[ KEY_HANGUL_HANJA ] = rtl::OUString( sal_Unicode( ) ); 1108 aKeyMap[ KEY_DECIMAL ] = rtl::OUString( sal_Unicode( ) ); 1109 aKeyMap[ KEY_TILDE ] = rtl::OUString( sal_Unicode( ) ); 1110 aKeyMap[ KEY_QUOTELEFT ]= rtl::OUString( sal_Unicode( ) ); 1111 */ 1112 1113 } 1114 1115 rtl::OUStringBuffer aResult( 16 ); 1116 1117 sal_uInt16 nUnmodifiedCode = (nKeyCode & KEY_CODE); 1118 std::map< sal_uInt16, rtl::OUString >::const_iterator it = aKeyMap.find( nUnmodifiedCode ); 1119 if( it != aKeyMap.end() ) 1120 { 1121 if( (nKeyCode & KEY_SHIFT) != 0 ) 1122 aResult.append( sal_Unicode( 0x21e7 ) ); 1123 if( (nKeyCode & KEY_MOD1) != 0 ) 1124 aResult.append( sal_Unicode( 0x2318 ) ); 1125 // we do not really handle Alt (see below) 1126 // we map it to MOD3, whichis actually Command 1127 if( (nKeyCode & (KEY_MOD2|KEY_MOD3)) != 0 ) 1128 aResult.append( sal_Unicode( 0x2303 ) ); 1129 1130 aResult.append( it->second ); 1131 } 1132 1133 return aResult.makeStringAndClear(); 1134 } 1135 1136 // ----------------------------------------------------------------------- 1137 1138 XubString AquaSalFrame::GetSymbolKeyName( const XubString&, sal_uInt16 nKeyCode ) 1139 { 1140 return GetKeyName( nKeyCode ); 1141 } 1142 1143 // ----------------------------------------------------------------------- 1144 1145 static void getAppleScrollBarVariant(void) 1146 { 1147 bool bIsScrollbarDoubleMax = true; // default is DoubleMax 1148 1149 CFStringRef AppleScrollBarType = CFSTR("AppleScrollBarVariant"); 1150 if( AppleScrollBarType ) 1151 { 1152 CFStringRef ScrollBarVariant = ((CFStringRef)CFPreferencesCopyAppValue( AppleScrollBarType, kCFPreferencesCurrentApplication )); 1153 if( ScrollBarVariant ) 1154 { 1155 if( CFGetTypeID( ScrollBarVariant ) == CFStringGetTypeID() ) 1156 { 1157 // TODO: check for the less important variants "DoubleMin" and "DoubleBoth" too 1158 CFStringRef DoubleMax = CFSTR("DoubleMax"); 1159 if (DoubleMax) 1160 { 1161 if ( !CFStringCompare(ScrollBarVariant, DoubleMax, kCFCompareCaseInsensitive) ) 1162 bIsScrollbarDoubleMax = true; 1163 else 1164 bIsScrollbarDoubleMax = false; 1165 CFRelease(DoubleMax); 1166 } 1167 } 1168 CFRelease( ScrollBarVariant ); 1169 } 1170 CFRelease(AppleScrollBarType); 1171 } 1172 1173 GetSalData()->mbIsScrollbarDoubleMax = bIsScrollbarDoubleMax; 1174 1175 CFStringRef jumpScroll = CFSTR("AppleScrollerPagingBehavior"); 1176 if( jumpScroll ) 1177 { 1178 CFBooleanRef jumpStr = ((CFBooleanRef)CFPreferencesCopyAppValue( jumpScroll, kCFPreferencesCurrentApplication )); 1179 if( jumpStr ) 1180 { 1181 if( CFGetTypeID( jumpStr ) == CFBooleanGetTypeID() ) 1182 ImplGetSVData()->maNWFData.mbScrollbarJumpPage = (jumpStr == kCFBooleanTrue); 1183 CFRelease( jumpStr ); 1184 } 1185 CFRelease( jumpScroll ); 1186 } 1187 } 1188 1189 static Color getColor( NSColor* pSysColor, const Color& rDefault, NSWindow* pWin ) 1190 { 1191 Color aRet( rDefault ); 1192 if( pSysColor ) 1193 { 1194 // transform to RGB 1195 NSColor* pRBGColor = [pSysColor colorUsingColorSpaceName: NSDeviceRGBColorSpace device: [pWin deviceDescription]]; 1196 if( pRBGColor ) 1197 { 1198 float r = 0, g = 0, b = 0, a = 0; 1199 [pRBGColor getRed: &r green: &g blue: &b alpha: &a]; 1200 aRet = Color( int(r*255.999), int(g*255.999), int(b*255.999) ); 1201 /* 1202 do not release here; leads to duplicate free in yield 1203 it seems the converted color comes out autoreleased, although this 1204 is not documented 1205 [pRBGColor release]; 1206 */ 1207 } 1208 } 1209 return aRet; 1210 } 1211 1212 static Font getFont( NSFont* pFont, long nDPIY, const Font& rDefault ) 1213 { 1214 Font aResult( rDefault ); 1215 if( pFont ) 1216 { 1217 aResult.SetName( GetOUString( [pFont familyName] ) ); 1218 aResult.SetHeight( static_cast<int>(([pFont pointSize] * 72.0 / (float)nDPIY)+0.5) ); 1219 aResult.SetItalic( ([pFont italicAngle] != 0.0) ? ITALIC_NORMAL : ITALIC_NONE ); 1220 // FIMXE: bold ? 1221 } 1222 1223 return aResult; 1224 } 1225 1226 void AquaSalFrame::getResolution( long& o_rDPIX, long& o_rDPIY ) 1227 { 1228 if( ! mpGraphics ) 1229 { 1230 GetGraphics(); 1231 ReleaseGraphics( mpGraphics ); 1232 } 1233 mpGraphics->GetResolution( o_rDPIX, o_rDPIY ); 1234 } 1235 1236 // on OSX-Aqua the style settings are independent of the frame, so it does 1237 // not really belong here. Since the connection to the Appearance_Manager 1238 // is currently done in salnativewidgets.cxx this would be a good place. 1239 // On the other hand VCL's platform independent code currently only asks 1240 // SalFrames for system settings anyway, so moving the code somewhere else 1241 // doesn't make the anything cleaner for now 1242 void AquaSalFrame::UpdateSettings( AllSettings& rSettings ) 1243 { 1244 if ( !mpWindow ) 1245 return; 1246 1247 // #i113170# may not be the main thread if called from UNO API 1248 SalData::ensureThreadAutoreleasePool(); 1249 1250 [mpView lockFocus]; 1251 1252 StyleSettings aStyleSettings = rSettings.GetStyleSettings(); 1253 1254 // Background Color 1255 Color aBackgroundColor = Color( 0xEC, 0xEC, 0xEC ); 1256 aStyleSettings.Set3DColors( aBackgroundColor ); 1257 aStyleSettings.SetFaceColor( aBackgroundColor ); 1258 Color aInactiveTabColor( aBackgroundColor ); 1259 aInactiveTabColor.DecreaseLuminance( 32 ); 1260 aStyleSettings.SetInactiveTabColor( aInactiveTabColor ); 1261 1262 aStyleSettings.SetDialogColor( aBackgroundColor ); 1263 aStyleSettings.SetLightBorderColor( aBackgroundColor ); 1264 Color aShadowColor( aStyleSettings.GetShadowColor() ); 1265 aStyleSettings.SetDarkShadowColor( aShadowColor ); 1266 aShadowColor.IncreaseLuminance( 32 ); 1267 aStyleSettings.SetShadowColor( aShadowColor ); 1268 1269 // get the system font settings 1270 Font aAppFont = aStyleSettings.GetAppFont(); 1271 long nDPIX = 72, nDPIY = 72; 1272 getResolution( nDPIX, nDPIY ); 1273 aAppFont = getFont( [NSFont systemFontOfSize: 0], nDPIY, aAppFont ); 1274 1275 // TODO: better mapping of aqua<->ooo font settings 1276 aStyleSettings.SetAppFont( aAppFont ); 1277 aStyleSettings.SetHelpFont( aAppFont ); 1278 aStyleSettings.SetPushButtonFont( aAppFont ); 1279 1280 Font aTitleFont( getFont( [NSFont titleBarFontOfSize: 0], nDPIY, aAppFont ) ); 1281 aStyleSettings.SetTitleFont( aTitleFont ); 1282 aStyleSettings.SetFloatTitleFont( aTitleFont ); 1283 1284 Font aMenuFont( getFont( [NSFont menuFontOfSize: 0], nDPIY, aAppFont ) ); 1285 aStyleSettings.SetMenuFont( aMenuFont ); 1286 1287 aStyleSettings.SetToolFont( aAppFont ); 1288 1289 Font aLabelFont( getFont( [NSFont labelFontOfSize: 0], nDPIY, aAppFont ) ); 1290 aStyleSettings.SetLabelFont( aLabelFont ); 1291 aStyleSettings.SetInfoFont( aLabelFont ); 1292 aStyleSettings.SetRadioCheckFont( aLabelFont ); 1293 aStyleSettings.SetFieldFont( aLabelFont ); 1294 aStyleSettings.SetGroupFont( aLabelFont ); 1295 aStyleSettings.SetIconFont( aLabelFont ); 1296 1297 Color aHighlightColor( getColor( [NSColor selectedTextBackgroundColor], 1298 aStyleSettings.GetHighlightColor(), mpWindow ) ); 1299 aStyleSettings.SetHighlightColor( aHighlightColor ); 1300 Color aHighlightTextColor( getColor( [NSColor selectedTextColor], 1301 aStyleSettings.GetHighlightTextColor(), mpWindow ) ); 1302 aStyleSettings.SetHighlightTextColor( aHighlightTextColor ); 1303 1304 Color aMenuHighlightColor( getColor( [NSColor selectedMenuItemColor], 1305 aStyleSettings.GetMenuHighlightColor(), mpWindow ) ); 1306 aStyleSettings.SetMenuHighlightColor( aMenuHighlightColor ); 1307 Color aMenuHighlightTextColor( getColor( [NSColor selectedMenuItemTextColor], 1308 aStyleSettings.GetMenuHighlightTextColor(), mpWindow ) ); 1309 aStyleSettings.SetMenuHighlightTextColor( aMenuHighlightTextColor ); 1310 1311 aStyleSettings.SetMenuColor( aBackgroundColor ); 1312 Color aMenuTextColor( getColor( [NSColor textColor], 1313 aStyleSettings.GetMenuTextColor(), mpWindow ) ); 1314 aStyleSettings.SetMenuTextColor( aMenuTextColor ); 1315 aStyleSettings.SetMenuBarTextColor( aMenuTextColor ); 1316 1317 aStyleSettings.SetCursorBlinkTime( 500 ); 1318 1319 // no mnemonics on aqua 1320 aStyleSettings.SetOptions( aStyleSettings.GetOptions() | STYLE_OPTION_NOMNEMONICS ); 1321 1322 getAppleScrollBarVariant(); 1323 1324 // set scrollbar size 1325 aStyleSettings.SetScrollBarSize( static_cast<long int>([NSScroller scrollerWidth]) ); 1326 1327 // images in menus false for MacOSX 1328 aStyleSettings.SetUseImagesInMenus( false ); 1329 1330 rSettings.SetStyleSettings( aStyleSettings ); 1331 1332 [mpView unlockFocus]; 1333 } 1334 1335 // ----------------------------------------------------------------------- 1336 1337 const SystemEnvData* AquaSalFrame::GetSystemData() const 1338 { 1339 return &maSysData; 1340 } 1341 1342 // ----------------------------------------------------------------------- 1343 1344 void AquaSalFrame::Beep( SoundType eSoundType ) 1345 { 1346 switch( eSoundType ) 1347 { 1348 case SOUND_DISABLE: 1349 // don't beep 1350 break; 1351 default: 1352 NSBeep(); 1353 break; 1354 } 1355 } 1356 1357 // ----------------------------------------------------------------------- 1358 1359 void AquaSalFrame::SetPosSize(long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags) 1360 { 1361 if ( !mpWindow ) 1362 return; 1363 1364 // #i113170# may not be the main thread if called from UNO API 1365 SalData::ensureThreadAutoreleasePool(); 1366 1367 sal_uInt16 nEvent = 0; 1368 1369 if( [mpWindow isMiniaturized] ) 1370 [mpWindow deminiaturize: NSApp]; // expand the window 1371 1372 if (nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y)) 1373 { 1374 mbPositioned = true; 1375 nEvent = SALEVENT_MOVE; 1376 } 1377 1378 if (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) 1379 { 1380 mbSized = true; 1381 nEvent = (nEvent == SALEVENT_MOVE) ? SALEVENT_MOVERESIZE : SALEVENT_RESIZE; 1382 } 1383 1384 NSRect aFrameRect = [mpWindow frame]; 1385 NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask]; 1386 1387 // position is always relative to parent frame 1388 NSRect aParentContentRect; 1389 1390 if( mpParent ) 1391 { 1392 if( Application::GetSettings().GetLayoutRTL() ) 1393 { 1394 if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 ) 1395 nX = mpParent->maGeometry.nWidth - nWidth-1 - nX; 1396 else 1397 nX = mpParent->maGeometry.nWidth - static_cast<long int>( aContentRect.size.width-1) - nX; 1398 } 1399 NSRect aParentFrameRect = [mpParent->mpWindow frame]; 1400 aParentContentRect = [NSWindow contentRectForFrameRect: aParentFrameRect styleMask: mpParent->mnStyleMask]; 1401 } 1402 else 1403 aParentContentRect = maScreenRect; // use screen if no parent 1404 1405 CocoaToVCL( aContentRect ); 1406 CocoaToVCL( aParentContentRect ); 1407 1408 bool bPaint = false; 1409 if( (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) != 0 ) 1410 { 1411 if( nWidth != aContentRect.size.width || nHeight != aContentRect.size.height ) 1412 bPaint = true; 1413 } 1414 1415 // use old window pos if no new pos requested 1416 if( (nFlags & SAL_FRAME_POSSIZE_X) != 0 ) 1417 aContentRect.origin.x = nX + aParentContentRect.origin.x; 1418 if( (nFlags & SAL_FRAME_POSSIZE_Y) != 0) 1419 aContentRect.origin.y = nY + aParentContentRect.origin.y; 1420 1421 // use old size if no new size requested 1422 if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 ) 1423 aContentRect.size.width = nWidth; 1424 if( (nFlags & SAL_FRAME_POSSIZE_HEIGHT) != 0) 1425 aContentRect.size.height = nHeight; 1426 1427 VCLToCocoa( aContentRect ); 1428 1429 // do not display yet, we need to update our backbuffer 1430 { 1431 [mpWindow setFrame: [NSWindow frameRectForContentRect: aContentRect styleMask: mnStyleMask] display: NO]; 1432 } 1433 1434 UpdateFrameGeometry(); 1435 1436 if (nEvent) 1437 CallCallback(nEvent, NULL); 1438 1439 if( mbShown && bPaint ) 1440 { 1441 // trigger filling our backbuffer 1442 SendPaintEvent(); 1443 1444 // now inform the system that the views need to be drawn 1445 [mpWindow display]; 1446 } 1447 } 1448 1449 void AquaSalFrame::GetWorkArea( Rectangle& rRect ) 1450 { 1451 if ( !mpWindow ) 1452 return; 1453 1454 // #i113170# may not be the main thread if called from UNO API 1455 SalData::ensureThreadAutoreleasePool(); 1456 1457 NSScreen* pScreen = [mpWindow screen]; 1458 if( pScreen == nil ) 1459 pScreen = [NSScreen mainScreen]; 1460 NSRect aRect = [pScreen visibleFrame]; 1461 CocoaToVCL( aRect ); 1462 rRect.nLeft = static_cast<long>(aRect.origin.x); 1463 rRect.nTop = static_cast<long>(aRect.origin.y); 1464 rRect.nRight = static_cast<long>(aRect.origin.x + aRect.size.width - 1); 1465 rRect.nBottom = static_cast<long>(aRect.origin.y + aRect.size.height - 1); 1466 } 1467 1468 SalPointerState AquaSalFrame::GetPointerState() 1469 { 1470 // #i113170# may not be the main thread if called from UNO API 1471 SalData::ensureThreadAutoreleasePool(); 1472 1473 SalPointerState state; 1474 state.mnState = 0; 1475 1476 // get position 1477 NSPoint aPt = [mpWindow mouseLocationOutsideOfEventStream]; 1478 CocoaToVCL( aPt, false ); 1479 state.maPos = Point(static_cast<long>(aPt.x), static_cast<long>(aPt.y)); 1480 1481 NSEvent* pCur = [NSApp currentEvent]; 1482 bool bMouseEvent = false; 1483 if( pCur ) 1484 { 1485 bMouseEvent = true; 1486 switch( [pCur type] ) 1487 { 1488 case NSLeftMouseDown: state.mnState |= MOUSE_LEFT; break; 1489 case NSLeftMouseUp: break; 1490 case NSRightMouseDown: state.mnState |= MOUSE_RIGHT; break; 1491 case NSRightMouseUp: break; 1492 case NSOtherMouseDown: state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0; break; 1493 case NSOtherMouseUp: break; 1494 case NSMouseMoved: break; 1495 case NSLeftMouseDragged: state.mnState |= MOUSE_LEFT; break; 1496 case NSRightMouseDragged: state.mnState |= MOUSE_RIGHT; break; 1497 case NSOtherMouseDragged: state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0; break; 1498 break; 1499 default: 1500 bMouseEvent = false; 1501 break; 1502 } 1503 } 1504 if( bMouseEvent ) 1505 { 1506 unsigned int nMask = (unsigned int)[pCur modifierFlags]; 1507 if( (nMask & NSShiftKeyMask) != 0 ) 1508 state.mnState |= KEY_SHIFT; 1509 if( (nMask & NSControlKeyMask) != 0 ) 1510 state.mnState |= KEY_MOD3; 1511 if( (nMask & NSAlternateKeyMask) != 0 ) 1512 state.mnState |= KEY_MOD2; 1513 if( (nMask & NSCommandKeyMask) != 0 ) 1514 state.mnState |= KEY_MOD1; 1515 1516 } 1517 else 1518 { 1519 // FIXME: replace Carbon by Cocoa 1520 // Cocoa does not have an equivalent for GetCurrentEventButtonState 1521 // and GetCurrentEventKeyModifiers. 1522 // we could try to get away with tracking all events for modifierKeys 1523 // and all mouse events for button state in VCL_NSApllication::sendEvent, 1524 // but it is unclear whether this will get us the same result. 1525 // leave in GetCurrentEventButtonState and GetCurrentEventKeyModifiers for now 1526 1527 // fill in button state 1528 UInt32 nState = GetCurrentEventButtonState(); 1529 state.mnState = 0; 1530 if( nState & 1 ) 1531 state.mnState |= MOUSE_LEFT; // primary button 1532 if( nState & 2 ) 1533 state.mnState |= MOUSE_RIGHT; // secondary button 1534 if( nState & 4 ) 1535 state.mnState |= MOUSE_MIDDLE; // tertiary button 1536 1537 // fill in modifier state 1538 nState = GetCurrentEventKeyModifiers(); 1539 if( nState & shiftKey ) 1540 state.mnState |= KEY_SHIFT; 1541 if( nState & controlKey ) 1542 state.mnState |= KEY_MOD3; 1543 if( nState & optionKey ) 1544 state.mnState |= KEY_MOD2; 1545 if( nState & cmdKey ) 1546 state.mnState |= KEY_MOD1; 1547 } 1548 1549 1550 return state; 1551 } 1552 1553 bool AquaSalFrame::SetPluginParent( SystemParentData* ) 1554 { 1555 // plugin parent may be killed unexpectedly by 1556 // plugging process; 1557 1558 //TODO: implement 1559 return sal_False; 1560 } 1561 1562 sal_Bool AquaSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , KeyCode& ) 1563 { 1564 // not supported yet 1565 return FALSE; 1566 } 1567 1568 LanguageType AquaSalFrame::GetInputLanguage() 1569 { 1570 //TODO: implement 1571 return LANGUAGE_DONTKNOW; 1572 } 1573 1574 void AquaSalFrame::DrawMenuBar() 1575 { 1576 } 1577 1578 void AquaSalFrame::SetMenu( SalMenu* pSalMenu ) 1579 { 1580 // #i113170# may not be the main thread if called from UNO API 1581 SalData::ensureThreadAutoreleasePool(); 1582 1583 AquaSalMenu* pMenu = static_cast<AquaSalMenu*>(pSalMenu); 1584 DBG_ASSERT( ! pMenu || pMenu->mbMenuBar, "setting non menubar on frame" ); 1585 mpMenu = pMenu; 1586 if( mpMenu ) 1587 mpMenu->setMainMenu(); 1588 } 1589 1590 void AquaSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle ) 1591 { 1592 if ( mpWindow ) 1593 { 1594 // #i113170# may not be the main thread if called from UNO API 1595 SalData::ensureThreadAutoreleasePool(); 1596 1597 if( (mnExtStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) != (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) ) 1598 [mpWindow setDocumentEdited: (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) ? YES : NO]; 1599 } 1600 1601 mnExtStyle = nStyle; 1602 } 1603 1604 void AquaSalFrame::SetBackgroundBitmap( SalBitmap* ) 1605 { 1606 //TODO: implement 1607 } 1608 1609 SalBitmap* AquaSalFrame::SnapShot() 1610 { 1611 return mpGraphics ? mpGraphics->getBitmap( 0, 0, maGeometry.nWidth, maGeometry.nHeight ) : NULL; 1612 } 1613 1614 SalFrame* AquaSalFrame::GetParent() const 1615 { 1616 return mpParent; 1617 } 1618 1619 void AquaSalFrame::SetParent( SalFrame* pNewParent ) 1620 { 1621 bool bShown = mbShown; 1622 // remove from child list 1623 Show( FALSE ); 1624 mpParent = (AquaSalFrame*)pNewParent; 1625 // insert to correct parent and paint 1626 Show( bShown ); 1627 } 1628 1629 void AquaSalFrame::UpdateFrameGeometry() 1630 { 1631 if ( !mpWindow ) 1632 { 1633 return; 1634 } 1635 1636 // keep in mind that view and window coordinates are lower left 1637 // whereas vcl's are upper left 1638 1639 // update screen rect 1640 NSScreen * pScreen = [mpWindow screen]; 1641 if( pScreen ) 1642 { 1643 maScreenRect = [pScreen frame]; 1644 NSArray* pScreens = [NSScreen screens]; 1645 if( pScreens ) 1646 maGeometry.nScreenNumber = [pScreens indexOfObject: pScreen]; 1647 } 1648 1649 NSRect aFrameRect = [mpWindow frame]; 1650 NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask]; 1651 1652 // release old track rect 1653 [mpView removeTrackingRect: mnTrackingRectTag]; 1654 // install the new track rect 1655 NSRect aTrackRect = { { 0, 0 }, aContentRect.size }; 1656 mnTrackingRectTag = [mpView addTrackingRect: aTrackRect owner: mpView userData: nil assumeInside: NO]; 1657 1658 // convert to vcl convention 1659 CocoaToVCL( aFrameRect ); 1660 CocoaToVCL( aContentRect ); 1661 1662 maGeometry.nX = static_cast<int>(aContentRect.origin.x); 1663 maGeometry.nY = static_cast<int>(aContentRect.origin.y); 1664 1665 maGeometry.nLeftDecoration = static_cast<unsigned int>(aContentRect.origin.x - aFrameRect.origin.x); 1666 maGeometry.nRightDecoration = static_cast<unsigned int>((aFrameRect.origin.x + aFrameRect.size.width) - 1667 (aContentRect.origin.x + aContentRect.size.width)); 1668 1669 maGeometry.nTopDecoration = static_cast<unsigned int>(aContentRect.origin.y - aFrameRect.origin.y); 1670 maGeometry.nBottomDecoration = static_cast<unsigned int>((aFrameRect.origin.y + aFrameRect.size.height) - 1671 (aContentRect.origin.y + aContentRect.size.height)); 1672 1673 maGeometry.nWidth = static_cast<unsigned int>(aContentRect.size.width); 1674 maGeometry.nHeight = static_cast<unsigned int>(aContentRect.size.height); 1675 } 1676 1677 // ----------------------------------------------------------------------- 1678 1679 void AquaSalFrame::CaptureMouse( sal_Bool bCapture ) 1680 { 1681 /* Remark: 1682 we'll try to use a pidgin version of capture mouse 1683 on MacOSX (neither carbon nor cocoa) there is a 1684 CaptureMouse equivalent (in Carbon there is TrackMouseLocation 1685 but this is useless to use since it is blocking) 1686 1687 However on cocoa the active frame seems to get mouse events 1688 also outside the window, so we'll try to forward mouse events 1689 to the capture frame in the hope that one of our frames 1690 gets a mouse event. 1691 1692 This will break as soon as the user activates another app, but 1693 a mouse click will normally lead to a release of the mouse anyway. 1694 1695 Let's see how far we get this way. Alternatively we could use one 1696 large overlay window like we did for the carbon implementation, 1697 however that is resource intensive. 1698 */ 1699 1700 if( bCapture ) 1701 s_pCaptureFrame = this; 1702 else if( ! bCapture && s_pCaptureFrame == this ) 1703 s_pCaptureFrame = NULL; 1704 } 1705 1706 void AquaSalFrame::ResetClipRegion() 1707 { 1708 if ( !mpWindow ) 1709 { 1710 return; 1711 } 1712 1713 // #i113170# may not be the main thread if called from UNO API 1714 SalData::ensureThreadAutoreleasePool(); 1715 1716 // release old path and indicate no clipping 1717 CGPathRelease( mrClippingPath ); 1718 mrClippingPath = NULL; 1719 1720 if( mpView && mbShown ) 1721 [mpView setNeedsDisplay: YES]; 1722 if( mpWindow ) 1723 { 1724 [mpWindow setOpaque: YES]; 1725 [mpWindow invalidateShadow]; 1726 } 1727 } 1728 1729 void AquaSalFrame::BeginSetClipRegion( sal_uLong nRects ) 1730 { 1731 if ( !mpWindow ) 1732 { 1733 return; 1734 } 1735 1736 // #i113170# may not be the main thread if called from UNO API 1737 SalData::ensureThreadAutoreleasePool(); 1738 1739 // release old path 1740 if( mrClippingPath ) 1741 { 1742 CGPathRelease( mrClippingPath ); 1743 mrClippingPath = NULL; 1744 } 1745 1746 if( maClippingRects.size() > SAL_CLIPRECT_COUNT && nRects < maClippingRects.size() ) 1747 { 1748 std::vector<CGRect> aEmptyVec; 1749 maClippingRects.swap( aEmptyVec ); 1750 } 1751 maClippingRects.clear(); 1752 maClippingRects.reserve( nRects ); 1753 } 1754 1755 void AquaSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight ) 1756 { 1757 // #i113170# may not be the main thread if called from UNO API 1758 SalData::ensureThreadAutoreleasePool(); 1759 1760 if( nWidth && nHeight ) 1761 { 1762 NSRect aRect = { { nX, nY }, { nWidth, nHeight } }; 1763 VCLToCocoa( aRect, false ); 1764 maClippingRects.push_back( CGRectMake(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height) ); 1765 } 1766 } 1767 1768 void AquaSalFrame::EndSetClipRegion() 1769 { 1770 if ( !mpWindow ) 1771 { 1772 return; 1773 } 1774 1775 // #i113170# may not be the main thread if called from UNO API 1776 SalData::ensureThreadAutoreleasePool(); 1777 1778 if( ! maClippingRects.empty() ) 1779 { 1780 mrClippingPath = CGPathCreateMutable(); 1781 CGPathAddRects( mrClippingPath, NULL, &maClippingRects[0], maClippingRects.size() ); 1782 } 1783 if( mpView && mbShown ) 1784 [mpView setNeedsDisplay: YES]; 1785 if( mpWindow ) 1786 { 1787 [mpWindow setOpaque: (mrClippingPath != NULL) ? NO : YES]; 1788 [mpWindow setBackgroundColor: [NSColor clearColor]]; 1789 // shadow is invalidated when view gets drawn again 1790 } 1791 } 1792 1793