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_mac_MacGestureSupport.h"
  31 
  32 #import "GlassMacros.h"
  33 #import "GlassView2D.h"
  34 
  35 //#define VERBOSE
  36 #ifndef VERBOSE
  37     #define LOG(MSG, ...)
  38 #else
  39     #define LOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__);
  40 #endif
  41 
  42 @implementation GlassView2D
  43 
  44 - (id)initWithFrame:(NSRect)frame withJview:(jobject)jView withJproperties:(jobject)jproperties
  45 {
  46     self = [super initWithFrame:frame];
  47     if (self != nil)
  48     {
  49         self->delegate = [[GlassViewDelegate alloc] initWithView:self withJview:jView];
  50 
  51         self->trackingArea = [[NSTrackingArea alloc] initWithRect:frame
  52             options:(NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect)
  53             owner:self userInfo:nil];
  54         [self addTrackingArea: self->trackingArea];
  55     }
  56     return self;
  57 }
  58 
  59 - (void)dealloc
  60 {
  61     [self->delegate release];
  62     self->delegate = nil;
  63 
  64     [self removeTrackingArea: self->trackingArea];
  65     [self->trackingArea release];
  66     self->trackingArea = nil;
  67 
  68     [super dealloc];
  69 }
  70 
  71 - (BOOL)becomeFirstResponder
  72 {
  73     return YES;
  74 }
  75 
  76 - (BOOL)acceptsFirstResponder
  77 {
  78     return YES;
  79 }
  80 
  81 - (BOOL)canBecomeKeyView
  82 {
  83     return YES;
  84 }
  85 
  86 - (BOOL)postsBoundsChangedNotifications
  87 {
  88     return NO;
  89 }
  90 
  91 - (BOOL)postsFrameChangedNotifications
  92 {
  93     return NO;
  94 }
  95 
  96 - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
  97 {
  98     return YES;
  99 }
 100 
 101 - (BOOL)isFlipped
 102 {
 103     return YES;
 104 }
 105 
 106 - (BOOL)isOpaque
 107 {
 108     return NO;
 109 }
 110 
 111 - (BOOL)mouseDownCanMoveWindow
 112 {
 113     return NO;
 114 }
 115 
 116 // also called when closing window, when [self window] == nil
 117 - (void)viewDidMoveToWindow
 118 {
 119     [self->delegate viewDidMoveToWindow];
 120 }
 121 
 122 - (void)setFrameOrigin:(NSPoint)newOrigin
 123 {
 124     [super setFrameOrigin:newOrigin];
 125     [self->delegate setFrameOrigin:newOrigin];
 126 }
 127 
 128 - (void)setFrameSize:(NSSize)newSize
 129 {
 130     [super setFrameSize:newSize];
 131     [self->delegate setFrameSize:newSize];
 132 }
 133 
 134 - (void)setFrame:(NSRect)frameRect
 135 {
 136     [super setFrame:frameRect];
 137     [self->delegate setFrame:frameRect];
 138 }
 139 
 140 - (void)updateTrackingAreas
 141 {
 142     [super updateTrackingAreas];
 143     [self->delegate updateTrackingAreas];
 144 }
 145 
 146 - (NSMenu *)menuForEvent:(NSEvent *)theEvent
 147 {
 148     [self->delegate sendJavaMenuEvent:theEvent];
 149     return [super menuForEvent: theEvent];
 150 }
 151 
 152 - (void)mouseEntered:(NSEvent *)theEvent
 153 {
 154     [self->delegate sendJavaMouseEvent:theEvent];
 155 }
 156 
 157 - (void)mouseMoved:(NSEvent *)theEvent
 158 {
 159     [self->delegate sendJavaMouseEvent:theEvent];
 160 }
 161 
 162 - (void)mouseExited:(NSEvent *)theEvent
 163 {
 164     [self->delegate sendJavaMouseEvent:theEvent];
 165 }
 166 
 167 - (void)mouseDown:(NSEvent *)theEvent
 168 {
 169     [self->delegate sendJavaMouseEvent:theEvent];
 170 }
 171 
 172 - (void)mouseDragged:(NSEvent *)theEvent
 173 {
 174     [self->delegate sendJavaMouseEvent:theEvent];
 175 }
 176 
 177 - (void)mouseUp:(NSEvent *)theEvent
 178 {
 179     [self->delegate sendJavaMouseEvent:theEvent];
 180 }
 181 
 182 - (void)rightMouseDown:(NSEvent *)theEvent
 183 {
 184     [self->delegate sendJavaMouseEvent:theEvent];
 185     // By default, calling rightMouseDown: generates menuForEvent: but none of the other glass mouse handlers call the super
 186     // To be consistent with the rest of glass, call the menu event handler directly rather than letting the operating system do it
 187     [self->delegate sendJavaMenuEvent:theEvent];
 188 //    return [super rightMouseDown: theEvent];
 189 }
 190 
 191 - (void)rightMouseDragged:(NSEvent *)theEvent
 192 {
 193     [self->delegate sendJavaMouseEvent:theEvent];
 194 }
 195 
 196 - (void)rightMouseUp:(NSEvent *)theEvent
 197 {
 198     [self->delegate sendJavaMouseEvent:theEvent];
 199 }
 200 
 201 - (void)otherMouseDown:(NSEvent *)theEvent
 202 {
 203     [self->delegate sendJavaMouseEvent:theEvent];
 204 }
 205 
 206 - (void)otherMouseDragged:(NSEvent *)theEvent
 207 {
 208     [self->delegate sendJavaMouseEvent:theEvent];
 209 }
 210 
 211 - (void)otherMouseUp:(NSEvent *)theEvent
 212 {
 213     [self->delegate sendJavaMouseEvent:theEvent];
 214 }
 215 
 216 - (void)rotateWithEvent:(NSEvent *)theEvent
 217 {
 218     [self->delegate sendJavaGestureEvent:theEvent type:com_sun_glass_ui_mac_MacGestureSupport_GESTURE_ROTATE];
 219 }
 220 
 221 - (void)swipeWithEvent:(NSEvent *)theEvent
 222 {
 223     [self->delegate sendJavaGestureEvent:theEvent type:com_sun_glass_ui_mac_MacGestureSupport_GESTURE_SWIPE];
 224 }
 225 
 226 - (void)magnifyWithEvent:(NSEvent *)theEvent
 227 {
 228     [self->delegate sendJavaGestureEvent:theEvent type:com_sun_glass_ui_mac_MacGestureSupport_GESTURE_MAGNIFY];
 229 }
 230 
 231 - (void)endGestureWithEvent:(NSEvent *)theEvent
 232 {
 233     [self->delegate sendJavaGestureEndEvent:theEvent];
 234 }
 235 
 236 - (void)beginGestureWithEvent:(NSEvent *)theEvent
 237 {
 238     [self->delegate sendJavaGestureBeginEvent:theEvent];
 239 }
 240 
 241 - (void)scrollWheel:(NSEvent *)theEvent
 242 {
 243     [self->delegate sendJavaMouseEvent:theEvent];
 244 }
 245 
 246 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent
 247 {
 248     [self->delegate sendJavaKeyEvent:theEvent isDown:YES];
 249     return NO; // return NO to allow system-default processing of Cmd+Q, etc.
 250 }
 251 
 252 - (void)keyDown:(NSEvent *)theEvent
 253 {
 254     [self->delegate sendJavaKeyEvent:theEvent isDown:YES];
 255 }
 256 
 257 - (void)keyUp:(NSEvent *)theEvent
 258 {
 259     [self->delegate sendJavaKeyEvent:theEvent isDown:NO];
 260 }
 261 
 262 - (void)flagsChanged:(NSEvent *)theEvent
 263 {
 264     [self->delegate sendJavaModifierKeyEvent:theEvent];
 265 }
 266 
 267 - (BOOL)wantsPeriodicDraggingUpdates
 268 {
 269     // we only want want updated drag operations when the mouse position changes
 270     return NO;
 271 }
 272 
 273 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
 274 {
 275     return YES;
 276 }
 277 
 278 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
 279 {
 280     [self->delegate sendJavaDndEvent:sender type:com_sun_glass_events_DndEvent_PERFORM];
 281 
 282     return YES;
 283 }
 284 
 285 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
 286 {
 287 
 288 }
 289 
 290 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
 291 {
 292     return [self->delegate sendJavaDndEvent:sender type:com_sun_glass_events_DndEvent_ENTER];
 293 }
 294 
 295 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
 296 {
 297     return [self->delegate sendJavaDndEvent:sender type:com_sun_glass_events_DndEvent_UPDATE];
 298 }
 299 
 300 - (void)draggingEnded:(id <NSDraggingInfo>)sender
 301 {
 302     [self->delegate draggingEnded];
 303 }
 304 
 305 - (void)draggingExited:(id <NSDraggingInfo>)sender
 306 {
 307     [self->delegate sendJavaDndEvent:sender type:com_sun_glass_events_DndEvent_EXIT];
 308 }
 309 
 310 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
 311 {
 312     return [self->delegate draggingSourceOperationMaskForLocal:isLocal];
 313 }
 314 
 315 - (void)drawRect:(NSRect)dirtyRect
 316 {
 317     [self->delegate drawRect:dirtyRect];
 318 }
 319 
 320 - (void)enterFullscreenWithAnimate:(BOOL)animate withKeepRatio:(BOOL)keepRatio withHideCursor:(BOOL)hideCursor
 321 {
 322     [self->delegate enterFullscreenWithAnimate:animate withKeepRatio:keepRatio withHideCursor:hideCursor];
 323 }
 324 
 325 - (void)exitFullscreenWithAnimate:(BOOL)animate
 326 {
 327     [self->delegate exitFullscreenWithAnimate:animate];
 328 }
 329 
 330 // below are methods that are 2D specific
 331 - (void)begin
 332 {
 333     CGContextRef cgContext = [[NSGraphicsContext currentContext] graphicsPort];
 334     CGContextSaveGState(cgContext);
 335     {
 336 #if 0
 337         NSRect bounds = [self bounds];
 338         fprintf(stderr, "bounds: %f,%f %fx%f\n", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
 339         NSRect frame = [self frame];
 340         fprintf(stderr, "frame: %f,%f %fx%f\n", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
 341 
 342         CGRect bbox = CGContextGetClipBoundingBox(cgContext);
 343         fprintf(stderr, "bbox: %f,%f %fx%f\n", bbox.origin.x, bbox.origin.y, bbox.size.width, bbox.size.height);
 344         CGAffineTransform ctm = CGContextGetCTM(cgContext);
 345         fprintf(stderr, "ctm: a:%f, b:%f, c:%f, d:%f, tx:%f, ty:%f\n", ctm.a, ctm.b, ctm.c, ctm.d, ctm.tx, ctm.ty);
 346 #endif
 347         // gznote: we could clear the surface for the client, but the client should be responsible for drawing
 348         // and if garbage appears on the screen it's because the client is not drawing in response to system repaints
 349         //CGContextClearRect(cgContext, CGRectMake(0, 0, [self bounds].size.width, [self bounds].size.height));
 350     }
 351 }
 352 
 353 - (void)end
 354 {
 355     CGContextRef cgContext = [[NSGraphicsContext currentContext] graphicsPort];
 356     {
 357 #if 0
 358         [[NSColor blackColor] setStroke];
 359         NSBezierPath *path = [NSBezierPath bezierPath];
 360         [path moveToPoint:NSMakePoint(0.0f, 0.0f)];
 361         [path lineToPoint:NSMakePoint([self bounds].size.width, [self bounds].size.height)];
 362         [path moveToPoint:NSMakePoint(0.0f, [self bounds].size.height)];
 363         [path lineToPoint:NSMakePoint([self bounds].size.width, 0.0f)];
 364         [path stroke];
 365 #endif
 366 #if 0
 367         CGContextFillRect(cgContext, CGRectMake(0, 0, 128, 128));
 368 #endif
 369 
 370         CGContextFlush(cgContext);
 371     }
 372     CGContextRestoreGState(cgContext);
 373 }
 374 
 375 - (void)pushPixels:(void*)pixels withWidth:(GLuint)width withHeight:(GLuint)height withScaleX:(GLfloat)scalex withScaleY:(GLfloat)scaley withEnv:(JNIEnv *)env
 376 {
 377     assert([NSGraphicsContext currentContext] != nil);
 378 
 379     CGContextRef cgContext = [[NSGraphicsContext currentContext] graphicsPort];
 380     {
 381         CGImageRef cgImage = NULL;
 382         CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
 383         {
 384             CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, width*height*4, NULL);
 385             {
 386                 cgImage = CGImageCreate(width, height, 8, 32, 4*width, colorSpace, kCGImageAlphaPremultipliedFirst|kCGBitmapByteOrder32Little, provider, NULL, true, kCGRenderingIntentDefault);
 387                 {
 388                     NSSize size = [self bounds].size;
 389                     if ((size.width != width) || (size.height != height))
 390                     {
 391                         //NSLog(@"Glass View2D size: %dx%d, but pixels size: %dx%d", (int)size.width, (int)size.height, width, height);
 392                         //CGContextClearRect(cgContext, CGRectMake(0, 0, size.width, size.height));
 393                     }
 394 
 395                     CGContextSaveGState(cgContext);
 396                     {
 397                         CGContextTranslateCTM(cgContext, 0, size.height);
 398                         CGContextScaleCTM(cgContext, 1, -1);
 399                         CGContextSetBlendMode(cgContext, kCGBlendModeCopy);
 400                         CGContextDrawImage(cgContext, CGRectMake(0, 0, width/scalex, height/scaley), cgImage);
 401                     }
 402                     CGContextRestoreGState(cgContext);
 403                 }
 404                 CGImageRelease(cgImage);
 405             }
 406             CGDataProviderRelease(provider);
 407         }
 408         CGColorSpaceRelease(colorSpace);
 409     }
 410     CGContextFlush(cgContext); // implicit flush
 411 }
 412 
 413 - (GlassViewDelegate*)delegate
 414 {
 415     return self->delegate;
 416 }
 417 
 418 - (void)setInputMethodEnabled:(BOOL)enabled
 419 {
 420     // Just a no-op here, GlassView2D does not support the IM interface
 421 }
 422 
 423 - (void)notifyScaleFactorChanged:(CGFloat)scale
 424 {
 425     // no-op
 426 }
 427 
 428 @end