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