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