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