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 #include <X11/Xlib.h> 26 #include <X11/Xutil.h> 27 #include <X11/extensions/XTest.h> 28 #include <assert.h> 29 #include <stdlib.h> 30 #include <gdk/gdk.h> 31 #include <gdk/gdkx.h> 32 33 #include <com_sun_glass_ui_gtk_GtkRobot.h> 34 #include <com_sun_glass_events_MouseEvent.h> 35 #include "glass_general.h" 36 #include "glass_gtkcompat.h" 37 #include "glass_key.h" 38 39 40 static void checkXTest(JNIEnv* env) { 41 int32_t major_opcode, first_event, first_error; 42 int32_t event_basep, error_basep, majorp, minorp; 43 static int32_t isXTestAvailable; 44 static gboolean checkDone = FALSE; 45 if (!checkDone) { 46 /* check if XTest is available */ 47 isXTestAvailable = XQueryExtension(gdk_x11_get_default_xdisplay(), XTestExtensionName, &major_opcode, &first_event, &first_error); 48 if (isXTestAvailable) { 49 /* check if XTest version is OK */ 50 XTestQueryExtension(gdk_x11_get_default_xdisplay(), &event_basep, &error_basep, &majorp, &minorp); 51 if (majorp < 2 || (majorp == 2 && minorp < 2)) { 52 isXTestAvailable = False; 53 } else { 54 XTestGrabControl(gdk_x11_get_default_xdisplay(), True); 55 } 56 } 57 checkDone = TRUE; 58 } 59 if (!isXTestAvailable) { 60 jclass cls = env->FindClass("java/lang/UnsupportedOperationException"); 61 if (env->ExceptionCheck()) return; 62 env->ThrowNew(cls, "Glass Robot needs XTest extension to work"); 63 } 64 } 65 66 static void keyButton(jint code, gboolean press) 67 { 68 Display *xdisplay = gdk_x11_get_default_xdisplay(); 69 gint gdk_keyval = find_gdk_keyval_for_glass_keycode(code); 70 GdkKeymapKey *keys; 71 gint n_keys; 72 if (gdk_keyval == -1) { 73 return; 74 } 75 gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), 76 gdk_keyval, &keys, &n_keys); 77 if (n_keys < 1) { 78 return; 79 } 80 81 XTestFakeKeyEvent(xdisplay, 82 keys[0].keycode, 83 press ? True : False, 84 CurrentTime); 85 g_free(keys); 86 XSync(xdisplay, False); 87 } 88 89 extern "C" { 90 91 /* 92 * Class: com_sun_glass_ui_gtk_GtkRobot 93 * Method: _keyPress 94 * Signature: (I)V 95 */ 96 JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1keyPress 97 (JNIEnv *env, jobject obj, jint code) 98 { 99 (void)obj; 100 101 checkXTest(env); 102 keyButton(code, TRUE); 103 } 104 105 /* 106 * Class: com_sun_glass_ui_gtk_GtkRobot 107 * Method: _keyRelease 108 * Signature: (I)V 109 */ 110 JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1keyRelease 111 (JNIEnv *env, jobject obj, jint code) 112 { 113 (void)obj; 114 115 checkXTest(env); 116 keyButton(code, FALSE); 117 } 118 119 /* 120 * Class: com_sun_glass_ui_gtk_GtkRobot 121 * Method: _mouseMove 122 * Signature: (II)V 123 */ 124 JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1mouseMove 125 (JNIEnv *env, jobject obj, jint x, jint y) 126 { 127 (void)obj; 128 129 Display *xdisplay = gdk_x11_get_default_xdisplay(); 130 checkXTest(env); 131 XWarpPointer(xdisplay, 132 None, 133 XRootWindow(xdisplay,gdk_x11_get_default_screen()), 134 0, 0, 0, 0, x, y); 135 XSync(xdisplay, False); 136 } 137 138 static void mouseButtons(jint buttons, gboolean press) 139 { 140 Display *xdisplay = gdk_x11_get_default_xdisplay(); 141 if (buttons & com_sun_glass_ui_gtk_GtkRobot_MOUSE_LEFT_BTN) { 142 XTestFakeButtonEvent(xdisplay, 1, press, CurrentTime); 143 } 144 if (buttons & com_sun_glass_ui_gtk_GtkRobot_MOUSE_MIDDLE_BTN) { 145 XTestFakeButtonEvent(xdisplay, 2, press, CurrentTime); 146 } 147 if (buttons & com_sun_glass_ui_gtk_GtkRobot_MOUSE_RIGHT_BTN) { 148 XTestFakeButtonEvent(xdisplay, 3, press, CurrentTime); 149 } 150 151 XSync(xdisplay, False); 152 } 153 154 /* 155 * Class: com_sun_glass_ui_gtk_GtkRobot 156 * Method: _mousePress 157 * Signature: (I)V 158 */ 159 JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1mousePress 160 (JNIEnv *env, jobject obj, jint buttons) 161 { 162 (void)obj; 163 164 checkXTest(env); 165 mouseButtons(buttons, TRUE); 166 } 167 168 /* 169 * Class: com_sun_glass_ui_gtk_GtkRobot 170 * Method: _mouseRelease 171 * Signature: (I)V 172 */ 173 JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1mouseRelease 174 (JNIEnv *env, jobject obj, jint buttons) 175 { 176 (void)obj; 177 178 checkXTest(env); 179 mouseButtons(buttons, FALSE); 180 } 181 182 /* 183 * Class: com_sun_glass_ui_gtk_GtkRobot 184 * Method: _mouseWheel 185 * Signature: (I)V 186 */ 187 JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1mouseWheel 188 (JNIEnv *env, jobject obj, jint amt) 189 { 190 (void)obj; 191 192 Display *xdisplay = gdk_x11_get_default_xdisplay(); 193 int repeat = abs(amt); 194 int button = amt < 0 ? 5 : 4; 195 int i; 196 197 checkXTest(env); 198 for (i = 0; i < repeat; i++) { 199 XTestFakeButtonEvent(xdisplay, button, True, CurrentTime); 200 XTestFakeButtonEvent(xdisplay, button, False, CurrentTime); 201 } 202 XSync(xdisplay, False); 203 } 204 205 /* 206 * Class: com_sun_glass_ui_gtk_GtkRobot 207 * Method: _getMouseX 208 * Signature: ()I 209 */ 210 JNIEXPORT jint JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1getMouseX 211 (JNIEnv *env, jobject obj) 212 { 213 (void)env; 214 (void)obj; 215 216 jint x; 217 glass_gdk_display_get_pointer(gdk_display_get_default(), &x, NULL); 218 return x; 219 } 220 221 /* 222 * Class: com_sun_glass_ui_gtk_GtkRobot 223 * Method: _getMouseY 224 * Signature: ()I 225 */ 226 JNIEXPORT jint JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1getMouseY 227 (JNIEnv *env, jobject obj) 228 { 229 (void)env; 230 (void)obj; 231 232 jint y; 233 glass_gdk_display_get_pointer(gdk_display_get_default(), NULL, &y); 234 return y; 235 } 236 237 /* 238 * Class: com_sun_glass_ui_gtk_GtkRobot 239 * Method: _getScreenCapture 240 * Signature: (IIII[I)V 241 */ 242 JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1getScreenCapture 243 (JNIEnv * env, jobject obj, jint x, jint y, jint width, jint height, jintArray data) 244 { 245 (void)obj; 246 247 GdkPixbuf *screenshot, *tmp; 248 GdkWindow *root_window = gdk_get_default_root_window(); 249 250 tmp = gdk_pixbuf_get_from_drawable (NULL, root_window, NULL, 251 x, y, 0, 0, width, height); 252 screenshot = gdk_pixbuf_add_alpha(tmp, FALSE, 0, 0, 0); 253 g_object_unref(tmp); 254 255 jint *pixels = (jint *)convert_BGRA_to_RGBA((int*)gdk_pixbuf_get_pixels(screenshot), width * 4, height); 256 env->SetIntArrayRegion(data, 0, height * width, pixels); 257 g_free(pixels); 258 259 g_object_unref(screenshot); 260 } 261 262 } // extern "C"