1 /* 2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #import "common.h" 27 #import "com_sun_glass_events_DndEvent.h" 28 #import "com_sun_glass_events_KeyEvent.h" 29 #import "com_sun_glass_events_MouseEvent.h" 30 #import "com_sun_glass_ui_View_Capability.h" 31 #import "com_sun_glass_ui_mac_MacGestureSupport.h" 32 #import "GlassKey.h" 33 #import "GlassMacros.h" 34 #import "GlassView3D.h" 35 #import "GlassLayer3D.h" 36 #import "GlassApplication.h" 37 38 //#define VERBOSE 39 #ifndef VERBOSE 40 #define LOG(MSG, ...) 41 #else 42 #define LOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__); 43 #endif 44 45 //#define MOUSEVERBOSE 46 #ifndef MOUSEVERBOSE 47 #define MOUSELOG(MSG, ...) 48 #else 49 #define MOUSELOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__); 50 #endif 51 52 //#define KEYVERBOSE 53 #ifndef KEYVERBOSE 54 #define KEYLOG(MSG, ...) 55 #else 56 #define KEYLOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__); 57 #endif 58 59 //#define DNDVERBOSE 60 #ifndef DNDVERBOSE 61 #define DNDLOG(MSG, ...) 62 #else 63 #define DNDLOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__); 64 #endif 65 66 //#define IMVERBOSE 67 #ifndef IMVERBOSE 68 #define IMLOG(MSG, ...) 69 #else 70 #define IMLOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__); 71 #endif 72 73 #define SHARE_GL_CONTEXT 74 //#define DEBUG_COLORS 75 76 // http://developer.apple.com/library/mac/#technotes/tn2085/_index.html 77 //#define ENABLE_MULTITHREADED_GL 78 79 @implementation GlassView3D 80 81 - (CGLPixelFormatObj)_createPixelFormatWithDepth:(CGLPixelFormatAttribute)depth 82 { 83 CGLPixelFormatObj pix = NULL; 84 { 85 const CGLPixelFormatAttribute attributes[] = 86 { 87 kCGLPFAAccelerated, 88 kCGLPFAColorSize, 32, 89 kCGLPFAAlphaSize, 8, 90 kCGLPFADepthSize, depth, 91 kCGLPFAAllowOfflineRenderers, // lets OpenGL know this context is offline renderer aware 92 (CGLPixelFormatAttribute)0 93 }; 94 GLint npix = 0; 95 CGLError err = CGLChoosePixelFormat(attributes, &pix, &npix); 96 if (err != kCGLNoError) 97 { 98 NSLog(@"CGLChoosePixelFormat error: %d", err); 99 } 100 } 101 return pix; 102 } 103 104 - (CGLContextObj)_createContextWithShared:(CGLContextObj)share withFormat:(CGLPixelFormatObj)format 105 { 106 CGLContextObj ctx = NULL; 107 { 108 CGLError err = CGLCreateContext(format, share, &ctx); 109 if (err != kCGLNoError) 110 { 111 NSLog(@"CGLCreateContext error: %d", err); 112 } 113 } 114 return ctx; 115 } 116 117 - (void)_initialize3dWithJproperties:(jobject)jproperties 118 { 119 GET_MAIN_JENV; 120 121 int depthBits = 0; 122 if (jproperties != NULL) 123 { 124 jobject k3dDepthKey = (*env)->NewObject(env, jIntegerClass, jIntegerInitMethod, com_sun_glass_ui_View_Capability_k3dDepthKeyValue); 125 GLASS_CHECK_EXCEPTION(env); 126 jobject k3dDepthKeyValue = (*env)->CallObjectMethod(env, jproperties, jMapGetMethod, k3dDepthKey); 127 GLASS_CHECK_EXCEPTION(env); 128 if (k3dDepthKeyValue != NULL) 129 { 130 depthBits = (*env)->CallIntMethod(env, k3dDepthKeyValue, jIntegerValueMethod); 131 GLASS_CHECK_EXCEPTION(env); 132 } 133 } 134 135 CGLContextObj sharedCGL = NULL; 136 if (jproperties != NULL) 137 { 138 jobject sharedContextPtrKey = (*env)->NewStringUTF(env, "shareContextPtr"); 139 jobject sharedContextPtrValue = (*env)->CallObjectMethod(env, jproperties, jMapGetMethod, sharedContextPtrKey); 140 GLASS_CHECK_EXCEPTION(env); 141 if (sharedContextPtrValue != NULL) 142 { 143 jlong jsharedContextPtr = (*env)->CallLongMethod(env, sharedContextPtrValue, jLongValueMethod); 144 GLASS_CHECK_EXCEPTION(env); 145 if (jsharedContextPtr != 0) 146 { 147 NSOpenGLContext *sharedContextNS = (NSOpenGLContext*)jlong_to_ptr(jsharedContextPtr); 148 sharedCGL = [sharedContextNS CGLContextObj]; 149 } 150 } 151 } 152 153 CGLContextObj clientCGL = NULL; 154 BOOL isSwPipe = NO; 155 156 if (jproperties != NULL) 157 { 158 jobject contextPtrKey = (*env)->NewStringUTF(env, "contextPtr"); 159 jobject contextPtrValue = (*env)->CallObjectMethod(env, jproperties, jMapGetMethod, contextPtrKey); 160 GLASS_CHECK_EXCEPTION(env); 161 if (contextPtrValue != NULL) 162 { 163 jlong jcontextPtr = (*env)->CallLongMethod(env, contextPtrValue, jLongValueMethod); 164 GLASS_CHECK_EXCEPTION(env); 165 if (jcontextPtr != 0) 166 { 167 NSOpenGLContext *clientContextNS = (NSOpenGLContext*)jlong_to_ptr(jcontextPtr); 168 clientCGL = [clientContextNS CGLContextObj]; 169 } 170 } 171 } 172 if (clientCGL == NULL) 173 { 174 CGLPixelFormatObj clientPixelFormat = [self _createPixelFormatWithDepth:(CGLPixelFormatAttribute)depthBits]; 175 clientCGL = [self _createContextWithShared:sharedCGL withFormat:clientPixelFormat]; 176 } 177 if (sharedCGL == NULL) 178 { 179 // this can happen in Rain or clients other than Prism (ie. device details do not have the shared context set) 180 sharedCGL = clientCGL; 181 isSwPipe = YES; 182 } 183 184 self->isHiDPIAware = NO; 185 if (jproperties != NULL) 186 { 187 jobject kHiDPIAwareKey = (*env)->NewObject(env, jIntegerClass, jIntegerInitMethod, com_sun_glass_ui_View_Capability_kHiDPIAwareKeyValue); 188 GLASS_CHECK_EXCEPTION(env); 189 jobject kHiDPIAwareValue = (*env)->CallObjectMethod(env, jproperties, jMapGetMethod, kHiDPIAwareKey); 190 GLASS_CHECK_EXCEPTION(env); 191 if (kHiDPIAwareValue != NULL) 192 { 193 self->isHiDPIAware = (*env)->CallBooleanMethod(env, kHiDPIAwareValue, jBooleanValueMethod) ? YES : NO; 194 GLASS_CHECK_EXCEPTION(env); 195 } 196 } 197 198 GlassLayer3D *layer = [[GlassLayer3D alloc] initWithSharedContext:sharedCGL andClientContext:clientCGL withHiDPIAware:self->isHiDPIAware withIsSwPipe:isSwPipe]; 199 200 // https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/nsview_Class/Reference/NSView.html#//apple_ref/occ/instm/NSView/setWantsLayer: 201 // the order of the following 2 calls is important: here we indicate we want a layer-hosting view 202 { 203 [self setLayer:layer]; 204 [self setWantsLayer:YES]; 205 } 206 } 207 208 - (id)initWithFrame:(NSRect)frame withJview:(jobject)jView withJproperties:(jobject)jproperties 209 { 210 LOG("GlassView3D initWithFrame:withJview:withJproperties"); 211 212 NSOpenGLPixelFormatAttribute pixelFormatAttributes[] = 213 { 214 NSOpenGLPFAAllowOfflineRenderers, // Lets OpenGL know this context is offline renderer aware 215 (NSOpenGLPixelFormatAttribute)0 216 }; 217 NSOpenGLPixelFormat *pFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttributes] autorelease]; 218 if (!pFormat) 219 { 220 pFormat = [NSOpenGLView defaultPixelFormat]; 221 LOG("GlassView3D initWithFrame: initWithAttributes failed! Set pixel format to default pixel format"); 222 } 223 self = [super initWithFrame:frame pixelFormat:pFormat]; 224 if (self != nil) 225 { 226 [self _initialize3dWithJproperties:jproperties]; 227 228 self->_delegate = [[GlassViewDelegate alloc] initWithView:self withJview:jView]; 229 self->_drawCounter = 0; 230 self->_texture = 0; 231 232 self->_trackingArea = [[NSTrackingArea alloc] initWithRect:frame 233 options:(NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect) 234 owner:self userInfo:nil]; 235 [self addTrackingArea: self->_trackingArea]; 236 self->nsAttrBuffer = [[NSAttributedString alloc] initWithString:@""]; 237 self->imEnabled = NO; 238 self->shouldProcessKeyEvent = YES; 239 } 240 return self; 241 } 242 243 - (void)dealloc 244 { 245 if (self->_texture != 0) 246 { 247 GlassLayer3D *layer = (GlassLayer3D*)[self layer]; 248 [[layer getPainterOffscreen] bindForWidth:(GLuint)[self bounds].size.width andHeight:(GLuint)[self bounds].size.height]; 249 { 250 glDeleteTextures(1, &self->_texture); 251 } 252 [[layer getPainterOffscreen] unbind]; 253 } 254 255 [[self layer] release]; 256 [self->_delegate release]; 257 self->_delegate = nil; 258 259 [self removeTrackingArea: self->_trackingArea]; 260 [self->_trackingArea release]; 261 self->_trackingArea = nil; 262 263 [self->nsAttrBuffer release]; 264 self->nsAttrBuffer = nil; 265 266 [super dealloc]; 267 } 268 269 - (BOOL)becomeFirstResponder 270 { 271 return YES; 272 } 273 274 - (BOOL)acceptsFirstResponder 275 { 276 return YES; 277 } 278 279 - (BOOL)canBecomeKeyView 280 { 281 return YES; 282 } 283 284 - (BOOL)postsBoundsChangedNotifications 285 { 286 return NO; 287 } 288 289 - (BOOL)postsFrameChangedNotifications 290 { 291 return NO; 292 } 293 294 - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent 295 { 296 return YES; 297 } 298 299 - (BOOL)isFlipped 300 { 301 return YES; 302 } 303 304 - (BOOL)isOpaque 305 { 306 return NO; 307 } 308 309 - (BOOL)mouseDownCanMoveWindow 310 { 311 return NO; 312 } 313 314 // also called when closing window, when [self window] == nil 315 - (void)viewDidMoveToWindow 316 { 317 if ([self window] != nil) 318 { 319 GlassLayer3D *layer = (GlassLayer3D*)[self layer]; 320 [[layer getPainterOffscreen] setBackgroundColor:[[[self window] backgroundColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]]; 321 } 322 323 [self->_delegate viewDidMoveToWindow]; 324 } 325 326 - (void)setFrameOrigin:(NSPoint)newOrigin 327 { 328 [super setFrameOrigin:newOrigin]; 329 [self->_delegate setFrameOrigin:newOrigin]; 330 } 331 332 - (void)setFrameSize:(NSSize)newSize 333 { 334 [super setFrameSize:newSize]; 335 [self->_delegate setFrameSize:newSize]; 336 } 337 338 - (void)setFrame:(NSRect)frameRect 339 { 340 [super setFrame:frameRect]; 341 [self->_delegate setFrame:frameRect]; 342 } 343 344 - (void)updateTrackingAreas 345 { 346 [super updateTrackingAreas]; 347 [self->_delegate updateTrackingAreas]; 348 } 349 350 - (void)mouseEntered:(NSEvent *)theEvent 351 { 352 MOUSELOG("mouseEntered"); 353 [self->_delegate sendJavaMouseEvent:theEvent]; 354 } 355 356 - (void)mouseMoved:(NSEvent *)theEvent 357 { 358 MOUSELOG("mouseMoved"); 359 [self->_delegate sendJavaMouseEvent:theEvent]; 360 } 361 362 - (void)mouseExited:(NSEvent *)theEvent 363 { 364 MOUSELOG("mouseExited"); 365 [self->_delegate sendJavaMouseEvent:theEvent]; 366 } 367 368 - (void)mouseDown:(NSEvent *)theEvent 369 { 370 MOUSELOG("mouseDown"); 371 // First check if system Input Method Engine needs to handle this event 372 NSInputManager *inputManager = [NSInputManager currentInputManager]; 373 if ([inputManager wantsToHandleMouseEvents]) { 374 if ([inputManager handleMouseEvent:theEvent]) { 375 return; 376 } 377 } 378 [self->_delegate sendJavaMouseEvent:theEvent]; 379 } 380 381 - (void)mouseDragged:(NSEvent *)theEvent 382 { 383 MOUSELOG("mouseDragged"); 384 [self->_delegate sendJavaMouseEvent:theEvent]; 385 } 386 387 - (void)mouseUp:(NSEvent *)theEvent 388 { 389 MOUSELOG("mouseUp"); 390 [self->_delegate sendJavaMouseEvent:theEvent]; 391 } 392 393 - (void)rightMouseDown:(NSEvent *)theEvent 394 { 395 MOUSELOG("rightMouseDown"); 396 [self->_delegate sendJavaMouseEvent:theEvent]; 397 // NOTE: menuForEvent: is invoked differently for right-click 398 // and Ctrl+Click actions. So instead we always synthesize 399 // the menu event in Glass. See sendJavaMouseEvent for details. 400 } 401 402 - (void)rightMouseDragged:(NSEvent *)theEvent 403 { 404 MOUSELOG("rightMouseDragged"); 405 [self->_delegate sendJavaMouseEvent:theEvent]; 406 } 407 408 - (void)rightMouseUp:(NSEvent *)theEvent 409 { 410 MOUSELOG("rightMouseUp"); 411 [self->_delegate sendJavaMouseEvent:theEvent]; 412 } 413 414 - (void)otherMouseDown:(NSEvent *)theEvent 415 { 416 MOUSELOG("otherMouseDown"); 417 [self->_delegate sendJavaMouseEvent:theEvent]; 418 } 419 420 - (void)otherMouseDragged:(NSEvent *)theEvent 421 { 422 MOUSELOG("otherMouseDragged"); 423 [self->_delegate sendJavaMouseEvent:theEvent]; 424 } 425 426 - (void)otherMouseUp:(NSEvent *)theEvent 427 { 428 MOUSELOG("otherMouseUp"); 429 [self->_delegate sendJavaMouseEvent:theEvent]; 430 } 431 432 - (void)rotateWithEvent:(NSEvent *)theEvent 433 { 434 [self->_delegate sendJavaGestureEvent:theEvent type:com_sun_glass_ui_mac_MacGestureSupport_GESTURE_ROTATE]; 435 } 436 437 - (void)swipeWithEvent:(NSEvent *)theEvent 438 { 439 [self->_delegate sendJavaGestureEvent:theEvent type:com_sun_glass_ui_mac_MacGestureSupport_GESTURE_SWIPE]; 440 } 441 442 - (void)magnifyWithEvent:(NSEvent *)theEvent 443 { 444 [self->_delegate sendJavaGestureEvent:theEvent type:com_sun_glass_ui_mac_MacGestureSupport_GESTURE_MAGNIFY]; 445 } 446 447 - (void)endGestureWithEvent:(NSEvent *)theEvent 448 { 449 [self->_delegate sendJavaGestureEndEvent:theEvent]; 450 } 451 452 - (void)beginGestureWithEvent:(NSEvent *)theEvent 453 { 454 [self->_delegate sendJavaGestureBeginEvent:theEvent]; 455 } 456 457 - (void)scrollWheel:(NSEvent *)theEvent 458 { 459 MOUSELOG("scrollWheel"); 460 [self->_delegate sendJavaMouseEvent:theEvent]; 461 } 462 463 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent 464 { 465 KEYLOG("performKeyEquivalent"); 466 [GlassApplication registerKeyEvent:theEvent]; 467 468 // Crash if the FS window is released while performing a key equivalent 469 // Local copy of the id keeps the retain/release calls balanced. 470 id fsWindow = [self->_delegate->fullscreenWindow retain]; 471 472 // RT-37093, RT-37399 Command-EQUALS and Command-DOT needs special casing on Mac 473 // as it is passed through as two calls to performKeyEquivalent, which in turn 474 // create extra KeyEvents. 475 // 476 NSString *chars = [theEvent charactersIgnoringModifiers]; 477 if ([theEvent type] == NSKeyDown && [chars length] > 0) 478 { 479 unichar uch = [chars characterAtIndex:0]; 480 if ([theEvent modifierFlags] & NSCommandKeyMask && 481 (uch == com_sun_glass_events_KeyEvent_VK_PERIOD || 482 uch == com_sun_glass_events_KeyEvent_VK_EQUALS)) 483 { 484 GET_MAIN_JENV; 485 486 jcharArray jKeyChars = GetJavaKeyChars(env, theEvent); 487 jint jModifiers = GetJavaModifiers(theEvent); 488 489 (*env)->CallVoidMethod(env, self->_delegate->jView, jViewNotifyKey, 490 com_sun_glass_events_KeyEvent_PRESS, 491 uch, jKeyChars, jModifiers); 492 (*env)->CallVoidMethod(env, self->_delegate->jView, jViewNotifyKey, 493 com_sun_glass_events_KeyEvent_TYPED, 494 uch, jKeyChars, jModifiers); 495 (*env)->CallVoidMethod(env, self->_delegate->jView, jViewNotifyKey, 496 com_sun_glass_events_KeyEvent_RELEASE, 497 uch, jKeyChars, jModifiers); 498 (*env)->DeleteLocalRef(env, jKeyChars); 499 500 GLASS_CHECK_EXCEPTION(env); 501 [fsWindow release]; 502 return YES; 503 } 504 } 505 [self->_delegate sendJavaKeyEvent:theEvent isDown:YES]; 506 [fsWindow release]; 507 return NO; // return NO to allow system-default processing of Cmd+Q, etc. 508 } 509 510 - (void)keyDown:(NSEvent *)theEvent 511 { 512 KEYLOG("keyDown"); 513 [GlassApplication registerKeyEvent:theEvent]; 514 515 if (![[self inputContext] handleEvent:theEvent] || shouldProcessKeyEvent) { 516 [self->_delegate sendJavaKeyEvent:theEvent isDown:YES]; 517 } 518 shouldProcessKeyEvent = YES; 519 } 520 521 - (void)keyUp:(NSEvent *)theEvent 522 { 523 KEYLOG("keyUp"); 524 [self->_delegate sendJavaKeyEvent:theEvent isDown:NO]; 525 } 526 527 - (void)flagsChanged:(NSEvent *)theEvent 528 { 529 KEYLOG("flagsChanged"); 530 [self->_delegate sendJavaModifierKeyEvent:theEvent]; 531 } 532 533 - (BOOL)wantsPeriodicDraggingUpdates 534 { 535 // we only want want updated drag operations when the mouse position changes 536 return NO; 537 } 538 539 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender 540 { 541 DNDLOG("prepareForDragOperation"); 542 return YES; 543 } 544 545 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender 546 { 547 DNDLOG("performDragOperation"); 548 [self->_delegate sendJavaDndEvent:sender type:com_sun_glass_events_DndEvent_PERFORM]; 549 550 return YES; 551 } 552 553 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender 554 { 555 DNDLOG("concludeDragOperation"); 556 } 557 558 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender 559 { 560 DNDLOG("draggingEntered"); 561 return [self->_delegate sendJavaDndEvent:sender type:com_sun_glass_events_DndEvent_ENTER]; 562 } 563 564 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender 565 { 566 DNDLOG("draggingUpdated"); 567 return [self->_delegate sendJavaDndEvent:sender type:com_sun_glass_events_DndEvent_UPDATE]; 568 } 569 570 - (void)draggingEnded:(id <NSDraggingInfo>)sender 571 { 572 DNDLOG("draggingEnded"); 573 [self->_delegate draggingEnded]; 574 } 575 576 - (void)draggingExited:(id <NSDraggingInfo>)sender 577 { 578 DNDLOG("draggingExited"); 579 [self->_delegate sendJavaDndEvent:sender type:com_sun_glass_events_DndEvent_EXIT]; 580 } 581 582 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal 583 { 584 // Deprecated for 10.7 585 // use NSDraggingSession - (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context 586 DNDLOG("draggingSourceOperationMaskForLocal"); 587 return [self->_delegate draggingSourceOperationMaskForLocal:isLocal]; 588 } 589 590 #pragma mark --- Callbacks 591 592 - (void)enterFullscreenWithAnimate:(BOOL)animate withKeepRatio:(BOOL)keepRatio withHideCursor:(BOOL)hideCursor 593 { 594 [self->_delegate enterFullscreenWithAnimate:animate withKeepRatio:keepRatio withHideCursor:hideCursor]; 595 } 596 597 - (void)exitFullscreenWithAnimate:(BOOL)animate 598 { 599 [self->_delegate exitFullscreenWithAnimate:animate]; 600 } 601 602 - (void)begin 603 { 604 LOG("begin"); 605 assert(self->_drawCounter >= 0); 606 607 if (self->_drawCounter == 0) 608 { 609 GlassLayer3D *layer = (GlassLayer3D*)[self layer]; 610 NSRect bounds = (self->isHiDPIAware && [self respondsToSelector:@selector(convertRectToBacking:)]) ? 611 [self convertRectToBacking:[self bounds]] : [self bounds]; 612 [[layer getPainterOffscreen] bindForWidth:(GLuint)bounds.size.width andHeight:(GLuint)bounds.size.height]; 613 } 614 self->_drawCounter++; 615 } 616 617 - (void)end 618 { 619 assert(self->_drawCounter > 0); 620 621 self->_drawCounter--; 622 if (self->_drawCounter == 0) 623 { 624 GlassLayer3D *layer = (GlassLayer3D*)[self layer]; 625 [[layer getPainterOffscreen] unbind]; 626 [layer flush]; 627 } 628 LOG("end"); 629 } 630 631 - (void)drawRect:(NSRect)dirtyRect 632 { 633 [self->_delegate drawRect:dirtyRect]; 634 } 635 636 - (void)pushPixels:(void*)pixels withWidth:(GLuint)width withHeight:(GLuint)height withScale:(GLfloat)scale withEnv:(JNIEnv *)env 637 { 638 assert(self->_drawCounter > 0); 639 640 if (self->_texture == 0) 641 { 642 glGenTextures(1, &self->_texture); 643 } 644 645 BOOL uploaded = NO; 646 if ((self->_textureWidth != width) || (self->_textureHeight != height)) 647 { 648 uploaded = YES; 649 650 self->_textureWidth = width; 651 self->_textureHeight = height; 652 653 // GL_EXT_texture_rectangle is defined in OS X 10.6 GL headers, so we can depend on GL_TEXTURE_RECTANGLE_EXT being available 654 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, self->_texture); 655 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 656 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 657 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP); 658 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP); 659 glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA8, (GLsizei)self->_textureWidth, (GLsizei)self->_textureHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels); 660 } 661 662 glEnable(GL_TEXTURE_RECTANGLE_EXT); 663 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, self->_texture); 664 { 665 if (uploaded == NO) 666 { 667 glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, (GLsizei)self->_textureWidth, (GLsizei)self->_textureHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels); 668 } 669 670 GLfloat w = self->_textureWidth; 671 GLfloat h = self->_textureHeight; 672 673 NSSize size = [self bounds].size; 674 size.width *= scale; 675 size.height *= scale; 676 if ((size.width != w) || (size.height != h)) 677 { 678 // This could happen on live resize, clear the FBO to avoid rendering garbage 679 glClear(GL_COLOR_BUFFER_BIT); 680 } 681 682 glMatrixMode(GL_PROJECTION); 683 glPushMatrix(); 684 glLoadIdentity(); 685 glOrtho(0.0f, size.width, size.height, 0.0f, -1.0f, 1.0f); 686 { 687 glMatrixMode(GL_MODELVIEW); 688 glPushMatrix(); 689 glLoadIdentity(); 690 { 691 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // copy 692 693 glBegin(GL_QUADS); 694 { 695 glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f); 696 glTexCoord2f( w, 0.0f); glVertex2f( w, 0.0f); 697 glTexCoord2f( w, h); glVertex2f( w, h); 698 glTexCoord2f(0.0f, h); glVertex2f(0.0f, h); 699 } 700 glEnd(); 701 } 702 glMatrixMode(GL_MODELVIEW); 703 glPopMatrix(); 704 } 705 glMatrixMode(GL_PROJECTION); 706 glPopMatrix(); 707 } 708 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0); 709 glDisable(GL_TEXTURE_RECTANGLE_EXT); 710 711 glFinish(); 712 713 // The layer will be notified about redraw in _end() 714 } 715 716 - (GlassViewDelegate*)delegate 717 { 718 return self->_delegate; 719 } 720 721 - (void)setInputMethodEnabled:(BOOL)enabled 722 { 723 IMLOG("setInputMethodEnabled called with arg is %s", (enabled ? "YES" : "NO") ); 724 [self unmarkText]; 725 self->imEnabled = enabled; 726 } 727 728 /* 729 NSTextInputClient protocol implementation follows here. 730 */ 731 732 - (void)doCommandBySelector:(SEL)aSelector 733 { 734 IMLOG("doCommandBySelector called "); 735 // In case the IM was stopped with a mouse and the next typed key 736 // is a special command key (backspace, tab, etc.) 737 self->shouldProcessKeyEvent = YES; 738 } 739 740 - (void) insertText:(id)aString replacementRange:(NSRange)replacementRange 741 { 742 IMLOG("insertText called with string: %s", [aString UTF8String]); 743 if ([self->nsAttrBuffer length] > 0 || [aString length] > 1) { 744 [self->_delegate notifyInputMethod:aString attr:4 length:(int)[aString length] cursor:(int)[aString length] selectedRange: NSMakeRange(NSNotFound, 0)]; 745 self->shouldProcessKeyEvent = NO; 746 } else { 747 self->shouldProcessKeyEvent = YES; 748 } 749 self->nsAttrBuffer = [self->nsAttrBuffer initWithString:@""]; 750 } 751 752 - (void) setMarkedText:(id)aString selectedRange:(NSRange)selectionRange replacementRange:(NSRange)replacementRange 753 { 754 if (!self->imEnabled) { 755 self->shouldProcessKeyEvent = YES; 756 return; 757 } 758 BOOL isAttributedString = [aString isKindOfClass:[NSAttributedString class]]; 759 NSAttributedString *attrString = (isAttributedString ? (NSAttributedString *)aString : nil); 760 NSString *incomingString = (isAttributedString ? [aString string] : aString); 761 IMLOG("setMarkedText called, attempt to set string to %s", [incomingString UTF8String]); 762 [self->_delegate notifyInputMethod:incomingString attr:1 length:0 cursor:(int)[incomingString length] selectedRange:selectionRange ]; 763 self->nsAttrBuffer = (attrString == nil ? [self->nsAttrBuffer initWithString:incomingString] 764 : [self->nsAttrBuffer initWithAttributedString: attrString]); 765 self->shouldProcessKeyEvent = NO; 766 } 767 768 - (void) unmarkText 769 { 770 IMLOG("unmarkText called\n"); 771 if (self->nsAttrBuffer != nil && self->nsAttrBuffer.length != 0) { 772 self->nsAttrBuffer = [self->nsAttrBuffer initWithString:@""]; 773 [self->_delegate notifyInputMethod:@"" attr:4 length:0 cursor:0 selectedRange: NSMakeRange(NSNotFound, 0)]; 774 } 775 self->shouldProcessKeyEvent = YES; 776 } 777 778 - (BOOL) hasMarkedText 779 { 780 BOOL hmText = (self->imEnabled ? (self->nsAttrBuffer.length == 0 ? FALSE : TRUE) : FALSE); 781 IMLOG("hasMarkedText called return %s ", (hmText ? "true" : "false")); 782 return hmText; 783 } 784 785 - (NSRange) markedRange 786 { 787 IMLOG("markedRange called, return range in attributed string"); 788 if (self->imEnabled) { 789 return NSMakeRange(0, self->nsAttrBuffer.length); 790 } else { 791 return NSMakeRange(NSNotFound, 0); 792 } 793 } 794 795 - (NSAttributedString *) attributedSubstringForProposedRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange 796 { 797 IMLOG("attributedSubstringFromRange called: location=%lu, length=%lu", 798 (unsigned long)theRange.location, (unsigned long)theRange.length); 799 if (self->imEnabled) { 800 return self->nsAttrBuffer; 801 } else { 802 return NULL; 803 } 804 } 805 806 - (NSRange) selectedRange 807 { 808 IMLOG("selectedRange called"); 809 if (self->imEnabled) { 810 return NSMakeRange(0, [[self->nsAttrBuffer string] length]); 811 } else { 812 return NSMakeRange(NSNotFound, 0); 813 } 814 } 815 816 - (NSRect) firstRectForCharacterRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange 817 { 818 IMLOG("firstRectForCharacterRange called %lu %lu", 819 (unsigned long)theRange.location, (unsigned long)theRange.length); 820 NSRect result = [self->_delegate getInputMethodCandidatePosRequest:0]; 821 NSRect screenFrame = [[NSScreen mainScreen] frame]; 822 result.origin.y = screenFrame.size.height - result.origin.y; 823 return result; 824 } 825 826 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint 827 { 828 IMLOG("characterIndexForPoint (%f, %f) called", thePoint.x, thePoint.y); 829 return 0; 830 } 831 832 - (NSArray*) validAttributesForMarkedText 833 { 834 return [NSArray array]; 835 } 836 837 - (void)notifyScaleFactorChanged:(CGFloat)scale 838 { 839 GlassLayer3D *layer = (GlassLayer3D*)[self layer]; 840 [layer notifyScaleFactorChanged:scale]; 841 } 842 843 /* Accessibility support */ 844 845 - (NSArray *)accessibilityAttributeNames 846 { 847 NSArray *names = NULL; 848 GlassAccessible *accessible = [self->_delegate getAccessible]; 849 if (accessible) { 850 names = [accessible accessibilityAttributeNames]; 851 } 852 if (names == NULL) { 853 names = [super accessibilityAttributeNames]; 854 } 855 return names; 856 } 857 858 - (id)accessibilityAttributeValue:(NSString *)attribute 859 { 860 id value = NULL; 861 GlassAccessible *accessible = [self->_delegate getAccessible]; 862 if (accessible) { 863 value = [accessible accessibilityAttributeValue: attribute]; 864 } 865 if (value == NULL) { 866 value = [super accessibilityAttributeValue: attribute]; 867 } 868 return value; 869 } 870 871 - (BOOL)accessibilityIsIgnored 872 { 873 BOOL value = TRUE; /* This default value in the OS */ 874 GlassAccessible *accessible = [self->_delegate getAccessible]; 875 if (accessible) { 876 value = [accessible accessibilityIsIgnored]; 877 } 878 return value; 879 } 880 881 - (id)accessibilityHitTest:(NSPoint)point 882 { 883 id value = NULL; 884 GlassAccessible *accessible = [self->_delegate getAccessible]; 885 if (accessible) { 886 value = [accessible accessibilityHitTest: point]; 887 } 888 if (value == NULL) { 889 value = [super accessibilityHitTest: point]; 890 } 891 return value; 892 } 893 894 - (id)accessibilityFocusedUIElement 895 { 896 id value = NULL; 897 GlassAccessible *accessible = [self->_delegate getAccessible]; 898 if (accessible) { 899 value = [accessible accessibilityFocusedUIElement]; 900 } 901 if (value == NULL) { 902 value = [super accessibilityFocusedUIElement]; 903 } 904 return value; 905 } 906 907 908 @end