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_ui_Cursor.h"
  28 #import "com_sun_glass_ui_mac_MacCursor.h"
  29 
  30 #import <Cocoa/Cocoa.h>
  31 
  32 #import "GlassMacros.h"
  33 #import "GlassHelper.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 #define CURSOR_BEST_SIZE 32
  43 
  44 static NSArray *cursorCache;
  45 
  46 #pragma mark --- Java NSCursor
  47 
  48 @interface NSCursor (Java)
  49 
  50 + (NSCursor*)performJavaSelector:(SEL)aSelector;
  51 
  52 @end
  53 
  54 @implementation NSCursor (Java)
  55 
  56 + (NSCursor*)performJavaSelector:(SEL)aSelector
  57 {
  58     NSCursor *cursor = nil;
  59     if ([GlassHelper InvokeSelectorIfAvailable:aSelector forClass:[NSCursor class] withArgument:NULL withReturnValue:(void**)&cursor] == NO)
  60     {
  61         cursor = [NSCursor arrowCursor];
  62     }
  63     return cursor;
  64 }
  65 
  66 @end
  67 
  68 #pragma mark --- com_sun_glass_ui_mac_MacCursor
  69 
  70 /*
  71  * Class:     com_sun_glass_ui_mac_MacCursor
  72  * Method:    _initIDs
  73  * Signature: ()V
  74  */
  75 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacCursor__1initIDs
  76 (JNIEnv *env, jclass jCursorClass)
  77 {
  78     LOG("Java_com_sun_glass_ui_mac_MacCursor__1initIDs");
  79 
  80     NSString *base = @"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/Resources/cursors";
  81     NSString *nwse = @"resizenorthwestsoutheast";
  82     NSString *nesw = @"resizenortheastsouthwest";
  83     NSString *nwsePath = [base stringByAppendingPathComponent:nwse];
  84     NSString *neswPath = [base stringByAppendingPathComponent:nesw];
  85     NSString *nwseFile = [nwsePath stringByAppendingPathComponent:@"cursor.pdf"];
  86     NSString *neswFile = [neswPath stringByAppendingPathComponent:@"cursor.pdf"];
  87     NSString *nwseInfo = [nwsePath stringByAppendingPathComponent:@"info.plist"];
  88     NSString *neswInfo = [neswPath stringByAppendingPathComponent:@"info.plist"];
  89     NSImage  *nwseImage = [[NSImage alloc] initByReferencingFile:nwseFile];
  90     NSImage  *neswImage = [[NSImage alloc] initByReferencingFile:neswFile];
  91     NSDictionary *nwseDict = [NSDictionary dictionaryWithContentsOfFile:nwseInfo];
  92     NSDictionary *neswDict = [NSDictionary dictionaryWithContentsOfFile:neswInfo];
  93     NSPoint   nwsePoint = NSMakePoint([[nwseDict valueForKey:@"hotx"] doubleValue],
  94                                       [[nwseDict valueForKey:@"hoty"] doubleValue]);
  95     NSPoint   neswPoint = NSMakePoint([[neswDict valueForKey:@"hotx"] doubleValue],
  96                                       [[neswDict valueForKey:@"hoty"] doubleValue]);
  97 
  98     if (jSizeInit == NULL)
  99     {
 100         jSizeInit = (*env)->GetMethodID(env, [GlassHelper ClassForName:"com.sun.glass.ui.Size" withEnv:env],
 101                                         "<init>", "(II)V");
 102     }
 103     cursorCache = [NSArray arrayWithObjects:
 104                       /* CURSOR_CUSTOM */           [NSCursor arrowCursor],     // not handed out in set
 105                       /* CURSOR_DEFAULT */          [NSCursor arrowCursor],
 106                       /* CURSOR_TEXT */             [NSCursor IBeamCursor],
 107                       /* CURSOR_CROSSHAIR */        [NSCursor crosshairCursor],
 108                       /* CURSOR_CLOSED_HAND */      [NSCursor closedHandCursor],
 109                       /* CURSOR_OPEN_HAND */        [NSCursor openHandCursor],
 110                       /* CURSOR_POINTING_HAND */    [NSCursor pointingHandCursor],
 111                       /* CURSOR_RESIZE_LEFT: */     [NSCursor resizeLeftCursor],
 112                       /* CURSOR_RESIZE_RIGHT */     [NSCursor resizeRightCursor],
 113                       /* CURSOR_RESIZE_UP */        [NSCursor resizeUpCursor],
 114                       /* CURSOR_RESIZE_DOWN */      [NSCursor resizeDownCursor],
 115                       /* CURSOR_RESIZE_LEFTRIGHT */ [NSCursor resizeLeftRightCursor],
 116                       /* CURSOR_RESIZE_UPDOWN */    [NSCursor resizeUpDownCursor],
 117                       /* CURSOR_DISAPPEAR */        [NSCursor disappearingItemCursor],
 118                       /* CURSOR_WAIT */             [NSCursor performJavaSelector:@selector(javaBusyButClickableCursor)],
 119                       /* CURSOR_RESIZE_SOUTHWEST */ [[NSCursor alloc] initWithImage:neswImage hotSpot:neswPoint],
 120                       /* CURSOR_RESIZE_SOUTHEAST */ [[NSCursor alloc] initWithImage:nwseImage hotSpot:nwsePoint],
 121                       /* CURSOR_RESIZE_NORTHWEST */ [[NSCursor alloc] initWithImage:nwseImage hotSpot:nwsePoint],
 122                       /* CURSOR_RESIZE_NORTHEAST */ [[NSCursor alloc] initWithImage:neswImage hotSpot:neswPoint],
 123                       /* CURSOR_MOVE */             [NSCursor performJavaSelector:@selector(javaMoveCursor)],
 124                       /* NS_REQUIRES_NIL_TERM */    nil
 125                    ];
 126     [cursorCache retain];
 127 
 128     assert([cursorCache count] == (com_sun_glass_ui_Cursor_CURSOR_MAX + 1));
 129 }
 130 
 131 /*
 132  * Class:     com_sun_glass_ui_mac_MacCursor
 133  * Method:    _createCursor
 134  * Signature: (IILcom/sun/glass/ui/Pixels;)J
 135  */
 136 JNIEXPORT jlong JNICALL Java_com_sun_glass_ui_mac_MacCursor__1createCursor
 137 (JNIEnv *env, jclass jCursorClass, jint x, jint y, jobject jPixels)
 138 {
 139     LOG("Java_com_sun_glass_ui_mac_MacCursor__1createCursor");
 140     jlong jcursor = 0;
 141 
 142     GLASS_ASSERT_MAIN_JAVA_THREAD(env);
 143     GLASS_POOL_ENTER;
 144     {
 145         NSImage *image = NULL;
 146         (*env)->CallVoidMethod(env, jPixels, jPixelsAttachData, ptr_to_jlong(&image));
 147         if (image != NULL)
 148         {
 149             NSCursor *cursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint(x, y)];
 150             jcursor = ptr_to_jlong(cursor);
 151             [image release];
 152         }
 153     }
 154     GLASS_POOL_EXIT;
 155     GLASS_CHECK_EXCEPTION(env);
 156 
 157     return jcursor;
 158 }
 159 
 160 /*
 161  * Class:     com_sun_glass_ui_mac_MacCursor
 162  * Method:    _set
 163  * Signature: (I)V
 164  */
 165 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacCursor__1set
 166 (JNIEnv *env, jclass jCursorClass, jint jtype)
 167 {
 168     GLASS_ASSERT_MAIN_JAVA_THREAD(env);
 169     GLASS_POOL_ENTER;
 170     {
 171         LOG("Java_com_sun_glass_ui_mac_MacCursor__1set: %d", jtype);
 172         assert(jtype > 0 && jtype <= com_sun_glass_ui_Cursor_CURSOR_MAX);
 173 
 174         NSCursor *cursor = [cursorCache objectAtIndex: jtype];
 175 
 176         [cursor set];
 177     }
 178     GLASS_POOL_EXIT;
 179     GLASS_CHECK_EXCEPTION(env);
 180 }
 181 
 182 /*
 183  * Class:     com_sun_glass_ui_mac_MacCursor
 184  * Method:    _setCustom
 185  * Signature: (J)V
 186  */
 187 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacCursor__1setCustom
 188 (JNIEnv *env, jclass jCursorClass, jlong cursorPtr)
 189 {
 190     LOG("Java_com_sun_glass_ui_mac_MacCursor__1setCustom");
 191 
 192     GLASS_ASSERT_MAIN_JAVA_THREAD(env);
 193     GLASS_POOL_ENTER;
 194     {
 195         NSCursor *cursor = (NSCursor*)jlong_to_ptr(cursorPtr);
 196         [cursor set];
 197     }
 198     GLASS_POOL_EXIT;
 199     GLASS_CHECK_EXCEPTION(env);
 200 }
 201 
 202 /*
 203  * Class:     com_sun_glass_ui_mac_MacCursor
 204  * Method:    _setVisible
 205  * Signature: (Z)V
 206  */
 207 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacCursor__1setVisible
 208 (JNIEnv *env, jclass jCursorClass, jboolean visible)
 209 {
 210     LOG("Java_com_sun_glass_ui_mac_MacCursor__1setVisible");
 211 
 212     GLASS_ASSERT_MAIN_JAVA_THREAD(env);
 213     GLASS_POOL_ENTER;
 214     {
 215         if (visible == JNI_TRUE)
 216         {
 217             [NSCursor unhide];
 218         }
 219         else
 220         {
 221             [NSCursor hide];
 222         }
 223     }
 224     GLASS_POOL_EXIT;
 225     GLASS_CHECK_EXCEPTION(env);
 226 }
 227 
 228 /*
 229  * Class:     com_sun_glass_ui_mac_MacCursor
 230  * Method:    _getBestSize
 231  * Signature: (II)Lcom.sun.glass.ui.Size;
 232  */
 233 JNIEXPORT jobject JNICALL Java_com_sun_glass_ui_mac_MacCursor__1getBestSize
 234 (JNIEnv *env, jclass jCursorClass, jint width, jint height)
 235 {
 236     LOG("Java_com_sun_glass_ui_mac_MacCursor__1getBestSize");
 237 
 238     jobject jsize = NULL;
 239 
 240     GLASS_ASSERT_MAIN_JAVA_THREAD(env);
 241     GLASS_POOL_ENTER;
 242     {
 243         jint widthBest = width;
 244         jint heightBest = height;
 245 
 246         NSImage *image = [[[NSCursor arrowCursor] image] retain];
 247 
 248         if (widthBest <= 0)
 249         {
 250             if (image != nil)
 251             {
 252                 widthBest = (jint)[image size].width;
 253             }
 254             else
 255             {
 256                 widthBest = CURSOR_BEST_SIZE;
 257             }
 258         }
 259 
 260         if (heightBest <= 0)
 261         {
 262             if (image != nil)
 263             {
 264                 heightBest = (jint)[image size].height;
 265             }
 266             else
 267             {
 268                 heightBest = CURSOR_BEST_SIZE;
 269             }
 270         }
 271 
 272         [image release];
 273 
 274         jsize = (*env)->NewObject(env, [GlassHelper ClassForName:"com.sun.glass.ui.Size" withEnv:env], jSizeInit, widthBest, heightBest);
 275     }
 276     GLASS_POOL_EXIT;
 277     GLASS_CHECK_EXCEPTION(env);
 278 
 279     return jsize;
 280 }