1 /* 2 * Copyright (c) 2011, 2014, 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 "GlassMacros.h" 33 #import "GlassView3D.h" 34 #import "GlassLayer3D.h" 35 #import "GlassApplication.h" 36 37 //#define VERBOSE 38 #ifndef VERBOSE 39 #define LOG(MSG, ...) 40 #else 41 #define LOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__); 42 #endif 43 44 //#define MOUSEVERBOSE 45 #ifndef MOUSEVERBOSE 46 #define MOUSELOG(MSG, ...) 47 #else 48 #define MOUSELOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__); 49 #endif 50 51 //#define KEYVERBOSE 52 #ifndef KEYVERBOSE 53 #define KEYLOG(MSG, ...) 54 #else 55 #define KEYLOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__); 56 #endif 57 58 //#define DNDVERBOSE 59 #ifndef DNDVERBOSE 60 #define DNDLOG(MSG, ...) 61 #else 62 #define DNDLOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__); 63 #endif 64 65 //#define IMVERBOSE 66 #ifndef IMVERBOSE 67 #define IMLOG(MSG, ...) 68 #else 69 #define IMLOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__); 70 #endif 71 72 #define SHARE_GL_CONTEXT 73 //#define DEBUG_COLORS 74 75 // http://developer.apple.com/library/mac/#technotes/tn2085/_index.html 76 //#define ENABLE_MULTITHREADED_GL 77 78 @implementation GlassView3D 79 80 - (CGLPixelFormatObj)_createPixelFormatWithDepth:(CGLPixelFormatAttribute)depth 81 { 82 CGLPixelFormatObj pix = NULL; 83 { 84 const CGLPixelFormatAttribute attributes[] = 85 { 86 kCGLPFAAccelerated, 87 kCGLPFAColorSize, 32, 88 kCGLPFAAlphaSize, 8, 89 kCGLPFADepthSize, depth, 90 (CGLPixelFormatAttribute)0 91 }; 92 GLint npix = 0; 93 CGLError err = CGLChoosePixelFormat(attributes, &pix, &npix); 94 if (err != kCGLNoError) 95 { 96 NSLog(@"CGLChoosePixelFormat error: %d", err); 97 } 98 } 99 return pix; 100 } 101 102 - (CGLContextObj)_createContextWithShared:(CGLContextObj)share withFormat:(CGLPixelFormatObj)format 103 { 104 CGLContextObj ctx = NULL; 105 { 106 CGLError err = CGLCreateContext(format, share, &ctx); 107 if (err != kCGLNoError) 108 { 109 NSLog(@"CGLCreateContext error: %d", err); 110 } 111 } 112 return ctx; 113 } 114 115 - (void)_initialize3dWithJproperties:(jobject)jproperties 116 { 117 GET_MAIN_JENV; 118 119 int depthBits = 0; 120 if (jproperties != NULL) 121 { 122 jobject k3dDepthKey = (*env)->NewObject(env, jIntegerClass, jIntegerInitMethod, com_sun_glass_ui_View_Capability_k3dDepthKeyValue); 123 GLASS_CHECK_EXCEPTION(env); 124 jobject k3dDepthKeyValue = (*env)->CallObjectMethod(env, jproperties, jMapGetMethod, k3dDepthKey); 125 GLASS_CHECK_EXCEPTION(env); 126 if (k3dDepthKeyValue != NULL) 127 { 128 depthBits = (*env)->CallIntMethod(env, k3dDepthKeyValue, jIntegerValueMethod); 129 GLASS_CHECK_EXCEPTION(env); 130 } 131 } 132 133 CGLContextObj sharedCGL = NULL; 134 if (jproperties != NULL) 135 { 136 jobject sharedContextPtrKey = (*env)->NewStringUTF(env, "shareContextPtr"); 137 jobject sharedContextPtrValue = (*env)->CallObjectMethod(env, jproperties, jMapGetMethod, sharedContextPtrKey); 138 GLASS_CHECK_EXCEPTION(env); 139 if (sharedContextPtrValue != NULL) 140 { 141 jlong jsharedContextPtr = (*env)->CallLongMethod(env, sharedContextPtrValue, jLongValueMethod); 142 GLASS_CHECK_EXCEPTION(env); 143 if (jsharedContextPtr != 0) 144 { 145 NSOpenGLContext *sharedContextNS = (NSOpenGLContext*)jlong_to_ptr(jsharedContextPtr); 146 sharedCGL = [sharedContextNS CGLContextObj]; 147 } 148 } 149 } 150 151 CGLContextObj clientCGL = NULL; 152 if (jproperties != NULL) 153 { 154 jobject contextPtrKey = (*env)->NewStringUTF(env, "contextPtr"); 155 jobject contextPtrValue = (*env)->CallObjectMethod(env, jproperties, jMapGetMethod, contextPtrKey); 156 GLASS_CHECK_EXCEPTION(env); 157 if (contextPtrValue != NULL) 158 { 159 jlong jcontextPtr = (*env)->CallLongMethod(env, contextPtrValue, jLongValueMethod); 160 GLASS_CHECK_EXCEPTION(env); 161 if (jcontextPtr != 0) 162 { 163 NSOpenGLContext *clientContextNS = (NSOpenGLContext*)jlong_to_ptr(jcontextPtr); 164 clientCGL = [clientContextNS CGLContextObj]; 165 } 166 } 167 } 168 if (clientCGL == NULL) 169 { 170 CGLPixelFormatObj clientPixelFormat = [self _createPixelFormatWithDepth:(CGLPixelFormatAttribute)depthBits]; 171 clientCGL = [self _createContextWithShared:sharedCGL withFormat:clientPixelFormat]; 172 } 173 if (sharedCGL == NULL) 174 { 175 // this can happen in Rain or clients other than Prism (ie. device details do not have the shared context set) 176 sharedCGL = clientCGL; 177 } 178 179 self->isHiDPIAware = NO; 180 if (jproperties != NULL) 181 { 182 jobject kHiDPIAwareKey = (*env)->NewObject(env, jIntegerClass, jIntegerInitMethod, com_sun_glass_ui_View_Capability_kHiDPIAwareKeyValue); 183 GLASS_CHECK_EXCEPTION(env); 184 jobject kHiDPIAwareValue = (*env)->CallObjectMethod(env, jproperties, jMapGetMethod, kHiDPIAwareKey); 185 GLASS_CHECK_EXCEPTION(env); 186 if (kHiDPIAwareValue != NULL) 187 { 188 self->isHiDPIAware = (*env)->CallBooleanMethod(env, kHiDPIAwareValue, jBooleanValueMethod) ? YES : NO; 189 GLASS_CHECK_EXCEPTION(env); 190 } 191 } 192 193 GlassLayer3D *layer = [[GlassLayer3D alloc] initWithSharedContext:sharedCGL andClientContext:clientCGL withHiDPIAware:self->isHiDPIAware]; 194 195 // https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/nsview_Class/Reference/NSView.html#//apple_ref/occ/instm/NSView/setWantsLayer: 196 // the order of the following 2 calls is important: here we indicate we want a layer-hosting view 197 { 198 [self setLayer:layer]; 199 [self setWantsLayer:YES]; 200 } 201 } 202 203 - (id)initWithFrame:(NSRect)frame withJview:(jobject)jView withJproperties:(jobject)jproperties 204 { 205 LOG("GlassView3D initWithFrame:withJview:withJproperties"); 206 self = [super initWithFrame:frame pixelFormat:[NSOpenGLView defaultPixelFormat]]; 207 if (self != nil) 208 { 209 [self _initialize3dWithJproperties:jproperties]; 210 211 self->_delegate = [[GlassViewDelegate alloc] initWithView:self withJview:jView]; 212 self->_drawCounter = 0; 213 self->_texture = 0; 214 215 self->_trackingArea = [[NSTrackingArea alloc] initWithRect:frame 216 options:(NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect) 217 owner:self userInfo:nil]; 218 [self addTrackingArea: self->_trackingArea]; 219 self->nsAttrBuffer = [[NSAttributedString alloc] initWithString:@""]; 220 self->imEnabled = NO; 221 self->shouldProcessKeyEvent = YES; 222 } 223 return self; 224 } 225 226 - (void)dealloc 227 { 228 if (self->_texture != 0) 229 { 230 GlassLayer3D *layer = (GlassLayer3D*)[self layer]; 231 [[layer getPainterOffscreen] bindForWidth:(GLuint)[self bounds].size.width andHeight:(GLuint)[self bounds].size.height]; 232 { 233 glDeleteTextures(1, &self->_texture); 234 } 235 [[layer getPainterOffscreen] unbind]; 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 [self->_delegate sendJavaKeyEvent:theEvent isDown:YES]; 455 [fsWindow release]; 456 return NO; // return NO to allow system-default processing of Cmd+Q, etc. 457 } 458 459 - (void)keyDown:(NSEvent *)theEvent 460 { 461 KEYLOG("keyDown"); 462 [GlassApplication registerKeyEvent:theEvent]; 463 464 if (![[self inputContext] handleEvent:theEvent] || shouldProcessKeyEvent) { 465 [self->_delegate sendJavaKeyEvent:theEvent isDown:YES]; 466 } 467 shouldProcessKeyEvent = YES; 468 } 469 470 - (void)keyUp:(NSEvent *)theEvent 471 { 472 KEYLOG("keyUp"); 473 [self->_delegate sendJavaKeyEvent:theEvent isDown:NO]; 474 } 475 476 - (void)flagsChanged:(NSEvent *)theEvent 477 { 478 KEYLOG("flagsChanged"); 479 [self->_delegate sendJavaModifierKeyEvent:theEvent]; 480 } 481 482 - (BOOL)wantsPeriodicDraggingUpdates 483 { 484 // we only want want updated drag operations when the mouse position changes 485 return NO; 486 } 487 488 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender 489 { 490 DNDLOG("prepareForDragOperation"); 491 return YES; 492 } 493 494 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender 495 { 496 DNDLOG("performDragOperation"); 497 [self->_delegate sendJavaDndEvent:sender type:com_sun_glass_events_DndEvent_PERFORM]; 498 499 return YES; 500 } 501 502 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender 503 { 504 DNDLOG("concludeDragOperation"); 505 } 506 507 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender 508 { 509 DNDLOG("draggingEntered"); 510 return [self->_delegate sendJavaDndEvent:sender type:com_sun_glass_events_DndEvent_ENTER]; 511 } 512 513 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender 514 { 515 DNDLOG("draggingUpdated"); 516 return [self->_delegate sendJavaDndEvent:sender type:com_sun_glass_events_DndEvent_UPDATE]; 517 } 518 519 - (void)draggingEnded:(id <NSDraggingInfo>)sender 520 { 521 DNDLOG("draggingEnded"); 522 [self->_delegate draggingEnded]; 523 } 524 525 - (void)draggingExited:(id <NSDraggingInfo>)sender 526 { 527 DNDLOG("draggingExited"); 528 [self->_delegate sendJavaDndEvent:sender type:com_sun_glass_events_DndEvent_EXIT]; 529 } 530 531 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal 532 { 533 // Deprecated for 10.7 534 // use NSDraggingSession - (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context 535 DNDLOG("draggingSourceOperationMaskForLocal"); 536 return [self->_delegate draggingSourceOperationMaskForLocal:isLocal]; 537 } 538 539 #pragma mark --- Callbacks 540 541 - (void)enterFullscreenWithAnimate:(BOOL)animate withKeepRatio:(BOOL)keepRatio withHideCursor:(BOOL)hideCursor 542 { 543 [self->_delegate enterFullscreenWithAnimate:animate withKeepRatio:keepRatio withHideCursor:hideCursor]; 544 } 545 546 - (void)exitFullscreenWithAnimate:(BOOL)animate 547 { 548 [self->_delegate exitFullscreenWithAnimate:animate]; 549 } 550 551 - (void)begin 552 { 553 LOG("begin"); 554 assert(self->_drawCounter >= 0); 555 556 if (self->_drawCounter == 0) 557 { 558 GlassLayer3D *layer = (GlassLayer3D*)[self layer]; 559 NSRect bounds = (self->isHiDPIAware && [self respondsToSelector:@selector(convertRectToBacking:)]) ? 560 [self convertRectToBacking:[self bounds]] : [self bounds]; 561 [[layer getPainterOffscreen] bindForWidth:(GLuint)bounds.size.width andHeight:(GLuint)bounds.size.height]; 562 } 563 self->_drawCounter++; 564 } 565 566 - (void)end 567 { 568 assert(self->_drawCounter > 0); 569 570 self->_drawCounter--; 571 if (self->_drawCounter == 0) 572 { 573 GlassLayer3D *layer = (GlassLayer3D*)[self layer]; 574 [[layer getPainterOffscreen] unbind]; 575 [layer flush]; 576 } 577 LOG("end:%d", flush); 578 } 579 580 - (void)drawRect:(NSRect)dirtyRect 581 { 582 [self->_delegate drawRect:dirtyRect]; 583 } 584 585 - (void)pushPixels:(void*)pixels withWidth:(GLuint)width withHeight:(GLuint)height withEnv:(JNIEnv *)env 586 { 587 assert(self->_drawCounter > 0); 588 589 if (self->_texture == 0) 590 { 591 glGenTextures(1, &self->_texture); 592 } 593 594 BOOL uploaded = NO; 595 if ((self->_textureWidth != width) || (self->_textureHeight != height)) 596 { 597 uploaded = YES; 598 599 self->_textureWidth = width; 600 self->_textureHeight = height; 601 602 // GL_EXT_texture_rectangle is defined in OS X 10.6 GL headers, so we can depend on GL_TEXTURE_RECTANGLE_EXT being available 603 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, self->_texture); 604 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 605 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 606 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP); 607 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP); 608 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); 609 } 610 611 glEnable(GL_TEXTURE_RECTANGLE_EXT); 612 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, self->_texture); 613 { 614 if (uploaded == NO) 615 { 616 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); 617 } 618 619 GLfloat w = self->_textureWidth; 620 GLfloat h = self->_textureHeight; 621 622 NSSize size = [self bounds].size; 623 if ((size.width != w) || (size.height != h)) 624 { 625 // This could happen on live resize, clear the FBO to avoid rendering garbage 626 glClear(GL_COLOR_BUFFER_BIT); 627 } 628 629 glMatrixMode(GL_PROJECTION); 630 glPushMatrix(); 631 glLoadIdentity(); 632 glOrtho(0.0f, size.width, size.height, 0.0f, -1.0f, 1.0f); 633 { 634 glMatrixMode(GL_MODELVIEW); 635 glPushMatrix(); 636 glLoadIdentity(); 637 { 638 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // copy 639 640 glBegin(GL_QUADS); 641 { 642 glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f); 643 glTexCoord2f( w, 0.0f); glVertex2f( w, 0.0f); 644 glTexCoord2f( w, h); glVertex2f( w, h); 645 glTexCoord2f(0.0f, h); glVertex2f(0.0f, h); 646 } 647 glEnd(); 648 } 649 glMatrixMode(GL_MODELVIEW); 650 glPopMatrix(); 651 } 652 glMatrixMode(GL_PROJECTION); 653 glPopMatrix(); 654 } 655 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0); 656 glDisable(GL_TEXTURE_RECTANGLE_EXT); 657 658 glFinish(); 659 660 // The layer will be notified about redraw in _end() 661 } 662 663 - (GlassViewDelegate*)delegate 664 { 665 return self->_delegate; 666 } 667 668 - (void)setInputMethodEnabled:(BOOL)enabled 669 { 670 IMLOG("setInputMethodEnabled called with arg is %s", (enabled ? "YES" : "NO") ); 671 [self unmarkText]; 672 self->imEnabled = enabled; 673 } 674 675 /* 676 NSTextInputClient protocol implementation follows here. 677 */ 678 679 - (void)doCommandBySelector:(SEL)aSelector 680 { 681 IMLOG("doCommandBySelector called "); 682 // In case the IM was stopped with a mouse and the next typed key 683 // is a special command key (backspace, tab, etc.) 684 self->shouldProcessKeyEvent = YES; 685 } 686 687 - (void) insertText:(id)aString replacementRange:(NSRange)replacementRange 688 { 689 IMLOG("insertText called with string: %s", [aString UTF8String]); 690 if ([self->nsAttrBuffer length] > 0 || [aString length] > 1) { 691 [self->_delegate notifyInputMethod:aString attr:4 length:(int)[aString length] cursor:(int)[aString length] selectedRange: NSMakeRange(NSNotFound, 0)]; 692 self->shouldProcessKeyEvent = NO; 693 } else { 694 self->shouldProcessKeyEvent = YES; 695 } 696 self->nsAttrBuffer = [self->nsAttrBuffer initWithString:@""]; 697 } 698 699 - (void) setMarkedText:(id)aString selectedRange:(NSRange)selectionRange replacementRange:(NSRange)replacementRange 700 { 701 if (!self->imEnabled) { 702 self->shouldProcessKeyEvent = YES; 703 return; 704 } 705 BOOL isAttributedString = [aString isKindOfClass:[NSAttributedString class]]; 706 NSAttributedString *attrString = (isAttributedString ? (NSAttributedString *)aString : nil); 707 NSString *incomingString = (isAttributedString ? [aString string] : aString); 708 IMLOG("setMarkedText called, attempt to set string to %s", [incomingString UTF8String]); 709 [self->_delegate notifyInputMethod:incomingString attr:1 length:0 cursor:(int)[incomingString length] selectedRange:selectionRange ]; 710 self->nsAttrBuffer = (attrString == nil ? [self->nsAttrBuffer initWithString:incomingString] 711 : [self->nsAttrBuffer initWithAttributedString: attrString]); 712 self->shouldProcessKeyEvent = NO; 713 } 714 715 - (void) unmarkText 716 { 717 IMLOG("unmarkText called\n"); 718 if (self->nsAttrBuffer != nil && self->nsAttrBuffer.length != 0) { 719 self->nsAttrBuffer = [self->nsAttrBuffer initWithString:@""]; 720 [self->_delegate notifyInputMethod:@"" attr:4 length:0 cursor:0 selectedRange: NSMakeRange(NSNotFound, 0)]; 721 } 722 self->shouldProcessKeyEvent = YES; 723 } 724 725 - (BOOL) hasMarkedText 726 { 727 BOOL hmText = (self->imEnabled ? (self->nsAttrBuffer.length == 0 ? FALSE : TRUE) : FALSE); 728 IMLOG("hasMarkedText called return %s ", (hmText ? "true" : "false")); 729 return hmText; 730 } 731 732 - (NSRange) markedRange 733 { 734 IMLOG("markedRange called, return range in attributed string"); 735 if (self->imEnabled) { 736 return NSMakeRange(0, self->nsAttrBuffer.length); 737 } else { 738 return NSMakeRange(NSNotFound, 0); 739 } 740 } 741 742 - (NSAttributedString *) attributedSubstringForProposedRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange 743 { 744 IMLOG("attributedSubstringFromRange called: location=%lu, length=%lu", 745 (unsigned long)theRange.location, (unsigned long)theRange.length); 746 if (self->imEnabled) { 747 return self->nsAttrBuffer; 748 } else { 749 return NULL; 750 } 751 } 752 753 - (NSRange) selectedRange 754 { 755 IMLOG("selectedRange called"); 756 if (self->imEnabled) { 757 return NSMakeRange(0, [[self->nsAttrBuffer string] length]); 758 } else { 759 return NSMakeRange(NSNotFound, 0); 760 } 761 } 762 763 - (NSRect) firstRectForCharacterRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange 764 { 765 IMLOG("firstRectForCharacterRange called %lu %lu", 766 (unsigned long)theRange.location, (unsigned long)theRange.length); 767 NSRect result = [self->_delegate getInputMethodCandidatePosRequest:0]; 768 NSRect screenFrame = [[NSScreen mainScreen] frame]; 769 result.origin.y = screenFrame.size.height - result.origin.y; 770 return result; 771 } 772 773 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint 774 { 775 IMLOG("characterIndexForPoint (%f, %f) called", thePoint.x, thePoint.y); 776 return 0; 777 } 778 779 - (NSArray*) validAttributesForMarkedText 780 { 781 return [NSArray array]; 782 } 783 784 - (void)notifyScaleFactorChanged:(CGFloat)scale 785 { 786 GlassLayer3D *layer = (GlassLayer3D*)[self layer]; 787 [layer notifyScaleFactorChanged:scale]; 788 } 789 790 /* Accessibility support */ 791 792 - (NSArray *)accessibilityAttributeNames 793 { 794 NSArray *names = NULL; 795 GlassAccessible *accessible = [self->_delegate getAccessible]; 796 if (accessible) { 797 names = [accessible accessibilityAttributeNames]; 798 } 799 if (names == NULL) { 800 names = [super accessibilityAttributeNames]; 801 } 802 return names; 803 } 804 805 - (id)accessibilityAttributeValue:(NSString *)attribute 806 { 807 id value = NULL; 808 GlassAccessible *accessible = [self->_delegate getAccessible]; 809 if (accessible) { 810 value = [accessible accessibilityAttributeValue: attribute]; 811 } 812 if (value == NULL) { 813 value = [super accessibilityAttributeValue: attribute]; 814 } 815 return value; 816 } 817 818 - (BOOL)accessibilityIsIgnored 819 { 820 BOOL value = TRUE; /* This default value in the OS */ 821 GlassAccessible *accessible = [self->_delegate getAccessible]; 822 if (accessible) { 823 value = [accessible accessibilityIsIgnored]; 824 } 825 return value; 826 } 827 828 - (id)accessibilityHitTest:(NSPoint)point 829 { 830 id value = NULL; 831 GlassAccessible *accessible = [self->_delegate getAccessible]; 832 if (accessible) { 833 value = [accessible accessibilityHitTest: point]; 834 } 835 if (value == NULL) { 836 value = [super accessibilityHitTest: point]; 837 } 838 return value; 839 } 840 841 - (id)accessibilityFocusedUIElement 842 { 843 id value = NULL; 844 GlassAccessible *accessible = [self->_delegate getAccessible]; 845 if (accessible) { 846 value = [accessible accessibilityFocusedUIElement]; 847 } 848 if (value == NULL) { 849 value = [super accessibilityFocusedUIElement]; 850 } 851 return value; 852 } 853 854 855 @end