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