diff options
Diffstat (limited to 'src/newt/native')
-rw-r--r-- | src/newt/native/InputEvent.h | 31 | ||||
-rw-r--r-- | src/newt/native/KDWindow.c | 12 | ||||
-rw-r--r-- | src/newt/native/KeyEvent.h | 388 | ||||
-rw-r--r-- | src/newt/native/MacWindow.m | 975 | ||||
-rw-r--r-- | src/newt/native/NewtCommon.c | 99 | ||||
-rw-r--r-- | src/newt/native/NewtCommon.h | 26 | ||||
-rw-r--r-- | src/newt/native/NewtMacWindow.h | 126 | ||||
-rw-r--r-- | src/newt/native/NewtMacWindow.m | 1267 | ||||
-rw-r--r-- | src/newt/native/ScreenMode.h | 16 | ||||
-rw-r--r-- | src/newt/native/Window.h | 17 | ||||
-rw-r--r-- | src/newt/native/WindowsWindow.c | 2236 | ||||
-rw-r--r-- | src/newt/native/X11Common.h | 5 | ||||
-rw-r--r-- | src/newt/native/X11Display.c | 424 | ||||
-rw-r--r-- | src/newt/native/X11Event.c | 305 | ||||
-rw-r--r-- | src/newt/native/X11Event.h | 9 | ||||
-rw-r--r-- | src/newt/native/X11RandR11.c | 371 | ||||
-rw-r--r-- | src/newt/native/X11RandR13.c | 519 | ||||
-rw-r--r-- | src/newt/native/X11Screen.c | 422 | ||||
-rw-r--r-- | src/newt/native/X11Screen.h | 38 | ||||
-rw-r--r-- | src/newt/native/X11Window.c | 366 | ||||
-rw-r--r-- | src/newt/native/XCBEvent.c | 308 | ||||
-rw-r--r-- | src/newt/native/XCBEvent.h | 10 | ||||
-rw-r--r-- | src/newt/native/bcm_vc_iv.c | 373 | ||||
-rw-r--r-- | src/newt/native/bcm_vc_iv.h | 130 |
24 files changed, 5805 insertions, 2668 deletions
diff --git a/src/newt/native/InputEvent.h b/src/newt/native/InputEvent.h index 51c56c474..2de46f82e 100644 --- a/src/newt/native/InputEvent.h +++ b/src/newt/native/InputEvent.h @@ -38,15 +38,26 @@ #define EVENT_CTRL_MASK (1 << 1) #define EVENT_META_MASK (1 << 2) #define EVENT_ALT_MASK (1 << 3) -#define EVENT_ALT_GRAPH_MASK (1 << 5) -#define EVENT_BUTTON1_MASK (1 << 6) -#define EVENT_BUTTON2_MASK (1 << 7) -#define EVENT_BUTTON3_MASK (1 << 8) -#define EVENT_BUTTON4_MASK (1 << 9) -#define EVENT_BUTTON5_MASK (1 << 10) -#define EVENT_BUTTON6_MASK (1 << 11) -#define EVENT_AUTOREPEAT_MASK (1 << 15) -#define EVENT_CONFINED_MASK (1 << 16) -#define EVENT_INVISIBLE_MASK (1 << 17) +#define EVENT_ALT_GRAPH_MASK (1 << 4) + +#define EVENT_BUTTON1_MASK (1 << 5) +#define EVENT_BUTTON2_MASK (1 << 6) +#define EVENT_BUTTON3_MASK (1 << 7) +#define EVENT_BUTTON4_MASK (1 << 8) +#define EVENT_BUTTON5_MASK (1 << 9) +#define EVENT_BUTTON6_MASK (1 << 10) +#define EVENT_BUTTON7_MASK (1 << 11) +#define EVENT_BUTTON8_MASK (1 << 12) +#define EVENT_BUTTON9_MASK (1 << 13) + +/** 16 buttons */ +#define EVENT_BUTTONLAST_MASK (1 << 20) + +/** 16 buttons */ +#define EVENT_BUTTONALL_MASK ( 0xffff << 5 ) + +#define EVENT_AUTOREPEAT_MASK (1 << 29) +#define EVENT_CONFINED_MASK (1 << 30) +#define EVENT_INVISIBLE_MASK (1 << 31) #endif diff --git a/src/newt/native/KDWindow.c b/src/newt/native/KDWindow.c index f1d6aecdf..cfec60dc1 100644 --- a/src/newt/native/KDWindow.c +++ b/src/newt/native/KDWindow.c @@ -161,14 +161,14 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_kd_DisplayDriver_DispatchMessages if(KD_INPUT_POINTER_SELECT==ptr->index) { DBG_PRINT( "event mouse click: src: %p, s:%d, (%d,%d)\n", userData, ptr->select, ptr->x, ptr->y); (*env)->CallVoidMethod(env, javaWindow, sendMouseEventID, - (ptr->select==0) ? (jint) EVENT_MOUSE_RELEASED : (jint) EVENT_MOUSE_PRESSED, + (ptr->select==0) ? (jshort) EVENT_MOUSE_RELEASED : (jshort) EVENT_MOUSE_PRESSED, (jint) 0, - (jint) ptr->x, (jint) ptr->y, 1, 0); + (jint) ptr->x, (jint) ptr->y, (short)1, 0.0f); } else { DBG_PRINT( "event mouse: src: %d, s:%p, i:0x%X (%d,%d)\n", userData, ptr->select, ptr->index, ptr->x, ptr->y); - (*env)->CallVoidMethod(env, javaWindow, sendMouseEventID, (jint) EVENT_MOUSE_MOVED, + (*env)->CallVoidMethod(env, javaWindow, sendMouseEventID, (jshort) EVENT_MOUSE_MOVED, 0, - (jint) ptr->x, (jint) ptr->y, 0, 0); + (jint) ptr->x, (jint) ptr->y, (jshort)0, 0.0f); } } break; @@ -193,8 +193,8 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_kd_WindowDriver_initIDs sizeChangedID = (*env)->GetMethodID(env, clazz, "sizeChanged", "(ZIIZ)V"); visibleChangedID = (*env)->GetMethodID(env, clazz, "visibleChanged", "(ZZ)V"); windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "(Z)Z"); - sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIIII)V"); - sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(IIIC)V"); + sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(SIIISF)V"); + sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(SISSC)V"); if (windowCreatedID == NULL || sizeChangedID == NULL || visibleChangedID == NULL || diff --git a/src/newt/native/KeyEvent.h b/src/newt/native/KeyEvent.h index 0f7b1606b..c0a366a17 100644 --- a/src/newt/native/KeyEvent.h +++ b/src/newt/native/KeyEvent.h @@ -31,197 +31,203 @@ #define EVENT_KEY_PRESSED 300 #define EVENT_KEY_RELEASED 301 -#define EVENT_KEY_TYPED 302 - -#define J_CHAR_UNDEFINED 0xFFFF; -#define J_VK_ENTER '\n' -#define J_VK_BACK_SPACE '\b' -#define J_VK_TAB '\t' -#define J_VK_CANCEL 0x03 -#define J_VK_CLEAR 0x0C -#define J_VK_SHIFT 0x10 -#define J_VK_CONTROL 0x11 -#define J_VK_ALT 0x12 -#define J_VK_PAUSE 0x13 -#define J_VK_CAPS_LOCK 0x14 -#define J_VK_ESCAPE 0x1B -#define J_VK_SPACE 0x20 -#define J_VK_PAGE_UP 0x21 -#define J_VK_PAGE_DOWN 0x22 -#define J_VK_END 0x23 -#define J_VK_HOME 0x24 -#define J_VK_LEFT 0x25 -#define J_VK_UP 0x26 -#define J_VK_RIGHT 0x27 -#define J_VK_DOWN 0x28 -#define J_VK_COMMA 0x2C -#define J_VK_MINUS 0x2D -#define J_VK_PERIOD 0x2E -#define J_VK_SLASH 0x2F -#define J_VK_0 0x30 -#define J_VK_1 0x31 -#define J_VK_2 0x32 -#define J_VK_3 0x33 -#define J_VK_4 0x34 -#define J_VK_5 0x35 -#define J_VK_6 0x36 -#define J_VK_7 0x37 -#define J_VK_8 0x38 -#define J_VK_9 0x39 -#define J_VK_SEMICOLON 0x3B -#define J_VK_EQUALS 0x3D -#define J_VK_A 0x41 -#define J_VK_B 0x42 -#define J_VK_C 0x43 -#define J_VK_D 0x44 -#define J_VK_E 0x45 -#define J_VK_F 0x46 -#define J_VK_G 0x47 -#define J_VK_H 0x48 -#define J_VK_I 0x49 -#define J_VK_J 0x4A -#define J_VK_K 0x4B -#define J_VK_L 0x4C -#define J_VK_M 0x4D -#define J_VK_N 0x4E -#define J_VK_O 0x4F -#define J_VK_P 0x50 -#define J_VK_Q 0x51 -#define J_VK_R 0x52 -#define J_VK_S 0x53 -#define J_VK_T 0x54 -#define J_VK_U 0x55 -#define J_VK_V 0x56 -#define J_VK_W 0x57 -#define J_VK_X 0x58 -#define J_VK_Y 0x59 -#define J_VK_Z 0x5A -#define J_VK_OPEN_BRACKET 0x5B -#define J_VK_BACK_SLASH 0x5C -#define J_VK_CLOSE_BRACKET 0x5D -#define J_VK_NUMPAD0 0x60 -#define J_VK_NUMPAD1 0x61 -#define J_VK_NUMPAD2 0x62 -#define J_VK_NUMPAD3 0x63 -#define J_VK_NUMPAD4 0x64 -#define J_VK_NUMPAD5 0x65 -#define J_VK_NUMPAD6 0x66 -#define J_VK_NUMPAD7 0x67 -#define J_VK_NUMPAD8 0x68 -#define J_VK_NUMPAD9 0x69 -#define J_VK_MULTIPLY 0x6A -#define J_VK_ADD 0x6B -#define J_VK_SEPARATOR 0x6C -#define J_VK_SUBTRACT 0x6D -#define J_VK_DECIMAL 0x6E -#define J_VK_DIVIDE 0x6F -#define J_VK_DELETE 0x7F /* ASCII DEL */ -#define J_VK_NUM_LOCK 0x90 -#define J_VK_SCROLL_LOCK 0x91 -#define J_VK_F1 0x70 -#define J_VK_F2 0x71 -#define J_VK_F3 0x72 -#define J_VK_F4 0x73 -#define J_VK_F5 0x74 -#define J_VK_F6 0x75 -#define J_VK_F7 0x76 -#define J_VK_F8 0x77 -#define J_VK_F9 0x78 -#define J_VK_F10 0x79 -#define J_VK_F11 0x7A -#define J_VK_F12 0x7B -#define J_VK_F13 0xF000 -#define J_VK_F14 0xF001 -#define J_VK_F15 0xF002 -#define J_VK_F16 0xF003 -#define J_VK_F17 0xF004 -#define J_VK_F18 0xF005 -#define J_VK_F19 0xF006 -#define J_VK_F20 0xF007 -#define J_VK_F21 0xF008 -#define J_VK_F22 0xF009 -#define J_VK_F23 0xF00A -#define J_VK_F24 0xF00B -#define J_VK_PRINTSCREEN 0x9A -#define J_VK_INSERT 0x9B -#define J_VK_HELP 0x9C -#define J_VK_META 0x9D -#define J_VK_BACK_QUOTE 0xC0 -#define J_VK_QUOTE 0xDE -#define J_VK_KP_UP 0xE0 -#define J_VK_KP_DOWN 0xE1 -#define J_VK_KP_LEFT 0xE2 -#define J_VK_KP_RIGHT 0xE3 -#define J_VK_DEAD_GRAVE 0x80 -#define J_VK_DEAD_ACUTE 0x81 -#define J_VK_DEAD_CIRCUMFLEX 0x82 -#define J_VK_DEAD_TILDE 0x83 -#define J_VK_DEAD_MACRON 0x84 -#define J_VK_DEAD_BREVE 0x85 -#define J_VK_DEAD_ABOVEDOT 0x86 -#define J_VK_DEAD_DIAERESIS 0x87 -#define J_VK_DEAD_ABOVERING 0x88 -#define J_VK_DEAD_DOUBLEACUTE 0x89 -#define J_VK_DEAD_CARON 0x8a -#define J_VK_DEAD_CEDILLA 0x8b -#define J_VK_DEAD_OGONEK 0x8c -#define J_VK_DEAD_IOTA 0x8d -#define J_VK_DEAD_VOICED_SOUND 0x8e -#define J_VK_DEAD_SEMIVOICED_SOUND 0x8f -#define J_VK_AMPERSAND 0x96 -#define J_VK_ASTERISK 0x97 -#define J_VK_QUOTEDBL 0x98 -#define J_VK_LESS 0x99 -#define J_VK_GREATER 0xa0 -#define J_VK_BRACELEFT 0xa1 -#define J_VK_BRACERIGHT 0xa2 -#define J_VK_AT 0x0200 -#define J_VK_COLON 0x0201 -#define J_VK_CIRCUMFLEX 0x0202 -#define J_VK_DOLLAR 0x0203 -#define J_VK_EURO_SIGN 0x0204 -#define J_VK_EXCLAMATION_MARK 0x0205 -#define J_VK_INVERTED_EXCLAMATION_MARK 0x0206 -#define J_VK_LEFT_PARENTHESIS 0x0207 -#define J_VK_NUMBER_SIGN 0x0208 -#define J_VK_PLUS 0x0209 -#define J_VK_RIGHT_PARENTHESIS 0x020A -#define J_VK_UNDERSCORE 0x020B -#define J_VK_WINDOWS 0x020C -#define J_VK_CONTEXT_MENU 0x020D -#define J_VK_FINAL 0x0018 -#define J_VK_CONVERT 0x001C -#define J_VK_NONCONVERT 0x001D -#define J_VK_ACCEPT 0x001E -#define J_VK_MODECHANGE 0x001F -#define J_VK_KANA 0x0015 -#define J_VK_KANJI 0x0019 -#define J_VK_ALPHANUMERIC 0x00F0 -#define J_VK_KATAKANA 0x00F1 -#define J_VK_HIRAGANA 0x00F2 -#define J_VK_FULL_WIDTH 0x00F3 -#define J_VK_HALF_WIDTH 0x00F4 -#define J_VK_ROMAN_CHARACTERS 0x00F5 -#define J_VK_ALL_CANDIDATES 0x0100 -#define J_VK_PREVIOUS_CANDIDATE 0x0101 -#define J_VK_CODE_INPUT 0x0102 -#define J_VK_JAPANESE_KATAKANA 0x0103 -#define J_VK_JAPANESE_HIRAGANA 0x0104 -#define J_VK_JAPANESE_ROMAN 0x0105 -#define J_VK_KANA_LOCK 0x0106 -#define J_VK_INPUT_METHOD_ON_OFF 0x0107 -#define J_VK_CUT 0xFFD1 -#define J_VK_COPY 0xFFCD -#define J_VK_PASTE 0xFFCF -#define J_VK_UNDO 0xFFCB -#define J_VK_AGAIN 0xFFC9 -#define J_VK_FIND 0xFFD0 -#define J_VK_PROPS 0xFFCA -#define J_VK_STOP 0xFFC8 -#define J_VK_COMPOSE 0xFF20 -#define J_VK_ALT_GRAPH 0xFF7E -#define J_VK_BEGIN 0xFF58 -#define J_VK_UNDEFINED 0x0 + +#define J_VK_UNDEFINED ( 0x0U ) +#define J_VK_HOME ( 0x02U ) +#define J_VK_END ( 0x03U ) +#define J_VK_FINAL ( 0x04U ) +#define J_VK_PRINTSCREEN ( 0x05U ) +#define J_VK_BACK_SPACE ( 0x08U ) +#define J_VK_TAB ( 0x09U ) +#define J_VK_PAGE_DOWN ( 0x0BU ) +#define J_VK_CLEAR ( 0x0CU ) +#define J_VK_ENTER ( 0x0DU ) +#define J_VK_SHIFT ( 0x0FU ) +#define J_VK_PAGE_UP ( 0x10U ) +#define J_VK_CONTROL ( 0x11U ) +#define J_VK_ALT ( 0x12U ) +#define J_VK_ALT_GRAPH ( 0x13U ) +#define J_VK_CAPS_LOCK ( 0x14U ) +#define J_VK_PAUSE ( 0x16U ) +#define J_VK_SCROLL_LOCK ( 0x17U ) +#define J_VK_CANCEL ( 0x18U ) +#define J_VK_INSERT ( 0x1AU ) +#define J_VK_ESCAPE ( 0x1BU ) +#define J_VK_CONVERT ( 0x1CU ) +#define J_VK_NONCONVERT ( 0x1DU ) +#define J_VK_ACCEPT ( 0x1EU ) +#define J_VK_MODECHANGE ( 0x1FU ) + +// +// Unicode: Printable [0x20 - 0x7E] +// + +#define J_VK_SPACE ( 0x20U ) +#define J_VK_EXCLAMATION_MARK ( 0x21U ) +#define J_VK_QUOTEDBL ( 0x22U ) +#define J_VK_NUMBER_SIGN ( 0x23U ) +#define J_VK_DOLLAR ( 0x24U ) +#define J_VK_PERCENT ( 0x25U ) +#define J_VK_AMPERSAND ( 0x26U ) +#define J_VK_QUOTE ( 0x27U ) +#define J_VK_LEFT_PARENTHESIS ( 0x28U ) +#define J_VK_RIGHT_PARENTHESIS ( 0x29U ) +#define J_VK_ASTERISK ( 0x2AU ) +#define J_VK_PLUS ( 0x2BU ) +#define J_VK_COMMA ( 0x2CU ) +#define J_VK_MINUS ( 0x2DU ) +#define J_VK_PERIOD ( 0x2EU ) +#define J_VK_SLASH ( 0x2FU ) +#define J_VK_0 ( 0x30U ) +#define J_VK_1 ( 0x31U ) +#define J_VK_2 ( 0x32U ) +#define J_VK_3 ( 0x33U ) +#define J_VK_4 ( 0x34U ) +#define J_VK_5 ( 0x35U ) +#define J_VK_6 ( 0x36U ) +#define J_VK_7 ( 0x37U ) +#define J_VK_8 ( 0x38U ) +#define J_VK_9 ( 0x39U ) +#define J_VK_COLON ( 0x3AU ) +#define J_VK_SEMICOLON ( 0x3BU ) +#define J_VK_LESS ( 0x3CU ) +#define J_VK_EQUALS ( 0x3DU ) +#define J_VK_GREATER ( 0x3EU ) +#define J_VK_QUESTIONMARK ( 0x3FU ) +#define J_VK_AT ( 0x40U ) +#define J_VK_A ( 0x41U ) +#define J_VK_B ( 0x42U ) +#define J_VK_C ( 0x43U ) +#define J_VK_D ( 0x44U ) +#define J_VK_E ( 0x45U ) +#define J_VK_F ( 0x46U ) +#define J_VK_G ( 0x47U ) +#define J_VK_H ( 0x48U ) +#define J_VK_I ( 0x49U ) +#define J_VK_J ( 0x4AU ) +#define J_VK_K ( 0x4BU ) +#define J_VK_L ( 0x4CU ) +#define J_VK_M ( 0x4DU ) +#define J_VK_N ( 0x4EU ) +#define J_VK_O ( 0x4FU ) +#define J_VK_P ( 0x50U ) +#define J_VK_Q ( 0x51U ) +#define J_VK_R ( 0x52U ) +#define J_VK_S ( 0x53U ) +#define J_VK_T ( 0x54U ) +#define J_VK_U ( 0x55U ) +#define J_VK_V ( 0x56U ) +#define J_VK_W ( 0x57U ) +#define J_VK_X ( 0x58U ) +#define J_VK_Y ( 0x59U ) +#define J_VK_Z ( 0x5AU ) +#define J_VK_OPEN_BRACKET ( 0x5BU ) +#define J_VK_BACK_SLASH ( 0x5CU ) +#define J_VK_CLOSE_BRACKET ( 0x5DU ) +#define J_VK_CIRCUMFLEX ( 0x5EU ) +#define J_VK_UNDERSCORE ( 0x5FU ) +#define J_VK_BACK_QUOTE ( 0x60U ) +#define J_VK_F1 ( 0x60U+ 1U ) +#define J_VK_F2 ( 0x60U+ 2U ) +#define J_VK_F3 ( 0x60U+ 3U ) +#define J_VK_F4 ( 0x60U+ 4U ) +#define J_VK_F5 ( 0x60U+ 5U ) +#define J_VK_F6 ( 0x60U+ 6U ) +#define J_VK_F7 ( 0x60U+ 7U ) +#define J_VK_F8 ( 0x60U+ 8U ) +#define J_VK_F9 ( 0x60U+ 9U ) +#define J_VK_F10 ( 0x60U+10U ) +#define J_VK_F11 ( 0x60U+11U ) +#define J_VK_F12 ( 0x60U+12U ) +#define J_VK_F13 ( 0x60U+13U ) +#define J_VK_F14 ( 0x60U+14U ) +#define J_VK_F15 ( 0x60U+15U ) +#define J_VK_F16 ( 0x60U+16U ) +#define J_VK_F17 ( 0x60U+17U ) +#define J_VK_F18 ( 0x60U+18U ) +#define J_VK_F19 ( 0x60U+19U ) +#define J_VK_F20 ( 0x60U+20U ) +#define J_VK_F21 ( 0x60U+21U ) +#define J_VK_F22 ( 0x60U+22U ) +#define J_VK_F23 ( 0x60U+23U ) +#define J_VK_F24 ( 0x60U+24U ) +#define J_VK_LEFT_BRACE ( 0x7BU ) +#define J_VK_PIPE ( 0x7CU ) +#define J_VK_RIGHT_BRACE ( 0x7DU ) +#define J_VK_TILDE ( 0x7EU ) + +// +// Unicode: Non printable controls: [0x7F - 0x9F] +// + +#define J_VK_SEPARATOR ( 0x7FU ) +#define J_VK_NUMPAD0 ( 0x80U ) +#define J_VK_NUMPAD1 ( 0x81U ) +#define J_VK_NUMPAD2 ( 0x82U ) +#define J_VK_NUMPAD3 ( 0x83U ) +#define J_VK_NUMPAD4 ( 0x84U ) +#define J_VK_NUMPAD5 ( 0x85U ) +#define J_VK_NUMPAD6 ( 0x86U ) +#define J_VK_NUMPAD7 ( 0x87U ) +#define J_VK_NUMPAD8 ( 0x88U ) +#define J_VK_NUMPAD9 ( 0x89U ) +#define J_VK_DECIMAL ( 0x8AU ) +#define J_VK_ADD ( 0x8BU ) +#define J_VK_SUBTRACT ( 0x8CU ) +#define J_VK_MULTIPLY ( 0x8DU ) +#define J_VK_DIVIDE ( 0x8EU ) + +#define J_VK_DELETE ( 0x93U ) +#define J_VK_NUM_LOCK ( 0x94U ) +#define J_VK_LEFT ( 0x95U ) +#define J_VK_UP ( 0x96U ) +#define J_VK_RIGHT ( 0x97U ) +#define J_VK_DOWN ( 0x98U ) +#define J_VK_CONTEXT_MENU ( 0x99U ) +#define J_VK_WINDOWS ( 0x9AU ) +#define J_VK_META ( 0x9BU ) +#define J_VK_HELP ( 0x9CU ) +#define J_VK_COMPOSE ( 0x9DU ) +#define J_VK_BEGIN ( 0x9EU ) +#define J_VK_STOP ( 0x9FU ) + +// +// Unicode: Printable [0x00A0 - 0xDFFF] +// + +#define J_VK_INVERTED_EXCLAMATION_MARK ( 0xA1U ) +#define J_VK_EURO_SIGN ( 0x20ACU ) + +// +// Unicode: Private 0xE000 - 0xF8FF (Marked Non-Printable) +// + +/* for Sun keyboards */ +#define J_VK_CUT ( 0xF879U ) +#define J_VK_COPY ( 0xF87AU ) +#define J_VK_PASTE ( 0xF87BU ) +#define J_VK_UNDO ( 0xF87CU ) +#define J_VK_AGAIN ( 0xF87DU ) +#define J_VK_FIND ( 0xF87EU ) +#define J_VK_PROPS ( 0xF87FU ) + +/* for input method support on Asian Keyboards */ +#define J_VK_INPUT_METHOD_ON_OFF ( 0xF890U ) +#define J_VK_CODE_INPUT ( 0xF891U ) +#define J_VK_ROMAN_CHARACTERS ( 0xF892U ) +#define J_VK_ALL_CANDIDATES ( 0xF893U ) +#define J_VK_PREVIOUS_CANDIDATE ( 0xF894U ) +#define J_VK_ALPHANUMERIC ( 0xF895U ) +#define J_VK_KATAKANA ( 0xF896U ) +#define J_VK_HIRAGANA ( 0xF897U ) +#define J_VK_FULL_WIDTH ( 0xF898U ) +#define J_VK_HALF_WIDTH ( 0xF89AU ) +#define J_VK_JAPANESE_KATAKANA ( 0xF89BU ) +#define J_VK_JAPANESE_HIRAGANA ( 0xF89CU ) +#define J_VK_JAPANESE_ROMAN ( 0xF89DU ) +#define J_VK_KANA_LOCK ( 0xF89FU ) + +#define J_VK_KEYBOARD_INVISIBLE ( 0xF8FFU ) #endif diff --git a/src/newt/native/MacWindow.m b/src/newt/native/MacWindow.m index b9c339285..2bd11da3c 100644 --- a/src/newt/native/MacWindow.m +++ b/src/newt/native/MacWindow.m @@ -62,12 +62,36 @@ static NSString* jstringToNSString(JNIEnv* env, jstring jstr) return str; } -static void setFrameTopLeftPoint(NSWindow* pWin, NewtMacWindow* mWin, jint x, jint y) { - NSPoint pS = [mWin newtScreenWinPos2OSXScreenPos: NSMakePoint(x, y)]; +static void setWindowClientTopLeftPoint(NewtMacWindow* mWin, jint x, jint y, BOOL doDisplay) { + DBG_PRINT( "setWindowClientTopLeftPoint.0 - window: %p %d/%d, display %d\n", mWin, (int)x, (int)y, (int)doDisplay); + NSPoint pS = [mWin newtAbsClientTLWinPos2AbsBLScreenPos: NSMakePoint(x, y)]; + DBG_PRINT( "setWindowClientTopLeftPoint.1: %d/%d\n", (int)pS.x, (int)pS.y); + [mWin setFrameOrigin: pS]; + DBG_PRINT( "setWindowClientTopLeftPoint.X: %d/%d\n", (int)pS.x, (int)pS.y); + + if( doDisplay ) { + NSView* mView = [mWin contentView]; + [mWin invalidateCursorRectsForView: mView]; + } +} - NSView* mView = [mWin contentView]; - [mWin invalidateCursorRectsForView: mView]; +static void setWindowClientTopLeftPointAndSize(NewtMacWindow* mWin, jint x, jint y, jint width, jint height, BOOL doDisplay) { + DBG_PRINT( "setWindowClientTopLeftPointAndSize.0 - window: %p %d/%d %dx%d, display %d\n", mWin, (int)x, (int)y, (int)width, (int)height, (int)doDisplay); + NSSize clientSZ = NSMakeSize(width, height); + NSPoint pS = [mWin newtAbsClientTLWinPos2AbsBLScreenPos: NSMakePoint(x, y) size: clientSZ]; + NSSize topSZ = [mWin newtClientSize2TLSize: clientSZ]; + NSRect rect = { pS, topSZ }; + DBG_PRINT( "setWindowClientTopLeftPointAndSize.1: %d/%d %dx%d\n", (int)rect.origin.x, (int)rect.origin.y, (int)rect.size.width, (int)rect.size.height); + + [mWin setFrame: rect display:doDisplay]; + DBG_PRINT( "setWindowClientTopLeftPointAndSize.X: %d/%d %dx%d\n", (int)rect.origin.x, (int)rect.origin.y, (int)rect.size.width, (int)rect.size.height); + + // -> display:YES + // if( doDisplay ) { + // NSView* mView = [mWin contentView]; + // [mWin invalidateCursorRectsForView: mView]; + // } } #ifdef VERBOSE_ON @@ -76,22 +100,38 @@ static int getRetainCount(NSObject * obj) { } #endif -static void changeContentView(JNIEnv *env, jobject javaWindowObject, NSView *pview, NewtMacWindow *win, NewtView *newView) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; +static void setJavaWindowObject(JNIEnv *env, jobject newJavaWindowObject, NewtView *view, BOOL enable) { + DBG_PRINT( "setJavaWindowObject.0: View %p\n", view); + if( !enable) { + jobject globJavaWindowObject = [view getJavaWindowObject]; + if( NULL != globJavaWindowObject ) { + DBG_PRINT( "setJavaWindowObject.1: View %p - Clear old javaWindowObject %p\n", view, globJavaWindowObject); + (*env)->DeleteGlobalRef(env, globJavaWindowObject); + [view setJavaWindowObject: NULL]; + } + } else if( NULL != newJavaWindowObject ) { + DBG_PRINT( "setJavaWindowObject.2: View %p - Set new javaWindowObject %p\n", view, newJavaWindowObject); + jobject globJavaWindowObject = (*env)->NewGlobalRef(env, newJavaWindowObject); + [view setJavaWindowObject: globJavaWindowObject]; + } + DBG_PRINT( "setJavaWindowObject.X: View %p\n", view); +} + +static void changeContentView(JNIEnv *env, jobject javaWindowObject, NSView *pview, NewtMacWindow *win, NewtView *newView, BOOL setJavaWindow) { NSView* oldNSView = [win contentView]; - NewtView* oldView = NULL; + NewtView* oldNewtView = NULL; #ifdef VERBOSE_ON int dbgIdx = 1; #endif - if( [oldNSView isMemberOfClass:[NewtView class]] ) { - oldView = (NewtView *) oldNSView; + if( [oldNSView isKindOfClass:[NewtView class]] ) { + oldNewtView = (NewtView *) oldNSView; } DBG_PRINT( "changeContentView.%d win %p, view (%p,%d (%d) -> %p,%d), parent view %p\n", - dbgIdx++, win, oldNSView, getRetainCount(oldNSView), NULL!=oldView, newView, getRetainCount(newView), pview); + dbgIdx++, win, oldNSView, getRetainCount(oldNSView), NULL!=oldNewtView, newView, getRetainCount(newView), pview); - if(NULL!=oldNSView) { + if( NULL!=oldNSView ) { NS_DURING // Available >= 10.5 - Makes the menubar disapear BOOL iifs; @@ -106,34 +146,21 @@ NS_DURING NS_HANDLER NS_ENDHANDLER DBG_PRINT( "changeContentView.%d win %p, view (%p,%d (%d) -> %p,%d)\n", - dbgIdx++, win, oldNSView, getRetainCount(oldNSView), NULL!=oldView, newView, getRetainCount(newView)); + dbgIdx++, win, oldNSView, getRetainCount(oldNSView), NULL!=oldNewtView, newView, getRetainCount(newView)); - if( NULL != oldView ) { - jobject globJavaWindowObject = [oldView getJavaWindowObject]; - (*env)->DeleteGlobalRef(env, globJavaWindowObject); - [oldView setJavaWindowObject: NULL]; - [oldView setDestroyNotifySent: false]; + if( NULL != oldNewtView ) { + [oldNewtView setDestroyNotifySent: false]; + setJavaWindowObject(env, NULL, oldNewtView, NO); } [oldNSView removeFromSuperviewWithoutNeedingDisplay]; } DBG_PRINT( "changeContentView.%d win %p, view (%p,%d -> %p,%d), isHidden %d, isHiddenOrHasHiddenAncestor: %d\n", dbgIdx++, win, oldNSView, getRetainCount(oldNSView), newView, getRetainCount(newView), [newView isHidden], [newView isHiddenOrHasHiddenAncestor]); - if(NULL!=newView) { - jobject globJavaWindowObject = (*env)->NewGlobalRef(env, javaWindowObject); - [newView setJavaWindowObject: globJavaWindowObject]; + if( NULL!=newView ) { [newView setDestroyNotifySent: false]; - { - JavaVM *jvmHandle = NULL; - int jvmVersion = 0; - - if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { - jvmHandle = NULL; - } else { - jvmVersion = (*env)->GetVersion(env); - } - [newView setJVMHandle: jvmHandle]; - [newView setJVMVersion: jvmVersion]; + if( setJavaWindow ) { + setJavaWindowObject(env, javaWindowObject, newView, YES); } DBG_PRINT( "changeContentView.%d win %p, view (%p,%d -> %p,%d)\n", @@ -152,12 +179,10 @@ NS_ENDHANDLER dbgIdx++, win, oldNSView, getRetainCount(oldNSView), newView, getRetainCount(newView), [newView isHidden], [newView isHiddenOrHasHiddenAncestor]); // make sure the insets are updated in the java object - [win updateInsets: env]; + [win updateInsets: env jwin:javaWindowObject]; DBG_PRINT( "changeContentView.X win %p, view (%p,%d -> %p,%d)\n", win, oldNSView, getRetainCount(oldNSView), newView, getRetainCount(newView)); - - [pool release]; } /* @@ -173,6 +198,8 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_initNSAp if(initialized) return JNI_TRUE; initialized = 1; + NewtCommon_init(env); + // This little bit of magic is needed in order to receive mouse // motion events and allow key focus to be properly transferred. // FIXME: are these Carbon APIs? They come from the @@ -248,50 +275,151 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_stopNSApplic [pool release]; } -static NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx) { - NSArray *screens = [NSScreen screens]; - if(screen_idx<0) screen_idx=0; - if(screen_idx>=[screens count]) screen_idx=0; - return (NSScreen *) [screens objectAtIndex: screen_idx]; +static NSImage * createNSImageFromData(JNIEnv *env, unsigned char * iconData, jint jiconWidth, jint jiconHeight) { + if( NULL != iconData ) { + NSInteger iconWidth = (NSInteger) jiconWidth; + NSInteger iconHeight = (NSInteger) jiconHeight; + const NSInteger bpc = 8 /* bits per component */, spp=4 /* RGBA */, bpp = bpc * spp; + const NSBitmapFormat bfmt = NSAlphaNonpremultipliedBitmapFormat; + const BOOL hasAlpha = YES; + + NSBitmapImageRep* bir = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: &iconData + pixelsWide: iconWidth + pixelsHigh: iconHeight + bitsPerSample: bpc + samplesPerPixel: spp + hasAlpha: hasAlpha + isPlanar: NO + colorSpaceName: NSCalibratedRGBColorSpace + bitmapFormat: bfmt + bytesPerRow: iconWidth*4 + bitsPerPixel: bpp]; + [bir autorelease]; + NSImage* nsImage = [[NSImage alloc] initWithCGImage: [bir CGImage] size:NSZeroSize]; + return nsImage; + } + return NULL; } /* - * Class: jogamp_newt_driver_macosx_ScreenDriver - * Method: getWidthImpl - * Signature: (I)I + * Class: jogamp_newt_driver_macosx_DisplayDriver + * Method: setAppIcon0 */ -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getWidthImpl0 - (JNIEnv *env, jclass clazz, jint screen_idx) +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_setAppIcon0 + (JNIEnv *env, jobject unused, jobject pixels, jint pixels_byte_offset, jboolean pixels_is_direct, jint width, jint height) { + if( 0 == pixels ) { + return; + } NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - - NSScreen *screen = NewtScreen_getNSScreenByIndex((int)screen_idx); - NSRect rect = [screen frame]; - + // NOTE: MUST BE DIRECT BUFFER, since NSBitmapImageRep uses buffer directly! + unsigned char * pixelPtr = (unsigned char *) ( JNI_TRUE == pixels_is_direct ? + (*env)->GetDirectBufferAddress(env, pixels) : + (*env)->GetPrimitiveArrayCritical(env, pixels, NULL) ); + NSImage * nsImage = createNSImageFromData(env, pixelPtr + pixels_byte_offset, width, height); + if( NULL != nsImage ) { + [nsImage autorelease]; + [NSApp setApplicationIconImage: nsImage]; + } + if ( JNI_FALSE == pixels_is_direct ) { + (*env)->ReleasePrimitiveArrayCritical(env, pixels, (void*)pixelPtr, JNI_ABORT); + } [pool release]; +} - return (jint) (rect.size.width); +JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_createPointerIcon0 + (JNIEnv *env, jobject unused, jobject pixels, jint pixels_byte_offset, jboolean pixels_is_direct, jint width, jint height, jint hotX, jint hotY) +{ + if( 0 == pixels ) { + return 0; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + unsigned char * pixelPtr = (unsigned char *) ( JNI_TRUE == pixels_is_direct ? + (*env)->GetDirectBufferAddress(env, pixels) : + (*env)->GetPrimitiveArrayCritical(env, pixels, NULL) ); + NSImage * nsImage = createNSImageFromData(env, pixelPtr + pixels_byte_offset, width, height); + NSCursor * res = NULL; + if( NULL != nsImage ) { + [nsImage autorelease]; + NSPoint hotP = { hotX, hotY }; + res = [[NSCursor alloc] initWithImage: nsImage hotSpot: hotP]; + } + if ( JNI_FALSE == pixels_is_direct ) { + (*env)->ReleasePrimitiveArrayCritical(env, pixels, (void*)pixelPtr, JNI_ABORT); + } + [pool release]; + DBG_PRINT( "createPointerIcon0 %p\n", res); + return (jlong) (intptr_t) res; } -/* - * Class: jogamp_newt_driver_macosx_ScreenDriver - * Method: getHeightImpl - * Signature: (I)I - */ -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getHeightImpl0 - (JNIEnv *env, jclass clazz, jint screen_idx) +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_destroyPointerIcon0 + (JNIEnv *env, jobject unused, jlong handle) { + NSCursor * c = (NSCursor*) (intptr_t) handle ; + if( NULL != c && NO == [c isKindOfClass:[NSCursor class]] ) { + NewtCommon_throwNewRuntimeException(env, "Not a NSCursor %p", c); + return; + } + DBG_PRINT( "destroyPointerIcon0 %p\n", c); NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [c release]; + [pool release]; +} - NSScreen *screen = NewtScreen_getNSScreenByIndex((int)screen_idx); - NSRect rect = [screen frame]; +NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx, BOOL cap) { + NSArray *screens = [NSScreen screens]; + if( screen_idx<0 || screen_idx>=[screens count] ) { + if( cap ) { + screen_idx=0; + } else { + return NULL; + } + } + return (NSScreen *) [screens objectAtIndex: screen_idx]; +} - [pool release]; +NSScreen * NewtScreen_getNSScreenByCoord(int x, int y) { + NSArray *screens = [NSScreen screens]; + int i; + for(i=[screens count]-1; i>=0; i--) { + NSScreen * screen = (NSScreen *) [screens objectAtIndex: i]; + NSRect frame = [screen frame]; + if( x >= frame.origin.x && + y >= frame.origin.y && + x < frame.origin.x + frame.size.width && + y < frame.origin.y + frame.size.height ) { + return screen; + } + } + return (NSScreen *) [screens objectAtIndex: 0]; +} - return (jint) (rect.size.height); +static void NewtScreen_dump() { +#ifdef VERBOSE_ON + NSArray *screens = [NSScreen screens]; + int i; + for(i=0; i<[screens count]; i++) { + NSScreen * screen = (NSScreen *) [screens objectAtIndex: i]; + NSRect screenFrame = [screen frame]; + NSRect screenVisibleFrame = [screen visibleFrame]; + CGFloat pixelScale = 1.0; // default +NS_DURING + // Available >= 10.7 + pixelScale = [screen backingScaleFactor]; // HiDPI scaling +NS_HANDLER +NS_ENDHANDLER + NSWindowDepth depth = [screen depth]; // an (int) value! + DBG_PRINT( "NSScreen #%d (%p): Frame %lf/%lf %lfx%lf (vis %lf/%lf %lfx%lf), scale %lf, depth %d\n", + i, screen, + screenFrame.origin.x, screenFrame.origin.y, screenFrame.size.width, screenFrame.size.height, + screenVisibleFrame.origin.x, screenVisibleFrame.origin.y, screenVisibleFrame.size.width, screenVisibleFrame.size.height, + pixelScale, depth); + } +#endif } -static CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen) { + +CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen) { // Mind: typedef uint32_t CGDirectDisplayID; - however, we assume it's 64bit on 64bit ?! NSDictionary * dict = [screen deviceDescription]; NSNumber * val = (NSNumber *) [dict objectForKey: @"NSScreenNumber"]; @@ -325,11 +453,25 @@ static long GetDictionaryLong(CFDictionaryRef theDict, const void* key) /* * Class: jogamp_newt_driver_macosx_ScreenDriver - * Method: getScreenSizeMM0 + * Method: getMonitorCount0 + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getMonitorCount0 + (JNIEnv *env, jobject obj) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSArray *screens = [NSScreen screens]; + [pool release]; + return (jint) [screens count]; +} + +/* + * Class: jogamp_newt_driver_macosx_ScreenDriver + * Method: getMonitorProps0 * Signature: (I)[I */ -JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getScreenSizeMM0 - (JNIEnv *env, jobject obj, jint scrn_idx) +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getMonitorProps0 + (JNIEnv *env, jobject obj, jint crt_idx) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; @@ -339,33 +481,58 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getScree timespec_now(&t0); #endif - NSScreen *screen = NewtScreen_getNSScreenByIndex((int)scrn_idx); #ifdef DBG_PERF timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td); - fprintf(stderr, "MacScreen_getScreenSizeMM0.1: %ld ms\n", td_ms); fflush(NULL); + fprintf(stderr, "MacScreen_getMonitorProps0.1: %ld ms\n", td_ms); fflush(NULL); #endif - + NSScreen *screen = NewtScreen_getNSScreenByIndex((int)crt_idx, false); + if( NULL == screen ) { + [pool release]; + return NULL; + } CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen); #ifdef DBG_PERF timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td); - fprintf(stderr, "MacScreen_getScreenSizeMM0.2: %ld ms\n", td_ms); fflush(NULL); + fprintf(stderr, "MacScreen_getMonitorProps0.2: %ld ms\n", td_ms); fflush(NULL); #endif - CGSize screenDim = CGDisplayScreenSize(display); + CGSize sizeMM = CGDisplayScreenSize(display); #ifdef DBG_PERF timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td); - fprintf(stderr, "MacScreen_getScreenSizeMM0.3: %ld ms\n", td_ms); fflush(NULL); + fprintf(stderr, "MacScreen_getMonitorProps0.3: %ld ms\n", td_ms); fflush(NULL); #endif - jint prop[ 2 ]; - prop[0] = (jint) screenDim.width; - prop[1] = (jint) screenDim.height; + CGRect dBounds = CGDisplayBounds (display); // origin top-left +#ifdef VERBOSE_ON + BOOL usesGL = CGDisplayUsesOpenGLAcceleration(display); + NSRect sFrame = [screen frame]; // origin bottom-left + DBG_PRINT( "getMonitorProps0: scrn %d, top-left displayBounds[%d/%d %dx%d], bottom-left screenFrame[%d/%d %dx%d], usesGL %d\n", (int)crt_idx, + (int)dBounds.origin.x, (int)dBounds.origin.y, (int)dBounds.size.width, (int)dBounds.size.height, + (int)sFrame.origin.x, (int)sFrame.origin.y, (int)sFrame.size.width, (int)sFrame.size.height, + (int)usesGL); +#endif - jintArray properties = (*env)->NewIntArray(env, 2); + jsize propCount = MIN_MONITOR_DEVICE_PROPERTIES - 1 - NUM_MONITOR_MODE_PROPERTIES; + jint prop[ propCount ]; + int offset = 0; + prop[offset++] = propCount; + prop[offset++] = crt_idx; + prop[offset++] = (jint) sizeMM.width; + prop[offset++] = (jint) sizeMM.height; + prop[offset++] = (jint) dBounds.origin.x; // rotated viewport x (pixel units, will be fixed in java code) + prop[offset++] = (jint) dBounds.origin.y; // rotated viewport y (pixel units, will be fixed in java code) + prop[offset++] = (jint) dBounds.size.width; // rotated viewport width (pixel units, will be fixed in java code) + prop[offset++] = (jint) dBounds.size.height; // rotated viewport height (pixel units, will be fixed in java code) + prop[offset++] = (jint) dBounds.origin.x; // rotated viewport x (window units, will be fixed in java code) + prop[offset++] = (jint) dBounds.origin.y; // rotated viewport y (window units, will be fixed in java code) + prop[offset++] = (jint) dBounds.size.width; // rotated viewport width (window units, will be fixed in java code) + prop[offset++] = (jint) dBounds.size.height; // rotated viewport height (window units, will be fixed in java code) + + jintArray properties = (*env)->NewIntArray(env, propCount); if (properties == NULL) { - NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size 2"); + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", propCount); } - (*env)->SetIntArrayRegion(env, properties, 0, 2, prop); + (*env)->SetIntArrayRegion(env, properties, 0, propCount, prop); [pool release]; @@ -374,16 +541,26 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getScree /* * Class: jogamp_newt_driver_macosx_ScreenDriver - * Method: getScreenMode0 - * Signature: (IIII)[I + * Method: getMonitorMode0 + * Signature: (II)[I */ -JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getScreenMode0 - (JNIEnv *env, jobject obj, jint scrn_idx, jint mode_idx, jint widthMM, jint heightMM) +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getMonitorMode0 + (JNIEnv *env, jobject obj, jint crt_idx, jint mode_idx) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - int prop_num = NUM_SCREEN_MODE_PROPERTIES_ALL; - NSScreen *screen = NewtScreen_getNSScreenByIndex((int)scrn_idx); + NSScreen *screen = NewtScreen_getNSScreenByIndex((int)crt_idx, false); + if( NULL == screen ) { + [pool release]; + return NULL; + } + CGFloat pixelScale = 1.0; // default +NS_DURING + // Available >= 10.7 + pixelScale = [screen backingScaleFactor]; // HiDPI scaling +NS_HANDLER +NS_ENDHANDLER + CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen); CFArrayRef availableModes = CGDisplayAvailableModes(display); @@ -392,12 +569,13 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getScree CFDictionaryRef mode = NULL; int currentCCWRot = (int)CGDisplayRotation(display); jint ccwRot = 0; + int nativeId = 0; #ifdef VERBOSE_ON if(0 >= mode_idx) { // only for current mode (-1) and first mode (scanning) - DBG_PRINT( "getScreenMode0: scrn %d (%p, %p), mode %d, avail: %d/%d, current rot %d ccw\n", - (int)scrn_idx, screen, (void*)(intptr_t)display, (int)mode_idx, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots, currentCCWRot); + DBG_PRINT( "getScreenMode0: scrn %d (s %p, d %p, pscale %lf), mode %d, avail: %d/%d, current rot %d ccw\n", + (int)crt_idx, screen, (void*)(intptr_t)display, pixelScale, (int)mode_idx, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots, currentCCWRot); } #endif @@ -406,21 +584,27 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getScree DBG_PRINT( "getScreenMode0: end of modes: mode %d, avail: %d/%d\n", (int)mode_idx, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots); [pool release]; - return (*env)->NewIntArray(env, 0); + return NULL; } else if(-1 < mode_idx) { // only at initialization time, where index >= 0 - prop_num++; // add 1st extra prop, mode_idx - mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, mode_idx / ROTMODES_PER_REALMODE); + nativeId = mode_idx / ROTMODES_PER_REALMODE; ccwRot = mode_idx % ROTMODES_PER_REALMODE * 90; + mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, nativeId); } else { // current mode mode = CGDisplayCurrentMode(display); ccwRot = currentCCWRot; + CFRange range = CFRangeMake (0, numberOfAvailableModes); + nativeId = CFArrayGetFirstIndexOfValue(availableModes, range, (CFDictionaryRef)mode); } // mode = CGDisplayModeRetain(mode); // 10.6 on CGDisplayModeRef int mWidth = CGDDGetModeWidth(mode); int mHeight = CGDDGetModeHeight(mode); + if( -1 == mode_idx ) { + mWidth *= (int)pixelScale; // accomodate HiDPI + mHeight *= (int)pixelScale; // accomodate HiDPI + } // swap width and height, since OSX reflects rotated dimension, we don't if ( 90 == currentCCWRot || 270 == currentCCWRot ) { @@ -429,36 +613,30 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getScree mHeight = tempWidth; } - jint prop[ prop_num ]; + jint prop[ NUM_MONITOR_MODE_PROPERTIES_ALL ]; int propIndex = 0; - int propIndexRes = 0; - if( -1 < mode_idx ) { - prop[propIndex++] = mode_idx; - } int refreshRate = CGDDGetModeRefreshRate(mode); int fRefreshRate = ( 0 < refreshRate ) ? refreshRate : 60; // default .. (experienced on OSX 10.6.8) - prop[propIndex++] = 0; // set later for verification of iterator - propIndexRes = propIndex; + prop[propIndex++] = NUM_MONITOR_MODE_PROPERTIES_ALL; prop[propIndex++] = mWidth; prop[propIndex++] = mHeight; prop[propIndex++] = CGDDGetModeBitsPerPixel(mode); - prop[propIndex++] = widthMM; - prop[propIndex++] = heightMM; - prop[propIndex++] = fRefreshRate; + prop[propIndex++] = fRefreshRate * 100; // Hz*100 + prop[propIndex++] = 0; // flags + prop[propIndex++] = nativeId; prop[propIndex++] = ccwRot; - prop[propIndex - NUM_SCREEN_MODE_PROPERTIES_ALL] = ( -1 < mode_idx ) ? propIndex-1 : propIndex ; // count == NUM_SCREEN_MODE_PROPERTIES_ALL - - DBG_PRINT( "getScreenMode0: Mode %d/%d (%d): %dx%d, %d bpp, %dx%d mm, %d / %d Hz, rot %d ccw\n", + + DBG_PRINT( "getScreenMode0: Mode %d/%d (%d): %dx%d, %d bpp, %d / %d Hz, nativeId %d, rot %d ccw\n", (int)mode_idx, (int)numberOfAvailableModesRots, (int)numberOfAvailableModes, - (int)prop[propIndexRes+0], (int)prop[propIndexRes+1], (int)prop[propIndexRes+2], - (int)prop[propIndexRes+3], (int)prop[propIndexRes+4], (int)prop[propIndexRes+5], refreshRate, (int)prop[propIndexRes+6]); + (int)prop[1], (int)prop[2], (int)prop[3], + (int)prop[4], refreshRate, (int)prop[6], (int)prop[7]); - jintArray properties = (*env)->NewIntArray(env, prop_num); + jintArray properties = (*env)->NewIntArray(env, NUM_MONITOR_MODE_PROPERTIES_ALL); if (properties == NULL) { - NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", prop_num); + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", NUM_MONITOR_MODE_PROPERTIES_ALL); } - (*env)->SetIntArrayRegion(env, properties, 0, prop_num, prop); + (*env)->SetIntArrayRegion(env, properties, 0, NUM_MONITOR_MODE_PROPERTIES_ALL, prop); // CGDisplayModeRelease(mode); // 10.6 on CGDisplayModeRef [pool release]; @@ -468,36 +646,47 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getScree /* * Class: jogamp_newt_driver_macosx_ScreenDriver - * Method: setScreenMode0 - * Signature: (II)Z + * Method: setMonitorMode0 + * Signature: (III)Z */ -JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_setScreenMode0 - (JNIEnv *env, jobject object, jint scrn_idx, jint mode_idx) +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_setMonitorMode0 + (JNIEnv *env, jobject object, jint crt_idx, jint nativeId, jint ccwRot) { jboolean res = JNI_TRUE; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSScreen *screen = NewtScreen_getNSScreenByIndex((int)scrn_idx); + NSScreen *screen = NewtScreen_getNSScreenByIndex((int)crt_idx, false); + if( NULL == screen ) { + [pool release]; + return JNI_FALSE; + } CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen); CFArrayRef availableModes = CGDisplayAvailableModes(display); -#ifdef VERBOSE_ON CFIndex numberOfAvailableModes = CFArrayGetCount(availableModes); +#ifdef VERBOSE_ON CFIndex numberOfAvailableModesRots = ROTMODES_PER_REALMODE * numberOfAvailableModes; #endif - CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, mode_idx / ROTMODES_PER_REALMODE); - // mode = CGDisplayModeRetain(mode); // 10.6 on CGDisplayModeRef - int ccwRot = mode_idx % ROTMODES_PER_REALMODE * 90; - DBG_PRINT( "setScreenMode0: scrn %d (%p, %p), mode %d, rot %d ccw, avail: %d/%d\n", - (int)scrn_idx, screen, (void*)(intptr_t)display, (int)mode_idx, ccwRot, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots); + DBG_PRINT( "setScreenMode0: scrn %d (%p, %p), nativeID %d, rot %d ccw, avail: %d/%d\n", + (int)crt_idx, screen, (void*)(intptr_t)display, (int)nativeId, ccwRot, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots); + + CFDictionaryRef mode = NULL; - if(ccwRot!=0) { + if( 0 != ccwRot ) { // FIXME: How to rotate the display/screen on OSX programmatically ? DBG_PRINT( "setScreenMode0: Don't know how to rotate screen on OS X: rot %d ccw\n", ccwRot); res = JNI_FALSE; + } else { + if( numberOfAvailableModes <= nativeId ) { + res = JNI_FALSE; + } else { + mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, nativeId); + // mode = CGDisplayModeRetain(mode); // 10.6 on CGDisplayModeRef + } } - if(JNI_TRUE == res) { + + if( NULL != mode ) { CGError err = CGDisplaySwitchToMode(display, mode); if(kCGErrorSuccess != err) { DBG_PRINT( "setScreenMode0: SetMode failed: %d\n", (int)err); @@ -526,6 +715,8 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_initIDs0 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NewtScreen_dump(); + jclass c; c = (*env)->FindClass(env, ClazzNamePoint); if(NULL==c) { @@ -553,48 +744,106 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_initIDs0 return (jboolean) res; } -/* +/** + * Class: jogamp_newt_driver_macosx_WindowDriver + * Method: createView0 + * Signature: (IIII)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_createView0 + (JNIEnv *env, jobject jthis, jint x, jint y, jint w, jint h) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + DBG_PRINT( "createView0 - %p (this), %d/%d %dx%d (START)\n", + (void*)(intptr_t)jthis, (int)x, (int)y, (int)w, (int)h); + + NSRect rectView = NSMakeRect(0, 0, w, h); + NewtView *myView = [[NewtView alloc] initWithFrame: rectView] ; + DBG_PRINT( "createView0.X - new view: %p\n", myView); + + [pool release]; + + return (jlong) (intptr_t) myView; +} + +/** + * Method creates a deferred un-initialized Window, hence no special invocation required inside method. + * * Class: jogamp_newt_driver_macosx_WindowDriver * Method: createWindow0 - * Signature: (JIIIIZIIIJ)J + * Signature: (IIIIZIIJ)J */ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_createWindow0 - (JNIEnv *env, jobject jthis, jlong parent, jint x, jint y, jint w, jint h, jboolean opaque, jboolean fullscreen, jint styleMask, - jint bufferingType, jint screen_idx, jlong jview) + (JNIEnv *env, jobject jthis, jint x, jint y, jint w, jint h, + jboolean fullscreen, jint styleMask, jint bufferingType, jlong jview) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtView* myView = (NewtView*) (intptr_t) jview ; - DBG_PRINT( "createWindow0 - %p (this), %p (parent), %d/%d %dx%d, opaque %d, fs %d, style %X, buffType %X, screenidx %d, view %p (START)\n", - (void*)(intptr_t)jthis, (void*)(intptr_t)parent, (int)x, (int)y, (int)w, (int)h, (int) opaque, (int)fullscreen, - (int)styleMask, (int)bufferingType, (int)screen_idx, myView); - - NSArray *screens = [NSScreen screens]; - if(screen_idx<0) screen_idx=0; - if(screen_idx>=[screens count]) screen_idx=0; - NSScreen *myScreen = (NSScreen *) [screens objectAtIndex: screen_idx]; - NSRect rect; + DBG_PRINT( "createWindow0 - %p (this), %d/%d %dx%d, fs %d, style %X, buffType %X, view %p (START)\n", + (void*)(intptr_t)jthis, (int)x, (int)y, (int)w, (int)h, (int)fullscreen, + (int)styleMask, (int)bufferingType, myView); + (void)myView; if (fullscreen) { styleMask = NSBorderlessWindowMask; - rect = [myScreen frame]; - x = 0; - y = 0; - w = (jint) (rect.size.width); - h = (jint) (rect.size.height); - } else { - rect = NSMakeRect(x, y, w, h); } + NSRect rectWin = NSMakeRect(x, y, w, h); // Allocate the window - NewtMacWindow* myWindow = [[NewtMacWindow alloc] initWithContentRect: rect + NewtMacWindow* myWindow = [[NewtMacWindow alloc] initWithContentRect: rectWin styleMask: (NSUInteger) styleMask backing: (NSBackingStoreType) bufferingType - defer: NO - screen: myScreen + defer: YES isFullscreenWindow: fullscreen]; - [myWindow setReleasedWhenClosed: YES]; // default + // DBG_PRINT( "createWindow0.1 - %p, isVisible %d\n", myWindow, [myWindow isVisible]); + + DBG_PRINT( "createWindow0.X - %p, isVisible %d\n", myWindow, [myWindow isVisible]); + + [pool release]; + + return (jlong) ((intptr_t) myWindow); +} + +/** + * Method is called on Main-Thread, hence no special invocation required inside method. + * + * Class: jogamp_newt_driver_macosx_WindowDriver + * Method: initWindow0 + * Signature: (JJIIIIFZZZJ)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_initWindow0 + (JNIEnv *env, jobject jthis, jlong parent, jlong window, jint x, jint y, jint w, jint h, jfloat reqPixelScale, + jboolean opaque, jboolean visible, jlong jview) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NewtMacWindow* myWindow = (NewtMacWindow*) ((intptr_t) window); + NewtView* myView = (NewtView*) (intptr_t) jview ; + BOOL fullscreen = myWindow->isFullscreenWindow; + + DBG_PRINT( "initWindow0 - %p (this), %p (parent), %p (window), %d/%d %dx%d, reqPixScale %f, opaque %d, fs %d, visible %d, view %p (START)\n", + (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, (int)x, (int)y, (int)w, (int)h, (float)reqPixelScale, + (int) opaque, (int)fullscreen, (int)visible, myView); + +NS_DURING + // HiDPI scaling: Setup - Available >= 10.7 + if( 1.0 == reqPixelScale ) { + [myView setWantsBestResolutionOpenGLSurface: NO]; + } else { + [myView setWantsBestResolutionOpenGLSurface: YES]; + } +NS_HANDLER +NS_ENDHANDLER + + [myWindow setReleasedWhenClosed: NO]; // We control NSWindow destruction! [myWindow setPreservesContentDuringLiveResize: NO]; +NS_DURING + if ( [myWindow respondsToSelector:@selector(setRestorable:)] ) { + // Available >= 10.7 - Removes restauration 'feature', really close + [myWindow setRestorable: NO]; + } +NS_HANDLER +NS_ENDHANDLER NSObject* nsParentObj = (NSObject*) ((intptr_t) parent); NSWindow* parentWindow = NULL; @@ -602,15 +851,15 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_createWindow if( nsParentObj != NULL && [nsParentObj isKindOfClass:[NSWindow class]] ) { parentWindow = (NSWindow*) nsParentObj; parentView = [parentWindow contentView]; - DBG_PRINT( "createWindow0 - Parent is NSWindow : %p (win) -> %p (view) \n", parentWindow, parentView); + DBG_PRINT( "initWindow0 - Parent is NSWindow : %p (win) -> %p (view) \n", parentWindow, parentView); } else if( nsParentObj != NULL && [nsParentObj isKindOfClass:[NSView class]] ) { parentView = (NSView*) nsParentObj; parentWindow = [parentView window]; - DBG_PRINT( "createWindow0 - Parent is NSView : %p -(view) > %p (win) \n", parentView, parentWindow); + DBG_PRINT( "initWindow0 - Parent is NSView : %p -(view) > %p (win) \n", parentView, parentWindow); } else { - DBG_PRINT( "createWindow0 - Parent is neither NSWindow nor NSView : %p\n", nsParentObj); + DBG_PRINT( "initWindow0 - Parent is neither NSWindow nor NSView : %p\n", nsParentObj); } - DBG_PRINT( "createWindow0 - is visible.1: %d\n", [myWindow isVisible]); + DBG_PRINT( "initWindow0 - is visible.1: %d\n", [myWindow isVisible]); // Remove animations for child windows if(NULL != parentWindow) { @@ -628,11 +877,11 @@ NS_ENDHANDLER #endif if(opaque) { [myWindow setOpaque: YES]; - DBG_PRINT( "createWindow0.%d\n", dbgIdx++); + DBG_PRINT( "initWindow0.%d\n", dbgIdx++); if (!fullscreen) { [myWindow setShowsResizeIndicator: YES]; } - DBG_PRINT( "createWindow0.%d\n", dbgIdx++); + DBG_PRINT( "initWindow0.%d\n", dbgIdx++); } else { [myWindow setOpaque: NO]; [myWindow setBackgroundColor: [NSColor clearColor]]; @@ -640,35 +889,29 @@ NS_ENDHANDLER // specify we want mouse-moved events [myWindow setAcceptsMouseMovedEvents:YES]; - DBG_PRINT( "createWindow0.%d\n", dbgIdx++); - // Use given NewtView or allocate an NewtView if NULL - if(NULL == myView) { - myView = [[NewtView alloc] initWithFrame: rect] ; - DBG_PRINT( "createWindow0.%d - use new view: %p,%d\n", dbgIdx++, myView, getRetainCount(myView)); - } else { - DBG_PRINT( "createWindow0.%d - use given view: %p,%d\n", dbgIdx++, myView, getRetainCount(myView)); - } - - DBG_PRINT( "createWindow0.%d - %p,%d view %p,%d, isVisible %d\n", - dbgIdx++, myWindow, getRetainCount(myWindow), myView, getRetainCount(myView), [myWindow isVisible]); + DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", + dbgIdx++, myWindow, myView, [myWindow isVisible]); // Set the content view - changeContentView(env, jthis, parentView, myWindow, myView); + changeContentView(env, jthis, parentView, myWindow, myView, NO); + [myWindow setInitialFirstResponder: myView]; - DBG_PRINT( "createWindow0.%d - %p,%d view %p,%d, isVisible %d\n", - dbgIdx++, myWindow, getRetainCount(myWindow), myView, getRetainCount(myView), [myWindow isVisible]); + DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", + dbgIdx++, myWindow, myView, [myWindow isVisible]); if(NULL!=parentWindow) { [myWindow attachToParent: parentWindow]; } - // Immediately re-position the window based on an upper-left coordinate system - setFrameTopLeftPoint(parentWindow, myWindow, x, y); + DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d, visible %d\n", + dbgIdx++, myWindow, myView, [myWindow isVisible], visible); - // force surface creation - [myView lockFocus]; - [myView unlockFocus]; + // Immediately re-position this window based on an upper-left coordinate system + setWindowClientTopLeftPointAndSize(myWindow, x, y, w, h, NO); + + DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", + dbgIdx++, myWindow, myView, [myWindow isVisible]); NS_DURING // concurrent view rendering @@ -676,49 +919,115 @@ NS_DURING if ( [myWindow respondsToSelector:@selector(setAllowsConcurrentViewDrawing:)] ) { [myWindow setAllowsConcurrentViewDrawing: YES]; } + + DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", + dbgIdx++, myWindow, myView, [myWindow isVisible]); + if ( [myView respondsToSelector:@selector(setCanDrawConcurrently:)] ) { [myView setCanDrawConcurrently: YES]; } NS_HANDLER NS_ENDHANDLER + DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", + dbgIdx++, myWindow, myView, [myWindow isVisible]); + // visible on front - [myWindow orderFront: myWindow]; + if( visible ) { + [myWindow orderFront: myWindow]; + } + + DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", + dbgIdx++, myWindow, myView, [myWindow isVisible]); + + // force surface creation + // [myView lockFocus]; + // [myView unlockFocus]; + + // Set the next responder to be the window so that we can forward + // right mouse button down events + [myView setNextResponder: myWindow]; + + DBG_PRINT( "initWindow0.%d - %p (this), %p (parent): new window: %p, view %p\n", + dbgIdx++, (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, myView); + + [myView setDestroyNotifySent: false]; + setJavaWindowObject(env, jthis, myView, YES); + + DBG_PRINT( "initWindow0.%d - %p (this), %p (parent): new window: %p, view %p\n", + dbgIdx++, (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, myView); NS_DURING - // Available >= 10.5 - Makes the menubar disapear - if(fullscreen) { + if( fullscreen ) { + /** + * See Bug 914: We don't use exclusive fullscreen anymore (capturing display) + * allowing ALT-TAB to allow process/app switching! + * Shall have no penalty on modern GPU and is also recommended, see bottom box @ + * <https://developer.apple.com/library/mac/documentation/graphicsimaging/Conceptual/QuartzDisplayServicesConceptual/Articles/DisplayCapture.html> + * + NSScreen *myScreen = NewtScreen_getNSScreenByCoord(x, y); if ( [myView respondsToSelector:@selector(enterFullScreenMode:withOptions:)] ) { + // Available >= 10.5 - Makes the menubar disapear [myView enterFullScreenMode: myScreen withOptions:NULL]; + } */ + if( myWindow->hasPresentationSwitch ) { + DBG_PRINT( "initWindow0.%d - %p view %p, setPresentationOptions 0x%X\n", + dbgIdx++, myWindow, myView, (int)myWindow->fullscreenPresentationOptions); + [NSApp setPresentationOptions: myWindow->fullscreenPresentationOptions]; } } NS_HANDLER NS_ENDHANDLER - // Set the next responder to be the window so that we can forward - // right mouse button down events - [myView setNextResponder: myWindow]; - - DBG_PRINT( "createWindow0 - %p (this), %p (parent): new window: %p, view %p,%d (END)\n", - (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, myView, getRetainCount(myView)); + DBG_PRINT( "initWindow0.%d - %p (this), %p (parent): new window: %p, view %p\n", + dbgIdx++, (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, myView); [pool release]; - - return (jlong) ((intptr_t) myWindow); + DBG_PRINT( "initWindow0.X - %p (this), %p (parent): new window: %p, view %p\n", + (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, myView); } -// Footnote: Our view handling produces random 'Assertion failure' even w/o parenting: -// -// [NSThemeFrame lockFocus], /SourceCache/AppKit/AppKit-1138.23/AppKit.subproj/NSView.m:6053 -// [NSThemeFrame(0x7fe94bc72c80) lockFocus] failed with window=0x7fe94bc445a0, windowNumber=9425, [self isHiddenOrHasHiddenAncestor]=0 -// .. -// AppKit 0x00007fff89621001 -[NSView lockFocus] + 250 -// AppKit 0x00007fff8961eafa -[NSView _displayRectIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:] + 3780 -// AppKit 0x00007fff8961793e -[NSView displayIfNeeded] + 1676 -// AppKit 0x00007fff8961707d _handleWindowNeedsDisplayOrLayoutOrUpdateConstraints + 648 -// +/** + * Method is called on Main-Thread, hence no special invocation required inside method. + * + * Class: jogamp_newt_driver_macosx_WindowDriver + * Method: setPixelScale0 + * Signature: (JJF)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setPixelScale0 + (JNIEnv *env, jobject jthis, jlong window, jlong view, jfloat reqPixelScale) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NewtMacWindow* myWindow = (NewtMacWindow*) ((intptr_t) window); + NewtView* myView = (NewtView*) (intptr_t) view ; +#ifdef VERBOSE_ON + int dbgIdx = 1; +#endif + + DBG_PRINT( "setPixelScale0 - %p (this), %p (window), view %p, reqPixScale %f (START)\n", + (void*)(intptr_t)jthis, myWindow, myView, (float)reqPixelScale); -/* +NS_DURING + // HiDPI scaling: Setup - Available >= 10.7 + if( 1.0 == reqPixelScale ) { + [myView setWantsBestResolutionOpenGLSurface: NO]; + } else { + [myView setWantsBestResolutionOpenGLSurface: YES]; + } +NS_HANDLER +NS_ENDHANDLER + + DBG_PRINT( "setPixelScale0.%d - %p (this), window: %p, view %p\n", + dbgIdx++, (void*)(intptr_t)jthis, myWindow, myView); + + [pool release]; + DBG_PRINT( "setPixelScale0.X - %p (this), window: %p, view %p\n", + (void*)(intptr_t)jthis, myWindow, myView); +} + +/** + * Method is called on Main-Thread, hence no special invocation required inside method. + * * Class: jogamp_newt_driver_macosx_WindowDriver * Method: close0 * Signature: (J)V @@ -726,31 +1035,50 @@ NS_ENDHANDLER JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_close0 (JNIEnv *env, jobject unused, jlong window) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtMacWindow* mWin = (NewtMacWindow*) ((intptr_t) window); + if( NULL == mWin ) { + DBG_PRINT( "windowClose.0 - NULL NEWT win - abort\n"); + return; + } + BOOL isNSWin = [mWin isKindOfClass:[NSWindow class]]; + BOOL isNewtWin = [mWin isKindOfClass:[NewtMacWindow class]]; + NSWindow *pWin = [mWin parentWindow]; + DBG_PRINT( "windowClose.0 - %p [isNSWindow %d, isNewtWin %d], parent %p\n", mWin, isNSWin, isNewtWin, pWin); + (void)isNSWin; // silence + if( !isNewtWin ) { + NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtView* mView = (NewtView *)[mWin contentView]; - NSWindow* pWin = [mWin parentWindow]; - BOOL destroyNotifySent = (NULL != mView) ? [mView getDestroyNotifySent] : false; + BOOL fullscreen = mWin->isFullscreenWindow; + BOOL destroyNotifySent, isNSView, isNewtView; + if( NULL != mView ) { + isNSView = [mView isKindOfClass:[NSView class]]; + isNewtView = [mView isKindOfClass:[NewtView class]]; + destroyNotifySent = isNewtView ? [mView getDestroyNotifySent] : false; + } else { + isNSView = false; + isNewtView = false; + destroyNotifySent = false; + } - DBG_PRINT( "windowClose.0 - %p,%d, destroyNotifySent %d, view %p,%d, parent %p\n", - mWin, getRetainCount(mWin), destroyNotifySent, mView, getRetainCount(mView), pWin); + DBG_PRINT( "windowClose.0 - %p, destroyNotifySent %d, view %p [isNSView %d, isNewtView %d], fullscreen %d, parent %p\n", + mWin, destroyNotifySent, mView, isNSView, isNewtView, (int)fullscreen, pWin); - [mWin setUnrealized]; + [mWin setRealized: NO]; - if(NULL!=mView) { + if( isNewtView ) { // cleanup view - jobject javaWindowObject = [mView getJavaWindowObject]; [mView setDestroyNotifySent: true]; - if(NULL!=javaWindowObject) { - DBG_PRINT( "windowClose.0: Clear global javaWindowObject reference (%p)\n", javaWindowObject); - (*env)->DeleteGlobalRef(env, javaWindowObject); - [mView setJavaWindowObject: NULL]; - } + setJavaWindowObject(env, NULL, mView, NO); } NS_DURING + /** + * See Bug 914: We don't use exclusive fullscreen anymore (capturing display) + * See initWindow0(..) above .. if(NULL!=mView) { - // Available >= 10.5 - Makes the menubar disapear BOOL iifs; if ( [mView respondsToSelector:@selector(isInFullScreenMode)] ) { iifs = [mView isInFullScreenMode]; @@ -760,9 +1088,15 @@ NS_DURING if(iifs && [mView respondsToSelector:@selector(exitFullScreenModeWithOptions:)] ) { [mView exitFullScreenModeWithOptions: NULL]; } - // Note: mWin's release will also release it's mView! - // [mWin setContentView: nil]; - // [mView release]; + } */ + // Note: mWin's release will also release it's mView! + DBG_PRINT( "windowClose.1a - %p view %p, fullscreen %d, hasPresSwitch %d, defaultPresentationOptions 0x%X\n", + mWin, mView, (int)fullscreen, (int)mWin->hasPresentationSwitch, (int)mWin->defaultPresentationOptions); + + if( fullscreen && mWin->hasPresentationSwitch ) { + DBG_PRINT( "windowClose.1b - %p view %p, setPresentationOptions 0x%X\n", + mWin, mView, (int)mWin->defaultPresentationOptions); + [NSApp setPresentationOptions: mWin->defaultPresentationOptions]; } NS_HANDLER NS_ENDHANDLER @@ -770,19 +1104,13 @@ NS_ENDHANDLER if(NULL!=pWin) { [mWin detachFromParent: pWin]; } - [mWin performSelectorOnMainThread:@selector(orderOut:) withObject:mWin waitUntilDone:NO]; + [mWin orderOut: mWin]; - DBG_PRINT( "windowClose.1 - %p,%d view %p,%d, parent %p\n", - mWin, getRetainCount(mWin), mView, getRetainCount(mView), pWin); + DBG_PRINT( "windowClose.2 - %p view %p, parent %p\n", mWin, mView, pWin); - // Only release window, if release is not yet in process. - // E.g. destroyNotifySent:=true set by NewtMacWindow::windowWillClose(), i.e. window-close was clicked. - if(!destroyNotifySent) { - [mWin performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO]; - } + [mWin release]; - DBG_PRINT( "windowClose.X - %p,%d, released %d, view %p,%d, parent %p\n", - mWin, getRetainCount(mWin), !destroyNotifySent, mView, getRetainCount(mView), pWin); + DBG_PRINT( "windowClose.Xp\n"); [pool release]; } @@ -790,16 +1118,16 @@ NS_ENDHANDLER /* * Class: Java_jogamp_newt_driver_macosx_WindowDriver * Method: lockSurface0 - * Signature: (J)Z + * Signature: (JJ)Z */ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_lockSurface0 - (JNIEnv *env, jclass clazz, jlong window) + (JNIEnv *env, jclass clazz, jlong window, jlong view) { NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window); if(NO == [mWin isRealized]) { return JNI_FALSE; } - NewtView * mView = (NewtView *) [mWin contentView]; + NewtView * mView = (NewtView *) ((intptr_t) view); return [mView softLock] == YES ? JNI_TRUE : JNI_FALSE; /** deadlocks, since we render independent of focus return [mView lockFocusIfCanDraw] == YES ? JNI_TRUE : JNI_FALSE; */ @@ -808,14 +1136,15 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_lockSurfa /* * Class: Java_jogamp_newt_driver_macosx_WindowDriver * Method: unlockSurface0 - * Signature: (J)V + * Signature: (JJ)Z */ -JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_unlockSurface0 - (JNIEnv *env, jclass clazz, jlong window) +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_unlockSurface0 + (JNIEnv *env, jclass clazz, jlong window, jlong view) { - NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window); - NewtView * mView = (NewtView *) [mWin contentView]; - [mView softUnlock]; + // NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window); + (void) window; + NewtView * mView = (NewtView *) ((intptr_t) view); + return [mView softUnlock] == YES ? JNI_TRUE : JNI_FALSE; /** deadlocks, since we render independent of focus [mView unlockFocus]; */ } @@ -833,12 +1162,12 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_requestFocus0 #ifdef VERBOSE_ON BOOL hasFocus = [mWin isKeyWindow]; #endif - DBG_PRINT( "requestFocus - window: %p, force %d, hasFocus %d (START)\n", mWin, force, hasFocus); + [mWin setAcceptsMouseMovedEvents: YES]; [mWin makeFirstResponder: nil]; - [mWin performSelectorOnMainThread:@selector(orderFrontRegardless) withObject:nil waitUntilDone:NO]; - [mWin performSelectorOnMainThread:@selector(makeKeyWindow) withObject:nil waitUntilDone:NO]; + [mWin orderFrontRegardless]; + [mWin makeKeyWindow]; DBG_PRINT( "requestFocus - window: %p, force %d (END)\n", mWin, force); @@ -861,10 +1190,10 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_resignFocus0 DBG_PRINT( "requestFocusParent0 - window: %p, parent %p, hasFocus %d (START)\n", mWin, pWin, hasFocus ); if( hasFocus ) { if(NULL != pWin) { - // [mWin performSelectorOnMainThread:@selector(makeFirstResponder:) withObject:pWin waitUntilDone:NO]; - [pWin performSelectorOnMainThread:@selector(makeKeyWindow) withObject:nil waitUntilDone:NO]; + // [mWin makeFirstResponder: pWin]; + [pWin makeKeyWindow]; } else { - [mWin performSelectorOnMainThread:@selector(resignKeyWindow) withObject:nil waitUntilDone:NO]; + [pWin resignKeyWindow]; } } DBG_PRINT( "requestFocusParent0 - window: %p (END)\n", mWin); @@ -881,13 +1210,18 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_orderFront0 (JNIEnv *env, jobject unused, jlong window) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSWindow* win = (NSWindow*) ((intptr_t) window); + NSWindow* mWin = (NSWindow*) ((intptr_t) window); + NSWindow* pWin = [mWin parentWindow]; - DBG_PRINT( "orderFront0 - window: %p (START)\n", win); + DBG_PRINT( "orderFront0 - window: (parent %p) %p visible %d (START)\n", pWin, mWin, [mWin isVisible]); - [win performSelectorOnMainThread:@selector(orderFrontRegardless) withObject:nil waitUntilDone:NO]; + if( NULL == pWin ) { + [mWin orderFrontRegardless]; + } else { + [mWin orderWindow: NSWindowAbove relativeTo: [pWin windowNumber]]; + } - DBG_PRINT( "orderFront0 - window: %p (END)\n", win); + DBG_PRINT( "orderFront0 - window: (parent %p) %p (END)\n", pWin, mWin); [pool release]; } @@ -904,12 +1238,12 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_orderOut0 NSWindow* mWin = (NSWindow*) ((intptr_t) window); NSWindow* pWin = [mWin parentWindow]; - DBG_PRINT( "orderOut0 - window: (parent %p) %p (START)\n", pWin, mWin); + DBG_PRINT( "orderOut0 - window: (parent %p) %p visible %d (START)\n", pWin, mWin, [mWin isVisible]); - if(NULL == pWin) { - [mWin performSelectorOnMainThread:@selector(orderOut:) withObject:mWin waitUntilDone:NO]; + if( NULL == pWin ) { + [mWin orderOut: mWin]; } else { - [mWin performSelectorOnMainThread:@selector(orderBack:) withObject:mWin waitUntilDone:NO]; + [mWin orderWindow: NSWindowOut relativeTo: [pWin windowNumber]]; } DBG_PRINT( "orderOut0 - window: (parent %p) %p (END)\n", pWin, mWin); @@ -941,7 +1275,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setTitle0 /* * Class: jogamp_newt_driver_macosx_WindowDriver - * Method: contentView + * Method: contentView0 * Signature: (J)J */ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_contentView0 @@ -949,38 +1283,38 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_contentView0 { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSWindow* win = (NSWindow*) ((intptr_t) window); + NSView* nsView = [win contentView]; + NewtView* newtView = NULL; - DBG_PRINT( "contentView0 - window: %p (START)\n", win); + if( [nsView isKindOfClass:[NewtView class]] ) { + newtView = (NewtView *) nsView; + } - jlong res = (jlong) ((intptr_t) [win contentView]); + DBG_PRINT( "contentView0 - window: %p, view: %p, newtView %p\n", win, nsView, newtView); - DBG_PRINT( "contentView0 - window: %p (END)\n", win); + jlong res = (jlong) ((intptr_t) nsView); [pool release]; return res; } -/* +/** + * Method is called on Main-Thread, hence no special invocation required inside method. + * * Class: jogamp_newt_driver_macosx_WindowDriver * Method: changeContentView - * Signature: (J)J + * Signature: (J)V */ -JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_changeContentView0 +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_changeContentView0 (JNIEnv *env, jobject jthis, jlong parentWindowOrView, jlong window, jlong jview) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtView* newView = (NewtView *) ((intptr_t) jview); NewtMacWindow* win = (NewtMacWindow*) ((intptr_t) window); - NSView* oldNSView = [win contentView]; - NewtView* oldView = NULL; - if( [oldNSView isMemberOfClass:[NewtView class]] ) { - oldView = (NewtView *) oldNSView; - } - - DBG_PRINT( "changeContentView0.0 - win %p, view (%p,%d (%d) -> %p,%d)\n", - win, oldNSView, getRetainCount(oldNSView), NULL!=oldView, newView, getRetainCount(newView)); + DBG_PRINT( "changeContentView0.0 - win %p, view (%p,%d)\n", + win, newView, getRetainCount(newView)); NSObject *nsParentObj = (NSObject*) ((intptr_t) parentWindowOrView); NSView* pView = NULL; @@ -993,62 +1327,49 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_changeConten } } - changeContentView(env, jthis, pView, win, newView); + changeContentView(env, jthis, pView, win, newView, YES); - DBG_PRINT( "changeContentView0.X - win %p, view (%p,%d (%d) -> %p,%d)\n", - win, oldNSView, getRetainCount(oldNSView), NULL!=oldView, newView, getRetainCount(newView)); + DBG_PRINT( "changeContentView0.X\n"); [pool release]; - - return (jlong) ((intptr_t) oldView); } /* * Class: jogamp_newt_driver_macosx_WindowDriver - * Method: setContentSize - * Signature: (JII)V + * Method: setWindowClientTopLeftPointAndSize0 + * Signature: (JIIIIZ)V */ -JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setContentSize0 - (JNIEnv *env, jobject unused, jlong window, jint w, jint h) +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setWindowClientTopLeftPointAndSize0 + (JNIEnv *env, jobject unused, jlong window, jint x, jint y, jint w, jint h, jboolean display) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSWindow* win = (NSWindow*) ((intptr_t) window); + NewtMacWindow* mWin = (NewtMacWindow*) ((intptr_t) window); - DBG_PRINT( "setContentSize0 - window: %p (START)\n", win); + DBG_PRINT( "setWindowClientTopLeftPointAndSize - window: %p (START)\n", mWin); - NSSize sz = NSMakeSize(w, h); - [win setContentSize: sz]; + setWindowClientTopLeftPointAndSize(mWin, x, y, w, h, display); - DBG_PRINT( "setContentSize0 - window: %p (END)\n", win); + DBG_PRINT( "setWindowClientTopLeftPointAndSize - window: %p (END)\n", mWin); [pool release]; } /* * Class: jogamp_newt_driver_macosx_WindowDriver - * Method: setFrameTopLeftPoint - * Signature: (JJII)V + * Method: setWindowClientTopLeftPoint0 + * Signature: (JIIZ)V */ -JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setFrameTopLeftPoint0 - (JNIEnv *env, jobject unused, jlong parent, jlong window, jint x, jint y) +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setWindowClientTopLeftPoint0 + (JNIEnv *env, jobject unused, jlong window, jint x, jint y, jboolean display) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NewtMacWindow* mWin = (NewtMacWindow*) ((intptr_t) window); - NSObject *nsParentObj = (NSObject*) ((intptr_t) parent); - NSWindow* pWin = NULL; - if( nsParentObj != NULL && [nsParentObj isKindOfClass:[NSWindow class]] ) { - pWin = (NSWindow*) nsParentObj; - } else if( nsParentObj != NULL && [nsParentObj isKindOfClass:[NSView class]] ) { - NSView* pView = (NSView*) nsParentObj; - pWin = [pView window]; - } - - DBG_PRINT( "setFrameTopLeftPoint0 - window: %p, parent %p (START)\n", mWin, pWin); + DBG_PRINT( "setWindowClientTopLeftPoint - window: %p (START)\n", mWin); - setFrameTopLeftPoint(pWin, mWin, x, y); + setWindowClientTopLeftPoint(mWin, x, y, display); - DBG_PRINT( "setFrameTopLeftPoint0 - window: %p, parent %p (END)\n", mWin, pWin); + DBG_PRINT( "setWindowClientTopLeftPoint - window: %p (END)\n", mWin); [pool release]; } @@ -1064,7 +1385,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setAlwaysOnTo NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSWindow* win = (NSWindow*) ((intptr_t) window); - DBG_PRINT( "setAlwaysOnTop0 - window: %p (START)\n", win); + DBG_PRINT( "setAlwaysOnTop0 - window: %p, atop %d (START)\n", win, (int)atop); if(atop) { [win setLevel:NSFloatingWindowLevel]; @@ -1072,7 +1393,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setAlwaysOnTo [win setLevel:NSNormalWindowLevel]; } - DBG_PRINT( "setAlwaysOnTop0 - window: %p (END)\n", win); + DBG_PRINT( "setAlwaysOnTop0 - window: %p, atop %d (END)\n", win, (int)atop); [pool release]; } @@ -1085,31 +1406,60 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setAlwaysOnTo JNIEXPORT jobject JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_getLocationOnScreen0 (JNIEnv *env, jclass unused, jlong win, jint src_x, jint src_y) { - NSObject *nsObj = (NSObject*) ((intptr_t) win); - NewtMacWindow * mWin = NULL; - - if( [nsObj isKindOfClass:[NewtMacWindow class]] ) { - mWin = (NewtMacWindow*) nsObj; - } else { - NewtCommon_throwNewRuntimeException(env, "not NewtMacWindow %p\n", nsObj); + NewtMacWindow *mWin = (NewtMacWindow*) (intptr_t) win; + if( ![mWin isKindOfClass:[NewtMacWindow class]] ) { + NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin); + return NULL; } - NSPoint p0 = [mWin getLocationOnScreen: NSMakePoint(src_x, src_y)]; return (*env)->NewObject(env, pointClz, pointCstr, (jint)p0.x, (jint)p0.y); } +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setPointerIcon0 + (JNIEnv *env, jobject unused, jlong window, jlong handle) +{ + NSCursor *c = (NSCursor*) (intptr_t) handle ; + if ( NULL != c && NO == [c isKindOfClass:[NSCursor class]] ) { + NewtCommon_throwNewRuntimeException(env, "Not a NSCursor %p", c); + return; + } + NewtMacWindow *mWin = (NewtMacWindow*) (intptr_t) window; + if( ! [mWin isKindOfClass:[NewtMacWindow class]] ) { + NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin); + return; + } + NewtView* nView = (NewtView *) [mWin contentView]; + if( ! [nView isKindOfClass:[NewtView class]] ) { + NewtCommon_throwNewRuntimeException(env, "Not a NewtView %p", nView); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [nView setPointerIcon: c]; + [pool release]; +} + /* * Class: Java_jogamp_newt_driver_macosx_WindowDriver * Method: setPointerVisible0 * Signature: (JZ)Z */ -JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setPointerVisible0 +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setPointerVisible0 (JNIEnv *env, jclass clazz, jlong window, jboolean hasFocus, jboolean mouseVisible) { NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window); - [mWin setMouseVisible: ( JNI_TRUE == mouseVisible ) ? YES : NO - hasFocus: ( JNI_TRUE == hasFocus ) ? YES : NO]; - return JNI_TRUE; + if( ! [mWin isKindOfClass:[NewtMacWindow class]] ) { + NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin); + return; + } + NewtView* nView = (NewtView *) [mWin contentView]; + if( ! [nView isKindOfClass:[NewtView class]] ) { + NewtCommon_throwNewRuntimeException(env, "Not a NewtView %p", nView); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [nView setMouseVisible: ( JNI_TRUE == mouseVisible ) ? YES : NO + hasFocus: ( JNI_TRUE == hasFocus ) ? YES : NO]; + [pool release]; } /* @@ -1117,12 +1467,22 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_setPointe * Method: confinePointer0 * Signature: (JZ)Z */ -JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_confinePointer0 +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_confinePointer0 (JNIEnv *env, jclass clazz, jlong window, jboolean confine) { NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window); - [mWin setMouseConfined: ( JNI_TRUE == confine ) ? YES : NO]; - return JNI_TRUE; + if( ! [mWin isKindOfClass:[NewtMacWindow class]] ) { + NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin); + return; + } + NewtView* nView = (NewtView *) [mWin contentView]; + if( ! [nView isKindOfClass:[NewtView class]] ) { + NewtCommon_throwNewRuntimeException(env, "Not a NewtView %p", nView); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [nView setMouseConfined: ( JNI_TRUE == confine ) ? YES : NO]; + [pool release]; } /* @@ -1134,6 +1494,17 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_WindowDriver_warpPointer0 (JNIEnv *env, jclass clazz, jlong window, jint x, jint y) { NewtMacWindow *mWin = (NewtMacWindow*) ((intptr_t) window); - [mWin setMousePosition: [mWin newtClientWinPos2OSXScreenPos: NSMakePoint(x, y)]]; + if( ! [mWin isKindOfClass:[NewtMacWindow class]] ) { + NewtCommon_throwNewRuntimeException(env, "Not a NewtMacWindow %p", mWin); + return; + } + NewtView* nView = (NewtView *) [mWin contentView]; + if( ! [nView isKindOfClass:[NewtView class]] ) { + NewtCommon_throwNewRuntimeException(env, "Not a NewtView %p", nView); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [nView setMousePosition: [mWin newtRelClientTLWinPos2AbsBLScreenPos: NSMakePoint(x, y)]]; + [pool release]; } diff --git a/src/newt/native/NewtCommon.c b/src/newt/native/NewtCommon.c index 7f070e7d3..231d6182f 100644 --- a/src/newt/native/NewtCommon.c +++ b/src/newt/native/NewtCommon.c @@ -5,17 +5,43 @@ static const char * const ClazzNameRuntimeException = "java/lang/RuntimeException"; static jclass runtimeExceptionClz=NULL; +static JavaVM *_jvmHandle = NULL; +static int _jvmVersion = 0; + +void NewtCommon_init(JNIEnv *env) { + if(NULL==_jvmHandle) { + if(0 != (*env)->GetJavaVM(env, &_jvmHandle)) { + NewtCommon_FatalError(env, "NEWT: Can't fetch JavaVM handle"); + } else { + _jvmVersion = (*env)->GetVersion(env); + } + jclass c = (*env)->FindClass(env, ClazzNameRuntimeException); + if(NULL==c) { + NewtCommon_FatalError(env, "NEWT: Can't find %s", ClazzNameRuntimeException); + } + runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==runtimeExceptionClz) { + NewtCommon_FatalError(env, "NEWT: Can't use %s", ClazzNameRuntimeException); + } + } +} + void NewtCommon_FatalError(JNIEnv *env, const char* msg, ...) { char buffer[512]; va_list ap; - va_start(ap, msg); - vsnprintf(buffer, sizeof(buffer), msg, ap); - va_end(ap); + if( NULL != msg ) { + va_start(ap, msg); + vsnprintf(buffer, sizeof(buffer), msg, ap); + va_end(ap); - fprintf(stderr, "%s\n", buffer); - (*env)->FatalError(env, buffer); + fprintf(stderr, "%s\n", buffer); + if(NULL != env) { + (*env)->FatalError(env, buffer); + } + } } void NewtCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...) @@ -23,23 +49,18 @@ void NewtCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...) char buffer[512]; va_list ap; - va_start(ap, msg); - vsnprintf(buffer, sizeof(buffer), msg, ap); - va_end(ap); + if(NULL==_jvmHandle) { + NewtCommon_FatalError(env, "NEWT: NULL JVM handle, call NewtCommon_init 1st\n"); + return; + } - (*env)->ThrowNew(env, runtimeExceptionClz, buffer); -} + if( NULL != msg ) { + va_start(ap, msg); + vsnprintf(buffer, sizeof(buffer), msg, ap); + va_end(ap); -void NewtCommon_init(JNIEnv *env) { - if(NULL==runtimeExceptionClz) { - jclass c = (*env)->FindClass(env, ClazzNameRuntimeException); - if(NULL==c) { - NewtCommon_FatalError(env, "NEWT: can't find %s", ClazzNameRuntimeException); - } - runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); - (*env)->DeleteLocalRef(env, c); - if(NULL==runtimeExceptionClz) { - NewtCommon_FatalError(env, "NEWT: can't use %s", ClazzNameRuntimeException); + if(NULL != env) { + (*env)->ThrowNew(env, runtimeExceptionClz, buffer); } } } @@ -65,37 +86,57 @@ const char * NewtCommon_GetStaticStringMethod(JNIEnv *jniEnv, jclass clazz, jmet jchar* NewtCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) { jchar* strChars = NULL; - strChars = calloc((*env)->GetStringLength(env, str) + 1, sizeof(jchar)); - if (strChars != NULL) { - (*env)->GetStringRegion(env, str, 0, (*env)->GetStringLength(env, str), strChars); + if( NULL != env && 0 != str ) { + strChars = calloc((*env)->GetStringLength(env, str) + 1, sizeof(jchar)); + if (strChars != NULL) { + (*env)->GetStringRegion(env, str, 0, (*env)->GetStringLength(env, str), strChars); + } } return strChars; } -JNIEnv* NewtCommon_GetJNIEnv(JavaVM * jvmHandle, int jvmVersion, int * shallBeDetached) { +JNIEnv* NewtCommon_GetJNIEnv(int asDaemon, int * shallBeDetached) { JNIEnv* curEnv = NULL; JNIEnv* newEnv = NULL; int envRes; + if(NULL==_jvmHandle) { + fprintf(stderr, "NEWT GetJNIEnv: NULL JVM handle, call NewtCommon_init 1st\n"); + return NULL; + } + // retrieve this thread's JNIEnv curEnv - or detect it's detached - envRes = (*jvmHandle)->GetEnv(jvmHandle, (void **) &curEnv, jvmVersion) ; + envRes = (*_jvmHandle)->GetEnv(_jvmHandle, (void **) &curEnv, _jvmVersion) ; if( JNI_EDETACHED == envRes ) { // detached thread - attach to JVM - if( JNI_OK != ( envRes = (*jvmHandle)->AttachCurrentThread(jvmHandle, (void**) &newEnv, NULL) ) ) { - fprintf(stderr, "JNIEnv: can't attach thread: %d\n", envRes); + if( asDaemon ) { + envRes = (*_jvmHandle)->AttachCurrentThreadAsDaemon(_jvmHandle, (void**) &newEnv, NULL); + } else { + envRes = (*_jvmHandle)->AttachCurrentThread(_jvmHandle, (void**) &newEnv, NULL); + } + if( JNI_OK != envRes ) { + fprintf(stderr, "NEWT GetJNIEnv: Can't attach thread: %d\n", envRes); return NULL; } curEnv = newEnv; } else if( JNI_OK != envRes ) { // oops .. - fprintf(stderr, "can't GetEnv: %d\n", envRes); + fprintf(stderr, "NEWT GetJNIEnv: Can't GetEnv: %d\n", envRes); return NULL; } if (curEnv==NULL) { - fprintf(stderr, "env is NULL\n"); + fprintf(stderr, "NEWT GetJNIEnv: env is NULL\n"); return NULL; } *shallBeDetached = NULL != newEnv; return curEnv; } +void NewtCommon_ReleaseJNIEnv (int shallBeDetached) { + if(NULL == _jvmHandle) { + fprintf(stderr, "NEWT ReleaseJNIEnv: No JavaVM handle registered, call NewtCommon_init(..) 1st"); + } else if(shallBeDetached) { + (*_jvmHandle)->DetachCurrentThread(_jvmHandle); + } +} + diff --git a/src/newt/native/NewtCommon.h b/src/newt/native/NewtCommon.h index 9a4e5ac70..43db72b5b 100644 --- a/src/newt/native/NewtCommon.h +++ b/src/newt/native/NewtCommon.h @@ -42,23 +42,18 @@ void NewtCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...); /** * - * 1) Store jvmHandle and jvmVersion + * 1) Init static jvmHandle, jvmVersion and clazz references + * from an early initialization call w/ valid 'JNIEnv * env' - JavaVM *jvmHandle = NULL; - int jvmVersion = 0; - - if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { - jvmHandle = NULL; - } else { - jvmVersion = (*env)->GetVersion(env); - } + NewtCommon_init(env); * * 2) Use current thread JNIEnv or attach current thread to JVM, generating new JNIEnv * + int asDaemon = 0; int shallBeDetached = 0; - JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + JNIEnv* env = NewtCommon_GetJNIEnv(asDaemon, &shallBeDetached); if(NULL==env) { DBG_PRINT("drawRect: null JNIEnv\n"); return; @@ -70,12 +65,13 @@ void NewtCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...); .. your JNIEnv code here .. * - * 4) Detach thread from JVM, if required + * 4) Detach thread from JVM if required, i.e. not attached as daemon! + * Not recommended for recurring _daemon_ threads (performance) * - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } + NativewindowCommon_ReleaseJNIEnv(shallBeDetached); */ -JNIEnv* NewtCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int * shallBeDetached); +JNIEnv* NewtCommon_GetJNIEnv (int asDaemon, int * shallBeDetached); + +void NewtCommon_ReleaseJNIEnv (int shallBeDetached); #endif diff --git a/src/newt/native/NewtMacWindow.h b/src/newt/native/NewtMacWindow.h index c0912ad3c..0f80df2d7 100644 --- a/src/newt/native/NewtMacWindow.h +++ b/src/newt/native/NewtMacWindow.h @@ -41,53 +41,55 @@ // #define VERBOSE_ON 1 #ifdef VERBOSE_ON - #define DBG_PRINT(...) NSLog(@ __VA_ARGS__) + #define DBG_PRINT(...) NSLog(@ __VA_ARGS__) ; fflush(stderr) // #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) #else #define DBG_PRINT(...) #endif +// #define DBG_LIFECYCLE 1 + +NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx, BOOL cap); +NSScreen * NewtScreen_getNSScreenByCoord(int x, int y); +CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen); + @interface NewtView : NSView { jobject javaWindowObject; - // This is set while messages are being dispatched and cleared afterward - JavaVM *jvmHandle; - int jvmVersion; - volatile BOOL destroyNotifySent; - volatile BOOL softLocked; + volatile int softLockCount; pthread_mutex_t softLockSync; - NSTrackingRectTag ptrTrackingTag; + volatile NSTrackingRectTag ptrTrackingTag; NSRect ptrRect; NSCursor * myCursor; + BOOL modsDown[4]; // shift, ctrl, alt/option, win/command + + BOOL mouseConfined; + BOOL mouseInside; + BOOL mouseVisible; + BOOL cursorIsHidden; + NSPoint lastInsideMousePosition; } - (id)initWithFrame:(NSRect)frameRect; + +#ifdef DBG_LIFECYCLE - (void) release; +#endif - (void) dealloc; -/* Set during event dispatching cycle */ -- (void) setJVMHandle: (JavaVM*) vm; -- (JavaVM*) getJVMHandle; -- (void) setJVMVersion: (int) ver; -- (int) getJVMVersion; - /* Register or deregister (NULL) the java Window object, ie, if NULL, no events are send */ - (void) setJavaWindowObject: (jobject) javaWindowObj; - (jobject) getJavaWindowObject; -- (void) rightMouseDown: (NSEvent*) theEvent; -- (void) resetCursorRects; -- (NSCursor *) cursor; - - (void) setDestroyNotifySent: (BOOL) v; - (BOOL) getDestroyNotifySent; - (BOOL) softLock; -- (void) softUnlock; +- (BOOL) softUnlock; - (BOOL) needsDisplay; - (void) displayIfNeeded; @@ -96,6 +98,42 @@ - (void) viewDidHide; - (void) viewDidUnhide; - (BOOL) acceptsFirstResponder; +- (BOOL) becomeFirstResponder; +- (BOOL) resignFirstResponder; + +- (void) removeCursorRects; +- (void) addCursorRects; +- (void) removeMyCursor; +- (void) resetCursorRects; +- (void) setPointerIcon: (NSCursor*)c; +- (void) mouseEntered: (NSEvent*) theEvent; +- (void) mouseExited: (NSEvent*) theEvent; +- (BOOL) updateMouseInside; +- (void) cursorHide:(BOOL)v enter:(int)enterState; +- (void) setPointerIcon:(NSCursor*)c; +- (void) setMouseVisible:(BOOL)v hasFocus:(BOOL)focus; +- (BOOL) isMouseVisible; +- (void) setMouseConfined:(BOOL)v; +- (void) setMousePosition:(NSPoint)p; +- (void) mouseMoved: (NSEvent*) theEvent; +- (void) scrollWheel: (NSEvent*) theEvent; +- (void) mouseDown: (NSEvent*) theEvent; +- (void) mouseDragged: (NSEvent*) theEvent; +- (void) mouseUp: (NSEvent*) theEvent; +- (void) rightMouseDown: (NSEvent*) theEvent; +- (void) rightMouseDragged: (NSEvent*) theEvent; +- (void) rightMouseUp: (NSEvent*) theEvent; +- (void) otherMouseDown: (NSEvent*) theEvent; +- (void) otherMouseDragged: (NSEvent*) theEvent; +- (void) otherMouseUp: (NSEvent*) theEvent; +- (void) sendMouseEvent: (NSEvent*) event eventType: (jshort) evType; +- (NSPoint) screenPos2NewtClientWinPos: (NSPoint) p; + +- (void) handleFlagsChanged:(NSUInteger) mods; +- (void) handleFlagsChanged:(int) keyMask keyIndex: (int) keyIdx keyCode: (int) keyCode modifiers: (NSUInteger) mods; +- (void) sendKeyEvent: (NSEvent*) event eventType: (jshort) evType; +- (void) sendKeyEvent: (jshort) keyCode characters: (NSString*) chars modifiers: (NSUInteger)mods eventType: (jshort) evType; +- (void) viewDidChangeBackingProperties; @end @@ -105,14 +143,12 @@ @interface NewtMacWindow : NSWindow #endif { - BOOL isFullscreenWindow; - BOOL mouseConfined; - BOOL mouseVisible; - BOOL mouseInside; - BOOL cursorIsHidden; BOOL realized; - NSPoint lastInsideMousePosition; @public + BOOL hasPresentationSwitch; + NSUInteger defaultPresentationOptions; + NSUInteger fullscreenPresentationOptions; + BOOL isFullscreenWindow; int cachedInsets[4]; // l, r, t, b } @@ -122,32 +158,31 @@ styleMask: (NSUInteger) windowStyle backing: (NSBackingStoreType) bufferingType defer: (BOOL) deferCreation - screen:(NSScreen *)screen isFullscreenWindow:(BOOL)isfs; +#ifdef DBG_LIFECYCLE - (void) release; +#endif - (void) dealloc; -- (void) setUnrealized; +- (void) setRealized: (BOOL)v; - (BOOL) isRealized; -- (void) updateInsets: (JNIEnv*) env; +- (void) updateInsets: (JNIEnv*) env jwin: (jobject) javaWin; - (void) attachToParent: (NSWindow*) parent; - (void) detachFromParent: (NSWindow*) parent; -- (NSPoint) newtScreenWinPos2OSXScreenPos: (NSPoint) p; -- (NSPoint) newtClientWinPos2OSXScreenPos: (NSPoint) p; +- (NSPoint) newtAbsClientTLWinPos2AbsBLScreenPos: (NSPoint) p; +- (NSPoint) newtAbsClientTLWinPos2AbsBLScreenPos: (NSPoint) p size: (NSSize) nsz; +- (NSPoint) newtRelClientTLWinPos2AbsBLScreenPos: (NSPoint) p; +- (NSSize) newtClientSize2TLSize: (NSSize) nsz; - (NSPoint) getLocationOnScreen: (NSPoint) p; -- (NSPoint) screenPos2NewtClientWinPos: (NSPoint) p; - -- (BOOL) isMouseInside; -- (void) cursorHide:(BOOL)v; -- (void) setMouseVisible:(BOOL)v hasFocus:(BOOL)focus; -- (void) setMouseConfined:(BOOL)v; -- (void) setMousePosition:(NSPoint)p; -- (void) sendKeyEvent: (NSEvent*) event eventType: (jint) evType; -- (void) sendMouseEvent: (NSEvent*) event eventType: (jint) evType; - (void) focusChanged: (BOOL) gained; +- (void) keyDown: (NSEvent*) theEvent; +- (void) keyUp: (NSEvent*) theEvent; +- (void) flagsChanged: (NSEvent *) theEvent; +- (BOOL) acceptsMouseMovedEvents; +- (BOOL) acceptsFirstResponder; - (BOOL) becomeFirstResponder; - (BOOL) resignFirstResponder; - (BOOL) canBecomeKeyWindow; @@ -155,20 +190,7 @@ - (void) resignKeyWindow; - (void) windowDidBecomeKey: (NSNotification *) notification; - (void) windowDidResignKey: (NSNotification *) notification; -- (void) keyDown: (NSEvent*) theEvent; -- (void) keyUp: (NSEvent*) theEvent; -- (void) mouseEntered: (NSEvent*) theEvent; -- (void) mouseExited: (NSEvent*) theEvent; -- (void) mouseMoved: (NSEvent*) theEvent; -- (void) scrollWheel: (NSEvent*) theEvent; -- (void) mouseDown: (NSEvent*) theEvent; -- (void) mouseDragged: (NSEvent*) theEvent; -- (void) mouseUp: (NSEvent*) theEvent; -- (void) rightMouseDown: (NSEvent*) theEvent; -- (void) rightMouseDragged: (NSEvent*) theEvent; -- (void) rightMouseUp: (NSEvent*) theEvent; -- (void) otherMouseDown: (NSEvent*) theEvent; -- (void) otherMouseUp: (NSEvent*) theEvent; + - (void) windowDidResize: (NSNotification*) notification; - (void) windowDidMove: (NSNotification*) notification; - (BOOL) windowClosingImpl: (BOOL) force; diff --git a/src/newt/native/NewtMacWindow.m b/src/newt/native/NewtMacWindow.m index b58b99e38..caf9e54e0 100644 --- a/src/newt/native/NewtMacWindow.m +++ b/src/newt/native/NewtMacWindow.m @@ -36,70 +36,171 @@ #import "KeyEvent.h" #import "MouseEvent.h" -jint GetDeltaY(NSEvent *event, jint javaMods) { - CGFloat deltaY = 0.0; +#include <CoreFoundation/CoreFoundation.h> +#include <Carbon/Carbon.h> /* For kVK_ constants, and TIS functions. */ + +#include <math.h> + +#define PRINTF(...) NSLog(@ __VA_ARGS__) + +static jfloat GetDelta(NSEvent *event, jint javaMods[]) { CGEventRef cgEvent = [event CGEvent]; + CGFloat deltaY = 0.0; + CGFloat deltaX = 0.0; + CGFloat delta = 0.0; if (CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventIsContinuous)) { // mouse pad case - deltaY = - CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis1); - // fprintf(stderr, "WHEEL/PAD: %lf\n", (double)deltaY); + deltaX = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis2); + deltaY = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis1); + // fprintf(stderr, "WHEEL/PAD: %lf/%lf - 0x%X\n", (double)deltaX, (double)deltaY, javaMods[0]); + if( fabsf(deltaX) > fabsf(deltaY) ) { + javaMods[0] |= EVENT_SHIFT_MASK; + delta = deltaX; + } else { + delta = deltaY; + } } else { // traditional mouse wheel case + deltaX = [event deltaX]; deltaY = [event deltaY]; - // fprintf(stderr, "WHEEL/TRAD: %lf\n", (double)deltaY); - if (deltaY == 0.0 && (javaMods & EVENT_SHIFT_MASK) != 0) { + // fprintf(stderr, "WHEEL/TRACK: %lf/%lf - 0x%X\n", (double)deltaX, (double)deltaY, javaMods[0]); + if (deltaY == 0.0 && (javaMods[0] & EVENT_SHIFT_MASK) != 0) { // shift+vertical wheel scroll produces horizontal scroll // we convert it to vertical - deltaY = [event deltaX]; + delta = deltaX; + } else { + delta = deltaY; } - if (-1.0 < deltaY && deltaY < 1.0) { - deltaY *= 10.0; + if (-1.0 < delta && delta < 1.0) { + delta *= 10.0; } else { - if (deltaY < 0.0) { - deltaY = deltaY - 0.5f; + if (delta < 0.0) { + delta = delta - 0.5f; } else { - deltaY = deltaY + 0.5f; + delta = delta + 0.5f; + } + } + } + // fprintf(stderr, "WHEEL/RES: %lf - 0x%X\n", (double)delta, javaMods[0]); + return (jfloat) delta; +} + +#define kVK_Shift 0x38 +#define kVK_Option 0x3A +#define kVK_Control 0x3B +#define kVK_Command 0x37 + +static jint mods2JavaMods(NSUInteger mods) +{ + int javaMods = 0; + if (mods & NSShiftKeyMask) { + javaMods |= EVENT_SHIFT_MASK; + } + if (mods & NSControlKeyMask) { + javaMods |= EVENT_CTRL_MASK; + } + if (mods & NSCommandKeyMask) { + javaMods |= EVENT_META_MASK; + } + if (mods & NSAlternateKeyMask) { + javaMods |= EVENT_ALT_MASK; + } + return javaMods; +} + +static CFStringRef CKCH_CreateStringForKey(CGKeyCode keyCode, const UCKeyboardLayout *keyboardLayout) { + UInt32 keysDown = 0; + UniChar chars[4]; + UniCharCount realLength; + + UCKeyTranslate(keyboardLayout, keyCode, + kUCKeyActionDisplay, 0, + LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit, + &keysDown, sizeof(chars) / sizeof(chars[0]), &realLength, chars); + + return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1); +} + +static CFMutableDictionaryRef CKCH_CreateCodeToCharDict(TISInputSourceRef keyboard) { + CFDataRef layoutData = (CFDataRef) TISGetInputSourceProperty(keyboard, kTISPropertyUnicodeKeyLayoutData); + if( NULL == layoutData ) { + return NULL; + } + const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); + + CFMutableDictionaryRef codeToCharDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 128, NULL, NULL); + if ( NULL != codeToCharDict ) { + intptr_t i; + for (i = 0; i < 128; ++i) { + CFStringRef string = CKCH_CreateStringForKey((CGKeyCode)i, keyboardLayout); + if( NULL != string ) { + CFIndex stringLen = CFStringGetLength (string); + if ( 0 < stringLen ) { + UniChar character = CFStringGetCharacterAtIndex(string, 0); + DBG_PRINT("CKCH: MAP 0x%X -> %c\n", (int)i, character); + CFDictionaryAddValue(codeToCharDict, (const void *)i, (const void *)(intptr_t)character); + } + CFRelease(string); } } } - // fprintf(stderr, "WHEEL/res: %d\n", (int)deltaY); - return (jint) deltaY; + return codeToCharDict; +} + +static CFMutableDictionaryRef CKCH_USCodeToNNChar = NULL; + +static void CKCH_CreateDictionaries() { + TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); + if( NULL != currentKeyboard ) { + CKCH_USCodeToNNChar = CKCH_CreateCodeToCharDict(currentKeyboard); + CFRelease(currentKeyboard); + } +} + +static UniChar CKCH_CharForKeyCode(jshort keyCode) { + UniChar rChar = 0; + + if ( NULL != CKCH_USCodeToNNChar ) { + intptr_t code = (intptr_t) keyCode; + intptr_t character = 0; + + if ( CFDictionaryGetValueIfPresent(CKCH_USCodeToNNChar, (void *)code, (const void **)&character) ) { + rChar = (UniChar) character; + DBG_PRINT("CKCH: OK 0x%X -> 0x%X\n", (int)keyCode, (int)rChar); + } + } + return rChar; } static jmethodID enqueueMouseEventID = NULL; -static jmethodID sendMouseEventID = NULL; static jmethodID enqueueKeyEventID = NULL; -static jmethodID sendKeyEventID = NULL; static jmethodID requestFocusID = NULL; static jmethodID insetsChangedID = NULL; static jmethodID sizeChangedID = NULL; +static jmethodID updatePixelScaleID = NULL; static jmethodID visibleChangedID = NULL; static jmethodID positionChangedID = NULL; static jmethodID focusChangedID = NULL; static jmethodID windowDestroyNotifyID = NULL; static jmethodID windowRepaintID = NULL; -// Can't use USE_SENDIO_DIRECT, ie w/o enqueueing to EDT, +// Need to enqueue all events to EDT, // since we may operate on AWT-AppKit (Main Thread) // and direct issuing 'requestFocus()' would deadlock: // AWT-AppKit // AWT-EventQueue-0 -// -// #define USE_SENDIO_DIRECT 1 @implementation NewtView - (id)initWithFrame:(NSRect)frameRect { + id res = [super initWithFrame:frameRect]; javaWindowObject = NULL; - jvmHandle = NULL; - jvmVersion = 0; destroyNotifySent = NO; - softLocked = NO; + softLockCount = 0; pthread_mutexattr_t softLockSyncAttr; pthread_mutexattr_init(&softLockSyncAttr); @@ -107,59 +208,46 @@ static jmethodID windowRepaintID = NULL; pthread_mutex_init(&softLockSync, &softLockSyncAttr); // recursive ptrTrackingTag = 0; - - /** - NSCursor crs = [NSCursor arrowCursor]; - NSImage crsImg = [crs image]; - NSPoint crsHot = [crs hotSpot]; - myCursor = [[NSCursor alloc] initWithImage: crsImg hotSpot:crsHot]; - */ myCursor = NULL; - return [super initWithFrame:frameRect]; + modsDown[0] = NO; // shift + modsDown[1] = NO; // ctrl + modsDown[2] = NO; // alt + modsDown[3] = NO; // win + mouseConfined = NO; + mouseVisible = YES; + mouseInside = NO; + cursorIsHidden = NO; + + DBG_PRINT("NewtView::create: %p (refcnt %d)\n", res, (int)[res retainCount]); + return res; } +#ifdef DBG_LIFECYCLE - (void) release { -#ifdef VERBOSE_ON - NSLog(@"NewtView::release\n"); - NSLog(@"%@",[NSThread callStackSymbols]); -#endif + DBG_PRINT("NewtView::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); [super release]; } +#endif - (void) dealloc { - if(softLocked) { + DBG_PRINT("NewtView::dealloc.0: %p (refcnt %d), ptrTrackingTag %d\n", self, (int)[self retainCount], (int)ptrTrackingTag); +#ifdef DBG_LIFECYCLE + NSLog(@"%@",[NSThread callStackSymbols]); +#endif + if( 0 < softLockCount ) { NSLog(@"NewtView::dealloc: softLock still hold @ dealloc!\n"); } + [self removeCursorRects]; + [self removeMyCursor]; + pthread_mutex_destroy(&softLockSync); -#ifdef VERBOSE_ON - NSLog(@"NewtView::dealloc\n"); - NSLog(@"%@",[NSThread callStackSymbols]); -#endif + DBG_PRINT("NewtView::dealloc.X: %p\n", self); [super dealloc]; } -- (void) setJVMHandle: (JavaVM*) vm -{ - jvmHandle = vm; -} -- (JavaVM*) getJVMHandle -{ - return jvmHandle; -} - -- (void) setJVMVersion: (int) ver -{ - jvmVersion = ver; -} - -- (int) getJVMVersion -{ - return jvmVersion; -} - - (void) setJavaWindowObject: (jobject) javaWindowObj { javaWindowObject = javaWindowObj; @@ -170,32 +258,6 @@ static jmethodID windowRepaintID = NULL; return javaWindowObject; } -- (void) rightMouseDown: (NSEvent*) theEvent -{ - NSResponder* next = [self nextResponder]; - if (next != nil) { - [next rightMouseDown: theEvent]; - } -} - -- (void) resetCursorRects -{ - [super resetCursorRects]; - - if(0 != ptrTrackingTag) { - // [self removeCursorRect: ptrRect cursor: myCursor]; - [self removeTrackingRect: ptrTrackingTag]; - } - ptrRect = [self bounds]; - // [self addCursorRect: ptrRect cursor: myCursor]; - ptrTrackingTag = [self addTrackingRect: ptrRect owner: self userData: nil assumeInside: NO]; -} - -- (NSCursor *) cursor -{ - return myCursor; -} - - (void) setDestroyNotifySent: (BOOL) v { destroyNotifySent = v; @@ -209,18 +271,27 @@ static jmethodID windowRepaintID = NULL; - (BOOL) softLock { // DBG_PRINT("*************** softLock.0: %p\n", (void*)pthread_self()); - // NSLog(@"NewtView::softLock: %@",[NSThread callStackSymbols]); - pthread_mutex_lock(&softLockSync); - softLocked = YES; + int err; + if( 0 != ( err = pthread_mutex_lock(&softLockSync) ) ) { + NSLog(@"NewtView::softLock failed: errCode %d - %@", err, [NSThread callStackSymbols]); + return NO; + } + softLockCount++; // DBG_PRINT("*************** softLock.X: %p\n", (void*)pthread_self()); - return softLocked; + return 0 < softLockCount; } -- (void) softUnlock +- (BOOL) softUnlock { // DBG_PRINT("*************** softUnlock: %p\n", (void*)pthread_self()); - softLocked = NO; - pthread_mutex_unlock(&softLockSync); + softLockCount--; + int err; + if( 0 != ( err = pthread_mutex_unlock(&softLockSync) ) ) { + softLockCount++; + NSLog(@"NewtView::softUnlock failed: Not locked by current thread - errCode %d - %@", err, [NSThread callStackSymbols]); + return NO; + } + return YES; } - (BOOL) needsDisplay @@ -256,7 +327,7 @@ static jmethodID windowRepaintID = NULL; return; } int shallBeDetached = 0; - JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); if(NULL==env) { DBG_PRINT("drawRect: null JNIEnv\n"); return; @@ -265,12 +336,11 @@ static jmethodID windowRepaintID = NULL; NSRect viewFrame = [self frame]; (*env)->CallVoidMethod(env, javaWindowObject, windowRepaintID, JNI_TRUE, // defer .. - dirtyRect.origin.x, viewFrame.size.height - dirtyRect.origin.y, - dirtyRect.size.width, dirtyRect.size.height); + (int)dirtyRect.origin.x, (int)viewFrame.size.height - (int)dirtyRect.origin.y, + (int)dirtyRect.size.width, (int)dirtyRect.size.height); - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); } - (void) viewDidHide @@ -280,7 +350,7 @@ static jmethodID windowRepaintID = NULL; return; } int shallBeDetached = 0; - JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); if(NULL==env) { DBG_PRINT("viewDidHide: null JNIEnv\n"); return; @@ -288,9 +358,8 @@ static jmethodID windowRepaintID = NULL; (*env)->CallVoidMethod(env, javaWindowObject, visibleChangedID, JNI_FALSE, JNI_FALSE); - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); [super viewDidHide]; } @@ -302,7 +371,7 @@ static jmethodID windowRepaintID = NULL; return; } int shallBeDetached = 0; - JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); if(NULL==env) { DBG_PRINT("viewDidUnhide: null JNIEnv\n"); return; @@ -310,9 +379,8 @@ static jmethodID windowRepaintID = NULL; (*env)->CallVoidMethod(env, javaWindowObject, visibleChangedID, JNI_FALSE, JNI_TRUE); - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); [super viewDidUnhide]; } @@ -322,232 +390,152 @@ static jmethodID windowRepaintID = NULL; return YES; } -@end - -@implementation NewtMacWindow - -+ (BOOL) initNatives: (JNIEnv*) env forClass: (jclass) clazz +- (BOOL) becomeFirstResponder { - enqueueMouseEventID = (*env)->GetMethodID(env, clazz, "enqueueMouseEvent", "(ZIIIIII)V"); - sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIIII)V"); - enqueueKeyEventID = (*env)->GetMethodID(env, clazz, "enqueueKeyEvent", "(ZIIIC)V"); - sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(IIIC)V"); - sizeChangedID = (*env)->GetMethodID(env, clazz, "sizeChanged", "(ZIIZ)V"); - visibleChangedID = (*env)->GetMethodID(env, clazz, "visibleChanged", "(ZZ)V"); - insetsChangedID = (*env)->GetMethodID(env, clazz, "insetsChanged", "(ZIIII)V"); - positionChangedID = (*env)->GetMethodID(env, clazz, "positionChanged", "(ZII)V"); - focusChangedID = (*env)->GetMethodID(env, clazz, "focusChanged", "(ZZ)V"); - windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "(Z)Z"); - windowRepaintID = (*env)->GetMethodID(env, clazz, "windowRepaint", "(ZIIII)V"); - requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V"); - if (enqueueMouseEventID && sendMouseEventID && enqueueKeyEventID && sendKeyEventID && sizeChangedID && visibleChangedID && insetsChangedID && - positionChangedID && focusChangedID && windowDestroyNotifyID && requestFocusID && windowRepaintID) - { - return YES; - } - return NO; + DBG_PRINT( "*************** View.becomeFirstResponder\n"); + return [super becomeFirstResponder]; } -- (id) initWithContentRect: (NSRect) contentRect - styleMask: (NSUInteger) windowStyle - backing: (NSBackingStoreType) bufferingType - defer: (BOOL) deferCreation - screen:(NSScreen *)screen - isFullscreenWindow:(BOOL)isfs +- (BOOL) resignFirstResponder { - id res = [super initWithContentRect: contentRect - styleMask: windowStyle - backing: bufferingType - defer: deferCreation - screen: screen]; - isFullscreenWindow = isfs; - // Why is this necessary? Without it we don't get any of the - // delegate methods like resizing and window movement. - [self setDelegate: self]; - cachedInsets[0] = 0; // l - cachedInsets[1] = 0; // r - cachedInsets[2] = 0; // t - cachedInsets[3] = 0; // b - mouseConfined = NO; - mouseVisible = YES; - mouseInside = NO; - cursorIsHidden = NO; - realized = YES; - return res; + DBG_PRINT( "*************** View.resignFirstResponder\n"); + return [super resignFirstResponder]; } -- (void) release +- (void) removeCursorRects { -#ifdef VERBOSE_ON - NSLog(@"NewtWindow::release\n"); - NSLog(@"%@",[NSThread callStackSymbols]); -#endif - [super release]; + if(0 != ptrTrackingTag) { + if(NULL != myCursor) { + [self removeCursorRect: ptrRect cursor: myCursor]; + } + [self removeTrackingRect: ptrTrackingTag]; + ptrTrackingTag = 0; + } } -- (void) dealloc +- (void) addCursorRects { -#ifdef VERBOSE_ON - NSLog(@"NewtWindow::dealloc\n"); - NSLog(@"%@",[NSThread callStackSymbols]); -#endif - [super dealloc]; + ptrRect = [self bounds]; + if(NULL != myCursor) { + [self addCursorRect: ptrRect cursor: myCursor]; + } + ptrTrackingTag = [self addTrackingRect: ptrRect owner: self userData: nil assumeInside: NO]; } -- (void) setUnrealized +- (void) removeMyCursor { - realized = NO; + if(NULL != myCursor) { + [myCursor release]; + myCursor = NULL; + } } -- (BOOL) isRealized +- (void) resetCursorRects { - return realized; + [super resetCursorRects]; + + [self removeCursorRects]; + [self addCursorRects]; } -- (void) updateInsets: (JNIEnv*) env +- (void) setPointerIcon: (NSCursor*)c { - NSView* nsview = [self contentView]; - if( ! [nsview isMemberOfClass:[NewtView class]] ) { - return; + DBG_PRINT( "setPointerIcon: %p -> %p, top %p, mouseInside %d\n", myCursor, c, [NSCursor currentCursor], (int)mouseInside); + if( c != myCursor ) { + [self removeCursorRects]; + [self removeMyCursor]; + myCursor = c; + if( NULL != myCursor ) { + [myCursor retain]; + } } - NewtView* view = (NewtView *) nsview; - jobject javaWindowObject = [view getJavaWindowObject]; - if (env==NULL || javaWindowObject == NULL) { - return; + NSWindow* nsWin = [self window]; + if( NULL != nsWin ) { + [nsWin invalidateCursorRectsForView: self]; } - - NSRect frameRect = [self frame]; - NSRect contentRect = [self contentRectForFrameRect: frameRect]; - - // note: this is a simplistic implementation which doesn't take - // into account DPI and scaling factor - CGFloat l = contentRect.origin.x - frameRect.origin.x; - cachedInsets[0] = (int)l; // l - cachedInsets[1] = (int)(frameRect.size.width - (contentRect.size.width + l)); // r - cachedInsets[2] = (jint)(frameRect.size.height - contentRect.size.height); // t - cachedInsets[3] = (jint)(contentRect.origin.y - frameRect.origin.y); // b - - DBG_PRINT( "updateInsets: [ l %d, r %d, t %d, b %d ]\n", cachedInsets[0], cachedInsets[1], cachedInsets[2], cachedInsets[3]); - - (*env)->CallVoidMethod(env, javaWindowObject, insetsChangedID, JNI_FALSE, cachedInsets[0], cachedInsets[1], cachedInsets[2], cachedInsets[3]); -} - -- (void) attachToParent: (NSWindow*) parent -{ - DBG_PRINT( "attachToParent.1\n"); - [parent addChildWindow: self ordered: NSWindowAbove]; - DBG_PRINT( "attachToParent.2\n"); - [self setParentWindow: parent]; - DBG_PRINT( "attachToParent.X\n"); } -- (void) detachFromParent: (NSWindow*) parent +- (void) mouseEntered: (NSEvent*) theEvent { - DBG_PRINT( "detachFromParent.1\n"); - [self setParentWindow: nil]; - if(NULL != parent) { - DBG_PRINT( "detachFromParent.2\n"); - [parent removeChildWindow: self]; + DBG_PRINT( "mouseEntered: confined %d, visible %d, PointerIcon %p, top %p\n", mouseConfined, mouseVisible, myCursor, [NSCursor currentCursor]); + mouseInside = YES; + [self cursorHide: !mouseVisible enter: 1]; + if(NO == mouseConfined) { + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_ENTERED]; + } + NSWindow* nsWin = [self window]; + if( NULL != nsWin ) { + [nsWin makeFirstResponder: self]; } - DBG_PRINT( "detachFromParent.X\n"); -} - -/** - * p abs screen position w/ top-left origin - * returns: abs screen position w/ bottom-left origin - */ -- (NSPoint) newtScreenWinPos2OSXScreenPos: (NSPoint) p -{ - NSView* mView = [self contentView]; - NSRect mViewFrame = [mView frame]; - int totalHeight = mViewFrame.size.height + cachedInsets[2] + cachedInsets[3]; // height + insets[top+bottom] - - NSScreen* screen = [self screen]; - NSRect screenFrame = [screen frame]; - - return NSMakePoint(screenFrame.origin.x + p.x + cachedInsets[0], - screenFrame.origin.y + screenFrame.size.height - p.y - totalHeight); } -/** - * p rel client window position w/ top-left origin - * returns: abs screen position w/ bottom-left origin - */ -- (NSPoint) newtClientWinPos2OSXScreenPos: (NSPoint) p +- (void) mouseExited: (NSEvent*) theEvent { - NSRect winFrame = [self frame]; - - NSView* mView = [self contentView]; - NSRect mViewFrame = [mView frame]; - - return NSMakePoint(winFrame.origin.x + p.x, - winFrame.origin.y + ( mViewFrame.size.height - p.y ) ); // y-flip in view + DBG_PRINT( "mouseExited: confined %d, visible %d, PointerIcon %p, top %p\n", mouseConfined, mouseVisible, myCursor, [NSCursor currentCursor]); + if(NO == mouseConfined) { + mouseInside = NO; + [self cursorHide: NO enter: -1]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_EXITED]; + [self resignFirstResponder]; + } else { + [self setMousePosition: lastInsideMousePosition]; + } } /** - * y-flips input / output - * p rel client window position w/ top-left origin - * returns: location in 0/0 top-left space. + * p abs screen position w/ bottom-left origin */ -- (NSPoint) getLocationOnScreen: (NSPoint) p +- (void) setMousePosition:(NSPoint)p { - NSScreen* screen = [self screen]; - NSRect screenRect = [screen frame]; + NSWindow* nsWin = [self window]; + if( NULL != nsWin ) { + NSScreen* screen = [nsWin screen]; - NSView* view = [self contentView]; - NSRect viewFrame = [view frame]; + CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen); + CGRect frameTL = CGDisplayBounds (display); // origin top-left + NSRect frameBL = [screen frame]; // origin bottom-left + CGPoint pt = { p.x, frameTL.origin.y + frameTL.size.height - ( p.y - frameBL.origin.y ) }; // y-flip from BL-screen -> TL-screen - NSRect r; - r.origin.x = p.x; - r.origin.y = viewFrame.size.height - p.y; // y-flip - r.size.width = 0; - r.size.height = 0; - // NSRect rS = [win convertRectToScreen: r]; // 10.7 - NSPoint oS = [self convertBaseToScreen: r.origin]; - oS.y = screenRect.origin.y + screenRect.size.height - oS.y; - return oS; -} + DBG_PRINT( "setMousePosition: point-in[%d/%d], screen tl[%d/%d %dx%d] bl[%d/%d %dx%d] -> %d/%d\n", + (int)p.x, (int)p.y, + (int)frameTL.origin.x, (int)frameTL.origin.y, (int)frameTL.size.width, (int)frameTL.size.height, + (int)frameBL.origin.x, (int)frameBL.origin.y, (int)frameBL.size.width, (int)frameBL.size.height, + (int)pt.x, (int)pt.y); -- (NSPoint) screenPos2NewtClientWinPos: (NSPoint) p -{ - NSView* view = [self contentView]; - NSRect viewFrame = [view frame]; - - NSRect r; - r.origin.x = p.x; - r.origin.y = p.y; - r.size.width = 0; - r.size.height = 0; - // NSRect rS = [win convertRectFromScreen: r]; // 10.7 - NSPoint oS = [self convertScreenToBase: r.origin]; - oS.y = viewFrame.size.height - oS.y; // y-flip - return oS; + CGEventRef ev = CGEventCreateMouseEvent (NULL, kCGEventMouseMoved, pt, kCGMouseButtonLeft); + CGEventPost (kCGHIDEventTap, ev); + } } -- (BOOL) isMouseInside +- (BOOL) updateMouseInside { - NSView* view = [self contentView]; - NSRect viewFrame = [view frame]; + NSRect viewFrame = [self frame]; NSPoint l1 = [NSEvent mouseLocation]; NSPoint l0 = [self screenPos2NewtClientWinPos: l1]; - return viewFrame.origin.x <= l0.x && l0.x < (viewFrame.origin.x+viewFrame.size.width) && - viewFrame.origin.y <= l0.y && l0.y < (viewFrame.origin.y+viewFrame.size.height) ; + mouseInside = viewFrame.origin.x <= l0.x && l0.x < (viewFrame.origin.x+viewFrame.size.width) && + viewFrame.origin.y <= l0.y && l0.y < (viewFrame.origin.y+viewFrame.size.height) ; + return mouseInside; } - (void) setMouseVisible:(BOOL)v hasFocus:(BOOL)focus { mouseVisible = v; - mouseInside = [self isMouseInside]; + [self updateMouseInside]; DBG_PRINT( "setMouseVisible: confined %d, visible %d (current: %d), mouseInside %d, hasFocus %d\n", mouseConfined, mouseVisible, !cursorIsHidden, mouseInside, focus); if(YES == focus && YES == mouseInside) { - [self cursorHide: !mouseVisible]; + [self cursorHide: !mouseVisible enter: 0]; } } +- (BOOL) isMouseVisible +{ + return mouseVisible; +} -- (void) cursorHide:(BOOL)v +- (void) cursorHide:(BOOL)v enter:(int)enterState { - DBG_PRINT( "cursorHide: %d -> %d\n", cursorIsHidden, v); + DBG_PRINT( "cursorHide: %d -> %d, enter %d; PointerIcon: %p, top %p\n", + cursorIsHidden, v, enterState, myCursor, [NSCursor currentCursor]); if(v) { if(!cursorIsHidden) { [NSCursor hide]; @@ -567,108 +555,105 @@ static jmethodID windowRepaintID = NULL; DBG_PRINT( "setMouseConfined: confined %d, visible %d\n", mouseConfined, mouseVisible); } -- (void) setMousePosition:(NSPoint)p +- (void) mouseMoved: (NSEvent*) theEvent { - NSScreen* screen = [self screen]; - NSRect screenRect = [screen frame]; + if( mouseInside ) { + NSCursor * currentCursor = [NSCursor currentCursor]; + BOOL setCursor = NULL != myCursor && NO == cursorIsHidden && currentCursor != myCursor; + DBG_PRINT( "mouseMoved.set: %d; mouseInside %d, CursorHidden %d, PointerIcon: %p, top %p\n", + setCursor, mouseInside, cursorIsHidden, myCursor, currentCursor); + if( setCursor ) { + // FIXME: Workaround missing NSCursor update for 'fast moving' pointer + [myCursor set]; + } + lastInsideMousePosition = [NSEvent mouseLocation]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; + } +} - CGPoint pt = { p.x, screenRect.size.height - p.y }; // y-flip (CG is top-left origin) - CGEventRef ev = CGEventCreateMouseEvent (NULL, kCGEventMouseMoved, pt, kCGMouseButtonLeft); - CGEventPost (kCGHIDEventTap, ev); +- (void) scrollWheel: (NSEvent*) theEvent +{ + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_WHEEL_MOVED]; } -static jint mods2JavaMods(NSUInteger mods) +- (void) mouseDown: (NSEvent*) theEvent { - int javaMods = 0; - if (mods & NSShiftKeyMask) { - javaMods |= EVENT_SHIFT_MASK; - } - if (mods & NSControlKeyMask) { - javaMods |= EVENT_CTRL_MASK; - } - if (mods & NSCommandKeyMask) { - javaMods |= EVENT_META_MASK; - } - if (mods & NSAlternateKeyMask) { - javaMods |= EVENT_ALT_MASK; - } - return javaMods; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; } -- (void) sendKeyEvent: (NSEvent*) event eventType: (jint) evType +- (void) mouseDragged: (NSEvent*) theEvent { - NSView* nsview = [self contentView]; - if( ! [nsview isMemberOfClass:[NewtView class]] ) { - return; - } - NewtView* view = (NewtView *) nsview; - jobject javaWindowObject = [view getJavaWindowObject]; - if (javaWindowObject == NULL) { - DBG_PRINT("sendKeyEvent: null javaWindowObject\n"); - return; - } - int shallBeDetached = 0; - JavaVM *jvmHandle = [view getJVMHandle]; - JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); - if(NULL==env) { - DBG_PRINT("sendKeyEvent: null JNIEnv\n"); - return; + lastInsideMousePosition = [NSEvent mouseLocation]; + // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; +} + +- (void) mouseUp: (NSEvent*) theEvent +{ + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; +} + +- (void) rightMouseDown: (NSEvent*) theEvent +{ + NSResponder* next = [self nextResponder]; + if (next != nil) { + [next rightMouseDown: theEvent]; } + // FIXME: ^^ OR [super rightMouseDown: theEvent] ? + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; +} - int i; - jint keyCode = (jint) [event keyCode]; - NSString* chars = [event charactersIgnoringModifiers]; - int len = [chars length]; - jint javaMods = mods2JavaMods([event modifierFlags]); +- (void) rightMouseDragged: (NSEvent*) theEvent +{ + lastInsideMousePosition = [NSEvent mouseLocation]; + // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; +} - for (i = 0; i < len; i++) { - // Note: the key code in the NSEvent does not map to anything we can use - jchar keyChar = (jchar) [chars characterAtIndex: i]; +- (void) rightMouseUp: (NSEvent*) theEvent +{ + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; +} - DBG_PRINT("sendKeyEvent: %d/%d char 0x%X, code 0x%X\n", i, len, (int)keyChar, (int)keyCode); +- (void) otherMouseDown: (NSEvent*) theEvent +{ + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; +} - #ifdef USE_SENDIO_DIRECT - (*env)->CallVoidMethod(env, javaWindowObject, sendKeyEventID, - evType, javaMods, keyCode, keyChar); - #else - (*env)->CallVoidMethod(env, javaWindowObject, enqueueKeyEventID, JNI_FALSE, - evType, javaMods, keyCode, keyChar); - #endif - } +- (void) otherMouseDragged: (NSEvent*) theEvent +{ + lastInsideMousePosition = [NSEvent mouseLocation]; + // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; +} - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } +- (void) otherMouseUp: (NSEvent*) theEvent +{ + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; } -- (void) sendMouseEvent: (NSEvent*) event eventType: (jint) evType +- (void) sendMouseEvent: (NSEvent*) event eventType: (jshort) evType { - NSView* nsview = [self contentView]; - if( ! [nsview isMemberOfClass:[NewtView class]] ) { - return; - } - NewtView* view = (NewtView *) nsview; - jobject javaWindowObject = [view getJavaWindowObject]; if (javaWindowObject == NULL) { DBG_PRINT("sendMouseEvent: null javaWindowObject\n"); return; } int shallBeDetached = 0; - JavaVM *jvmHandle = [view getJVMHandle]; - JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); if(NULL==env) { DBG_PRINT("sendMouseEvent: null JNIEnv\n"); return; } - jint javaMods = mods2JavaMods([event modifierFlags]); + jint javaMods[] = { 0 } ; + javaMods[0] = mods2JavaMods([event modifierFlags]); // convert to 1-based button number (or use zero if no button is involved) // TODO: detect mouse button when mouse wheel scrolled - jint javaButtonNum = 0; - jint scrollDeltaY = 0; + jshort javaButtonNum = 0; + jfloat scrollDeltaY = 0.0f; switch ([event type]) { case NSScrollWheel: { - scrollDeltaY = GetDeltaY(event, javaMods); + scrollDeltaY = GetDelta(event, javaMods); javaButtonNum = 1; break; } @@ -699,246 +684,537 @@ static jint mods2JavaMods(NSUInteger mods) NSPoint location = [self screenPos2NewtClientWinPos: [NSEvent mouseLocation]]; - #ifdef USE_SENDIO_DIRECT - (*env)->CallVoidMethod(env, javaWindowObject, sendMouseEventID, - evType, javaMods, - (jint) location.x, (jint) location.y, - javaButtonNum, scrollDeltaY); - #else (*env)->CallVoidMethod(env, javaWindowObject, enqueueMouseEventID, JNI_FALSE, - evType, javaMods, + evType, javaMods[0], (jint) location.x, (jint) location.y, javaButtonNum, scrollDeltaY); - #endif - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); +} + +- (NSPoint) screenPos2NewtClientWinPos: (NSPoint) p +{ + NSRect viewFrame = [self frame]; + + NSRect r; + r.origin.x = p.x; + r.origin.y = p.y; + r.size.width = 0; + r.size.height = 0; + // NSRect rS = [[self window] convertRectFromScreen: r]; // 10.7 + NSPoint oS = [[self window] convertScreenToBase: r.origin]; + oS.y = viewFrame.size.height - oS.y; // y-flip + return oS; +} + +- (void) handleFlagsChanged:(NSUInteger) mods +{ + [self handleFlagsChanged: NSShiftKeyMask keyIndex: 0 keyCode: kVK_Shift modifiers: mods]; + [self handleFlagsChanged: NSControlKeyMask keyIndex: 1 keyCode: kVK_Control modifiers: mods]; + [self handleFlagsChanged: NSAlternateKeyMask keyIndex: 2 keyCode: kVK_Option modifiers: mods]; + [self handleFlagsChanged: NSCommandKeyMask keyIndex: 3 keyCode: kVK_Command modifiers: mods]; +} + +- (void) handleFlagsChanged:(int) keyMask keyIndex: (int) keyIdx keyCode: (int) keyCode modifiers: (NSUInteger) mods +{ + if ( NO == modsDown[keyIdx] && 0 != ( mods & keyMask ) ) { + modsDown[keyIdx] = YES; + [self sendKeyEvent: (jshort)keyCode characters: NULL modifiers: mods|keyMask eventType: (jshort)EVENT_KEY_PRESSED]; + } else if ( YES == modsDown[keyIdx] && 0 == ( mods & keyMask ) ) { + modsDown[keyIdx] = NO; + [self sendKeyEvent: (jshort)keyCode characters: NULL modifiers: mods|keyMask eventType: (jshort)EVENT_KEY_RELEASED]; } } -- (void) focusChanged: (BOOL) gained +- (void) sendKeyEvent: (NSEvent*) event eventType: (jshort) evType { - DBG_PRINT( "focusChanged: gained %d\n", gained); - NSView* nsview = [self contentView]; - if( ! [nsview isMemberOfClass:[NewtView class]] ) { + jshort keyCode = (jshort) [event keyCode]; + NSString* chars = [event charactersIgnoringModifiers]; + NSUInteger mods = [event modifierFlags]; + [self sendKeyEvent: keyCode characters: chars modifiers: mods eventType: evType]; +} + +- (void) sendKeyEvent: (jshort) keyCode characters: (NSString*) chars modifiers: (NSUInteger)mods eventType: (jshort) evType +{ + if (javaWindowObject == NULL) { + DBG_PRINT("sendKeyEvent: null javaWindowObject\n"); return; } - NewtView* view = (NewtView *) nsview; - jobject javaWindowObject = [view getJavaWindowObject]; + int shallBeDetached = 0; + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); + if(NULL==env) { + DBG_PRINT("sendKeyEvent: null JNIEnv\n"); + return; + } + + int i; + int len = NULL != chars ? [chars length] : 0; + jint javaMods = mods2JavaMods(mods); + + if(len > 0) { + // printable chars + for (i = 0; i < len; i++) { + // Note: the key code in the NSEvent does not map to anything we can use + UniChar keyChar = (UniChar) [chars characterAtIndex: i]; + UniChar keySymChar = CKCH_CharForKeyCode(keyCode); + + DBG_PRINT("sendKeyEvent: %d/%d code 0x%X, char 0x%X, mods 0x%X/0x%X -> keySymChar 0x%X\n", i, len, (int)keyCode, (int)keyChar, + (int)mods, (int)javaMods, (int)keySymChar); + + (*env)->CallVoidMethod(env, javaWindowObject, enqueueKeyEventID, JNI_FALSE, + evType, javaMods, keyCode, (jchar)keyChar, (jchar)keySymChar); + } + } else { + // non-printable chars + jchar keyChar = (jchar) 0; + + DBG_PRINT("sendKeyEvent: code 0x%X\n", (int)keyCode); + + (*env)->CallVoidMethod(env, javaWindowObject, enqueueKeyEventID, JNI_FALSE, + evType, javaMods, keyCode, keyChar, keyChar); + } + + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); +} + +- (void)viewDidChangeBackingProperties +{ + [super viewDidChangeBackingProperties]; + + // HiDPI scaling + BOOL useHiDPI = [self wantsBestResolutionOpenGLSurface]; + CGFloat pixelScaleNative = [[self window] backingScaleFactor]; + CGFloat pixelScaleUse = useHiDPI ? pixelScaleNative : 1.0; + DBG_PRINT("viewDidChangeBackingProperties: PixelScale: HiDPI %d, native %f -> use %f\n", useHiDPI, (float)pixelScaleNative, (float)pixelScaleUse); + [[self layer] setContentsScale: pixelScaleUse]; + if (javaWindowObject == NULL) { - DBG_PRINT("focusChanged: null javaWindowObject\n"); + DBG_PRINT("viewDidChangeBackingProperties: null javaWindowObject\n"); return; } int shallBeDetached = 0; - JavaVM *jvmHandle = [view getJVMHandle]; - JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); if(NULL==env) { - DBG_PRINT("focusChanged: null JNIEnv\n"); + DBG_PRINT("viewDidChangeBackingProperties: null JNIEnv\n"); return; } - (*env)->CallVoidMethod(env, javaWindowObject, focusChangedID, JNI_FALSE, (gained == YES) ? JNI_TRUE : JNI_FALSE); + (*env)->CallVoidMethod(env, javaWindowObject, updatePixelScaleID, JNI_TRUE, (jfloat)pixelScaleUse, (jfloat)pixelScaleNative); // defer + + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); +} + + +@end + +@implementation NewtMacWindow + ++ (BOOL) initNatives: (JNIEnv*) env forClass: (jclass) clazz +{ + enqueueMouseEventID = (*env)->GetMethodID(env, clazz, "enqueueMouseEvent", "(ZSIIISF)V"); + enqueueKeyEventID = (*env)->GetMethodID(env, clazz, "enqueueKeyEvent", "(ZSISCC)V"); + sizeChangedID = (*env)->GetMethodID(env, clazz, "sizeChanged", "(ZIIZ)V"); + updatePixelScaleID = (*env)->GetMethodID(env, clazz, "updatePixelScale", "(ZFF)V"); + visibleChangedID = (*env)->GetMethodID(env, clazz, "visibleChanged", "(ZZ)V"); + insetsChangedID = (*env)->GetMethodID(env, clazz, "insetsChanged", "(ZIIII)V"); + positionChangedID = (*env)->GetMethodID(env, clazz, "screenPositionChanged", "(ZII)V"); + focusChangedID = (*env)->GetMethodID(env, clazz, "focusChanged", "(ZZ)V"); + windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "(Z)Z"); + windowRepaintID = (*env)->GetMethodID(env, clazz, "windowRepaint", "(ZIIII)V"); + requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V"); + if (enqueueMouseEventID && enqueueKeyEventID && sizeChangedID && updatePixelScaleID && visibleChangedID && insetsChangedID && + positionChangedID && focusChangedID && windowDestroyNotifyID && requestFocusID && windowRepaintID) + { + CKCH_CreateDictionaries(); + return YES; + } + return NO; +} - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); +- (id) initWithContentRect: (NSRect) contentRect + styleMask: (NSUInteger) windowStyle + backing: (NSBackingStoreType) bufferingType + defer: (BOOL) deferCreation + isFullscreenWindow:(BOOL)isfs +{ + id res = [super initWithContentRect: contentRect + styleMask: windowStyle + backing: bufferingType + defer: deferCreation]; + // OSX 10.6 + if ( [NSApp respondsToSelector:@selector(currentSystemPresentationOptions)] && + [NSApp respondsToSelector:@selector(setPresentationOptions:)] ) { + hasPresentationSwitch = YES; + defaultPresentationOptions = [NSApp currentSystemPresentationOptions]; + fullscreenPresentationOptions = + // NSApplicationPresentationDefault| + // NSApplicationPresentationAutoHideDock| + NSApplicationPresentationHideDock| + // NSApplicationPresentationAutoHideMenuBar| + NSApplicationPresentationHideMenuBar| + NSApplicationPresentationDisableAppleMenu| + // NSApplicationPresentationDisableProcessSwitching| + // NSApplicationPresentationDisableSessionTermination| + NSApplicationPresentationDisableHideApplication| + // NSApplicationPresentationDisableMenuBarTransparency| + // NSApplicationPresentationFullScreen| // OSX 10.7 + 0 ; + } else { + hasPresentationSwitch = NO; + defaultPresentationOptions = 0; + fullscreenPresentationOptions = 0; } + + isFullscreenWindow = isfs; + // Why is this necessary? Without it we don't get any of the + // delegate methods like resizing and window movement. + [self setDelegate: self]; + + cachedInsets[0] = 0; // l + cachedInsets[1] = 0; // r + cachedInsets[2] = 0; // t + cachedInsets[3] = 0; // b + + realized = YES; + DBG_PRINT("NewtWindow::create: %p, realized %d, hasPresentationSwitch %d[defaultOptions 0x%X, fullscreenOptions 0x%X], (refcnt %d)\n", + res, realized, (int)hasPresentationSwitch, (int)defaultPresentationOptions, (int)fullscreenPresentationOptions, (int)[res retainCount]); + return res; } -- (BOOL) becomeFirstResponder +#ifdef DBG_LIFECYCLE +- (void) release { - DBG_PRINT( "*************** becomeFirstResponder\n"); - return [super becomeFirstResponder]; + DBG_PRINT("NewtWindow::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"%@",[NSThread callStackSymbols]); + [super release]; } +#endif -- (BOOL) resignFirstResponder +- (void) dealloc { - DBG_PRINT( "*************** resignFirstResponder\n"); - return [super resignFirstResponder]; + DBG_PRINT("NewtWindow::dealloc.0: %p (refcnt %d)\n", self, (int)[self retainCount]); +#ifdef DBG_LIFECYCLE + NSLog(@"%@",[NSThread callStackSymbols]); +#endif + + NewtView* mView = (NewtView *)[self contentView]; + if( NULL != mView ) { + [mView release]; + } + [super dealloc]; + DBG_PRINT("NewtWindow::dealloc.X: %p\n", self); } -- (BOOL) canBecomeKeyWindow +- (void) setRealized: (BOOL)v { - // Even if the window is borderless, we still want it to be able - // to become the key window to receive keyboard events - return YES; + realized = v; } -- (void) becomeKeyWindow +- (BOOL) isRealized { - DBG_PRINT( "*************** becomeKeyWindow\n"); - [super becomeKeyWindow]; + return realized; } -- (void) resignKeyWindow +- (void) updateInsets: (JNIEnv*) env jwin: (jobject) javaWin { - DBG_PRINT( "*************** resignKeyWindow: isFullscreen %d\n", (int)isFullscreenWindow); - if(!isFullscreenWindow) { - [super resignKeyWindow]; + NSRect frameRect = [self frame]; + NSRect contentRect = [self contentRectForFrameRect: frameRect]; + + // note: this is a simplistic implementation which doesn't take + // into account DPI and scaling factor + CGFloat l = contentRect.origin.x - frameRect.origin.x; + cachedInsets[0] = (int)l; // l + cachedInsets[1] = (int)(frameRect.size.width - (contentRect.size.width + l)); // r + cachedInsets[2] = (jint)(frameRect.size.height - contentRect.size.height); // t + cachedInsets[3] = (jint)(contentRect.origin.y - frameRect.origin.y); // b + + DBG_PRINT( "updateInsets: [ l %d, r %d, t %d, b %d ]\n", cachedInsets[0], cachedInsets[1], cachedInsets[2], cachedInsets[3]); + + if( NULL != env && NULL != javaWin ) { + (*env)->CallVoidMethod(env, javaWin, insetsChangedID, JNI_FALSE, cachedInsets[0], cachedInsets[1], cachedInsets[2], cachedInsets[3]); } } -- (void) windowDidBecomeKey: (NSNotification *) notification +- (void) attachToParent: (NSWindow*) parent { - DBG_PRINT( "*************** windowDidBecomeKey\n"); - mouseInside = [self isMouseInside]; - if(YES == mouseInside) { - [self cursorHide: !mouseVisible]; + DBG_PRINT( "attachToParent.1\n"); + [parent addChildWindow: self ordered: NSWindowAbove]; + DBG_PRINT( "attachToParent.2\n"); + [self setParentWindow: parent]; + DBG_PRINT( "attachToParent.X\n"); +} + +- (void) detachFromParent: (NSWindow*) parent +{ + DBG_PRINT( "detachFromParent.1\n"); + [self setParentWindow: nil]; + if(NULL != parent) { + DBG_PRINT( "detachFromParent.2\n"); + [parent removeChildWindow: self]; } - [self focusChanged: YES]; + DBG_PRINT( "detachFromParent.X\n"); } -- (void) windowDidResignKey: (NSNotification *) notification +/** + * p abs screen position of client-area pos w/ top-left origin, using contentView's client NSSize + * returns: abs screen position w/ bottom-left origin + */ +- (NSPoint) newtAbsClientTLWinPos2AbsBLScreenPos: (NSPoint) p { - DBG_PRINT( "*************** windowDidResignKey\n"); - // Implicit mouse exit by OS X - [self focusChanged: NO]; + NSView* mView = [self contentView]; + NSRect mViewFrame = [mView frame]; + return [self newtAbsClientTLWinPos2AbsBLScreenPos: p size: mViewFrame.size]; } -- (void) keyDown: (NSEvent*) theEvent +/** + * p abs screen position of client-area pos w/ top-left origin, using given client NSSize + * returns: abs screen position w/ bottom-left origin + */ +- (NSPoint) newtAbsClientTLWinPos2AbsBLScreenPos: (NSPoint) p size: (NSSize) nsz { - [self sendKeyEvent: theEvent eventType: EVENT_KEY_PRESSED]; + int totalHeight = nsz.height + cachedInsets[3]; // height + insets.bottom + + DBG_PRINT( "newtAbsClientTLWinPos2AbsBLScreenPos: point-in[%d/%d], size-in[%dx%d], insets bottom %d -> totalHeight %d\n", + (int)p.x, (int)p.y, (int)nsz.width, (int)nsz.height, cachedInsets[3], totalHeight); + + NSScreen* screen = [self screen]; + + CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen); + CGRect frameTL = CGDisplayBounds (display); // origin top-left + NSRect frameBL = [screen frame]; // origin bottom-left + NSPoint r = NSMakePoint(p.x, frameBL.origin.y + frameBL.size.height - ( p.y - frameTL.origin.y ) - totalHeight); // y-flip from TL-screen -> BL-screen + + DBG_PRINT( "newtAbsClientTLWinPos2AbsBLScreenPos: screen tl[%d/%d %dx%d] bl[%d/%d %dx%d -> %d/%d\n", + (int)frameTL.origin.x, (int)frameTL.origin.y, (int)frameTL.size.width, (int)frameTL.size.height, + (int)frameBL.origin.x, (int)frameBL.origin.y, (int)frameBL.size.width, (int)frameBL.size.height, + (int)r.x, (int)r.y); + + return r; } -- (void) keyUp: (NSEvent*) theEvent +/** + * p rel client window position w/ top-left origin + * returns: abs screen position w/ bottom-left origin + */ +- (NSPoint) newtRelClientTLWinPos2AbsBLScreenPos: (NSPoint) p { - [self sendKeyEvent: theEvent eventType: EVENT_KEY_RELEASED]; - [self sendKeyEvent: theEvent eventType: EVENT_KEY_TYPED]; + NSRect winFrame = [self frame]; + + NSView* mView = [self contentView]; + NSRect mViewFrame = [mView frame]; + NSPoint r = NSMakePoint(winFrame.origin.x + p.x, + winFrame.origin.y + ( mViewFrame.size.height - p.y ) ); // y-flip in view + + DBG_PRINT( "newtRelClientTLWinPos2AbsBLScreenPos: point-in[%d/%d], winFrame[%d/%d %dx%d], viewFrame[%d/%d %dx%d] -> %d/%d\n", + (int)p.x, (int)p.y, + (int)winFrame.origin.x, (int)winFrame.origin.y, (int)winFrame.size.width, (int)winFrame.size.height, + (int)mViewFrame.origin.x, (int)mViewFrame.origin.y, (int)mViewFrame.size.width, (int)mViewFrame.size.height, + (int)r.x, (int)r.y); + + return r; } -- (void) mouseEntered: (NSEvent*) theEvent +- (NSSize) newtClientSize2TLSize: (NSSize) nsz { - DBG_PRINT( "mouseEntered: confined %d, visible %d\n", mouseConfined, mouseVisible); - mouseInside = YES; - [self cursorHide: !mouseVisible]; - if(NO == mouseConfined) { - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_ENTERED]; + NSSize topSZ = { nsz.width, nsz.height + cachedInsets[2] + cachedInsets[3] }; // height + insets.top + insets.bottom + return topSZ; +} + +/** + * y-flips input / output + * p rel client window position w/ top-left origin + * returns: location in 0/0 top-left space. + */ +- (NSPoint) getLocationOnScreen: (NSPoint) p +{ + NSView* view = [self contentView]; + NSRect viewFrame = [view frame]; + NSRect r; + r.origin.x = p.x; + r.origin.y = viewFrame.size.height - p.y; // y-flip + r.size.width = 0; + r.size.height = 0; + // NSRect rS = [self convertRectToScreen: r]; // 10.7 + NSPoint oS = [self convertBaseToScreen: r.origin]; // BL-screen + + NSScreen* screen = [self screen]; + CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen); + CGRect frameTL = CGDisplayBounds (display); // origin top-left + NSRect frameBL = [screen frame]; // origin bottom-left + oS.y = frameTL.origin.y + frameTL.size.height - ( oS.y - frameBL.origin.y ); // y-flip from BL-screen -> TL-screen + +#ifdef VERBOSE_ON + NSRect winFrame = [self frame]; + DBG_PRINT( "getLocationOnScreen: point-in[%d/%d], winFrame[%d/%d %dx%d], viewFrame[%d/%d %dx%d], screen tl[%d/%d %dx%d] bl[%d/%d %dx%d] -> %d/%d\n", + (int)p.x, (int)p.y, + (int)winFrame.origin.x, (int)winFrame.origin.y, (int)winFrame.size.width, (int)winFrame.size.height, + (int)viewFrame.origin.x, (int)viewFrame.origin.y, (int)viewFrame.size.width, (int)viewFrame.size.height, + (int)frameTL.origin.x, (int)frameTL.origin.y, (int)frameTL.size.width, (int)frameTL.size.height, + (int)frameBL.origin.x, (int)frameBL.origin.y, (int)frameBL.size.width, (int)frameBL.size.height, + (int)oS.x, (int)oS.y); +#endif + + return oS; +} + +- (void) focusChanged: (BOOL) gained +{ + DBG_PRINT( "focusChanged: gained %d\n", gained); + NewtView* newtView = (NewtView *) [self contentView]; + if( ! [newtView isKindOfClass:[NewtView class]] ) { + return; } + jobject javaWindowObject = [newtView getJavaWindowObject]; + if (javaWindowObject == NULL) { + DBG_PRINT("focusChanged: null javaWindowObject\n"); + return; + } + int shallBeDetached = 0; + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); + if(NULL==env) { + DBG_PRINT("focusChanged: null JNIEnv\n"); + return; + } + + (*env)->CallVoidMethod(env, javaWindowObject, focusChangedID, JNI_FALSE, (gained == YES) ? JNI_TRUE : JNI_FALSE); + + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); } -- (void) mouseExited: (NSEvent*) theEvent +- (void) keyDown: (NSEvent*) theEvent { - DBG_PRINT( "mouseExited: confined %d, visible %d\n", mouseConfined, mouseVisible); - if(NO == mouseConfined) { - mouseInside = NO; - [self cursorHide: NO]; - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_EXITED]; - } else { - [self setMousePosition: lastInsideMousePosition]; + NewtView* newtView = (NewtView *) [self contentView]; + if( [newtView isKindOfClass:[NewtView class]] ) { + [newtView sendKeyEvent: theEvent eventType: (jshort)EVENT_KEY_PRESSED]; } } -- (void) mouseMoved: (NSEvent*) theEvent +- (void) keyUp: (NSEvent*) theEvent { - lastInsideMousePosition = [NSEvent mouseLocation]; - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; + NewtView* newtView = (NewtView *) [self contentView]; + if( [newtView isKindOfClass:[NewtView class]] ) { + [newtView sendKeyEvent: theEvent eventType: (jshort)EVENT_KEY_RELEASED]; + } } -- (void) scrollWheel: (NSEvent*) theEvent +- (void) flagsChanged:(NSEvent *) theEvent { - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_WHEEL_MOVED]; + NSUInteger mods = [theEvent modifierFlags]; + NewtView* newtView = (NewtView *) [self contentView]; + if( [newtView isKindOfClass:[NewtView class]] ) { + [newtView handleFlagsChanged: mods]; + } } -- (void) mouseDown: (NSEvent*) theEvent +- (BOOL) acceptsMouseMovedEvents { - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; + return YES; } -- (void) mouseDragged: (NSEvent*) theEvent +- (BOOL) acceptsFirstResponder { - lastInsideMousePosition = [NSEvent mouseLocation]; - // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; + return YES; } -- (void) mouseUp: (NSEvent*) theEvent +- (BOOL) becomeFirstResponder { - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; + DBG_PRINT( "*************** Win.becomeFirstResponder\n"); + return [super becomeFirstResponder]; } -- (void) rightMouseDown: (NSEvent*) theEvent +- (BOOL) resignFirstResponder { - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; + DBG_PRINT( "*************** Win.resignFirstResponder\n"); + return [super resignFirstResponder]; } -- (void) rightMouseDragged: (NSEvent*) theEvent +- (BOOL) canBecomeKeyWindow { - lastInsideMousePosition = [NSEvent mouseLocation]; - // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; + // Even if the window is borderless, we still want it to be able + // to become the key window to receive keyboard events + return YES; } -- (void) rightMouseUp: (NSEvent*) theEvent +- (void) becomeKeyWindow { - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; + DBG_PRINT( "*************** becomeKeyWindow\n"); + [super becomeKeyWindow]; } -- (void) otherMouseDown: (NSEvent*) theEvent +- (void) resignKeyWindow { - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; + DBG_PRINT( "*************** resignKeyWindow: isFullscreen %d\n", (int)isFullscreenWindow); + if(!isFullscreenWindow) { + [super resignKeyWindow]; + } } -- (void) otherMouseDragged: (NSEvent*) theEvent +- (void) windowDidBecomeKey: (NSNotification *) notification { - lastInsideMousePosition = [NSEvent mouseLocation]; - // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; + DBG_PRINT( "*************** windowDidBecomeKey\n"); + NewtView* newtView = (NewtView *) [self contentView]; + if( [newtView isKindOfClass:[NewtView class]] ) { + BOOL mouseInside = [newtView updateMouseInside]; + if(YES == mouseInside) { + [newtView cursorHide: ![newtView isMouseVisible] enter: 1]; + } + } + [self focusChanged: YES]; } -- (void) otherMouseUp: (NSEvent*) theEvent +- (void) windowDidResignKey: (NSNotification *) notification { - [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; + DBG_PRINT( "*************** windowDidResignKey\n"); + // Implicit mouse exit by OS X + [self focusChanged: NO]; } - (void)windowDidResize: (NSNotification*) notification { - NSView* nsview = [self contentView]; - if( ! [nsview isMemberOfClass:[NewtView class]] ) { - return; - } - NewtView* view = (NewtView *) nsview; - jobject javaWindowObject = [view getJavaWindowObject]; - if (javaWindowObject == NULL) { - DBG_PRINT("windowDidResize: null javaWindowObject\n"); - return; - } + jobject javaWindowObject = NULL; int shallBeDetached = 0; - JavaVM *jvmHandle = [view getJVMHandle]; - JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); - if(NULL==env) { + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); + + if( NULL == env ) { DBG_PRINT("windowDidResize: null JNIEnv\n"); return; } + NewtView* newtView = (NewtView *) [self contentView]; + if( [newtView isKindOfClass:[NewtView class]] ) { + javaWindowObject = [newtView getJavaWindowObject]; + } + if( NULL != javaWindowObject ) { + // update insets on every window resize for lack of better hook place + [self updateInsets: env jwin:javaWindowObject]; - // update insets on every window resize for lack of better hook place - [self updateInsets: env]; - - NSRect frameRect = [self frame]; - NSRect contentRect = [self contentRectForFrameRect: frameRect]; - - (*env)->CallVoidMethod(env, javaWindowObject, sizeChangedID, JNI_FALSE, - (jint) contentRect.size.width, - (jint) contentRect.size.height, JNI_FALSE); + NSRect frameRect = [self frame]; + NSRect contentRect = [self contentRectForFrameRect: frameRect]; - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); + (*env)->CallVoidMethod(env, javaWindowObject, sizeChangedID, JNI_TRUE, // defer + (jint) contentRect.size.width, + (jint) contentRect.size.height, JNI_FALSE); } + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); } - (void)windowDidMove: (NSNotification*) notification { - NSView* nsview = [self contentView]; - if( ! [nsview isMemberOfClass:[NewtView class]] ) { + NewtView* newtView = (NewtView *) [self contentView]; + if( ! [newtView isKindOfClass:[NewtView class]] ) { return; } - NewtView* view = (NewtView *) nsview; - jobject javaWindowObject = [view getJavaWindowObject]; + jobject javaWindowObject = [newtView getJavaWindowObject]; if (javaWindowObject == NULL) { DBG_PRINT("windowDidMove: null javaWindowObject\n"); return; } int shallBeDetached = 0; - JavaVM *jvmHandle = [view getJVMHandle]; - JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); if(NULL==env) { DBG_PRINT("windowDidMove: null JNIEnv\n"); return; @@ -948,9 +1224,8 @@ static jint mods2JavaMods(NSUInteger mods) p0 = [self getLocationOnScreen: p0]; (*env)->CallVoidMethod(env, javaWindowObject, positionChangedID, JNI_FALSE, (jint) p0.x, (jint) p0.y); - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); } - (BOOL)windowShouldClose: (id) sender @@ -966,41 +1241,38 @@ static jint mods2JavaMods(NSUInteger mods) - (BOOL) windowClosingImpl: (BOOL) force { jboolean closed = JNI_FALSE; - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [self cursorHide: NO]; - - NSView* nsview = [self contentView]; - if( ! [nsview isMemberOfClass:[NewtView class]] ) { + NewtView* newtView = (NewtView *) [self contentView]; + if( ! [newtView isKindOfClass:[NewtView class]] ) { return NO; } - NewtView* view = (NewtView *) nsview; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [newtView cursorHide: NO enter: -1]; - if( false == [view getDestroyNotifySent] ) { - jobject javaWindowObject = [view getJavaWindowObject]; + if( false == [newtView getDestroyNotifySent] ) { + jobject javaWindowObject = [newtView getJavaWindowObject]; DBG_PRINT( "*************** windowWillClose.0: %p\n", (void *)(intptr_t)javaWindowObject); if (javaWindowObject == NULL) { DBG_PRINT("windowWillClose: null javaWindowObject\n"); + [pool release]; return NO; } int shallBeDetached = 0; - JavaVM *jvmHandle = [view getJVMHandle]; - JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); if(NULL==env) { DBG_PRINT("windowWillClose: null JNIEnv\n"); + [pool release]; return NO; } - - [view setDestroyNotifySent: true]; // earmark assumption of being closed + [newtView setDestroyNotifySent: true]; // earmark assumption of being closed closed = (*env)->CallBooleanMethod(env, javaWindowObject, windowDestroyNotifyID, force ? JNI_TRUE : JNI_FALSE); if(!force && !closed) { // not closed on java side, not force -> clear flag - [view setDestroyNotifySent: false]; + [newtView setDestroyNotifySent: false]; } - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); DBG_PRINT( "*************** windowWillClose.X: %p, closed %d\n", (void *)(intptr_t)javaWindowObject, (int)closed); } else { DBG_PRINT( "*************** windowWillClose (skip)\n"); @@ -1010,3 +1282,4 @@ static jint mods2JavaMods(NSUInteger mods) } @end + diff --git a/src/newt/native/ScreenMode.h b/src/newt/native/ScreenMode.h index bb782910e..56c424b11 100644 --- a/src/newt/native/ScreenMode.h +++ b/src/newt/native/ScreenMode.h @@ -33,12 +33,18 @@ #ifndef _SCREEN_MODE_H #define _SCREEN_MODE_H -#define NUM_RESOLUTION_PROPERTIES 2 /* width, height */ -#define NUM_SURFACE_SIZE_PROPERTIES 1 /* bpp */ -#define NUM_MONITOR_MODE_PROPERTIES 3 /* ScreenSizeMM[width, height], refresh-rate */ -#define NUM_SCREEN_MODE_PROPERTIES 1 /* rotation */ +#define NUM_RESOLUTION_PROPERTIES 2 /* width, height */ +#define NUM_SURFACE_SIZE_PROPERTIES 1 /* bpp */ +#define NUM_SIZEANDRATE_PROPERTIES 2 /* refresh-rate, flags */ +#define NUM_MONITOR_MODE_PROPERTIES 2 /* id, rotation */ -#define NUM_SCREEN_MODE_PROPERTIES_ALL 8 /* count + the above */ +#define NUM_MONITOR_MODE_PROPERTIES_ALL 8 /* count + the above */ + +#define MIN_MONITOR_DEVICE_PROPERTIES 15 /* count + id, ScreenSizeMM[width, height], rotated Viewport pixel-units, rotated Viewport pixel-units, currentMonitorModeId, rotation, supportedModeId+ */ + /* Viewport := [x, y, width, height] (4 elements) */ + +#define FLAG_INTERLACE ( 1 << 0 ) +#define FLAG_DOUBLESCAN ( 1 << 1 ) #endif diff --git a/src/newt/native/Window.h b/src/newt/native/Window.h index 4755c4fc5..d9ee5fd1f 100644 --- a/src/newt/native/Window.h +++ b/src/newt/native/Window.h @@ -38,8 +38,9 @@ #define FLAG_HAS_PARENT ( 1 << 8 ) #define FLAG_IS_UNDECORATED ( 1 << 9 ) #define FLAG_IS_FULLSCREEN ( 1 << 10 ) -#define FLAG_IS_ALWAYSONTOP ( 1 << 11 ) -#define FLAG_IS_VISIBLE ( 1 << 12 ) +#define FLAG_IS_FULLSCREEN_SPAN ( 1 << 11 ) +#define FLAG_IS_ALWAYSONTOP ( 1 << 12 ) +#define FLAG_IS_VISIBLE ( 1 << 13 ) #define TST_FLAG_CHANGE_PARENTING(f) ( 0 != ( (f) & FLAG_CHANGE_PARENTING ) ) #define TST_FLAG_CHANGE_DECORATION(f) ( 0 != ( (f) & FLAG_CHANGE_DECORATION ) ) @@ -47,11 +48,11 @@ #define TST_FLAG_CHANGE_ALWAYSONTOP(f) ( 0 != ( (f) & FLAG_CHANGE_ALWAYSONTOP ) ) #define TST_FLAG_CHANGE_VISIBILITY(f) ( 0 != ( (f) & FLAG_CHANGE_VISIBILITY ) ) -#define TST_FLAG_HAS_PARENT(f) ( 0 != ( (f) & FLAG_HAS_PARENT ) ) -#define TST_FLAG_IS_UNDECORATED(f) ( 0 != ( (f) & FLAG_IS_UNDECORATED ) ) -#define TST_FLAG_IS_FULLSCREEN(f) ( 0 != ( (f) & FLAG_IS_FULLSCREEN ) ) -#define TST_FLAG_IS_FULLSCREEN(f) ( 0 != ( (f) & FLAG_IS_FULLSCREEN ) ) -#define TST_FLAG_IS_ALWAYSONTOP(f) ( 0 != ( (f) & FLAG_IS_ALWAYSONTOP ) ) -#define TST_FLAG_IS_VISIBLE(f) ( 0 != ( (f) & FLAG_IS_VISIBLE ) ) +#define TST_FLAG_HAS_PARENT(f) ( 0 != ( (f) & FLAG_HAS_PARENT ) ) +#define TST_FLAG_IS_UNDECORATED(f) ( 0 != ( (f) & FLAG_IS_UNDECORATED ) ) +#define TST_FLAG_IS_FULLSCREEN(f) ( 0 != ( (f) & FLAG_IS_FULLSCREEN ) ) +#define TST_FLAG_IS_FULLSCREEN_SPAN(f) ( 0 != ( (f) & FLAG_IS_FULLSCREEN_SPAN ) ) +#define TST_FLAG_IS_ALWAYSONTOP(f) ( 0 != ( (f) & FLAG_IS_ALWAYSONTOP ) ) +#define TST_FLAG_IS_VISIBLE(f) ( 0 != ( (f) & FLAG_IS_VISIBLE ) ) #endif diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c index 40252f59b..70d0c6f83 100644 --- a/src/newt/native/WindowsWindow.c +++ b/src/newt/native/WindowsWindow.c @@ -32,6 +32,16 @@ * */ +// +// Min. required version Windows 7 (For WM_TOUCH) +// +#if WINVER < 0x0601 +#error WINVER must be >= 0x0601 +#endif +#if _WIN32_WINNT < 0x0601 +#error _WIN32_WINNT must be >= 0x0601 +#endif + #include <Windows.h> #include <Windowsx.h> #include <tchar.h> @@ -49,13 +59,22 @@ #define strdup(s) _strdup(s) #endif +/* GetProcAddress doesn't exist in A/W variants under desktop Windows */ +#ifndef UNDER_CE +#define GetProcAddressA GetProcAddress +#endif + #ifndef WM_MOUSEWHEEL #define WM_MOUSEWHEEL 0x020A #endif //WM_MOUSEWHEEL -#ifndef WHEEL_DELTA -#define WHEEL_DELTA 120 -#endif //WHEEL_DELTA +#ifndef WM_MOUSEHWHEEL +#define WM_MOUSEHWHEEL 0x020E +#endif //WM_MOUSEHWHEEL + +#ifndef WHEEL_DELTAf +#define WHEEL_DELTAf (120.0f) +#endif //WHEEL_DELTAf #ifndef WHEEL_PAGESCROLL #define WHEEL_PAGESCROLL (UINT_MAX) @@ -64,6 +83,30 @@ #ifndef GET_WHEEL_DELTA_WPARAM // defined for (_WIN32_WINNT >= 0x0500) #define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam)) #endif +#ifndef GET_KEYSTATE_WPARAM +#define GET_KEYSTATE_WPARAM(wParam) ((short)LOWORD(wParam)) +#endif + +#ifndef WM_HSCROLL +#define WM_HSCROLL 0x0114 +#endif +#ifndef WM_VSCROLL +#define WM_VSCROLL 0x0115 +#endif + +#ifndef WH_MOUSE +#define WH_MOUSE 7 +#endif +#ifndef WH_MOUSE_LL +#define WH_MOUSE_LL 14 +#endif + +#ifndef WM_TOUCH +#define WM_TOUCH 0x0240 +#endif +#ifndef TOUCH_COORD_TO_PIXEL +#define TOUCH_COORD_TO_PIXEL(l) (l/100) +#endif #ifndef MONITOR_DEFAULTTONULL #define MONITOR_DEFAULTTONULL 0 @@ -80,6 +123,9 @@ #ifndef DISPLAY_DEVICE_ACTIVE #define DISPLAY_DEVICE_ACTIVE 0x00000001 #endif +#ifndef DM_INTERLACED +#define DM_INTERLACED 2 +#endif #include "jogamp_newt_driver_windows_DisplayDriver.h" #include "jogamp_newt_driver_windows_ScreenDriver.h" @@ -111,504 +157,442 @@ static jmethodID focusChangedID = NULL; static jmethodID visibleChangedID = NULL; static jmethodID windowDestroyNotifyID = NULL; static jmethodID windowRepaintID = NULL; -static jmethodID enqueueMouseEventID = NULL; static jmethodID sendMouseEventID = NULL; -static jmethodID enqueueKeyEventID = NULL; +static jmethodID sendTouchScreenEventID = NULL; static jmethodID sendKeyEventID = NULL; static jmethodID requestFocusID = NULL; +typedef WINBOOL (WINAPI *CloseTouchInputHandlePROCADDR)(HANDLE hTouchInput); +typedef WINBOOL (WINAPI *GetTouchInputInfoPROCADDR)(HANDLE hTouchInput, UINT cInputs, PTOUCHINPUT pInputs, int cbSize); +typedef WINBOOL (WINAPI *IsTouchWindowPROCADDR)(HWND hWnd,PULONG pulFlags); +typedef WINBOOL (WINAPI *RegisterTouchWindowPROCADDR)(HWND hWnd,ULONG ulFlags); +typedef WINBOOL (WINAPI *UnregisterTouchWindowPROCADDR)(HWND hWnd); + +static int WinTouch_func_avail = 0; +static CloseTouchInputHandlePROCADDR WinTouch_CloseTouchInputHandle = NULL; +static GetTouchInputInfoPROCADDR WinTouch_GetTouchInputInfo = NULL; +static IsTouchWindowPROCADDR WinTouch_IsTouchWindow = NULL; +static RegisterTouchWindowPROCADDR WinTouch_RegisterTouchWindow = NULL; +static UnregisterTouchWindowPROCADDR WinTouch_UnregisterTouchWindow = NULL; + static RECT* UpdateInsets(JNIEnv *env, jobject window, HWND hwnd); typedef struct { JNIEnv* jenv; jobject jinstance; + /* client size width */ + int width; + /* client size height */ + int height; + /** Tristate: -1 HIDE, 0 NOP, 1 SHOW */ + int setPointerVisible; + /** Tristate: -1 RESET, 0 NOP, 1 SET-NEW */ + int setPointerAction; + HCURSOR setPointerHandle; + HCURSOR defPointerHandle; + /** Bool: 0 NOP, 1 FULLSCREEN */ + int isFullscreen; + /** Bool: 0 TOP, 1 CHILD */ + int isChildWindow; + int pointerCaptured; + int pointerInside; + int touchDownCount; + int touchDownLastUp; // mitigate LBUTTONUP after last TOUCH lift + int supportsMTouch; } WindowUserData; typedef struct { - UINT javaKey; - UINT windowsKey; + USHORT javaKey; + USHORT windowsKey; + USHORT windowsScanCodeUS; } KeyMapEntry; // Static table, arranged more or less spatially. static KeyMapEntry keyMapTable[] = { // Modifier keys - {J_VK_CAPS_LOCK, VK_CAPITAL}, - {J_VK_SHIFT, VK_SHIFT}, - {J_VK_CONTROL, VK_CONTROL}, - {J_VK_ALT, VK_MENU}, - {J_VK_NUM_LOCK, VK_NUMLOCK}, + {J_VK_CAPS_LOCK, VK_CAPITAL, 0}, + {J_VK_SHIFT, VK_SHIFT, 0}, + {J_VK_SHIFT, VK_LSHIFT, 0}, + {J_VK_SHIFT, VK_RSHIFT, 0}, + {J_VK_CONTROL, VK_CONTROL, 0}, + {J_VK_CONTROL, VK_LCONTROL, 0}, + {J_VK_CONTROL, VK_RCONTROL, 0}, + {J_VK_ALT, VK_MENU, 0}, + {J_VK_ALT, VK_LMENU, 0}, + {J_VK_ALT_GRAPH, VK_RMENU, 0}, + {J_VK_NUM_LOCK, VK_NUMLOCK, 0}, // Miscellaneous Windows keys - {J_VK_WINDOWS, VK_LWIN}, - {J_VK_WINDOWS, VK_RWIN}, - {J_VK_CONTEXT_MENU, VK_APPS}, + {J_VK_WINDOWS, VK_LWIN, 0}, + {J_VK_WINDOWS, VK_RWIN, 0}, + {J_VK_CONTEXT_MENU, VK_APPS, 0}, // Alphabet - {J_VK_A, 'A'}, - {J_VK_B, 'B'}, - {J_VK_C, 'C'}, - {J_VK_D, 'D'}, - {J_VK_E, 'E'}, - {J_VK_F, 'F'}, - {J_VK_G, 'G'}, - {J_VK_H, 'H'}, - {J_VK_I, 'I'}, - {J_VK_J, 'J'}, - {J_VK_K, 'K'}, - {J_VK_L, 'L'}, - {J_VK_M, 'M'}, - {J_VK_N, 'N'}, - {J_VK_O, 'O'}, - {J_VK_P, 'P'}, - {J_VK_Q, 'Q'}, - {J_VK_R, 'R'}, - {J_VK_S, 'S'}, - {J_VK_T, 'T'}, - {J_VK_U, 'U'}, - {J_VK_V, 'V'}, - {J_VK_W, 'W'}, - {J_VK_X, 'X'}, - {J_VK_Y, 'Y'}, - {J_VK_Z, 'Z'}, - {J_VK_0, '0'}, - {J_VK_1, '1'}, - {J_VK_2, '2'}, - {J_VK_3, '3'}, - {J_VK_4, '4'}, - {J_VK_5, '5'}, - {J_VK_6, '6'}, - {J_VK_7, '7'}, - {J_VK_8, '8'}, - {J_VK_9, '9'}, - {J_VK_ENTER, VK_RETURN}, - {J_VK_SPACE, VK_SPACE}, - {J_VK_BACK_SPACE, VK_BACK}, - {J_VK_TAB, VK_TAB}, - {J_VK_ESCAPE, VK_ESCAPE}, - {J_VK_INSERT, VK_INSERT}, - {J_VK_DELETE, VK_DELETE}, - {J_VK_HOME, VK_HOME}, - {J_VK_END, VK_END}, - {J_VK_PAGE_UP, VK_PRIOR}, - {J_VK_PAGE_DOWN, VK_NEXT}, - {J_VK_CLEAR, VK_CLEAR}, // NumPad 5 + {J_VK_A, 'A', 0}, + {J_VK_B, 'B', 0}, + {J_VK_C, 'C', 0}, + {J_VK_D, 'D', 0}, + {J_VK_E, 'E', 0}, + {J_VK_F, 'F', 0}, + {J_VK_G, 'G', 0}, + {J_VK_H, 'H', 0}, + {J_VK_I, 'I', 0}, + {J_VK_J, 'J', 0}, + {J_VK_K, 'K', 0}, + {J_VK_L, 'L', 0}, + {J_VK_M, 'M', 0}, + {J_VK_N, 'N', 0}, + {J_VK_O, 'O', 0}, + {J_VK_P, 'P', 0}, + {J_VK_Q, 'Q', 0}, + {J_VK_R, 'R', 0}, + {J_VK_S, 'S', 0}, + {J_VK_T, 'T', 0}, + {J_VK_U, 'U', 0}, + {J_VK_V, 'V', 0}, + {J_VK_W, 'W', 0}, + {J_VK_X, 'X', 0}, + {J_VK_Y, 'Y', 0}, + {J_VK_Z, 'Z', 0}, + {J_VK_0, '0', 0}, + {J_VK_1, '1', 0}, + {J_VK_2, '2', 0}, + {J_VK_3, '3', 0}, + {J_VK_4, '4', 0}, + {J_VK_5, '5', 0}, + {J_VK_6, '6', 0}, + {J_VK_7, '7', 0}, + {J_VK_8, '8', 0}, + {J_VK_9, '9', 0}, + {J_VK_ENTER, VK_RETURN, 0}, + {J_VK_SPACE, VK_SPACE, 0}, + {J_VK_BACK_SPACE, VK_BACK, 0}, + {J_VK_TAB, VK_TAB, 0}, + {J_VK_ESCAPE, VK_ESCAPE, 0}, + {J_VK_INSERT, VK_INSERT, 0}, + {J_VK_DELETE, VK_DELETE, 0}, + {J_VK_HOME, VK_HOME, 0}, + // {J_VK_BEGIN, VK_BEGIN, 0}, // not mapped + {J_VK_END, VK_END, 0}, + {J_VK_PAGE_UP, VK_PRIOR, 0}, + {J_VK_PAGE_DOWN, VK_NEXT, 0}, + {J_VK_CLEAR, VK_CLEAR, 0}, // NumPad 5 // NumPad with NumLock off & extended arrows block (triangular) - {J_VK_LEFT, VK_LEFT}, - {J_VK_RIGHT, VK_RIGHT}, - {J_VK_UP, VK_UP}, - {J_VK_DOWN, VK_DOWN}, + {J_VK_LEFT, VK_LEFT, 0}, + {J_VK_RIGHT, VK_RIGHT, 0}, + {J_VK_UP, VK_UP, 0}, + {J_VK_DOWN, VK_DOWN, 0}, // NumPad with NumLock on: numbers - {J_VK_NUMPAD0, VK_NUMPAD0}, - {J_VK_NUMPAD1, VK_NUMPAD1}, - {J_VK_NUMPAD2, VK_NUMPAD2}, - {J_VK_NUMPAD3, VK_NUMPAD3}, - {J_VK_NUMPAD4, VK_NUMPAD4}, - {J_VK_NUMPAD5, VK_NUMPAD5}, - {J_VK_NUMPAD6, VK_NUMPAD6}, - {J_VK_NUMPAD7, VK_NUMPAD7}, - {J_VK_NUMPAD8, VK_NUMPAD8}, - {J_VK_NUMPAD9, VK_NUMPAD9}, + {J_VK_NUMPAD0, VK_NUMPAD0, 0}, + {J_VK_NUMPAD1, VK_NUMPAD1, 0}, + {J_VK_NUMPAD2, VK_NUMPAD2, 0}, + {J_VK_NUMPAD3, VK_NUMPAD3, 0}, + {J_VK_NUMPAD4, VK_NUMPAD4, 0}, + {J_VK_NUMPAD5, VK_NUMPAD5, 0}, + {J_VK_NUMPAD6, VK_NUMPAD6, 0}, + {J_VK_NUMPAD7, VK_NUMPAD7, 0}, + {J_VK_NUMPAD8, VK_NUMPAD8, 0}, + {J_VK_NUMPAD9, VK_NUMPAD9, 0}, // NumPad with NumLock on - {J_VK_MULTIPLY, VK_MULTIPLY}, - {J_VK_ADD, VK_ADD}, - {J_VK_SEPARATOR, VK_SEPARATOR}, - {J_VK_SUBTRACT, VK_SUBTRACT}, - {J_VK_DECIMAL, VK_DECIMAL}, - {J_VK_DIVIDE, VK_DIVIDE}, + {J_VK_MULTIPLY, VK_MULTIPLY, 0}, + {J_VK_ADD, VK_ADD, 0}, + {J_VK_SEPARATOR, VK_SEPARATOR, 0}, + {J_VK_SUBTRACT, VK_SUBTRACT, 0}, + {J_VK_DECIMAL, VK_DECIMAL, 0}, + {J_VK_DIVIDE, VK_DIVIDE, 0}, // Functional keys - {J_VK_F1, VK_F1}, - {J_VK_F2, VK_F2}, - {J_VK_F3, VK_F3}, - {J_VK_F4, VK_F4}, - {J_VK_F5, VK_F5}, - {J_VK_F6, VK_F6}, - {J_VK_F7, VK_F7}, - {J_VK_F8, VK_F8}, - {J_VK_F9, VK_F9}, - {J_VK_F10, VK_F10}, - {J_VK_F11, VK_F11}, - {J_VK_F12, VK_F12}, - {J_VK_F13, VK_F13}, - {J_VK_F14, VK_F14}, - {J_VK_F15, VK_F15}, - {J_VK_F16, VK_F16}, - {J_VK_F17, VK_F17}, - {J_VK_F18, VK_F18}, - {J_VK_F19, VK_F19}, - {J_VK_F20, VK_F20}, - {J_VK_F21, VK_F21}, - {J_VK_F22, VK_F22}, - {J_VK_F23, VK_F23}, - {J_VK_F24, VK_F24}, - - {J_VK_PRINTSCREEN, VK_SNAPSHOT}, - {J_VK_SCROLL_LOCK, VK_SCROLL}, - {J_VK_PAUSE, VK_PAUSE}, - {J_VK_CANCEL, VK_CANCEL}, - {J_VK_HELP, VK_HELP}, + {J_VK_F1, VK_F1, 0}, + {J_VK_F2, VK_F2, 0}, + {J_VK_F3, VK_F3, 0}, + {J_VK_F4, VK_F4, 0}, + {J_VK_F5, VK_F5, 0}, + {J_VK_F6, VK_F6, 0}, + {J_VK_F7, VK_F7, 0}, + {J_VK_F8, VK_F8, 0}, + {J_VK_F9, VK_F9, 0}, + {J_VK_F10, VK_F10, 0}, + {J_VK_F11, VK_F11, 0}, + {J_VK_F12, VK_F12, 0}, + {J_VK_F13, VK_F13, 0}, + {J_VK_F14, VK_F14, 0}, + {J_VK_F15, VK_F15, 0}, + {J_VK_F16, VK_F16, 0}, + {J_VK_F17, VK_F17, 0}, + {J_VK_F18, VK_F18, 0}, + {J_VK_F19, VK_F19, 0}, + {J_VK_F20, VK_F20, 0}, + {J_VK_F21, VK_F21, 0}, + {J_VK_F22, VK_F22, 0}, + {J_VK_F23, VK_F23, 0}, + {J_VK_F24, VK_F24, 0}, + + {J_VK_PRINTSCREEN, VK_SNAPSHOT, 0}, + {J_VK_SCROLL_LOCK, VK_SCROLL, 0}, + {J_VK_PAUSE, VK_PAUSE, 0}, + {J_VK_CANCEL, VK_CANCEL, 0}, + {J_VK_HELP, VK_HELP, 0}, + + // Since we unify mappings via US kbd layout .. this is valid: + {J_VK_SEMICOLON, VK_OEM_1, 0}, // US only ';:' + {J_VK_EQUALS, VK_OEM_PLUS, 0}, // '=+' + {J_VK_COMMA, VK_OEM_COMMA, 0}, // ',<' + {J_VK_MINUS, VK_OEM_MINUS, 0}, // '-_' + {J_VK_PERIOD, VK_OEM_PERIOD, 0}, // '.>' + {J_VK_SLASH, VK_OEM_2, 0}, // US only '/?' + {J_VK_BACK_QUOTE, VK_OEM_3, 0}, // US only '`~' + {J_VK_OPEN_BRACKET, VK_OEM_4, 0}, // US only '[}' + {J_VK_BACK_SLASH, VK_OEM_5, 0}, // US only '\|' + {J_VK_CLOSE_BRACKET, VK_OEM_6, 0}, // US only ']}' + {J_VK_QUOTE, VK_OEM_7, 0}, // US only ''"' + // {J_VK_????, VK_OEM_8, 0}, // varies .. + // {J_VK_????, VK_OEM_102, 0}, // angle-bracket or backslash key on RT 102-key kbd // Japanese /* - {J_VK_CONVERT, VK_CONVERT}, - {J_VK_NONCONVERT, VK_NONCONVERT}, - {J_VK_INPUT_METHOD_ON_OFF, VK_KANJI}, - {J_VK_ALPHANUMERIC, VK_DBE_ALPHANUMERIC}, - {J_VK_KATAKANA, VK_DBE_KATAKANA}, - {J_VK_HIRAGANA, VK_DBE_HIRAGANA}, - {J_VK_FULL_WIDTH, VK_DBE_DBCSCHAR}, - {J_VK_HALF_WIDTH, VK_DBE_SBCSCHAR}, - {J_VK_ROMAN_CHARACTERS, VK_DBE_ROMAN}, + {J_VK_CONVERT, VK_CONVERT, 0}, + {J_VK_NONCONVERT, VK_NONCONVERT, 0}, + {J_VK_INPUT_METHOD_ON_OFF, VK_KANJI, 0}, + {J_VK_ALPHANUMERIC, VK_DBE_ALPHANUMERIC, 0}, + {J_VK_KATAKANA, VK_DBE_KATAKANA, 0}, + {J_VK_HIRAGANA, VK_DBE_HIRAGANA, 0}, + {J_VK_FULL_WIDTH, VK_DBE_DBCSCHAR, 0}, + {J_VK_HALF_WIDTH, VK_DBE_SBCSCHAR, 0}, + {J_VK_ROMAN_CHARACTERS, VK_DBE_ROMAN, 0}, */ - {J_VK_UNDEFINED, 0} -}; - -/* -Dynamic mapping table for OEM VK codes. This table is refilled -by BuildDynamicKeyMapTable when keyboard layout is switched. -(see NT4 DDK src/input/inc/vkoem.h for OEM VK_ values). -*/ -typedef struct { - // OEM VK codes known in advance - UINT windowsKey; - // depends on input langauge (kbd layout) - UINT javaKey; -} DynamicKeyMapEntry; - -static DynamicKeyMapEntry dynamicKeyMapTable[] = { - {0x00BA, J_VK_UNDEFINED}, // VK_OEM_1 - {0x00BB, J_VK_UNDEFINED}, // VK_OEM_PLUS - {0x00BC, J_VK_UNDEFINED}, // VK_OEM_COMMA - {0x00BD, J_VK_UNDEFINED}, // VK_OEM_MINUS - {0x00BE, J_VK_UNDEFINED}, // VK_OEM_PERIOD - {0x00BF, J_VK_UNDEFINED}, // VK_OEM_2 - {0x00C0, J_VK_UNDEFINED}, // VK_OEM_3 - {0x00DB, J_VK_UNDEFINED}, // VK_OEM_4 - {0x00DC, J_VK_UNDEFINED}, // VK_OEM_5 - {0x00DD, J_VK_UNDEFINED}, // VK_OEM_6 - {0x00DE, J_VK_UNDEFINED}, // VK_OEM_7 - {0x00DF, J_VK_UNDEFINED}, // VK_OEM_8 - {0x00E2, J_VK_UNDEFINED}, // VK_OEM_102 - {0, 0} + {J_VK_UNDEFINED, 0, 0} }; -// Auxiliary tables used to fill the above dynamic table. We first -// find the character for the OEM VK code using ::MapVirtualKey and -// then go through these auxiliary tables to map it to Java VK code. +#ifndef KLF_ACTIVATE + #define KLF_ACTIVATE 0x00000001 +#endif +#ifndef MAPVK_VK_TO_VSC + #define MAPVK_VK_TO_VSC 0 +#endif +#ifndef MAPVK_VSC_TO_VK + #define MAPVK_VSC_TO_VK 1 +#endif +#ifndef MAPVK_VK_TO_CHAR + #define MAPVK_VK_TO_CHAR 2 +#endif +#ifndef MAPVK_VSC_TO_VK_EX + #define MAPVK_VSC_TO_VK_EX 3 +#endif +#ifndef MAPVK_VK_TO_VSC_EX + #define MAPVK_VK_TO_VSC_EX 4 +#endif -typedef struct { - WCHAR c; - UINT javaKey; -} CharToVKEntry; - -static const CharToVKEntry charToVKTable[] = { - {L'!', J_VK_EXCLAMATION_MARK}, - {L'"', J_VK_QUOTEDBL}, - {L'#', J_VK_NUMBER_SIGN}, - {L'$', J_VK_DOLLAR}, - {L'&', J_VK_AMPERSAND}, - {L'\'', J_VK_QUOTE}, - {L'(', J_VK_LEFT_PARENTHESIS}, - {L')', J_VK_RIGHT_PARENTHESIS}, - {L'*', J_VK_ASTERISK}, - {L'+', J_VK_PLUS}, - {L',', J_VK_COMMA}, - {L'-', J_VK_MINUS}, - {L'.', J_VK_PERIOD}, - {L'/', J_VK_SLASH}, - {L':', J_VK_COLON}, - {L';', J_VK_SEMICOLON}, - {L'<', J_VK_LESS}, - {L'=', J_VK_EQUALS}, - {L'>', J_VK_GREATER}, - {L'@', J_VK_AT}, - {L'[', J_VK_OPEN_BRACKET}, - {L'\\', J_VK_BACK_SLASH}, - {L']', J_VK_CLOSE_BRACKET}, - {L'^', J_VK_CIRCUMFLEX}, - {L'_', J_VK_UNDERSCORE}, - {L'`', J_VK_BACK_QUOTE}, - {L'{', J_VK_BRACELEFT}, - {L'}', J_VK_BRACERIGHT}, - {0x00A1, J_VK_INVERTED_EXCLAMATION_MARK}, - {0x20A0, J_VK_EURO_SIGN}, // ???? - {0,0} -}; +#define IS_WITHIN(k,a,b) ((a)<=(k)&&(k)<=(b)) -// For dead accents some layouts return ASCII punctuation, while some -// return spacing accent chars, so both should be listed. NB: MS docs -// say that conversion routings return spacing accent character, not -// combining. -static const CharToVKEntry charToDeadVKTable[] = { - {L'`', J_VK_DEAD_GRAVE}, - {L'\'', J_VK_DEAD_ACUTE}, - {0x00B4, J_VK_DEAD_ACUTE}, - {L'^', J_VK_DEAD_CIRCUMFLEX}, - {L'~', J_VK_DEAD_TILDE}, - {0x02DC, J_VK_DEAD_TILDE}, - {0x00AF, J_VK_DEAD_MACRON}, - {0x02D8, J_VK_DEAD_BREVE}, - {0x02D9, J_VK_DEAD_ABOVEDOT}, - {L'"', J_VK_DEAD_DIAERESIS}, - {0x00A8, J_VK_DEAD_DIAERESIS}, - {0x02DA, J_VK_DEAD_ABOVERING}, - {0x02DD, J_VK_DEAD_DOUBLEACUTE}, - {0x02C7, J_VK_DEAD_CARON}, // aka hacek - {L',', J_VK_DEAD_CEDILLA}, - {0x00B8, J_VK_DEAD_CEDILLA}, - {0x02DB, J_VK_DEAD_OGONEK}, - {0x037A, J_VK_DEAD_IOTA}, // ASCII ??? - {0x309B, J_VK_DEAD_VOICED_SOUND}, - {0x309C, J_VK_DEAD_SEMIVOICED_SOUND}, - {0,0} -}; +static HKL kbdLayoutUS = 0; +static const LPCSTR US_LAYOUT_NAME = "00000409"; -// ANSI CP identifiers are no longer than this -#define MAX_ACP_STR_LEN 7 +static BYTE kbdState[256]; +static USHORT spaceScanCode; -static void BuildDynamicKeyMapTable() -{ +static void InitKeyMapTableScanCode(JNIEnv *env) { HKL hkl = GetKeyboardLayout(0); - // Will need this to reset layout after dead keys. - UINT spaceScanCode = MapVirtualKeyEx(VK_SPACE, 0, hkl); - DynamicKeyMapEntry *dynamic; - - LANGID idLang = LOWORD(GetKeyboardLayout(0)); - UINT codePage; - TCHAR strCodePage[MAX_ACP_STR_LEN]; - // use the LANGID to create a LCID - LCID idLocale = MAKELCID(idLang, SORT_DEFAULT); - // get the ANSI code page associated with this locale - if (GetLocaleInfo(idLocale, LOCALE_IDEFAULTANSICODEPAGE, - strCodePage, sizeof(strCodePage)/sizeof(TCHAR)) > 0 ) - { - codePage = _ttoi(strCodePage); - } else { - codePage = GetACP(); + int i; + + kbdLayoutUS = LoadKeyboardLayout( US_LAYOUT_NAME, 0 /* ? KLF_ACTIVATE ? */ ); + if( 0 == kbdLayoutUS ) { + int lastError = (int) GetLastError(); + kbdLayoutUS = hkl; // use prev. layout .. well + STD_PRINT("Warning: NEWT Windows: LoadKeyboardLayout(US, ..) failed: winErr 0x%X %d\n", lastError, lastError); } + ActivateKeyboardLayout(hkl, 0); - // Entries in dynamic table that maps between Java VK and Windows - // VK are built in three steps: - // 1. Map windows VK to ANSI character (cannot map to unicode - // directly, since ::ToUnicode is not implemented on win9x) - // 2. Convert ANSI char to Unicode char - // 3. Map Unicode char to Java VK via two auxilary tables. + spaceScanCode = MapVirtualKeyEx(VK_SPACE, MAPVK_VK_TO_VSC, hkl); - for (dynamic = dynamicKeyMapTable; dynamic->windowsKey != 0; ++dynamic) - { - char cbuf[2] = { '\0', '\0'}; - WCHAR ucbuf[2] = { L'\0', L'\0' }; - int nchars; - UINT scancode; - const CharToVKEntry *charMap; - int nconverted; - WCHAR uc; - BYTE kbdState[256]; - - // Defaults to J_VK_UNDEFINED - dynamic->javaKey = J_VK_UNDEFINED; - - GetKeyboardState(kbdState); - - kbdState[dynamic->windowsKey] |= 0x80; // Press the key. - - // Unpress modifiers, since they are most likely pressed as - // part of the keyboard switching shortcut. - kbdState[VK_CONTROL] &= ~0x80; - kbdState[VK_SHIFT] &= ~0x80; - kbdState[VK_MENU] &= ~0x80; - - scancode = MapVirtualKeyEx(dynamic->windowsKey, 0, hkl); - nchars = ToAsciiEx(dynamic->windowsKey, scancode, kbdState, - (WORD*)cbuf, 0, hkl); - - // Auxiliary table used to map Unicode character to Java VK. - // Will assign a different table for dead keys (below). - charMap = charToVKTable; - - if (nchars < 0) { // Dead key - char junkbuf[2] = { '\0', '\0'}; - // Use a different table for dead chars since different layouts - // return different characters for the same dead key. - charMap = charToDeadVKTable; - - // We also need to reset layout so that next translation - // is unaffected by the dead status. We do this by - // translating <SPACE> key. - kbdState[dynamic->windowsKey] &= ~0x80; - kbdState[VK_SPACE] |= 0x80; - - ToAsciiEx(VK_SPACE, spaceScanCode, kbdState, - (WORD*)junkbuf, 0, hkl); + // Setup keyMapTable's windowsScanCodeUS + for (i = 0; keyMapTable[i].windowsKey != 0; i++) { + USHORT scancode = (USHORT) MapVirtualKeyEx(keyMapTable[i].windowsKey, MAPVK_VK_TO_VSC_EX, kbdLayoutUS); + #ifdef DEBUG_KEYS + if( 0 == scancode ) { + int lastError = (int) GetLastError(); + STD_PRINT("*** WindowsWindow: InitKeyMapTableScanCode: No ScanCode for windows vkey 0x%X (item %d), winErr 0x%X %d\n", + keyMapTable[i].windowsKey, i, lastError, lastError); } + STD_PRINT("*** WindowsWindow: InitKeyMapTableScanCode: %3.3d windows vkey 0x%X -> scancode 0x%X\n", + i, keyMapTable[i].windowsKey, scancode); + #endif + keyMapTable[i].windowsScanCodeUS = scancode; + } +} - nconverted = MultiByteToWideChar(codePage, 0, - cbuf, 1, ucbuf, 2); +static void ParseWmVKeyAndScanCode(USHORT winVKey, BYTE winScanCode, BYTE flags, USHORT *outJavaVKeyUS, USHORT *outJavaVKeyXX, USHORT *outUTF16Char) { + wchar_t uniChars[2] = { L'\0', L'\0' }; // uint16_t + USHORT winVKeyUS = 0; + int nUniChars, i, j; + USHORT javaVKeyUS = J_VK_UNDEFINED; + USHORT javaVKeyXX = J_VK_UNDEFINED; - uc = ucbuf[0]; - { - const CharToVKEntry *map; - for (map = charMap; map->c != 0; ++map) { - if (uc == map->c) { - dynamic->javaKey = map->javaKey; - break; - } + HKL hkl = GetKeyboardLayout(0); + + // + // winVKey, winScanCode -> UTF16 w/ current KeyboardLayout + // + GetKeyboardState(kbdState); + kbdState[winVKey] |= 0x80; + nUniChars = ToUnicodeEx(winVKey, winScanCode, kbdState, uniChars, 2, 0, hkl); + kbdState[winVKey] &= ~0x80; + + *outUTF16Char = (USHORT)(uniChars[0]); // Note: Even dead key are written in uniChar's .. + + if ( 0 > nUniChars ) { // Dead key + char junkbuf[2] = { '\0', '\0'}; + + // We need to reset layout so that next translation + // is unaffected by the dead status. We do this by + // translating <SPACE> key. + kbdState[VK_SPACE] |= 0x80; + ToAsciiEx(VK_SPACE, spaceScanCode, kbdState, (WORD*)junkbuf, 0, hkl); + kbdState[VK_SPACE] &= ~0x80; + } + + // + // winVKey -> javaVKeyXX + // + for (i = 0; keyMapTable[i].windowsKey != 0; i++) { + if ( keyMapTable[i].windowsKey == winVKey ) { + javaVKeyXX = keyMapTable[i].javaKey; + break; + } + } + if( IS_WITHIN( winVKey, VK_NUMPAD0, VK_DIVIDE ) ) { + // Use modded keySym for keypad for US and NN + winVKeyUS = winVKey; + javaVKeyUS = javaVKeyXX; + } else { + // Assume extended scan code 0xE0 if extended flags is set (no 0xE1 from WM_KEYUP/WM_KEYDOWN) + USHORT winScanCodeExt = winScanCode; + if( 0 != ( 0x01 & flags ) ) { + winScanCodeExt |= 0xE000; + } + + // + // winVKey, winScanCodeExt -> javaVKeyUS w/ US KeyboardLayout + // + for (i = 0; keyMapTable[i].windowsKey != 0; i++) { + if ( keyMapTable[i].windowsScanCodeUS == winScanCodeExt ) { + winVKeyUS = keyMapTable[i].windowsKey; + javaVKeyUS = keyMapTable[i].javaKey; + break; } } + if( J_VK_UNDEFINED == javaVKeyUS ) { + javaVKeyUS = javaVKeyXX; + } + } + + *outJavaVKeyUS = javaVKeyUS; + *outJavaVKeyXX = javaVKeyXX; - } // for each VK_OEM_* +#ifdef DEBUG_KEYS + STD_PRINT("*** WindowsWindow: ParseWmVKeyAndScanCode winVKey 0x%X, winScanCode 0x%X, flags 0x%X -> UTF(0x%X, %c, res %d, sizeof %d), vKeys( US(win 0x%X, java 0x%X), XX(win 0x%X, java 0x%X))\n", + (int)winVKey, (int)winScanCode, (int)flags, + *outUTF16Char, *outUTF16Char, nUniChars, sizeof(uniChars[0]), + winVKeyUS, javaVKeyUS, winVKey, javaVKeyXX); +#endif } -static jint GetModifiers() { +static jint GetModifiers(USHORT jkey) { jint modifiers = 0; // have to do &0xFFFF to avoid runtime assert caused by compiling with // /RTCcsu - if (HIBYTE((GetKeyState(VK_CONTROL) & 0xFFFF)) != 0) { + if ( HIBYTE((GetKeyState(VK_CONTROL) & 0xFFFF)) != 0 || J_VK_CONTROL == jkey ) { modifiers |= EVENT_CTRL_MASK; } - if (HIBYTE((GetKeyState(VK_SHIFT) & 0xFFFF)) != 0) { + if ( HIBYTE((GetKeyState(VK_SHIFT) & 0xFFFF)) != 0 || J_VK_SHIFT == jkey ) { modifiers |= EVENT_SHIFT_MASK; } - if (HIBYTE((GetKeyState(VK_MENU) & 0xFFFF)) != 0) { + if ( HIBYTE((GetKeyState(VK_LMENU) & 0xFFFF)) != 0 || J_VK_ALT == jkey ) { modifiers |= EVENT_ALT_MASK; } - if (HIBYTE((GetKeyState(VK_LBUTTON) & 0xFFFF)) != 0) { + if ( HIBYTE((GetKeyState(VK_RMENU) & 0xFFFF)) != 0 || (USHORT)J_VK_ALT_GRAPH == jkey ) { + modifiers |= EVENT_ALT_GRAPH_MASK; + } + if ( HIBYTE((GetKeyState(VK_LBUTTON) & 0xFFFF)) != 0 ) { modifiers |= EVENT_BUTTON1_MASK; } - if (HIBYTE((GetKeyState(VK_MBUTTON) & 0xFFFF)) != 0) { + if ( HIBYTE((GetKeyState(VK_MBUTTON) & 0xFFFF)) != 0 ) { modifiers |= EVENT_BUTTON2_MASK; } - if (HIBYTE((GetKeyState(VK_RBUTTON) & 0xFFFF)) != 0) { + if ( HIBYTE((GetKeyState(VK_RBUTTON) & 0xFFFF)) != 0 ) { modifiers |= EVENT_BUTTON3_MASK; } return modifiers; } -static int WmChar(JNIEnv *env, jobject window, UINT character, UINT repCnt, - UINT flags, BOOL system) -{ +/** +static BOOL IsAltKeyDown(BYTE flags, BOOL system) { // The Alt modifier is reported in the 29th bit of the lParam, - // i.e., it is the 13th bit of `flags' (which is HIWORD(lParam)). - BOOL alt_is_down = (flags & (1<<13)) != 0; - if (system && alt_is_down) { - if (character == VK_SPACE) { - return 1; - } - } + // i.e., it is the 5th bit of `flags' (which is HIBYTE(HIWORD(lParam))). + return system && ( flags & (1<<5) ) != 0; +} */ - if (character == VK_RETURN) { - character = J_VK_ENTER; - } - (*env)->CallVoidMethod(env, window, sendKeyEventID, - (jint) EVENT_KEY_TYPED, - GetModifiers(), - (jint) -1, - (jchar) character); - return 1; -} - -UINT WindowsKeyToJavaKey(UINT windowsKey, UINT modifiers) -{ - int i, j; - // for the general case, use a bi-directional table - for (i = 0; keyMapTable[i].windowsKey != 0; i++) { - if (keyMapTable[i].windowsKey == windowsKey) { - return keyMapTable[i].javaKey; - } - } - for (j = 0; dynamicKeyMapTable[j].windowsKey != 0; j++) { - if (dynamicKeyMapTable[j].windowsKey == windowsKey) { - if (dynamicKeyMapTable[j].javaKey != J_VK_UNDEFINED) { - return dynamicKeyMapTable[j].javaKey; - } else { - break; - } - } - } - - return J_VK_UNDEFINED; -} - -static int WmKeyDown(JNIEnv *env, jobject window, UINT wkey, UINT repCnt, - UINT flags, BOOL system) -{ - UINT modifiers = 0, jkey = 0, character = -1; +static int WmKeyDown(JNIEnv *env, jobject window, USHORT wkey, WORD repCnt, BYTE scanCode, BYTE flags, BOOL system) { + UINT modifiers = 0; + USHORT javaVKeyUS=0, javaVKeyXX=0, utf16Char=0; if (wkey == VK_PROCESSKEY) { return 1; } - modifiers = GetModifiers(); - jkey = WindowsKeyToJavaKey(wkey, modifiers); + ParseWmVKeyAndScanCode(wkey, scanCode, flags, &javaVKeyUS, &javaVKeyXX, &utf16Char); -/* - character = WindowsKeyToJavaChar(wkey, modifiers, SAVE); -*/ + modifiers = GetModifiers( javaVKeyUS ); (*env)->CallVoidMethod(env, window, sendKeyEventID, - (jint) EVENT_KEY_PRESSED, - modifiers, - (jint) jkey, - (jchar) character); - - /* windows does not create a WM_CHAR for the Del key - for some reason, so we need to create the KEY_TYPED event on the - WM_KEYDOWN. - */ - if (jkey == J_VK_DELETE) { - (*env)->CallVoidMethod(env, window, sendKeyEventID, - (jint) EVENT_KEY_TYPED, - GetModifiers(), - (jint) -1, - (jchar) '\177'); - } + (jshort) EVENT_KEY_PRESSED, + (jint) modifiers, (jshort) javaVKeyUS, (jshort) javaVKeyXX, (jchar) utf16Char); return 0; } -static int WmKeyUp(JNIEnv *env, jobject window, UINT wkey, UINT repCnt, - UINT flags, BOOL system) -{ - UINT modifiers = 0, jkey = 0, character = -1; +static int WmKeyUp(JNIEnv *env, jobject window, USHORT wkey, WORD repCnt, BYTE scanCode, BYTE flags, BOOL system) { + UINT modifiers = 0; + USHORT javaVKeyUS=0, javaVKeyXX=0, utf16Char=0; if (wkey == VK_PROCESSKEY) { return 1; } - modifiers = GetModifiers(); - jkey = WindowsKeyToJavaKey(wkey, modifiers); -/* - character = WindowsKeyToJavaChar(wkey, modifiers, SAVE); -*/ + ParseWmVKeyAndScanCode(wkey, scanCode, flags, &javaVKeyUS, &javaVKeyXX, &utf16Char); + + modifiers = GetModifiers( javaVKeyUS ); (*env)->CallVoidMethod(env, window, sendKeyEventID, - (jint) EVENT_KEY_RELEASED, - modifiers, - (jint) jkey, - (jchar) character); + (jshort) EVENT_KEY_RELEASED, + (jint) modifiers, (jshort) javaVKeyUS, (jshort) javaVKeyXX, (jchar) utf16Char); return 0; } static void NewtWindows_requestFocus (JNIEnv *env, jobject window, HWND hwnd, jboolean force) { HWND pHwnd, current; + BOOL isEnabled = IsWindowEnabled(hwnd); pHwnd = GetParent(hwnd); current = GetFocus(); - DBG_PRINT("*** WindowsWindow: requestFocus.S parent %p, window %p, isCurrent %d\n", - (void*) pHwnd, (void*)hwnd, current==hwnd); + DBG_PRINT("*** WindowsWindow: requestFocus.S force %d, parent %p, window %p, isEnabled %d, isCurrent %d\n", + (int)force, (void*)pHwnd, (void*)hwnd, isEnabled, current==hwnd); - if( JNI_TRUE==force || current!=hwnd) { + if( JNI_TRUE==force || current!=hwnd || !isEnabled ) { UINT flags = SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE; + if(!isEnabled) { + EnableWindow(hwnd, TRUE); + } SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, flags); SetForegroundWindow(hwnd); // Slightly Higher Priority - SetFocus(hwnd);// Sets Keyboard Focus To Window + SetFocus(hwnd);// Sets Keyboard Focus To Window (activates parent window if exist, or this window) if(NULL!=pHwnd) { SetActiveWindow(hwnd); } - DBG_PRINT("*** WindowsWindow: requestFocus.X1\n"); + current = GetFocus(); + DBG_PRINT("*** WindowsWindow: requestFocus.X1 isCurrent %d\n", current==hwnd); } DBG_PRINT("*** WindowsWindow: requestFocus.XX\n"); } @@ -620,7 +604,33 @@ static void NewtWindows_trackPointerLeave(HWND hwnd) { tme.dwFlags = TME_LEAVE; tme.hwndTrack = hwnd; tme.dwHoverTime = 0; // we don't use TME_HOVER - TrackMouseEvent(&tme); + BOOL ok = TrackMouseEvent(&tme); + DBG_PRINT( "*** WindowsWindow: trackPointerLeave: %d\n", ok); + #ifdef VERBOSE_ON + if(!ok) { + int lastError = (int) GetLastError(); + DBG_PRINT( "*** WindowsWindow: trackPointerLeave: lastError 0x%X %d\n", lastError, lastError); + } + #endif + (void)ok; +} + +static jboolean NewtWindows_setFullScreen(jboolean fullscreen) +{ + int flags = 0; + DEVMODE dm; + + // initialize the DEVMODE structure + ZeroMemory(&dm, sizeof(dm)); + dm.dmSize = sizeof(dm); + + if (0 == EnumDisplaySettings(NULL /*current display device*/, ENUM_CURRENT_SETTINGS, &dm)) + { + return JNI_FALSE; + } + flags = ( JNI_TRUE == fullscreen ) ? CDS_FULLSCREEN : CDS_RESET ; + + return ( DISP_CHANGE_SUCCESSFUL == ChangeDisplaySettings(&dm, flags) ) ? JNI_TRUE : JNI_FALSE; } #if 0 @@ -711,7 +721,7 @@ static RECT* UpdateInsets(JNIEnv *env, jobject window, HWND hwnd) { LONG style = GetWindowLong(hwnd, GWL_STYLE); - BOOL bIsUndecorated = (style & (WS_CHILD|WS_POPUP|WS_SYSMENU)) != 0; + BOOL bIsUndecorated = (style & (WS_CHILD|WS_POPUP)) != 0; if (!bIsUndecorated) { /* Get outer frame sizes. */ if (style & WS_THICKFRAME) { @@ -745,11 +755,11 @@ static RECT* UpdateInsets(JNIEnv *env, jobject window, HWND hwnd) #endif -static void WmSize(JNIEnv *env, jobject window, HWND wnd, UINT type) +static void WmSize(JNIEnv *env, WindowUserData * wud, HWND wnd, UINT type) { RECT rc; - int w, h; BOOL isVisible = IsWindowVisible(wnd); + jobject window = wud->jinstance; if (type == SIZE_MINIMIZED) { // TODO: deal with minimized window sizing @@ -762,29 +772,147 @@ static void WmSize(JNIEnv *env, jobject window, HWND wnd, UINT type) GetClientRect(wnd, &rc); // we report back the dimensions of the client area - w = (int) ( rc.right - rc.left ); - h = (int) ( rc.bottom - rc.top ); + wud->width = (int) ( rc.right - rc.left ); + wud->height = (int) ( rc.bottom - rc.top ); - DBG_PRINT("*** WindowsWindow: WmSize window %p, %dx%d, visible %d\n", (void*)wnd, w, h, isVisible); + DBG_PRINT("*** WindowsWindow: WmSize window %p, %dx%d, visible %d\n", (void*)wnd, wud->width, wud->height, isVisible); - (*env)->CallVoidMethod(env, window, sizeChangedID, JNI_FALSE, w, h, JNI_FALSE); + (*env)->CallVoidMethod(env, window, sizeChangedID, JNI_FALSE, wud->width, wud->height, JNI_FALSE); } -static LRESULT CALLBACK wndProc(HWND wnd, UINT message, - WPARAM wParam, LPARAM lParam) +#ifdef TEST_MOUSE_HOOKS + +static HHOOK hookLLMP; +static HHOOK hookMP; + +static LRESULT CALLBACK HookLowLevelMouseProc (int code, WPARAM wParam, LPARAM lParam) { + // if (code == HC_ACTION) + { + const char *msg; + char msg_buff[128]; + switch (wParam) + { + case WM_LBUTTONDOWN: msg = "WM_LBUTTONDOWN"; break; + case WM_LBUTTONUP: msg = "WM_LBUTTONUP"; break; + case WM_MOUSEMOVE: msg = "WM_MOUSEMOVE"; break; + case WM_MOUSEWHEEL: msg = "WM_MOUSEWHEEL"; break; + case WM_MOUSEHWHEEL: msg = "WM_MOUSEHWHEEL"; break; + case WM_RBUTTONDOWN: msg = "WM_RBUTTONDOWN"; break; + case WM_RBUTTONUP: msg = "WM_RBUTTONUP"; break; + default: + sprintf(msg_buff, "Unknown msg: %u", wParam); + msg = msg_buff; + break; + }//switch + + const MSLLHOOKSTRUCT *p = (MSLLHOOKSTRUCT*)lParam; + DBG_PRINT("**** LLMP: Code: 0x%X: %s - %d/%d\n", code, msg, (int)p->pt.x, (int)p->pt.y); + //} else { + // DBG_PRINT("**** LLMP: CODE: 0x%X\n", code); + } + return CallNextHookEx(hookLLMP, code, wParam, lParam); +} + +static LRESULT CALLBACK HookMouseProc (int code, WPARAM wParam, LPARAM lParam) +{ + // if (code == HC_ACTION) + { + const char *msg; + char msg_buff[128]; + switch (wParam) + { + case WM_LBUTTONDOWN: msg = "WM_LBUTTONDOWN"; break; + case WM_LBUTTONUP: msg = "WM_LBUTTONUP"; break; + case WM_MOUSEMOVE: msg = "WM_MOUSEMOVE"; break; + case WM_MOUSEWHEEL: msg = "WM_MOUSEWHEEL"; break; + case WM_MOUSEHWHEEL: msg = "WM_MOUSEHWHEEL"; break; + case WM_RBUTTONDOWN: msg = "WM_RBUTTONDOWN"; break; + case WM_RBUTTONUP: msg = "WM_RBUTTONUP"; break; + default: + sprintf(msg_buff, "Unknown msg: %u", wParam); + msg = msg_buff; + break; + }//switch + + const MOUSEHOOKSTRUCT *p = (MOUSEHOOKSTRUCT*)lParam; + DBG_PRINT("**** MP: Code: 0x%X: %s - hwnd %p, %d/%d\n", code, msg, p->hwnd, (int)p->pt.x, (int)p->pt.y); + //} else { + // DBG_PRINT("**** MP: CODE: 0x%X\n", code); + } + return CallNextHookEx(hookMP, code, wParam, lParam); +} + +#endif + +static BOOL SafeShowCursor(BOOL show) { + int count, countPre; + BOOL b; + + if( show ) { + count = ShowCursor(TRUE); + if(count < 0) { + do { + countPre = count; + count = ShowCursor(TRUE); + } while( count > countPre && count < 0 ); + } + b = count>=0 ? TRUE : FALSE; + } else { + count = ShowCursor(FALSE); + if(count >= 0) { + do { + countPre = count; + count = ShowCursor(FALSE); + } while( count < countPre && count >= 0 ); + } + b = count<0 ? TRUE : FALSE; + } + return b; +} + +static void sendTouchScreenEvent(JNIEnv *env, jobject window, + short eventType, int modifiers, int actionIdx, + int count, jint* pointerNames, jint* x, jint* y, jfloat* pressure, float maxPressure) { + jintArray jNames = (*env)->NewIntArray(env, count); + if (jNames == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array (names) of size %d", count); + } + (*env)->SetIntArrayRegion(env, jNames, 0, count, pointerNames); + + jintArray jX = (*env)->NewIntArray(env, count); + if (jX == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array (x) of size %d", count); + } + (*env)->SetIntArrayRegion(env, jX, 0, count, x); + + jintArray jY = (*env)->NewIntArray(env, count); + if (jY == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array (y) of size %d", count); + } + (*env)->SetIntArrayRegion(env, jY, 0, count, y); + + jfloatArray jPressure = (*env)->NewFloatArray(env, count); + if (jPressure == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate float array (pressure) of size %d", count); + } + (*env)->SetFloatArrayRegion(env, jPressure, 0, count, pressure); + + (*env)->CallVoidMethod(env, window, sendTouchScreenEventID, + (jshort)eventType, (jint)modifiers, (jint)actionIdx, + jNames, jX, jY, jPressure, (jfloat)maxPressure); +} + + +static LRESULT CALLBACK wndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT res = 0; int useDefWindowProc = 0; JNIEnv *env = NULL; jobject window = NULL; BOOL isKeyDown = FALSE; WindowUserData * wud; - -#ifdef DEBUG_KEYS - if ( WM_KEYDOWN == message ) { - STD_PRINT("*** WindowsWindow: wndProc window %p, 0x%X %d/%d\n", wnd, message, (int)LOWORD(lParam), (int)HIWORD(lParam)); - } -#endif + WORD repCnt; + BYTE scanCode, flags; #if !defined(__MINGW64__) && ( defined(UNDER_CE) || _MSC_VER <= 1200 ) wud = (WindowUserData *) GetWindowLong(wnd, GWL_USERDATA); @@ -797,216 +925,580 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, env = wud->jenv; window = wud->jinstance; - // DBG_PRINT("*** WindowsWindow: thread 0x%X - window %p -> %p, 0x%X %d/%d\n", (int)GetCurrentThreadId(), wnd, window, message, (int)LOWORD(lParam), (int)HIWORD(lParam)); + // DBG_PRINT("*** WindowsWindow: thread 0x%X - window %p -> %p, msg 0x%X, %d/%d\n", (int)GetCurrentThreadId(), wnd, window, message, (int)LOWORD(lParam), (int)HIWORD(lParam)); if (NULL==window || NULL==env) { return DefWindowProc(wnd, message, wParam, lParam); } switch (message) { + // + // The signal pipeline for destruction is: + // Java::DestroyWindow(wnd) _or_ window-close-button -> + // WM_CLOSE -> Java::windowDestroyNotify -> W_DESTROY + case WM_CLOSE: + (*env)->CallBooleanMethod(env, window, windowDestroyNotifyID, JNI_FALSE); + break; - // - // The signal pipeline for destruction is: - // Java::DestroyWindow(wnd) _or_ window-close-button -> - // WM_CLOSE -> Java::windowDestroyNotify -> W_DESTROY - case WM_CLOSE: - (*env)->CallBooleanMethod(env, window, windowDestroyNotifyID, JNI_FALSE); - break; - - case WM_DESTROY: - { -#if !defined(__MINGW64__) && ( defined(UNDER_CE) || _MSC_VER <= 1200 ) - SetWindowLong(wnd, GWL_USERDATA, (intptr_t) NULL); -#else - SetWindowLongPtr(wnd, GWLP_USERDATA, (intptr_t) NULL); -#endif - free(wud); wud=NULL; - (*env)->DeleteGlobalRef(env, window); - } - break; + case WM_DESTROY: + { + #if !defined(__MINGW64__) && ( defined(UNDER_CE) || _MSC_VER <= 1200 ) + SetWindowLong(wnd, GWL_USERDATA, (intptr_t) NULL); + #else + SetWindowLongPtr(wnd, GWLP_USERDATA, (intptr_t) NULL); + #endif + free(wud); wud=NULL; + (*env)->DeleteGlobalRef(env, window); + } + break; - case WM_SYSCHAR: - useDefWindowProc = WmChar(env, window, wParam, - LOWORD(lParam), HIWORD(lParam), FALSE); - break; + case WM_ACTIVATE: { + HWND wndPrev = (HWND) lParam; + BOOL fMinimized = (BOOL) HIWORD(wParam); + int fActive = LOWORD(wParam); + BOOL inactive = WA_INACTIVE==fActive; + #ifdef VERBOSE_ON + BOOL anyActive = WA_ACTIVE==fActive, clickActive = WA_CLICKACTIVE==fActive; + DBG_PRINT("*** WindowsWindow: WM_ACTIVATE window %p, prev %p, minimized %d, active %d (any %d, click %d, inactive %d), FS %d\n", + wnd, wndPrev, fMinimized, fActive, anyActive, clickActive, inactive, wud->isFullscreen); + #endif + if( wud->isFullscreen ) { + // Bug 916 - NEWT Fullscreen Mode on Windows ALT-TAB doesn't allow Application Switching + // Remedy for 'some' display drivers, i.e. Intel HD: + // Explicitly push fullscreen window to BOTTOM when inactive (ALT-TAB) + UINT flags = SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE; + if( inactive ) { + SetWindowPos(wnd, HWND_BOTTOM, 0, 0, 0, 0, flags); + } else { + SetWindowPos(wnd, HWND_TOP, 0, 0, 0, 0, flags); + SetForegroundWindow(wnd); // Slightly Higher Priority + } + } + useDefWindowProc = 1; + } + break; - case WM_CHAR: - useDefWindowProc = WmChar(env, window, wParam, - LOWORD(lParam), HIWORD(lParam), TRUE); - break; - - case WM_KEYDOWN: -#ifdef DEBUG_KEYS - STD_PRINT("*** WindowsWindow: windProc sending window %p -> %p, 0x%X %d/%d\n", wnd, window, message, (int)LOWORD(lParam), (int)HIWORD(lParam)); -#endif - useDefWindowProc = WmKeyDown(env, window, wParam, - LOWORD(lParam), HIWORD(lParam), FALSE); - break; + case WM_SETTINGCHANGE: + if (wParam == SPI_SETNONCLIENTMETRICS) { + // make sure insets are updated, we don't need to resize the window + // because the size of the client area doesn't change + (void)UpdateInsets(env, window, wnd); + } else { + useDefWindowProc = 1; + } + break; - case WM_KEYUP: - useDefWindowProc = WmKeyUp(env, window, wParam, - LOWORD(lParam), HIWORD(lParam), FALSE); - break; + case WM_SIZE: + WmSize(env, wud, wnd, (UINT)wParam); + break; - case WM_SIZE: - WmSize(env, window, wnd, (UINT)wParam); - break; + case WM_SHOWWINDOW: + (*env)->CallVoidMethod(env, window, visibleChangedID, JNI_FALSE, wParam==TRUE?JNI_TRUE:JNI_FALSE); + break; - case WM_SETTINGCHANGE: - if (wParam == SPI_SETNONCLIENTMETRICS) { - // make sure insets are updated, we don't need to resize the window - // because the size of the client area doesn't change - (void)UpdateInsets(env, window, wnd); - } else { + case WM_MOVE: + DBG_PRINT("*** WindowsWindow: WM_MOVE window %p, %d/%d\n", wnd, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + (*env)->CallVoidMethod(env, window, positionChangedID, JNI_FALSE, (jint)GET_X_LPARAM(lParam), (jint)GET_Y_LPARAM(lParam)); useDefWindowProc = 1; + break; + + case WM_PAINT: { + RECT r; + if (GetUpdateRect(wnd, &r, FALSE /* do not erase background */)) { + // clear the whole client area and issue repaint for it, w/o looping through erase background + ValidateRect(wnd, NULL); // clear all! + (*env)->CallVoidMethod(env, window, windowRepaintID, JNI_FALSE, 0, 0, -1, -1); + } else { + // shall not happen ? + ValidateRect(wnd, NULL); // clear all! + } + // return 0 == done + break; } - break; + case WM_ERASEBKGND: + // ignore erase background + (*env)->CallVoidMethod(env, window, windowRepaintID, JNI_FALSE, 0, 0, -1, -1); + res = 1; // return 1 == done, OpenGL, etc .. erases the background, hence we claim to have just done this + break; + case WM_SETCURSOR : + if (0 != wud->setPointerVisible) { // Tristate, -1, 0, 1 + BOOL visibilityChangeSuccessful; + if (1 == wud->setPointerVisible) { + visibilityChangeSuccessful = SafeShowCursor(TRUE); + } else /* -1 == wud->setPointerVisible */ { + visibilityChangeSuccessful = SafeShowCursor(FALSE); + } + DBG_PRINT("*** WindowsWindow: WM_SETCURSOR requested visibility: %d success: %d\n", wud->setPointerVisible, visibilityChangeSuccessful); + wud->setPointerVisible = 0; + // own signal, consumed, no further processing + res = 1; + } else if( 0 != wud->setPointerAction ) { + if( -1 == wud->setPointerAction ) { + wud->setPointerHandle = wud->defPointerHandle; + } + HCURSOR preHandle = SetCursor(wud->setPointerHandle); + DBG_PRINT("*** WindowsWindow: WM_SETCURSOR PointerIcon change %d: pre %p -> set %p, def %p\n", + wud->setPointerAction, (void*)preHandle, (void*)wud->setPointerHandle, (void*)wud->defPointerHandle); + wud->setPointerAction = 0; + // own signal, consumed, no further processing + res = 1; + } else if( HTCLIENT == LOWORD(lParam) ) { + BOOL setCur = wud->isChildWindow && wud->defPointerHandle != wud->setPointerHandle; + #ifdef VERBOSE_ON + HCURSOR cur = GetCursor(); + DBG_PRINT("*** WindowsWindow: WM_SETCURSOR PointerIcon NOP [1 custom-override] set %p, def %p, cur %p, isChild %d, setCur %d\n", + (void*)wud->setPointerHandle, (void*)wud->defPointerHandle, (void*)cur, wud->isChildWindow, setCur); + #endif + if( setCur ) { + SetCursor(wud->setPointerHandle); + // own signal, consumed, no further processing + res = 1; + } else { + DBG_PRINT("*** WindowsWindow: WM_SETCURSOR PointerIcon NOP [2 parent-override] set %p, def %p\n", (void*)wud->setPointerHandle, (void*)wud->defPointerHandle); + // NOP for us, allow parent to act + res = 0; + } + } else { + DBG_PRINT("*** WindowsWindow: WM_SETCURSOR !HTCLIENT\n"); + // NOP for us, allow parent to act + res = 0; + } + break; - case WM_LBUTTONDOWN: - DBG_PRINT("*** WindowsWindow: LBUTTONDOWN\n"); - (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); - (*env)->CallVoidMethod(env, window, sendMouseEventID, - (jint) EVENT_MOUSE_PRESSED, - GetModifiers(), - (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), - (jint) 1, (jint) 0); - useDefWindowProc = 1; - break; + case WM_SETFOCUS: + DBG_PRINT("*** WindowsWindow: WM_SETFOCUS window %p, lost %p\n", wnd, (HWND)wParam); + (*env)->CallVoidMethod(env, window, focusChangedID, JNI_FALSE, JNI_TRUE); + useDefWindowProc = 1; + break; - case WM_LBUTTONUP: - (*env)->CallVoidMethod(env, window, sendMouseEventID, - (jint) EVENT_MOUSE_RELEASED, - GetModifiers(), - (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), - (jint) 1, (jint) 0); - useDefWindowProc = 1; - break; + case WM_KILLFOCUS: + DBG_PRINT("*** WindowsWindow: WM_KILLFOCUS window %p, received %p, inside %d, captured %d, tDown %d\n", + wnd, (HWND)wParam, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount); + if( wud->touchDownCount == 0 ) { + wud->pointerInside = 0; + if( wud->pointerCaptured ) { + wud->pointerCaptured = 0; + ReleaseCapture(); + } + (*env)->CallVoidMethod(env, window, focusChangedID, JNI_FALSE, JNI_FALSE); + useDefWindowProc = 1; + } else { + // quick focus .. we had it already, are enabled .. + SetFocus(wnd);// Sets Keyboard Focus To Window (activates parent window if exist, or this window) + } + break; - case WM_MBUTTONDOWN: - DBG_PRINT("*** WindowsWindow: MBUTTONDOWN\n"); - (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); - (*env)->CallVoidMethod(env, window, sendMouseEventID, - (jint) EVENT_MOUSE_PRESSED, - GetModifiers(), - (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), - (jint) 2, (jint) 0); - useDefWindowProc = 1; - break; + case WM_SYSCHAR: + useDefWindowProc = 1; + break; - case WM_MBUTTONUP: - (*env)->CallVoidMethod(env, window, sendMouseEventID, - (jint) EVENT_MOUSE_RELEASED, - GetModifiers(), - (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), - (jint) 2, (jint) 0); - useDefWindowProc = 1; - break; + case WM_SYSKEYDOWN: + repCnt = HIWORD(lParam); scanCode = LOBYTE(repCnt); flags = HIBYTE(repCnt); + repCnt = LOWORD(lParam); + #ifdef DEBUG_KEYS + DBG_PRINT("*** WindowsWindow: windProc WM_SYSKEYDOWN sending window %p -> %p, code 0x%X, repCnt %d, scanCode 0x%X, flags 0x%X\n", wnd, window, (int)wParam, (int)repCnt, (int)scanCode, (int)flags); + #endif + useDefWindowProc = WmKeyDown(env, window, (USHORT)wParam, repCnt, scanCode, flags, TRUE); + break; - case WM_RBUTTONDOWN: - DBG_PRINT("*** WindowsWindow: RBUTTONDOWN\n"); - (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); - (*env)->CallVoidMethod(env, window, sendMouseEventID, - (jint) EVENT_MOUSE_PRESSED, - GetModifiers(), - (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), - (jint) 3, (jint) 0); - useDefWindowProc = 1; - break; + case WM_SYSKEYUP: + repCnt = HIWORD(lParam); scanCode = LOBYTE(repCnt); flags = HIBYTE(repCnt); + repCnt = LOWORD(lParam); + #ifdef DEBUG_KEYS + DBG_PRINT("*** WindowsWindow: windProc WM_SYSKEYUP sending window %p -> %p, code 0x%X, repCnt %d, scanCode 0x%X, flags 0x%X\n", wnd, window, (int)wParam, (int)repCnt, (int)scanCode, (int)flags); + #endif + useDefWindowProc = WmKeyUp(env, window, (USHORT)wParam, repCnt, scanCode, flags, TRUE); + break; - case WM_RBUTTONUP: - (*env)->CallVoidMethod(env, window, sendMouseEventID, - (jint) EVENT_MOUSE_RELEASED, - GetModifiers(), - (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), - (jint) 3, (jint) 0); - useDefWindowProc = 1; - break; + case WM_CHAR: + useDefWindowProc = 1; + break; + + case WM_KEYDOWN: + repCnt = HIWORD(lParam); scanCode = LOBYTE(repCnt); flags = HIBYTE(repCnt); + #ifdef DEBUG_KEYS + DBG_PRINT("*** WindowsWindow: windProc WM_KEYDOWN sending window %p -> %p, code 0x%X, repCnt %d, scanCode 0x%X, flags 0x%X\n", wnd, window, (int)wParam, (int)repCnt, (int)scanCode, (int)flags); + #endif + useDefWindowProc = WmKeyDown(env, window, wParam, repCnt, scanCode, flags, FALSE); + break; - case WM_MOUSEMOVE: - (*env)->CallVoidMethod(env, window, sendMouseEventID, - (jint) EVENT_MOUSE_MOVED, - GetModifiers(), - (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), - (jint) 0, (jint) 0); - useDefWindowProc = 1; - break; - case WM_MOUSELEAVE: - (*env)->CallVoidMethod(env, window, enqueueMouseEventID, JNI_FALSE, - (jint) EVENT_MOUSE_EXITED, - 0, - (jint) -1, (jint) -1, // fake - (jint) 0, (jint) 0); - useDefWindowProc = 1; - break; - // Java synthesizes EVENT_MOUSE_ENTERED - - case WM_MOUSEWHEEL: { - // need to convert the coordinates to component-relative - int x = GET_X_LPARAM(lParam); - int y = GET_Y_LPARAM(lParam); - POINT eventPt; - eventPt.x = x; - eventPt.y = y; - ScreenToClient(wnd, &eventPt); - (*env)->CallVoidMethod(env, window, sendMouseEventID, - (jint) EVENT_MOUSE_WHEEL_MOVED, - GetModifiers(), - (jint) eventPt.x, (jint) eventPt.y, - (jint) 1, (jint) (GET_WHEEL_DELTA_WPARAM(wParam)/120.0f)); - useDefWindowProc = 1; - break; - } + case WM_KEYUP: + repCnt = HIWORD(lParam); scanCode = LOBYTE(repCnt); flags = HIBYTE(repCnt); + repCnt = LOWORD(lParam); + #ifdef DEBUG_KEYS + DBG_PRINT("*** WindowsWindow: windProc WM_KEYUP sending window %p -> %p, code 0x%X, repCnt %d, scanCode 0x%X, flags 0x%X\n", wnd, window, (int)wParam, (int)repCnt, (int)scanCode, (int)flags); + #endif + useDefWindowProc = WmKeyUp(env, window, wParam, repCnt, scanCode, flags, FALSE); + break; - case WM_SETFOCUS: - (*env)->CallVoidMethod(env, window, focusChangedID, JNI_FALSE, JNI_TRUE); - useDefWindowProc = 1; - break; + case WM_LBUTTONDOWN: { + DBG_PRINT("*** WindowsWindow: WM_LBUTTONDOWN %d/%d [%dx%d] inside %d, captured %d, tDown [c %d, lastUp %d]\n", + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), + wud->width, wud->height, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); + if( 0 == wud->touchDownLastUp && 0 == wud->touchDownCount ) { + if( 0 == wud->pointerInside ) { + wud->pointerInside = 1; + NewtWindows_trackPointerLeave(wnd); + } + (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, window, sendMouseEventID, + (jshort) EVENT_MOUSE_PRESSED, + GetModifiers( 0 ), + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), + (jshort) 1, (jfloat) 0.0f); + useDefWindowProc = 1; + } + } + break; - case WM_KILLFOCUS: - (*env)->CallVoidMethod(env, window, focusChangedID, JNI_FALSE, JNI_FALSE); - useDefWindowProc = 1; - break; + case WM_LBUTTONUP: { + DBG_PRINT("*** WindowsWindow: WM_LBUTTONUP %d/%d [%dx%d] inside %d, captured %d, tDown [c %d, lastUp %d]\n", + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), + wud->width, wud->height, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); + if( 0 < wud->touchDownLastUp ) { + // mitigate LBUTTONUP after last TOUCH lift + wud->touchDownLastUp = 0; + } else if( 0 == wud->touchDownCount ) { + jint modifiers = GetModifiers(0); + if( wud->pointerCaptured && 0 == ( modifiers & EVENT_BUTTONALL_MASK ) ) { + wud->pointerCaptured = 0; + ReleaseCapture(); + } + if( 0 == wud->pointerInside ) { + wud->pointerInside = 1; + NewtWindows_trackPointerLeave(wnd); + } + (*env)->CallVoidMethod(env, window, sendMouseEventID, + (jshort) EVENT_MOUSE_RELEASED, + GetModifiers( 0 ), + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), + (jshort) 1, (jfloat) 0.0f); + useDefWindowProc = 1; + } + } + break; - case WM_SHOWWINDOW: - (*env)->CallVoidMethod(env, window, visibleChangedID, JNI_FALSE, wParam==TRUE?JNI_TRUE:JNI_FALSE); - break; + case WM_MBUTTONDOWN: { + DBG_PRINT("*** WindowsWindow: WM_MBUTTONDOWN %d/%d [%dx%d] inside %d, captured %d, tDown [c %d, lastUp %d]\n", + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), + wud->width, wud->height, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); + if( 0 == wud->touchDownCount ) { + if( 0 == wud->pointerInside ) { + wud->pointerInside = 1; + NewtWindows_trackPointerLeave(wnd); + } + (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, window, sendMouseEventID, + (jshort) EVENT_MOUSE_PRESSED, + GetModifiers( 0 ), + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), + (jshort) 2, (jfloat) 0.0f); + useDefWindowProc = 1; + } + } + break; - case WM_MOVE: - DBG_PRINT("*** WindowsWindow: WM_MOVE window %p, %d/%d\n", wnd, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - (*env)->CallVoidMethod(env, window, positionChangedID, JNI_FALSE, (jint)GET_X_LPARAM(lParam), (jint)GET_Y_LPARAM(lParam)); - useDefWindowProc = 1; - break; + case WM_MBUTTONUP: { + DBG_PRINT("*** WindowsWindow: WM_MBUTTONUP %d/%d [%dx%d] inside %d, captured %d, tDown [c %d, lastUp %d]\n", + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), + wud->width, wud->height, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); + if( 0 == wud->touchDownCount ) { + jint modifiers = GetModifiers(0); + if( wud->pointerCaptured && 0 == ( modifiers & EVENT_BUTTONALL_MASK ) ) { + wud->pointerCaptured = 0; + ReleaseCapture(); + } + if( 0 == wud->pointerInside ) { + wud->pointerInside = 1; + NewtWindows_trackPointerLeave(wnd); + } + (*env)->CallVoidMethod(env, window, sendMouseEventID, + (jshort) EVENT_MOUSE_RELEASED, + GetModifiers( 0 ), + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), + (jshort) 2, (jfloat) 0.0f); + useDefWindowProc = 1; + } + } + break; - case WM_PAINT: { - RECT r; - useDefWindowProc = 0; - if (GetUpdateRect(wnd, &r, TRUE /* erase background */)) { - /* - jint width = r.right-r.left; - jint height = r.bottom-r.top; - if (width > 0 && height > 0) { - (*env)->CallVoidMethod(env, window, windowRepaintID, JNI_FALSE, r.left, r.top, width, height); + case WM_RBUTTONDOWN: { + DBG_PRINT("*** WindowsWindow: WM_RBUTTONDOWN %d/%d [%dx%d] inside %d, captured %d, tDown [c %d, lastUp %d]\n", + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), + wud->width, wud->height, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); + if( 0 == wud->touchDownCount ) { + if( 0 == wud->pointerInside ) { + wud->pointerInside = 1; + NewtWindows_trackPointerLeave(wnd); + } + (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, window, sendMouseEventID, + (jshort) EVENT_MOUSE_PRESSED, + GetModifiers( 0 ), + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), + (jshort) 3, (jfloat) 0.0f); + useDefWindowProc = 1; + } + } + break; + + case WM_RBUTTONUP: { + DBG_PRINT("*** WindowsWindow: WM_RBUTTONUP %d/%d [%dx%d] inside %d, captured %d, tDown [c %d, lastUp %d]\n", + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), + wud->width, wud->height, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); + if( 0 == wud->touchDownCount ) { + jint modifiers = GetModifiers(0); + if( wud->pointerCaptured && 0 == ( modifiers & EVENT_BUTTONALL_MASK ) ) { + wud->pointerCaptured = 0; + ReleaseCapture(); + } + if( 0 == wud->pointerInside ) { + wud->pointerInside = 1; + NewtWindows_trackPointerLeave(wnd); + } + (*env)->CallVoidMethod(env, window, sendMouseEventID, + (jshort) EVENT_MOUSE_RELEASED, + GetModifiers( 0 ), + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), + (jshort) 3, (jfloat) 0.0f); + useDefWindowProc = 1; + } + } + break; + + case WM_MOUSEMOVE: { + DBG_PRINT("*** WindowsWindow: WM_MOUSEMOVE %d/%d [%dx%d] inside %d, captured %d, tDown [c %d, lastUp %d]\n", + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), + wud->width, wud->height, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); + if( 0 == wud->touchDownLastUp && 0 == wud->touchDownCount ) { + jint modifiers = GetModifiers(0); + if( 0 == wud->pointerCaptured && 0 != ( modifiers & EVENT_BUTTONALL_MASK ) ) { + wud->pointerCaptured = 1; + SetCapture(wnd); + } + if( 0 == wud->pointerInside ) { + wud->pointerInside = 1; + NewtWindows_trackPointerLeave(wnd); + SetCursor(wud->setPointerHandle); + } + (*env)->CallVoidMethod(env, window, sendMouseEventID, + (jshort) EVENT_MOUSE_MOVED, + modifiers, + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), + (jshort) 0, (jfloat) 0.0f); + } + useDefWindowProc = 1; + } + break; + case WM_MOUSELEAVE: { + DBG_PRINT("*** WindowsWindow: WM_MOUSELEAVE %d/%d [%dx%d] inside %d, captured %d, tDown [c %d, lastUp %d]\n", + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), + wud->width, wud->height, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); + if( 0 == wud->touchDownCount ) { + wud->pointerInside = 0; + (*env)->CallVoidMethod(env, window, sendMouseEventID, + (jshort) EVENT_MOUSE_EXITED, + 0, + (jint) -1, (jint) -1, // fake + (jshort) 0, (jfloat) 0.0f); + useDefWindowProc = 1; + } + } + break; + // Java synthesizes EVENT_MOUSE_ENTERED + + case WM_HSCROLL: { // Only delivered if windows has WS_HSCROLL, hence dead code! + int sb = LOWORD(wParam); + int modifiers = GetModifiers( 0 ) | EVENT_SHIFT_MASK; + float rotation; + switch(sb) { + case SB_LINELEFT: + rotation = 1.0f; + break; + case SB_PAGELEFT: + rotation = 2.0f; + break; + case SB_LINERIGHT: + rotation = -1.0f; + break; + case SB_PAGERIGHT: + rotation = -1.0f; + break; + } + DBG_PRINT("*** WindowsWindow: WM_HSCROLL 0x%X, rotation %f, mods 0x%X\n", sb, rotation, modifiers); + (*env)->CallVoidMethod(env, window, sendMouseEventID, + (jshort) EVENT_MOUSE_WHEEL_MOVED, + modifiers, + (jint) 0, (jint) 0, + (jshort) 1, (jfloat) rotation); + useDefWindowProc = 1; + break; } - ValidateRect(wnd, &r); - */ + case WM_MOUSEHWHEEL: /* tilt */ + case WM_MOUSEWHEEL: /* rotation */ { + // need to convert the coordinates to component-relative + int x = GET_X_LPARAM(lParam); + int y = GET_Y_LPARAM(lParam); + int modifiers = GetModifiers( 0 ); + float rotationOrTilt = (float)(GET_WHEEL_DELTA_WPARAM(wParam))/WHEEL_DELTAf; + int vKeys = GET_KEYSTATE_WPARAM(wParam); + POINT eventPt; + eventPt.x = x; + eventPt.y = y; + ScreenToClient(wnd, &eventPt); + + if( WM_MOUSEHWHEEL == message ) { + modifiers |= EVENT_SHIFT_MASK; + DBG_PRINT("*** WindowsWindow: WM_MOUSEHWHEEL %d/%d, tilt %f, vKeys 0x%X, mods 0x%X\n", + (int)eventPt.x, (int)eventPt.y, rotationOrTilt, vKeys, modifiers); + } else { + DBG_PRINT("*** WindowsWindow: WM_MOUSEWHEEL %d/%d, rotation %f, vKeys 0x%X, mods 0x%X\n", + (int)eventPt.x, (int)eventPt.y, rotationOrTilt, vKeys, modifiers); + } + (*env)->CallVoidMethod(env, window, sendMouseEventID, + (jshort) EVENT_MOUSE_WHEEL_MOVED, + modifiers, + (jint) eventPt.x, (jint) eventPt.y, + (jshort) 1, (jfloat) rotationOrTilt); + useDefWindowProc = 1; + break; } - break; - } - case WM_ERASEBKGND: - // ignore erase background - (*env)->CallVoidMethod(env, window, windowRepaintID, JNI_FALSE, 0, 0, -1, -1); - useDefWindowProc = 0; - res = 1; // OpenGL, etc .. erases the background, hence we claim to have just done this - break; + case WM_TOUCH: if( wud->supportsMTouch ) { + UINT cInputs = LOWORD(wParam); + // DBG_PRINT("*** WindowsWindow: WM_TOUCH window %p, cInputs %d\n", wnd, cInputs); + HTOUCHINPUT hTouch = (HTOUCHINPUT)lParam; + PTOUCHINPUT pInputs = (PTOUCHINPUT) calloc(cInputs, sizeof(TOUCHINPUT)); + if (NULL != pInputs) { + if ( WinTouch_GetTouchInputInfo(hTouch, cInputs, pInputs, sizeof(TOUCHINPUT)) ) { + UINT i; + short eventType[cInputs]; + jint modifiers = GetModifiers( 0 ); + jint actionIdx = -1; + jint pointerNames[cInputs]; + jint x[cInputs], y[cInputs]; + jfloat pressure[cInputs]; + jfloat maxPressure = 1.0F; // FIXME: n/a on windows ? + int allPInside = 0 < cInputs; + int sendFocus = 0; + + for (i=0; i < cInputs; i++) { + PTOUCHINPUT pTi = & pInputs[i]; + POINT eventPt; + int isDown = pTi->dwFlags & TOUCHEVENTF_DOWN; + int isUp = pTi->dwFlags & TOUCHEVENTF_UP; + int isMove = pTi->dwFlags & TOUCHEVENTF_MOVE; + + int isPrim = pTi->dwFlags & TOUCHEVENTF_PRIMARY; + int isNoCoalesc = pTi->dwFlags & TOUCHEVENTF_NOCOALESCE; + + #ifdef VERBOSE_ON + const char * touchAction; + if( isDown ) { + touchAction = "down"; + } else if( isUp ) { + touchAction = "_up_"; + } else if( isMove ) { + touchAction = "move"; + } else { + touchAction = "undf"; + } + #endif + + pointerNames[i] = (jint)pTi->dwID; + eventPt.x = TOUCH_COORD_TO_PIXEL(pTi->x); + eventPt.y = TOUCH_COORD_TO_PIXEL(pTi->y); + ScreenToClient(wnd, &eventPt); + + int pInside = 0 <= eventPt.x && 0 <= eventPt.y && eventPt.x < wud->width && eventPt.y < wud->height; + allPInside &= pInside; + + x[i] = (jint)eventPt.x; + y[i] = (jint)eventPt.y; + pressure[i] = 1.0F; // FIXME: n/a on windows ? + if(isDown) { + sendFocus = 0 == wud->touchDownCount; + eventType[i] = (jshort) EVENT_MOUSE_PRESSED; + wud->touchDownCount++; + wud->touchDownLastUp = 0; + } else if(isUp) { + eventType[i] = (jshort) EVENT_MOUSE_RELEASED; + wud->touchDownCount--; + // mitigate LBUTTONUP after last TOUCH lift + wud->touchDownLastUp = 0 == wud->touchDownCount; + } else if(isMove) { + eventType[i] = (jshort) EVENT_MOUSE_MOVED; + wud->touchDownLastUp = 0; + } else { + eventType[i] = (jshort) 0; + } + if(isPrim) { + actionIdx = (jint)i; + } + + #ifdef VERBOSE_ON + DBG_PRINT("*** WindowsWindow: WM_TOUCH[%d/%d].%s name 0x%x, prim %d, nocoalsc %d, %d/%d [%dx%d] inside [%d/%d], tDown [c %d, lastUp %d]\n", + (i+1), cInputs, touchAction, (int)(pTi->dwID), isPrim, isNoCoalesc, x[i], y[i], wud->width, wud->height, + pInside, allPInside, wud->touchDownCount, wud->touchDownLastUp); + #endif + } + wud->pointerInside = allPInside; + if( sendFocus ) { + (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); + } + int sentCount = 0, updownCount=0, moveCount=0; + // Primary first, if available! + if( 0 <= actionIdx ) { + sendTouchScreenEvent(env, window, eventType[actionIdx], modifiers, actionIdx, + cInputs, pointerNames, x, y, pressure, maxPressure); + sentCount++; + } + // 1 Move second .. + for (i=0; i < cInputs; i++) { + short et = eventType[i]; + if( (jshort) EVENT_MOUSE_MOVED == et ) { + if( i != actionIdx && 0 == moveCount ) { + sendTouchScreenEvent(env, window, et, modifiers, i, + cInputs, pointerNames, x, y, pressure, maxPressure); + sentCount++; + } + moveCount++; + } + } + // Up and downs last + for (i=0; i < cInputs; i++) { + short et = eventType[i]; + if( (jshort) EVENT_MOUSE_MOVED != et ) { + if( i != actionIdx ) { + sendTouchScreenEvent(env, window, et, modifiers, i, + cInputs, pointerNames, x, y, pressure, maxPressure); + sentCount++; + } + updownCount++; + } + } + DBG_PRINT("*** WindowsWindow: WM_TOUCH.summary pCount %d, prim %d, updown %d, move %d, sent %d, inside %d, captured %d, tDown [c %d, lastUp %d]\n", + cInputs, actionIdx, updownCount, moveCount, sentCount, wud->pointerInside, wud->pointerCaptured, wud->touchDownCount, wud->touchDownLastUp); + + // Message processed - close it + WinTouch_CloseTouchInputHandle(hTouch); + } else { + useDefWindowProc = 1; + } + free(pInputs); + } + break; + } - default: - useDefWindowProc = 1; + default: + useDefWindowProc = 1; } - if (useDefWindowProc) + + if (useDefWindowProc) { return DefWindowProc(wnd, message, wParam, lParam); + } return res; } @@ -1028,12 +1520,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_DisplayDriver_DispatchMes // DBG_PRINT("*** WindowsWindow.DispatchMessages0: thread 0x%X - gotOne %d\n", (int)GetCurrentThreadId(), (int)gotOne); if (gotOne) { ++i; -#ifdef DEBUG_KEYS - if(WM_KEYDOWN == msg.message) { - STD_PRINT("*** WindowsWindow: DispatchMessages window %p, 0x%X %d/%d\n", msg.hwnd, msg.message, (int)LOWORD(msg.lParam), (int)HIWORD(msg.lParam)); - } -#endif - TranslateMessage(&msg); + // TranslateMessage(&msg); // No more needed: We translate V_KEY -> UTF Char manually in key up/down DispatchMessage(&msg); } } while (gotOne && i < 100); @@ -1041,11 +1528,11 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_DisplayDriver_DispatchMes /* * Class: jogamp_newt_driver_windows_ScreenDriver - * Method: getOriginX0 - * Signature: (I)I + * Method: getVirtualOriginX0 + * Signature: ()I */ -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getOriginX0 - (JNIEnv *env, jobject obj, jint scrn_idx) +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getVirtualOriginX0 + (JNIEnv *env, jobject obj) { if( GetSystemMetrics( SM_CMONITORS) > 1) { return (jint)GetSystemMetrics(SM_XVIRTUALSCREEN); @@ -1056,11 +1543,11 @@ JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getOriginX0 /* * Class: jogamp_newt_driver_windows_ScreenDriver - * Method: getOriginY0 - * Signature: (I)I + * Method: getVirtualOriginY0 + * Signature: ()I */ -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getOriginY0 - (JNIEnv *env, jobject obj, jint scrn_idx) +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getVirtualOriginY0 + (JNIEnv *env, jobject obj) { if( GetSystemMetrics( SM_CMONITORS ) > 1) { return (jint)GetSystemMetrics(SM_YVIRTUALSCREEN); @@ -1071,11 +1558,11 @@ JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getOriginY0 /* * Class: jogamp_newt_driver_windows_ScreenDriver - * Method: getWidthImpl - * Signature: (I)I + * Method: getVirtualWidthImpl + * Signature: ()I */ -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getWidthImpl0 - (JNIEnv *env, jobject obj, jint scrn_idx) +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getVirtualWidthImpl0 + (JNIEnv *env, jobject obj) { if( GetSystemMetrics( SM_CMONITORS) > 1) { return (jint)GetSystemMetrics(SM_CXVIRTUALSCREEN); @@ -1086,11 +1573,11 @@ JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getWidthImpl /* * Class: jogamp_newt_driver_windows_ScreenDriver - * Method: getHeightImpl - * Signature: (I)I + * Method: getVirtualHeightImpl + * Signature: ()I */ -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getHeightImpl0 - (JNIEnv *env, jobject obj, jint scrn_idx) +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getVirtualHeightImpl0 + (JNIEnv *env, jobject obj) { if( GetSystemMetrics( SM_CMONITORS ) > 1) { return (jint)GetSystemMetrics(SM_CYVIRTUALSCREEN); @@ -1142,65 +1629,137 @@ static int NewtScreen_RotationNewtCCW2NativeCCW(JNIEnv *env, jint newt) { return native; } -/* -static void NewtScreen_scanDisplayDevices() { - DISPLAY_DEVICE device; - int i = 0; - LPCTSTR name; - while(NULL != (name = NewtScreen_getDisplayDeviceName(&device, i))) { - fprintf(stderr, "*** [%d]: <%s> active %d\n", i, name, ( 0 != ( device.StateFlags & DISPLAY_DEVICE_ACTIVE ) ) ); - i++; +static LPCTSTR NewtScreen_getAdapterName(DISPLAY_DEVICE * device, int crt_idx) { + memset(device, 0, sizeof(DISPLAY_DEVICE)); + device->cb = sizeof(DISPLAY_DEVICE); + if( FALSE == EnumDisplayDevices(NULL, crt_idx, device, 0) ) { + DBG_PRINT("*** WindowsWindow: getAdapterName.EnumDisplayDevices(crt_idx %d) -> FALSE\n", crt_idx); + return NULL; } -}*/ -static LPCTSTR NewtScreen_getDisplayDeviceName(DISPLAY_DEVICE * device, int scrn_idx) { - device->cb = sizeof(DISPLAY_DEVICE); - if( FALSE == EnumDisplayDevices(NULL, scrn_idx, device, 0) ) { - DBG_PRINT("*** WindowsWindow: getDisplayDeviceName.EnumDisplayDevices(scrn_idx %d) -> FALSE\n", scrn_idx); + if( NULL == device->DeviceName || 0 == _tcslen(device->DeviceName) ) { return NULL; } - if( 0 == ( device->StateFlags & DISPLAY_DEVICE_ACTIVE ) ) { - DBG_PRINT("*** WindowsWindow: !DISPLAY_DEVICE_ACTIVE(scrn_idx %d)\n", scrn_idx); + return device->DeviceName; +} + +static LPCTSTR NewtScreen_getMonitorName(LPCTSTR adapterName, DISPLAY_DEVICE * device, int monitor_idx, BOOL onlyActive) { + memset(device, 0, sizeof(DISPLAY_DEVICE)); + device->cb = sizeof(DISPLAY_DEVICE); + if( 0 == monitor_idx ) { + if( FALSE == EnumDisplayDevices(adapterName, monitor_idx, device, 0) ) { + DBG_PRINT("*** WindowsWindow: getDisplayName.EnumDisplayDevices(monitor_idx %d).adapter -> FALSE\n", monitor_idx); + return NULL; + } + } + + if( onlyActive && 0 == ( device->StateFlags & DISPLAY_DEVICE_ACTIVE ) ) { + DBG_PRINT("*** WindowsWindow: !DISPLAY_DEVICE_ACTIVE(monitor_idx %d).display\n", monitor_idx); + return NULL; + } + if( NULL == device->DeviceName || 0 == _tcslen(device->DeviceName) ) { return NULL; } return device->DeviceName; } +JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_dumpMonitorInfo0 + (JNIEnv *env, jclass clazz) +{ + DISPLAY_DEVICE aDevice, dDevice; + int i = 0, j; + LPCTSTR aName, dName; + while(NULL != (aName = NewtScreen_getAdapterName(&aDevice, i))) { + fprintf(stderr, "*** [%d]: <%s> flags 0x%X active %d\n", i, aName, aDevice.StateFlags, ( 0 != ( aDevice.StateFlags & DISPLAY_DEVICE_ACTIVE ) ) ); + j=0; + while(NULL != (dName = NewtScreen_getMonitorName(aName, &dDevice, j, FALSE))) { + fprintf(stderr, "*** [%d][%d]: <%s> flags 0x%X active %d\n", i, j, dName, dDevice.StateFlags, ( 0 != ( dDevice.StateFlags & DISPLAY_DEVICE_ACTIVE ) ) ); + j++; + } + i++; + } +} + static HDC NewtScreen_createDisplayDC(LPCTSTR displayDeviceName) { return CreateDC("DISPLAY", displayDeviceName, NULL, NULL); } /* * Class: jogamp_newt_driver_windows_ScreenDriver - * Method: getScreenMode0 - * Signature: (II)[I + * Method: getAdapterName0 + * Signature: (I)Ljava/lang/String; */ -JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getScreenMode0 - (JNIEnv *env, jobject obj, jint scrn_idx, jint mode_idx) +JNIEXPORT jstring JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getAdapterName0 + (JNIEnv *env, jobject obj, jint crt_idx) { DISPLAY_DEVICE device; - int prop_num = NUM_SCREEN_MODE_PROPERTIES_ALL; - LPCTSTR deviceName = NewtScreen_getDisplayDeviceName(&device, scrn_idx); - if(NULL == deviceName) { - DBG_PRINT("*** WindowsWindow: getScreenMode.getDisplayDeviceName(scrn_idx %d) -> NULL\n", scrn_idx); - return (*env)->NewIntArray(env, 0); + LPCTSTR adapterName = NewtScreen_getAdapterName(&device, crt_idx); + DBG_PRINT("*** WindowsWindow: getAdapterName(crt_idx %d) -> %s, active %d\n", crt_idx, + (NULL==adapterName?"nil":adapterName), 0 == ( device.StateFlags & DISPLAY_DEVICE_ACTIVE )); + if(NULL == adapterName) { + return NULL; } +#ifdef UNICODE + return (*env)->NewString(env, adapterName, wcslen(adapterName)); +#else + return (*env)->NewStringUTF(env, adapterName); +#endif +} +/* + * Class: jogamp_newt_driver_windows_ScreenDriver + * Method: getActiveMonitorName0 + * Signature: (Ljava/lang/String;I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getActiveMonitorName0 + (JNIEnv *env, jobject obj, jstring jAdapterName, jint monitor_idx) +{ + DISPLAY_DEVICE device; + LPCTSTR monitorName; +#ifdef UNICODE + LPCTSTR adapterName = NewtCommon_GetNullTerminatedStringChars(env, jAdapterName); + monitorName = NewtScreen_getMonitorName(adapterName, &device, monitor_idx, TRUE); + DBG_PRINT("*** WindowsWindow: getMonitorName(%s, monitor_idx %d) -> %s\n", adapterName, monitor_idx, (NULL==monitorName?"nil":monitorName)); + free((void*) adapterName); +#else + LPCTSTR adapterName = (*env)->GetStringUTFChars(env, jAdapterName, NULL); + monitorName = NewtScreen_getMonitorName(adapterName, &device, monitor_idx, TRUE); + DBG_PRINT("*** WindowsWindow: getMonitorName(%s, monitor_idx %d) -> %s\n", adapterName, monitor_idx, (NULL==monitorName?"nil":monitorName)); + (*env)->ReleaseStringUTFChars(env, jAdapterName, adapterName); +#endif + if(NULL == monitorName) { + return NULL; + } +#ifdef UNICODE + return (*env)->NewString(env, monitorName, wcslen(monitorName)); +#else + return (*env)->NewStringUTF(env, monitorName); +#endif +} + +/* + * Class: jogamp_newt_driver_windows_ScreenDriver + * Method: getMonitorMode0 + * Signature: (Ljava/lang/String;I)[I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getMonitorMode0 + (JNIEnv *env, jobject obj, jstring jAdapterName, jint mode_idx) +{ + DISPLAY_DEVICE device; + LPCTSTR adapterName; + { +#ifdef UNICODE + adapterName = NewtCommon_GetNullTerminatedStringChars(env, jAdapterName); +#else + adapterName = (*env)->GetStringUTFChars(env, jAdapterName, NULL); +#endif + } int devModeID; - int widthmm, heightmm; if(-1 < mode_idx) { - // only at initialization time, where index >= 0 - HDC hdc = NewtScreen_createDisplayDC(deviceName); - widthmm = GetDeviceCaps(hdc, HORZSIZE); - heightmm = GetDeviceCaps(hdc, VERTSIZE); - DeleteDC(hdc); devModeID = (int) mode_idx; - prop_num++; // add 1st extra prop, mode_idx } else { - widthmm = 0; - heightmm = 0; devModeID = ENUM_CURRENT_SETTINGS; } @@ -1208,11 +1767,18 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getScre ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); - if (0 == EnumDisplaySettingsEx(deviceName, devModeID, &dm, ( ENUM_CURRENT_SETTINGS == devModeID ) ? 0 : EDS_ROTATEDMODE)) { - DBG_PRINT("*** WindowsWindow: getScreenMode.EnumDisplaySettingsEx(mode_idx %d/%d) -> NULL\n", mode_idx, devModeID); + int res = EnumDisplaySettingsEx(adapterName, devModeID, &dm, ( ENUM_CURRENT_SETTINGS == devModeID ) ? 0 : EDS_ROTATEDMODE); + DBG_PRINT("*** WindowsWindow: getMonitorMode.EnumDisplaySettingsEx(%s, mode_idx %d/%d) -> %d\n", adapterName, mode_idx, devModeID, res); +#ifdef UNICODE + free((void*) adapterName); +#else + (*env)->ReleaseStringUTFChars(env, jAdapterName, adapterName); +#endif + + if (0 == res) { return (*env)->NewIntArray(env, 0); } - + // swap width and height, since Windows reflects rotated dimension, we don't if (DMDO_90 == dm.dmDisplayOrientation || DMDO_270 == dm.dmDisplayOrientation) { int tempWidth = dm.dmPelsWidth; @@ -1220,43 +1786,114 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getScre dm.dmPelsHeight = tempWidth; } - jint prop[ prop_num ]; + int flags = 0; + if( 0 != ( dm.dmDisplayFlags & DM_INTERLACED ) ) { + flags |= FLAG_INTERLACE; + } + + jint prop[ NUM_MONITOR_MODE_PROPERTIES_ALL ]; int propIndex = 0; - if( -1 < mode_idx ) { - prop[propIndex++] = mode_idx; - } - prop[propIndex++] = 0; // set later for verification of iterator + prop[propIndex++] = NUM_MONITOR_MODE_PROPERTIES_ALL; prop[propIndex++] = dm.dmPelsWidth; prop[propIndex++] = dm.dmPelsHeight; prop[propIndex++] = dm.dmBitsPerPel; - prop[propIndex++] = widthmm; - prop[propIndex++] = heightmm; - prop[propIndex++] = dm.dmDisplayFrequency; + prop[propIndex++] = dm.dmDisplayFrequency * 100; // Hz*100 + prop[propIndex++] = flags; + prop[propIndex++] = 0; // not bound to id prop[propIndex++] = NewtScreen_RotationNativeCCW2NewtCCW(env, dm.dmDisplayOrientation); - prop[propIndex - NUM_SCREEN_MODE_PROPERTIES_ALL] = ( -1 < mode_idx ) ? propIndex-1 : propIndex ; // count == NUM_SCREEN_MODE_PROPERTIES_ALL - jintArray properties = (*env)->NewIntArray(env, prop_num); + jintArray properties = (*env)->NewIntArray(env, NUM_MONITOR_MODE_PROPERTIES_ALL); if (properties == NULL) { - NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", prop_num); + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", NUM_MONITOR_MODE_PROPERTIES_ALL); } - (*env)->SetIntArrayRegion(env, properties, 0, prop_num, prop); + (*env)->SetIntArrayRegion(env, properties, 0, NUM_MONITOR_MODE_PROPERTIES_ALL, prop); return properties; } /* * Class: jogamp_newt_driver_windows_ScreenDriver - * Method: setScreenMode0 - * Signature: (IIIIII)Z + * Method: getMonitorDevice0 + * Signature: (Ljava/lang/String;I)[I */ -JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_setScreenMode0 - (JNIEnv *env, jobject object, jint scrn_idx, jint width, jint height, jint bits, jint rate, jint rot) +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getMonitorDevice0 + (JNIEnv *env, jobject obj, jstring jAdapterName, jint monitor_idx) { DISPLAY_DEVICE device; - LPCTSTR deviceName = NewtScreen_getDisplayDeviceName(&device, scrn_idx); - if(NULL == deviceName) { - DBG_PRINT("*** WindowsWindow: setScreenMode.getDisplayDeviceName(scrn_idx %d) -> NULL\n", scrn_idx); + LPCTSTR adapterName; + { +#ifdef UNICODE + adapterName = NewtCommon_GetNullTerminatedStringChars(env, jAdapterName); +#else + adapterName = (*env)->GetStringUTFChars(env, jAdapterName, NULL); +#endif + } + + HDC hdc = NewtScreen_createDisplayDC(adapterName); + int widthmm = GetDeviceCaps(hdc, HORZSIZE); + int heightmm = GetDeviceCaps(hdc, VERTSIZE); + DeleteDC(hdc); + int devModeID = ENUM_CURRENT_SETTINGS; + + DEVMODE dm; + ZeroMemory(&dm, sizeof(dm)); + dm.dmSize = sizeof(dm); + + int res = EnumDisplaySettingsEx(adapterName, devModeID, &dm, 0); + DBG_PRINT("*** WindowsWindow: getMonitorDevice.EnumDisplaySettingsEx(%s, devModeID %d) -> %d\n", adapterName, devModeID, res); +#ifdef UNICODE + free((void*) adapterName); +#else + (*env)->ReleaseStringUTFChars(env, jAdapterName, adapterName); +#endif + if (0 == res) { + return (*env)->NewIntArray(env, 0); + } + + jsize propCount = MIN_MONITOR_DEVICE_PROPERTIES - 1 - NUM_MONITOR_MODE_PROPERTIES; + jint prop[ propCount ]; + int propIndex = 0; + + prop[propIndex++] = propCount; + prop[propIndex++] = monitor_idx; + prop[propIndex++] = widthmm; + prop[propIndex++] = heightmm; + prop[propIndex++] = dm.dmPosition.x; // rotated viewport pixel units + prop[propIndex++] = dm.dmPosition.y; // rotated viewport pixel units + prop[propIndex++] = dm.dmPelsWidth; // rotated viewport pixel units + prop[propIndex++] = dm.dmPelsHeight; // rotated viewport pixel units + prop[propIndex++] = dm.dmPosition.x; // rotated viewport window units (same) + prop[propIndex++] = dm.dmPosition.y; // rotated viewport window units (same) + prop[propIndex++] = dm.dmPelsWidth; // rotated viewport window units (same) + prop[propIndex++] = dm.dmPelsHeight; // rotated viewport window units (same) + + jintArray properties = (*env)->NewIntArray(env, propCount); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", propCount); + } + (*env)->SetIntArrayRegion(env, properties, 0, propCount, prop); + + return properties; +} + +/* + * Class: jogamp_newt_driver_windows_ScreenDriver + * Method: setMonitorMode0 + * Signature: (IIIIIIIII)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_setMonitorMode0 + (JNIEnv *env, jobject object, jint monitor_idx, jint x, jint y, jint width, jint height, jint bits, jint rate, jint flags, jint rot) +{ + DISPLAY_DEVICE adapterDevice, monitorDevice; + LPCTSTR adapterName = NewtScreen_getAdapterName(&adapterDevice, monitor_idx); + if(NULL == adapterName) { + DBG_PRINT("*** WindowsWindow: setMonitorMode.getAdapterName(monitor_idx %d) -> NULL\n", monitor_idx); + return JNI_FALSE; + } + LPCTSTR monitorName = NewtScreen_getMonitorName(adapterName, &monitorDevice, 0, TRUE); + if(NULL == monitorName) { + DBG_PRINT("*** WindowsWindow: setMonitorMode.getMonitorName(monitor_idx 0) -> NULL\n"); return JNI_FALSE; } @@ -1264,10 +1901,17 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_setScree // initialize the DEVMODE structure ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); + if( 0 <= x && 0 <= y ) { + dm.dmPosition.x = (int)x; + dm.dmPosition.y = (int)y; + } dm.dmPelsWidth = (int)width; dm.dmPelsHeight = (int)height; dm.dmBitsPerPel = (int)bits; dm.dmDisplayFrequency = (int)rate; + if( 0 != ( flags & FLAG_INTERLACE ) ) { + dm.dmDisplayFlags |= DM_INTERLACED; + } dm.dmDisplayOrientation = NewtScreen_RotationNewtCCW2NativeCCW(env, rot); // swap width and height, since Windows reflects rotated dimension, we don't @@ -1277,9 +1921,12 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_setScree dm.dmPelsHeight = tempWidth; } - dm.dmFields = DM_DISPLAYORIENTATION | DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; + dm.dmFields = DM_DISPLAYORIENTATION | DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS; + if( 0 <= x && 0 <= y ) { + dm.dmFields |= DM_POSITION; + } - return ( DISP_CHANGE_SUCCESSFUL == ChangeDisplaySettings(&dm, 0) ) ? JNI_TRUE : JNI_FALSE ; + return ( DISP_CHANGE_SUCCESSFUL == ChangeDisplaySettingsEx(adapterName, &dm, NULL, 0, NULL) ) ? JNI_TRUE : JNI_FALSE ; } /* @@ -1288,7 +1935,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_setScree * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowDriver_initIDs0 - (JNIEnv *env, jclass clazz) + (JNIEnv *env, jclass clazz, jlong hInstance) { NewtCommon_init(env); @@ -1299,10 +1946,9 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowDriver_initIDs0 visibleChangedID = (*env)->GetMethodID(env, clazz, "visibleChanged", "(ZZ)V"); windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "(Z)Z"); windowRepaintID = (*env)->GetMethodID(env, clazz, "windowRepaint", "(ZIIII)V"); - enqueueMouseEventID = (*env)->GetMethodID(env, clazz, "enqueueMouseEvent", "(ZIIIIII)V"); - sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIIII)V"); - enqueueKeyEventID = (*env)->GetMethodID(env, clazz, "enqueueKeyEvent", "(ZIIIC)V"); - sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(IIIC)V"); + sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(SIIISF)V"); + sendTouchScreenEventID = (*env)->GetMethodID(env, clazz, "sendTouchScreenEvent", "(SII[I[I[I[FF)V"); + sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(SISSC)V"); requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V"); if (insetsChangedID == NULL || @@ -1312,14 +1958,30 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowDriver_initIDs0 visibleChangedID == NULL || windowDestroyNotifyID == NULL || windowRepaintID == NULL || - enqueueMouseEventID == NULL || sendMouseEventID == NULL || - enqueueKeyEventID == NULL || + sendTouchScreenEventID == NULL || sendKeyEventID == NULL || requestFocusID == NULL) { return JNI_FALSE; } - BuildDynamicKeyMapTable(); + InitKeyMapTableScanCode(env); + + { + HANDLE shell = LoadLibrary(TEXT("user32.dll")); + if (shell) { + WinTouch_CloseTouchInputHandle = (CloseTouchInputHandlePROCADDR) GetProcAddressA(shell, "CloseTouchInputHandle"); + WinTouch_GetTouchInputInfo = (GetTouchInputInfoPROCADDR) GetProcAddressA(shell, "GetTouchInputInfo"); + WinTouch_IsTouchWindow = (IsTouchWindowPROCADDR) GetProcAddressA(shell, "IsTouchWindow"); + WinTouch_RegisterTouchWindow = (RegisterTouchWindowPROCADDR) GetProcAddressA(shell, "RegisterTouchWindow"); + WinTouch_UnregisterTouchWindow = (UnregisterTouchWindowPROCADDR) GetProcAddressA(shell, "UnregisterTouchWindow"); + if(NULL != WinTouch_CloseTouchInputHandle && NULL != WinTouch_GetTouchInputInfo && + NULL != WinTouch_IsTouchWindow && NULL != WinTouch_RegisterTouchWindow && NULL != WinTouch_UnregisterTouchWindow) { + WinTouch_func_avail = 1; + } else { + WinTouch_func_avail = 0; + } + } + } return JNI_TRUE; } @@ -1365,20 +2027,21 @@ static void NewtWindow_setVisiblePosSize(HWND hwnd, BOOL atop, BOOL visible, UpdateWindow(hwnd); } +#define WS_DEFAULT_STYLES (WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP) + /* * Class: jogamp_newt_driver_windows_WindowDriver * Method: CreateWindow */ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowDriver_CreateWindow0 (JNIEnv *env, jobject obj, - jlong hInstance, jstring jWndClassName, jstring jWndName, - jlong parent, - jint jx, jint jy, jint defaultWidth, jint defaultHeight, jboolean autoPosition, jint flags) + jlong hInstance, jstring jWndClassName, jstring jWndName, jint winMajor, jint winMinor, + jlong parent, jint jx, jint jy, jint defaultWidth, jint defaultHeight, jboolean autoPosition, jint flags) { HWND parentWindow = (HWND) (intptr_t) parent; const TCHAR* wndClassName = NULL; const TCHAR* wndName = NULL; - DWORD windowStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE | WS_TABSTOP; + DWORD windowStyle = WS_DEFAULT_STYLES | WS_VISIBLE; int x=(int)jx, y=(int)jy; int width=(int)defaultWidth, height=(int)defaultHeight; HWND window = NULL; @@ -1415,8 +2078,8 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowDriver_CreateWindo (HINSTANCE) (intptr_t) hInstance, NULL); - DBG_PRINT("*** WindowsWindow: CreateWindow thread 0x%X, parent %p, window %p, %d/%d %dx%d, undeco %d, alwaysOnTop %d, autoPosition %d\n", - (int)GetCurrentThreadId(), parentWindow, window, x, y, width, height, + DBG_PRINT("*** WindowsWindow: CreateWindow thread 0x%X, win %d.%d parent %p, window %p, %d/%d %dx%d, undeco %d, alwaysOnTop %d, autoPosition %d\n", + (int)GetCurrentThreadId(), winMajor, winMinor, parentWindow, window, x, y, width, height, TST_FLAG_IS_UNDECORATED(flags), TST_FLAG_IS_ALWAYSONTOP(flags), autoPosition); if (NULL == window) { @@ -1427,6 +2090,31 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowDriver_CreateWindo WindowUserData * wud = (WindowUserData *) malloc(sizeof(WindowUserData)); wud->jinstance = (*env)->NewGlobalRef(env, obj); wud->jenv = env; + wud->width = width; + wud->height = height; + wud->setPointerVisible = 0; + wud->setPointerAction = 0; + wud->defPointerHandle = LoadCursor( NULL, IDC_ARROW); + wud->setPointerHandle = wud->defPointerHandle; + wud->isFullscreen = 0; + wud->isChildWindow = NULL!=parentWindow; + wud->pointerCaptured = 0; + wud->pointerInside = 0; + wud->touchDownCount = 0; + wud->touchDownLastUp = 0; + wud->supportsMTouch = 0; + if ( WinTouch_func_avail && winMajor > 6 || ( winMajor == 6 && winMinor >= 1 ) ) { + int value = GetSystemMetrics(SM_DIGITIZER); + if (value & NID_READY) { /* ready */ + if (value & NID_MULTI_INPUT) { /* multitouch */ + wud->supportsMTouch = 1; + } + if (value & NID_INTEGRATED_TOUCH) { /* Integrated touch */ + } + } + } + DBG_PRINT("*** WindowsWindow: CreateWindow winTouchFuncAvail %d, supportsMTouch %d\n", WinTouch_func_avail, wud->supportsMTouch); + #if !defined(__MINGW64__) && ( defined(UNDER_CE) || _MSC_VER <= 1200 ) SetWindowLong(window, GWL_USERDATA, (intptr_t) wud); #else @@ -1459,6 +2147,9 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowDriver_CreateWindo NewtWindow_setVisiblePosSize(window, TST_FLAG_IS_ALWAYSONTOP(flags), TRUE, x, y, width, height); } + if( wud->supportsMTouch ) { + WinTouch_RegisterTouchWindow(window, 0); + } } #ifdef UNICODE @@ -1469,6 +2160,12 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowDriver_CreateWindo (*env)->ReleaseStringUTFChars(env, jWndName, wndName); #endif +#ifdef TEST_MOUSE_HOOKS + hookLLMP = SetWindowsHookEx(WH_MOUSE_LL, &HookLowLevelMouseProc, (HINSTANCE) (intptr_t) hInstance, 0); + hookMP = SetWindowsHookEx(WH_MOUSE_LL, &HookMouseProc, (HINSTANCE) (intptr_t) hInstance, 0); + DBG_PRINT("**** LLMP Hook %p, MP Hook %p\n", hookLLMP, hookMP); +#endif + return (jlong) (intptr_t) window; } @@ -1487,24 +2184,6 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowDriver_MonitorFrom #endif } -static jboolean NewtWindows_setFullScreen(jboolean fullscreen) -{ - int flags = 0; - DEVMODE dm; - // initialize the DEVMODE structure - ZeroMemory(&dm, sizeof(dm)); - dm.dmSize = sizeof(dm); - - if (0 == EnumDisplaySettings(NULL /*current display device*/, ENUM_CURRENT_SETTINGS, &dm)) - { - return JNI_FALSE; - } - - flags = ( JNI_TRUE == fullscreen ) ? CDS_FULLSCREEN : CDS_RESET ; - - return ( DISP_CHANGE_SUCCESSFUL == ChangeDisplaySettings(&dm, flags) ) ? JNI_TRUE : JNI_FALSE; -} - /* * Class: jogamp_newt_driver_windows_WindowDriver * Method: reconfigureWindow0 @@ -1516,16 +2195,23 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowDriver_reconfigureW { HWND hwndP = (HWND) (intptr_t) parent; HWND hwnd = (HWND) (intptr_t) window; - DWORD windowStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN ; + DWORD windowStyle = WS_DEFAULT_STYLES; BOOL styleChange = TST_FLAG_CHANGE_DECORATION(flags) || TST_FLAG_CHANGE_FULLSCREEN(flags) || TST_FLAG_CHANGE_PARENTING(flags) ; + WindowUserData * wud; +#if !defined(__MINGW64__) && ( defined(UNDER_CE) || _MSC_VER <= 1200 ) + wud = (WindowUserData *) GetWindowLong(hwnd, GWL_USERDATA); +#else + wud = (WindowUserData *) GetWindowLongPtr(hwnd, GWLP_USERDATA); +#endif - DBG_PRINT( "*** WindowsWindow: reconfigureWindow0 parent %p, window %p, %d/%d %dx%d, parentChange %d, hasParent %d, decorationChange %d, undecorated %d, fullscreenChange %d, fullscreen %d, alwaysOnTopChange %d, alwaysOnTop %d, visibleChange %d, visible %d -> styleChange %d\n", + + DBG_PRINT( "*** WindowsWindow: reconfigureWindow0 parent %p, window %p, %d/%d %dx%d, parentChange %d, hasParent %d, decorationChange %d, undecorated %d, fullscreenChange %d, fullscreen %d, alwaysOnTopChange %d, alwaysOnTop %d, visibleChange %d, visible %d -> styleChange %d, isChild %d, isFullscreen %d\n", parent, window, x, y, width, height, TST_FLAG_CHANGE_PARENTING(flags), TST_FLAG_HAS_PARENT(flags), TST_FLAG_CHANGE_DECORATION(flags), TST_FLAG_IS_UNDECORATED(flags), TST_FLAG_CHANGE_FULLSCREEN(flags), TST_FLAG_IS_FULLSCREEN(flags), TST_FLAG_CHANGE_ALWAYSONTOP(flags), TST_FLAG_IS_ALWAYSONTOP(flags), - TST_FLAG_CHANGE_VISIBILITY(flags), TST_FLAG_IS_VISIBLE(flags), styleChange); + TST_FLAG_CHANGE_VISIBILITY(flags), TST_FLAG_IS_VISIBLE(flags), styleChange, wud->isChildWindow, wud->isFullscreen); if (!IsWindow(hwnd)) { DBG_PRINT("*** WindowsWindow: reconfigureWindow0 failure: Passed window %p is invalid\n", (void*)hwnd); @@ -1537,6 +2223,8 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowDriver_reconfigureW return; } + wud->isChildWindow = NULL != hwndP; + if(TST_FLAG_IS_VISIBLE(flags)) { windowStyle |= WS_VISIBLE ; } @@ -1547,11 +2235,16 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowDriver_reconfigureW // if( TST_FLAG_CHANGE_PARENTING(flags) && NULL == hwndP ) { // TOP: in -> out + + // HIDE to allow setting ICONs (Windows bug?) .. WS_VISIBLE (style) will reset visibility + ShowWindow(hwnd, SW_HIDE); + SetParent(hwnd, NULL); } if( TST_FLAG_CHANGE_FULLSCREEN(flags) && TST_FLAG_IS_FULLSCREEN(flags) ) { // FS on // TOP: in -> out + wud->isFullscreen = 1; NewtWindows_setFullScreen(JNI_TRUE); } @@ -1569,6 +2262,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowDriver_reconfigureW if( TST_FLAG_CHANGE_FULLSCREEN(flags) && !TST_FLAG_IS_FULLSCREEN(flags) ) { // FS off // CHILD: out -> in + wud->isFullscreen = 0; NewtWindows_setFullScreen(JNI_FALSE); } @@ -1587,7 +2281,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowDriver_reconfigureW } } - DBG_PRINT("*** WindowsWindow: reconfigureWindow0.X\n"); + DBG_PRINT("*** WindowsWindow: reconfigureWindow0.X isChild %d, isFullscreen %d\n", wud->isChildWindow, wud->isFullscreen); } /* @@ -1629,34 +2323,16 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowDriver_setPoint (JNIEnv *env, jclass clazz, jlong window, jboolean mouseVisible) { HWND hwnd = (HWND) (intptr_t) window; - int res, resOld, i; - jboolean b; - - if(JNI_TRUE == mouseVisible) { - res = ShowCursor(TRUE); - if(res < 0) { - i=0; - do { - resOld = res; - res = ShowCursor(TRUE); - } while(res!=resOld && res<0 && ++i<10); - } - b = res>=0 ? JNI_TRUE : JNI_FALSE; - } else { - res = ShowCursor(FALSE); - if(res >= 0) { - i=0; - do { - resOld = res; - res = ShowCursor(FALSE); - } while(res!=resOld && res>=0 && ++i<10); - } - b = res<0 ? JNI_TRUE : JNI_FALSE; - } - - DBG_PRINT( "*** WindowsWindow: setPointerVisible0: %d, res %d/%d\n", mouseVisible, res, b); + WindowUserData * wud; +#if !defined(__MINGW64__) && ( defined(UNDER_CE) || _MSC_VER <= 1200 ) + wud = (WindowUserData *) GetWindowLong(hwnd, GWL_USERDATA); +#else + wud = (WindowUserData *) GetWindowLongPtr(hwnd, GWLP_USERDATA); +#endif + wud->setPointerVisible = mouseVisible ? 1 : -1; + SendMessage(hwnd, WM_SETCURSOR, 0, 0); - return b; + return JNI_TRUE; } /* @@ -1671,12 +2347,9 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowDriver_confineP jboolean res; if(JNI_TRUE == confine) { - // SetCapture(hwnd); - // res = ( GetCapture() == hwnd ) ? JNI_TRUE : JNI_FALSE; RECT rect = { l, t, r, b }; res = ClipCursor(&rect) ? JNI_TRUE : JNI_FALSE; } else { - // res = ReleaseCapture() ? JNI_TRUE : JNI_FALSE; res = ClipCursor(NULL) ? JNI_TRUE : JNI_FALSE; } DBG_PRINT( "*** WindowsWindow: confinePointer0: %d, [ l %d t %d r %d b %d ], res %d\n", @@ -1697,16 +2370,93 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowDriver_warpPointer0 SetCursorPos(x, y); } -/* - * Class: Java_jogamp_newt_driver_windows_WindowDriver - * Method: trackPointerLeave0 - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowDriver_trackPointerLeave0 - (JNIEnv *env, jclass clazz, jlong window) -{ +JNIEXPORT jlong JNICALL +Java_jogamp_newt_driver_windows_DisplayDriver_createBGRA8888Icon0(JNIEnv *env, jobject _unused, + jobject pixels, jint pixels_byte_offset, jboolean pixels_is_direct, jint width, jint height, jboolean isCursor, jint hotX, jint hotY) { + + if( 0 == pixels ) { + return 0; + } + + const unsigned char * pixelPtr = (const unsigned char *) ( JNI_TRUE == pixels_is_direct ? + (*env)->GetDirectBufferAddress(env, pixels) : + (*env)->GetPrimitiveArrayCritical(env, pixels, NULL) ); + const int bytes = 4 * width * height; // BGRA8888 + + DWORD dwWidth, dwHeight; + BITMAPV5HEADER bi; + HBITMAP hBitmap; + void *lpBits; + HICON handle = NULL; + + dwWidth = width; // width of cursor + dwHeight = height; // height of cursor + + ZeroMemory(&bi,sizeof(BITMAPV5HEADER)); + bi.bV5Size = sizeof(BITMAPV5HEADER); + bi.bV5Width = dwWidth; + bi.bV5Height = -1 * dwHeight; + bi.bV5Planes = 1; + bi.bV5BitCount = 32; + bi.bV5Compression = BI_BITFIELDS; + // The following mask specification specifies a supported 32 BPP + // alpha format for Windows XP. + bi.bV5RedMask = 0x00FF0000; + bi.bV5GreenMask = 0x0000FF00; + bi.bV5BlueMask = 0x000000FF; + bi.bV5AlphaMask = 0xFF000000; + + HDC hdc; + hdc = GetDC(NULL); + + // Create the DIB section with an alpha channel. + hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, + (void **)&lpBits, NULL, (DWORD)0); + + memcpy(lpBits, pixelPtr + pixels_byte_offset, bytes); + + ReleaseDC(NULL,hdc); + + if ( JNI_FALSE == pixels_is_direct ) { + (*env)->ReleasePrimitiveArrayCritical(env, pixels, (void*)pixelPtr, JNI_ABORT); + } + + // Create an empty mask bitmap. + HBITMAP hMonoBitmap = CreateBitmap(dwWidth,dwHeight,1,1,NULL); + + ICONINFO ii; + ii.fIcon = isCursor ? FALSE : TRUE; + ii.xHotspot = hotX; + ii.yHotspot = hotY; + ii.hbmMask = hMonoBitmap; + ii.hbmColor = hBitmap; + + // Create the alpha cursor with the alpha DIB section. + handle = CreateIconIndirect(&ii); + + DeleteObject(hBitmap); + DeleteObject(hMonoBitmap); + + return (jlong) (intptr_t) handle; +} + +JNIEXPORT void JNICALL +Java_jogamp_newt_driver_windows_DisplayDriver_destroyIcon0(JNIEnv *env, jobject _unused, jlong jhandle) { + HICON handle = (HICON) (intptr_t) jhandle; + DestroyIcon(handle); +} + +JNIEXPORT void JNICALL +Java_jogamp_newt_driver_windows_WindowDriver_setPointerIcon0(JNIEnv *env, jobject _unused, jlong window, jlong iconHandle) { HWND hwnd = (HWND) (intptr_t) window; - DBG_PRINT( "*** WindowsWindow: trackMouseLeave0\n"); - NewtWindows_trackPointerLeave(hwnd); + WindowUserData * wud; +#if !defined(__MINGW64__) && ( defined(UNDER_CE) || _MSC_VER <= 1200 ) + wud = (WindowUserData *) GetWindowLong(hwnd, GWL_USERDATA); +#else + wud = (WindowUserData *) GetWindowLongPtr(hwnd, GWLP_USERDATA); +#endif + wud->setPointerAction = 0 != iconHandle ? 1 : -1; + wud->setPointerHandle = (HCURSOR) (intptr_t) iconHandle; + SendMessage(hwnd, WM_SETCURSOR, 0, 0); } diff --git a/src/newt/native/X11Common.h b/src/newt/native/X11Common.h index 128b6b6f1..e58cdb755 100644 --- a/src/newt/native/X11Common.h +++ b/src/newt/native/X11Common.h @@ -45,8 +45,10 @@ #include <X11/extensions/Xrandr.h> -#include "jogamp_newt_driver_x11_ScreenDriver.h" #include "jogamp_newt_driver_x11_DisplayDriver.h" +#include "jogamp_newt_driver_x11_ScreenDriver.h" +#include "jogamp_newt_driver_x11_RandR11.h" +#include "jogamp_newt_driver_x11_RandR13.h" #include "jogamp_newt_driver_x11_WindowDriver.h" #include "Window.h" @@ -70,7 +72,6 @@ extern jclass X11NewtWindowClazz; extern jmethodID insetsChangedID; extern jmethodID visibleChangedID; -void NewtDisplay_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync); jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong javaObjectAtom, Bool showWarning); Status NewtWindows_getRootAndParent (Display *dpy, Window w, Window * root_return, Window * parent_return); diff --git a/src/newt/native/X11Display.c b/src/newt/native/X11Display.c index 84b3a7630..b62a9b234 100644 --- a/src/newt/native/X11Display.c +++ b/src/newt/native/X11Display.c @@ -28,7 +28,9 @@ #include "X11Common.h" -#define USE_SENDIO_DIRECT 1 +#include <X11/Xcursor/Xcursor.h> + +// #include <X11/XKBlib.h> // XKB disabled for now jclass X11NewtWindowClazz = NULL; jmethodID insetsChangedID = NULL; @@ -46,107 +48,35 @@ static jmethodID focusChangedID = NULL; static jmethodID reparentNotifyID = NULL; static jmethodID windowDestroyNotifyID = NULL; static jmethodID windowRepaintID = NULL; -static jmethodID enqueueMouseEventID = NULL; static jmethodID sendMouseEventID = NULL; -static jmethodID enqueueKeyEventID = NULL; static jmethodID sendKeyEventID = NULL; static jmethodID requestFocusID = NULL; -static JavaVM *jvmHandle = NULL; -static int jvmVersion = 0; - -static void setupJVMVars(JNIEnv * env) { - if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { - jvmHandle = NULL; - } - jvmVersion = (*env)->GetVersion(env); -} - -static XErrorHandler origErrorHandler = NULL ; -static int errorHandlerQuiet = 0 ; -static int errorHandlerDebug = 0 ; -static int errorHandlerThrowException = 0; - -static int x11ErrorHandler(Display *dpy, XErrorEvent *e) -{ - if(!errorHandlerQuiet) { - const char * errnoStr = strerror(errno); - char threadName[80]; - char errCodeStr[80]; - char reqCodeStr[80]; - - int shallBeDetached = 0; - JNIEnv *jniEnv = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); - - (void) NewtCommon_GetStaticStringMethod(jniEnv, X11NewtWindowClazz, getCurrentThreadNameID, threadName, sizeof(threadName), "n/a"); - snprintf(errCodeStr, sizeof(errCodeStr), "%d", e->request_code); - XGetErrorDatabaseText(dpy, "XRequest", errCodeStr, "Unknown", reqCodeStr, sizeof(reqCodeStr)); - XGetErrorText(dpy, e->error_code, errCodeStr, sizeof(errCodeStr)); - - fprintf(stderr, "Info: Newt X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", - threadName, e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, - (int)e->request_code, (int)e->minor_code, reqCodeStr); - - if( errorHandlerDebug ) { - (*jniEnv)->CallStaticVoidMethod(jniEnv, X11NewtWindowClazz, dumpStackID); - } - - if(errorHandlerThrowException) { - if(NULL != jniEnv) { - NewtCommon_throwNewRuntimeException(jniEnv, "Newt X11 Error (Thread: %s): %d - %s, dpy %p, id %x, # %d: %d:%d %s\n", - threadName, e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial, - (int)e->request_code, (int)e->minor_code, reqCodeStr); - } else { - fprintf(stderr, "Nativewindow X11 Error: null JNIEnv"); - #if 0 - if(NULL!=origErrorHandler) { - origErrorHandler(dpy, e); - } - #endif - } - } - fflush(stderr); - - if (NULL != jniEnv && shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } - } - - return 0; -} - -void NewtDisplay_x11ErrorHandlerEnable(JNIEnv * env, Display *dpy, int onoff, int quiet, int sync) { - errorHandlerQuiet = quiet; - if(onoff) { - if(NULL==origErrorHandler) { - setupJVMVars(env); - origErrorHandler = XSetErrorHandler(x11ErrorHandler); - if(sync && NULL!=dpy) { - XSync(dpy, False); - } - } - } else { - if(NULL!=origErrorHandler) { - if(sync && NULL!=dpy) { - XSync(dpy, False); - } - XSetErrorHandler(origErrorHandler); - origErrorHandler = NULL; - } - } -} - /** * Keycode */ +// #define DEBUG_KEYS 1 + #define IS_WITHIN(k,a,b) ((a)<=(k)&&(k)<=(b)) -static jint X11KeySym2NewtVKey(KeySym keySym) { - if(IS_WITHIN(keySym,XK_F1,XK_F12)) - return (keySym-XK_F1)+J_VK_F1; - if(IS_WITHIN(keySym,XK_KP_0,XK_KP_9)) - return (keySym-XK_KP_0)+J_VK_NUMPAD0; +/** + * QT Reference: + * <http://qt.gitorious.org/qt/qt/blobs/4.7/src/gui/kernel/qkeymapper_x11.cpp#line879> + */ +static short X11KeySym2NewtVKey(KeySym keySym) { + if( IS_WITHIN( keySym, XK_a, XK_z ) ) { + return ( keySym - XK_a ) + J_VK_A ; + } + if( IS_WITHIN( keySym, XK_0, XK_9 ) ) { + return ( keySym - XK_0 ) + J_VK_0 ; + } + if( IS_WITHIN( keySym, XK_KP_0, XK_KP_9 ) ) { + return ( keySym - XK_KP_0 ) + J_VK_NUMPAD0 ; + } + if( IS_WITHIN( keySym, XK_F1, XK_F12 ) ) { + return ( keySym - XK_F1 ) + J_VK_F1 ; + } switch(keySym) { case XK_Return: @@ -160,8 +90,6 @@ static jint X11KeySym2NewtVKey(KeySym keySym) { return J_VK_TAB; case XK_Cancel: return J_VK_CANCEL; - case XK_Clear: - return J_VK_CLEAR; case XK_Shift_L: case XK_Shift_R: return J_VK_SHIFT; @@ -169,8 +97,15 @@ static jint X11KeySym2NewtVKey(KeySym keySym) { case XK_Control_R: return J_VK_CONTROL; case XK_Alt_L: - case XK_Alt_R: return J_VK_ALT; + case XK_Alt_R: + case XK_ISO_Level3_Shift: + return J_VK_ALT_GRAPH; + case XK_Super_L: + case XK_Super_R: + return J_VK_WINDOWS; + case XK_Menu: + return J_VK_CONTEXT_MENU; case XK_Pause: return J_VK_PAUSE; case XK_Caps_Lock: @@ -189,6 +124,10 @@ static jint X11KeySym2NewtVKey(KeySym keySym) { case XK_End: case XK_KP_End: return J_VK_END; + case XK_Begin: + return J_VK_BEGIN; + case XK_KP_Begin: // NumPad 5 - equal behavior w/ QT/Windows + return J_VK_CLEAR; case XK_Home: case XK_KP_Home: return J_VK_HOME; @@ -216,6 +155,7 @@ static jint X11KeySym2NewtVKey(KeySym keySym) { return J_VK_DECIMAL; case XK_KP_Divide: return J_VK_DIVIDE; + case XK_Clear: // equal behavior w/ QT case XK_Delete: case XK_KP_Delete: return J_VK_DELETE; @@ -230,28 +170,43 @@ static jint X11KeySym2NewtVKey(KeySym keySym) { return J_VK_INSERT; case XK_Help: return J_VK_HELP; + case XK_grave: + return J_VK_BACK_QUOTE; + case XK_apostrophe: + return J_VK_QUOTE; } return keySym; } -static jint X11InputState2NewtModifiers(unsigned int xstate) { +#define ShiftCtrlModMask ( ShiftMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask ) + +static jboolean altGraphDown = JNI_FALSE; + +static jint X11InputState2NewtModifiers(unsigned int xstate, jshort javaVKey, jboolean keyDown) { jint modifiers = 0; - if ((ControlMask & xstate) != 0) { + if ( (ControlMask & xstate) != 0 || J_VK_CONTROL == javaVKey ) { modifiers |= EVENT_CTRL_MASK; } - if ((ShiftMask & xstate) != 0) { + if ( (ShiftMask & xstate) != 0 || J_VK_SHIFT == javaVKey ) { modifiers |= EVENT_SHIFT_MASK; } - if ((Mod1Mask & xstate) != 0) { + if ( J_VK_ALT == javaVKey ) { + altGraphDown = JNI_FALSE; modifiers |= EVENT_ALT_MASK; + } else if ( (short)J_VK_ALT_GRAPH == javaVKey ) { + altGraphDown = keyDown; + modifiers |= EVENT_ALT_GRAPH_MASK; + } else if ( (Mod1Mask & xstate) != 0 ) { + // XK_Alt_L or XK_Alt_R + modifiers |= altGraphDown ? EVENT_ALT_GRAPH_MASK : EVENT_ALT_MASK; } - if ((Button1Mask & xstate) != 0) { + if ( (Button1Mask & xstate) != 0 ) { modifiers |= EVENT_BUTTON1_MASK; } - if ((Button2Mask & xstate) != 0) { + if ( (Button2Mask & xstate) != 0 ) { modifiers |= EVENT_BUTTON2_MASK; } - if ((Button3Mask & xstate) != 0) { + if ( (Button3Mask & xstate) != 0 ) { modifiers |= EVENT_BUTTON3_MASK; } @@ -273,9 +228,6 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_initIDs0 { jclass c; - if(debug) { - errorHandlerDebug = 1 ; - } NewtCommon_init(env); if(NULL==X11NewtWindowClazz) { @@ -290,6 +242,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_initIDs0 } } + // displayCompletedID = (*env)->GetMethodID(env, clazz, "displayCompleted", "(JJJ)V"); // Variant using XKB displayCompletedID = (*env)->GetMethodID(env, clazz, "displayCompleted", "(JJ)V"); getCurrentThreadNameID = (*env)->GetStaticMethodID(env, X11NewtWindowClazz, "getCurrentThreadName", "()Ljava/lang/String;"); dumpStackID = (*env)->GetStaticMethodID(env, X11NewtWindowClazz, "dumpStack", "()V"); @@ -301,10 +254,8 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_initIDs0 reparentNotifyID = (*env)->GetMethodID(env, X11NewtWindowClazz, "reparentNotify", "(J)V"); windowDestroyNotifyID = (*env)->GetMethodID(env, X11NewtWindowClazz, "windowDestroyNotify", "(Z)Z"); windowRepaintID = (*env)->GetMethodID(env, X11NewtWindowClazz, "windowRepaint", "(ZIIII)V"); - enqueueMouseEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "enqueueMouseEvent", "(ZIIIIII)V"); - sendMouseEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sendMouseEvent", "(IIIIII)V"); - enqueueKeyEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "enqueueKeyEvent", "(ZIIIC)V"); - sendKeyEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sendKeyEvent", "(IIIC)V"); + sendMouseEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sendMouseEvent", "(SIIISF)V"); + sendKeyEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sendKeyEvent", "(SISSCLjava/lang/String;)V"); requestFocusID = (*env)->GetMethodID(env, X11NewtWindowClazz, "requestFocus", "(Z)V"); if (displayCompletedID == NULL || @@ -318,9 +269,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_initIDs0 reparentNotifyID == NULL || windowDestroyNotifyID == NULL || windowRepaintID == NULL || - enqueueMouseEventID == NULL || sendMouseEventID == NULL || - enqueueKeyEventID == NULL || sendKeyEventID == NULL || requestFocusID == NULL) { return JNI_FALSE; @@ -341,6 +290,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_CompleteDisplay Display * dpy = (Display *)(intptr_t)display; jlong javaObjectAtom; jlong windowDeleteAtom; + // jlong kbdHandle; // XKB disabled for now if(dpy==NULL) { NewtCommon_FatalError(env, "invalid display connection.."); @@ -359,10 +309,11 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_CompleteDisplay } // XSetCloseDownMode(dpy, RetainTemporary); // Just a try .. + // kbdHandle = (jlong) (intptr_t) XkbGetKeyboard(dpy, XkbAllComponentsMask, XkbUseCoreKbd); // XKB disabled for now DBG_PRINT("X11: X11Display_completeDisplay dpy %p\n", dpy); - (*env)->CallVoidMethod(env, obj, displayCompletedID, javaObjectAtom, windowDeleteAtom); + (*env)->CallVoidMethod(env, obj, displayCompletedID, javaObjectAtom, windowDeleteAtom /*, kbdHandle*/); // XKB disabled for now } /* @@ -371,11 +322,12 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_CompleteDisplay * Signature: (JJJ)V */ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DisplayRelease0 - (JNIEnv *env, jobject obj, jlong display, jlong javaObjectAtom, jlong windowDeleteAtom) + (JNIEnv *env, jobject obj, jlong display, jlong javaObjectAtom, jlong windowDeleteAtom /*, jlong kbdHandle*/) { Display * dpy = (Display *)(intptr_t)display; Atom wm_javaobject_atom = (Atom)javaObjectAtom; Atom wm_delete_atom = (Atom)windowDeleteAtom; + // XkbDescPtr kbdDesc = (XkbDescPtr)(intptr_t)kbdHandle; // XKB disabled for now if(dpy==NULL) { NewtCommon_FatalError(env, "invalid display connection.."); @@ -385,6 +337,8 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DisplayRelease0 (void) wm_javaobject_atom; (void) wm_delete_atom; + // XkbFreeKeyboard(kbdDesc, XkbAllNamesMask, True); // XKB disabled for now + XSync(dpy, True); // discard all pending events DBG_PRINT("X11: X11Display_DisplayRelease dpy %p\n", dpy); } @@ -392,13 +346,14 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DisplayRelease0 /* * Class: jogamp_newt_driver_x11_DisplayDriver * Method: DispatchMessages - * Signature: (JIJJ)V + * Signature: (JJJ)V */ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessages0 - (JNIEnv *env, jobject obj, jlong display, jlong javaObjectAtom, jlong windowDeleteAtom) + (JNIEnv *env, jobject obj, jlong display, jlong javaObjectAtom, jlong windowDeleteAtom /*, jlong kbdHandle*/) { Display * dpy = (Display *) (intptr_t) display; Atom wm_delete_atom = (Atom)windowDeleteAtom; + // XkbDescPtr kbdDesc = (XkbDescPtr)(intptr_t)kbdHandle; // XKB disabled for now int num_events = 100; int autoRepeatModifiers = 0; @@ -406,20 +361,30 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage return; } + /** XKB disabled for now + if( NULL == kbdDesc) { + NewtCommon_throwNewRuntimeException(env, "NULL kbd handle, bail out!"); + return; + } */ + // Periodically take a break while( num_events > 0 ) { jobject jwindow = NULL; XEvent evt; KeySym keySym = 0; + KeyCode keyCode = 0; + jshort javaVKeyUS = 0; + jshort javaVKeyNN = 0; jint modifiers = 0; - char keyChar = 0; + uint16_t keyChar = 0; + jstring keyString = NULL; char text[255]; // XEventsQueued(dpy, X): - // QueuedAlready : No I/O Flush or system call doesn't work on some cards (eg ATI) ?) + // QueuedAlready == XQLength(): No I/O Flush or system call doesn't work on some cards (eg ATI) ?) // QueuedAfterFlush == XPending(): I/O Flush only if no already queued events are available // QueuedAfterReading : QueuedAlready + if queue==0, attempt to read more .. - if ( 0 >= XPending(dpy) ) { + if ( 0 >= XEventsQueued(dpy, QueuedAfterFlush) ) { // DBG_PRINT( "X11: DispatchMessages 0x%X - Leave 1\n", dpy); return; } @@ -427,19 +392,17 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage XNextEvent(dpy, &evt); num_events--; - if( 0==evt.xany.window ) { - NewtCommon_throwNewRuntimeException(env, "event window NULL, bail out!"); - return ; - } - if(dpy!=evt.xany.display) { NewtCommon_throwNewRuntimeException(env, "wrong display, bail out!"); return ; } - // DBG_PRINT( "X11: DispatchMessages dpy %p, win %p, Event %d\n", (void*)dpy, (void*)evt.xany.window, (int)evt.type); + if( 0==evt.xany.window ) { + DBG_PRINT( "X11: DispatchMessages dpy %p, Event %d - Window NULL, ignoring\n", (void*)dpy, (int)evt.type); + continue; + } - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); + // DBG_PRINT( "X11: DispatchMessages dpy %p, win %p, Event %d\n", (void*)dpy, (void*)evt.xany.window, (int)evt.type); jwindow = getJavaWindowProperty(env, dpy, evt.xany.window, javaObjectAtom, #ifdef VERBOSE_ON @@ -449,11 +412,8 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage #endif ); - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); - if(NULL==jwindow) { - fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d for X11 window %p\n", - (void*)dpy, evt.type, (void*)evt.xany.window); + fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d for X11 window %p\n", (void*)dpy, evt.type, (void*)evt.xany.window); continue; } @@ -470,26 +430,73 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage } else { autoRepeatModifiers &= ~EVENT_AUTOREPEAT_MASK; } + } else { + autoRepeatModifiers &= ~EVENT_AUTOREPEAT_MASK; } // fall through intended - case KeyPress: - if(XLookupString(&evt.xkey,text,255,&keySym,0)==1) { - KeySym lower_return = 0, upper_return = 0; - keyChar=text[0]; - XConvertCase(keySym, &lower_return, &upper_return); - // always return upper case, set modifier masks (SHIFT, ..) - keySym = X11KeySym2NewtVKey(upper_return); - } else { - keyChar=0; - keySym = X11KeySym2NewtVKey(keySym); + case KeyPress: { + KeySym shiftedKeySym; // layout depending keySym w/ SHIFT + KeySym unShiftedKeySym; // layout depending keySym w/o SHIFT + unsigned int xkey_state = evt.xkey.state; + + keyCode = evt.xkey.keycode; + + // Layout depending keySym w/o SHIFT, + // using fixed group 0 (US default layout) + // + // unsigned int mods_rtrn = 0; + // Bool res = XkbTranslateKeyCode (kbdDesc, keyCode, 0, &mods_rtrn, &keySym); // XKB disabled for now + // if( !res ) { + keySym = XkbKeycodeToKeysym(dpy, keyCode, 0 /* group */, 0 /* shift level */); + // } + + text[0] = 0; text[1] = 0; text[2] = 0; + int charCount = XLookupString(&evt.xkey, text, 2, &shiftedKeySym, NULL); + if( 1 == charCount ) { + keyChar = 0x00FF & (uint16_t) (text[0]); + } else if( 2 == charCount ) { + // Example: UTF-16: 00DF, UTF-8: c3 9f, LATIN SMALL LETTER SHARP S + keyChar = ( 0x00FF & (uint16_t)(text[0]) ) << 8 | ( 0x00FF & (uint16_t)(text[1]) ); // UTF-16BE + keyString = (*env)->NewStringUTF(env, text); + } + + #ifdef DEBUG_KEYS + fprintf(stderr, "NEWT X11 Key.0: keyCode 0x%X keySym 0x%X, (shifted: 0x%X)\n", + (int)keyCode, (int)keySym, (int) shiftedKeySym); + #endif + if( IS_WITHIN( shiftedKeySym, XK_KP_Space, XK_KP_9 ) ) { + // Use modded keySym for keypad for US and NN + keySym = shiftedKeySym; + unShiftedKeySym = shiftedKeySym; + } else if( 0 == keyChar ) { + // Use keyCode's keySym for dead-key (aka modifiers, etc) + unShiftedKeySym = keySym; + } else if( 0 == ( evt.xkey.state & ShiftCtrlModMask ) ) { + // Use non modded keySym + unShiftedKeySym = shiftedKeySym; + } else { + evt.xkey.state = evt.xkey.state & ~ShiftCtrlModMask; // clear shift, ctrl and Mod* + XLookupString(&evt.xkey, text, 0, &unShiftedKeySym, NULL); + // unShiftedKeySym = XLookupKeysym(&evt.xkey, 0 /* index ? */); + } + + javaVKeyNN = X11KeySym2NewtVKey(unShiftedKeySym); + javaVKeyUS = X11KeySym2NewtVKey(keySym); + modifiers |= X11InputState2NewtModifiers(xkey_state, javaVKeyNN, evt.type == KeyPress) | autoRepeatModifiers; + + #ifdef DEBUG_KEYS + fprintf(stderr, "NEWT X11 Key.X: keyCode 0x%X keySym 0x%X, (0x%X, shifted: 0x%X), keyChar '%c' 0x%X %d, javaVKey[US 0x%X, NN 0x%X], xstate 0x%X %u, jmods 0x%X\n", + (int)keyCode, (int)keySym, (int) unShiftedKeySym, (int)shiftedKeySym, keyChar, keyChar, charCount, + (int)javaVKeyUS, (int)javaVKeyNN, + (int)xkey_state, (int)xkey_state, (int)modifiers); + #endif } - modifiers |= X11InputState2NewtModifiers(evt.xkey.state) | autoRepeatModifiers; break; case ButtonPress: case ButtonRelease: case MotionNotify: - modifiers |= X11InputState2NewtModifiers(evt.xbutton.state); + modifiers |= X11InputState2NewtModifiers(evt.xbutton.state, 0, JNI_FALSE); break; default: @@ -499,87 +506,43 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage switch(evt.type) { case ButtonPress: (*env)->CallVoidMethod(env, jwindow, requestFocusID, JNI_FALSE); - #ifdef USE_SENDIO_DIRECT - (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jshort) EVENT_MOUSE_PRESSED, modifiers, - (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0 /*rotation*/); - #else - (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_PRESSED, - modifiers, - (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0 /*rotation*/); - #endif + (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jshort) evt.xbutton.button, 0.0f /*rotation*/); break; case ButtonRelease: - #ifdef USE_SENDIO_DIRECT - (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_RELEASED, - modifiers, - (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0 /*rotation*/); - #else - (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_RELEASED, + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jshort) EVENT_MOUSE_RELEASED, modifiers, - (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0 /*rotation*/); - #endif + (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jshort) evt.xbutton.button, 0.0f /*rotation*/); break; case MotionNotify: - #ifdef USE_SENDIO_DIRECT - (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_MOVED, - modifiers, - (jint) evt.xmotion.x, (jint) evt.xmotion.y, (jint) 0, 0 /*rotation*/); - #else - (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_MOVED, + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jshort) EVENT_MOUSE_MOVED, modifiers, - (jint) evt.xmotion.x, (jint) evt.xmotion.y, (jint) 0, 0 /*rotation*/); - #endif + (jint) evt.xmotion.x, (jint) evt.xmotion.y, (jshort) 0, 0.0f /*rotation*/); break; case EnterNotify: DBG_PRINT( "X11: event . EnterNotify call %p %d/%d\n", (void*)evt.xcrossing.window, evt.xcrossing.x, evt.xcrossing.y); - #ifdef USE_SENDIO_DIRECT - (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_ENTERED, + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jshort) EVENT_MOUSE_ENTERED, modifiers, - (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0 /*rotation*/); - #else - (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_ENTERED, - modifiers, - (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0 /*rotation*/); - #endif + (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jshort) 0, 0.0f /*rotation*/); break; case LeaveNotify: DBG_PRINT( "X11: event . LeaveNotify call %p %d/%d\n", (void*)evt.xcrossing.window, evt.xcrossing.x, evt.xcrossing.y); - #ifdef USE_SENDIO_DIRECT - (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_EXITED, - modifiers, - (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0 /*rotation*/); - #else - (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_EXITED, + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jshort) EVENT_MOUSE_EXITED, modifiers, - (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0 /*rotation*/); - #endif + (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jshort) 0, 0.0f /*rotation*/); + break; + case MappingNotify: + DBG_PRINT( "X11: event . MappingNotify call %p type %d\n", (void*)evt.xmapping.window, evt.xmapping.type); + XRefreshKeyboardMapping(&evt.xmapping); break; case KeyPress: - #ifdef USE_SENDIO_DIRECT - (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_PRESSED, - modifiers, keySym, (jchar) -1); - #else - (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_PRESSED, - modifiers, keySym, (jchar) -1); - #endif - + (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jshort) EVENT_KEY_PRESSED, + modifiers, javaVKeyUS, javaVKeyNN, (jchar) keyChar, keyString); break; case KeyRelease: - #ifdef USE_SENDIO_DIRECT - (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_RELEASED, - modifiers, keySym, (jchar) -1); - - (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_TYPED, - modifiers, keySym, (jchar) keyChar); - #else - (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_RELEASED, - modifiers, keySym, (jchar) -1); - - (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_TYPED, - modifiers, keySym, (jchar) keyChar); - #endif - + (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jshort) EVENT_KEY_RELEASED, + modifiers, javaVKeyUS, javaVKeyNN, (jchar) keyChar, keyString); break; case DestroyNotify: DBG_PRINT( "X11: event . DestroyNotify call %p, parent %p, child-event: %d\n", @@ -709,4 +672,59 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage } } +/* + * Class: Java_jogamp_newt_driver_x11_DisplayDriver + * Method: createPointerIcon0 + * Signature: (JJILjava/lang/Object;I)V + */ +JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_createPointerIcon0 + (JNIEnv *env, jclass clazz, jlong display, jobject pixels, jint pixels_byte_offset, jboolean pixels_is_direct, jint width, jint height, jint hotX, jint hotY) +{ + Cursor c; + + if( 0 != pixels ) { + Display * dpy = (Display *) (intptr_t) display; + const unsigned char * pixelPtr = (const unsigned char *) ( JNI_TRUE == pixels_is_direct ? + (*env)->GetDirectBufferAddress(env, pixels) : + (*env)->GetPrimitiveArrayCritical(env, pixels, NULL) ); + XcursorImage ci; + ci.version = 1; // XCURSOR_IMAGE_VERSION; + ci.size = width; // nominal size (assume square ..) + ci.width = width; + ci.height = height; + ci.xhot = hotX; + ci.yhot = hotY; + ci.delay = 0; + ci.pixels = (XcursorPixel *)(intptr_t)(pixelPtr + pixels_byte_offset); + + c = XcursorImageLoadCursor (dpy, &ci); + + if ( JNI_FALSE == pixels_is_direct ) { + (*env)->ReleasePrimitiveArrayCritical(env, pixels, (void*)pixelPtr, JNI_ABORT); + } + DBG_PRINT( "X11: createPointerIcon0: %p %dx%d %d/%d -> %p\n", (pixelPtr+pixels_byte_offset), width, height, hotX, hotY, (void *)c); + + } else { + c = 0; + } + return (jlong) (intptr_t) c; +} + +/* + * Class: Java_jogamp_newt_driver_x11_DisplayDriver + * Method: destroyPointerIcon0 + * Signature: (JJILjava/lang/Object;I)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_destroyPointerIcon0 + (JNIEnv *env, jclass clazz, jlong display, jlong handle) +{ + Display * dpy = (Display *) (intptr_t) display; + + if( 0 != handle ) { + Cursor c = (Cursor) (intptr_t) handle; + DBG_PRINT( "X11: destroyPointerIcon0: %p\n", (void *)c); + XFreeCursor(dpy, c); + } +} + diff --git a/src/newt/native/X11Event.c b/src/newt/native/X11Event.c new file mode 100644 index 000000000..32a55c67c --- /dev/null +++ b/src/newt/native/X11Event.c @@ -0,0 +1,305 @@ + +#include "X11Event.h" + +void X11EventPoll(JNIEnv *env, jobject obj, Display *dpy, jlong javaObjectAtom, jlong windowDeleteAtom) { + Atom wm_delete_atom = (Atom)windowDeleteAtom; + int num_events = 100; + int autoRepeatModifiers = 0; + + if ( NULL == dpy ) { + return; + } + + // Periodically take a break + while( num_events > 0 ) { + jobject jwindow = NULL; + XEvent evt; + KeySym keySym = 0; + jint modifiers = 0; + char keyChar = 0; + char text[255]; + + // XEventsQueued(dpy, X): + // QueuedAlready == XQLength(): No I/O Flush or system call doesn't work on some cards (eg ATI) ?) + // QueuedAfterFlush == XPending(): I/O Flush only if no already queued events are available + // QueuedAfterReading : QueuedAlready + if queue==0, attempt to read more .. + // if ( 0 >= XPending(dpy) ) + if ( 0 >= XEventsQueued(dpy, QueuedAfterFlush) ) + { + // DBG_PRINT( "X11: DispatchMessages 0x%X - Leave 1\n", dpy); + return; + } + + XNextEvent(dpy, &evt); + num_events--; + + if(dpy!=evt.xany.display) { + NewtCommon_throwNewRuntimeException(env, "wrong display, bail out!"); + return ; + } + + if( 0==evt.xany.window ) { + DBG_PRINT( "X11: DispatchMessages dpy %p, Event %d - Window NULL, ignoring\n", (void*)dpy, (int)evt.type); + continue; + } + + // DBG_PRINT( "X11: DispatchMessages dpy %p, win %p, Event %d\n", (void*)dpy, (void*)evt.xany.window, (int)evt.type); + + jwindow = getJavaWindowProperty(env, dpy, evt.xany.window, javaObjectAtom, + #ifdef VERBOSE_ON + True + #else + False + #endif + ); + + if(NULL==jwindow) { + fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d for X11 window %p\n", (void*)dpy, evt.type, (void*)evt.xany.window); + continue; + } + + switch(evt.type) { + case KeyRelease: + if (XEventsQueued(dpy, QueuedAfterReading)) { + XEvent nevt; + XPeekEvent(dpy, &nevt); + + if (nevt.type == KeyPress && nevt.xkey.time == evt.xkey.time && + nevt.xkey.keycode == evt.xkey.keycode) + { + autoRepeatModifiers |= EVENT_AUTOREPEAT_MASK; + } else { + autoRepeatModifiers &= ~EVENT_AUTOREPEAT_MASK; + } + } + // fall through intended + case KeyPress: + if(XLookupString(&evt.xkey,text,255,&keySym,0)==1) { + KeySym lower_return = 0, upper_return = 0; + keyChar=text[0]; + XConvertCase(keySym, &lower_return, &upper_return); + // always return upper case, set modifier masks (SHIFT, ..) + keySym = X11KeySym2NewtVKey(upper_return); + } else { + keyChar=0; + keySym = X11KeySym2NewtVKey(keySym); + } + modifiers |= X11InputState2NewtModifiers(evt.xkey.state) | autoRepeatModifiers; + break; + + case ButtonPress: + case ButtonRelease: + case MotionNotify: + modifiers |= X11InputState2NewtModifiers(evt.xbutton.state); + break; + + default: + break; + } + + switch(evt.type) { + case ButtonPress: + (*env)->CallVoidMethod(env, jwindow, requestFocusID, JNI_FALSE); + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, + modifiers, + (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0.0f /*rotation*/); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_PRESSED, + modifiers, + (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0.0f /*rotation*/); + #endif + break; + case ButtonRelease: + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_RELEASED, + modifiers, + (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0.0f /*rotation*/); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_RELEASED, + modifiers, + (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0.0f /*rotation*/); + #endif + break; + case MotionNotify: + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_MOVED, + modifiers, + (jint) evt.xmotion.x, (jint) evt.xmotion.y, (jint) 0, 0.0f /*rotation*/); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_MOVED, + modifiers, + (jint) evt.xmotion.x, (jint) evt.xmotion.y, (jint) 0, 0.0f /*rotation*/); + #endif + break; + case EnterNotify: + DBG_PRINT( "X11: event . EnterNotify call %p %d/%d\n", (void*)evt.xcrossing.window, evt.xcrossing.x, evt.xcrossing.y); + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_ENTERED, + modifiers, + (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0.0f /*rotation*/); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_ENTERED, + modifiers, + (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0.0f /*rotation*/); + #endif + break; + case LeaveNotify: + DBG_PRINT( "X11: event . LeaveNotify call %p %d/%d\n", (void*)evt.xcrossing.window, evt.xcrossing.x, evt.xcrossing.y); + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_EXITED, + modifiers, + (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0.0f /*rotation*/); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_EXITED, + modifiers, + (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0.0f /*rotation*/); + #endif + break; + case KeyPress: + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_PRESSED, + modifiers, keySym, (jchar) -1); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_PRESSED, + modifiers, keySym, (jchar) -1); + #endif + + break; + case KeyRelease: + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_RELEASED, + modifiers, keySym, (jchar) -1); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_RELEASED, + modifiers, keySym, (jchar) -1); + #endif + + break; + case DestroyNotify: + DBG_PRINT( "X11: event . DestroyNotify call %p, parent %p, child-event: %d\n", + (void*)evt.xdestroywindow.window, (void*)evt.xdestroywindow.event, evt.xdestroywindow.window != evt.xdestroywindow.event); + if ( evt.xdestroywindow.window == evt.xdestroywindow.event ) { + // ignore child destroy notification + } + break; + case CreateNotify: + DBG_PRINT( "X11: event . CreateNotify call %p, parent %p, child-event: 1\n", + (void*)evt.xcreatewindow.window, (void*) evt.xcreatewindow.parent); + break; + case ConfigureNotify: + DBG_PRINT( "X11: event . ConfigureNotify call %p (parent %p, above %p) %d/%d %dx%d %d, child-event: %d\n", + (void*)evt.xconfigure.window, (void*)evt.xconfigure.event, (void*)evt.xconfigure.above, + evt.xconfigure.x, evt.xconfigure.y, evt.xconfigure.width, evt.xconfigure.height, + evt.xconfigure.override_redirect, evt.xconfigure.window != evt.xconfigure.event); + if ( evt.xconfigure.window == evt.xconfigure.event ) { + // ignore child window change notification + { + // update insets + int left, right, top, bottom; + NewtWindows_updateInsets(env, jwindow, dpy, evt.xany.window, &left, &right, &top, &bottom); + } + (*env)->CallVoidMethod(env, jwindow, sizeChangedID, JNI_FALSE, + (jint) evt.xconfigure.width, (jint) evt.xconfigure.height, JNI_FALSE); + (*env)->CallVoidMethod(env, jwindow, positionChangedID, JNI_FALSE, + (jint) evt.xconfigure.x, (jint) evt.xconfigure.y); + } + break; + case ClientMessage: + if (evt.xclient.send_event==True && evt.xclient.data.l[0]==wm_delete_atom) { // windowDeleteAtom + jboolean closed; + DBG_PRINT( "X11: event . ClientMessage call %p type 0x%X ..\n", + (void*)evt.xclient.window, (unsigned int)evt.xclient.message_type); + closed = (*env)->CallBooleanMethod(env, jwindow, windowDestroyNotifyID, JNI_FALSE); + DBG_PRINT( "X11: event . ClientMessage call %p type 0x%X, closed: %d\n", + (void*)evt.xclient.window, (unsigned int)evt.xclient.message_type, (int)closed); + // Called by Window.java: CloseWindow(); + num_events = 0; // end loop in case of destroyed display + } + break; + + case FocusIn: + DBG_PRINT( "X11: event . FocusIn call %p\n", (void*)evt.xvisibility.window); + (*env)->CallVoidMethod(env, jwindow, focusChangedID, JNI_FALSE, JNI_TRUE); + break; + + case FocusOut: + DBG_PRINT( "X11: event . FocusOut call %p\n", (void*)evt.xvisibility.window); + (*env)->CallVoidMethod(env, jwindow, focusChangedID, JNI_FALSE, JNI_FALSE); + break; + + case Expose: + DBG_PRINT( "X11: event . Expose call %p %d/%d %dx%d count %d\n", (void*)evt.xexpose.window, + evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height, evt.xexpose.count); + + if (evt.xexpose.count == 0 && evt.xexpose.width > 0 && evt.xexpose.height > 0) { + (*env)->CallVoidMethod(env, jwindow, windowRepaintID, JNI_FALSE, + evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height); + } + break; + + case MapNotify: + DBG_PRINT( "X11: event . MapNotify call Event %p, Window %p, override_redirect %d, child-event: %d\n", + (void*)evt.xmap.event, (void*)evt.xmap.window, (int)evt.xmap.override_redirect, + evt.xmap.event!=evt.xmap.window); + if( evt.xmap.event == evt.xmap.window ) { + // ignore child window notification + { + // update insets + int left, right, top, bottom; + NewtWindows_updateInsets(env, jwindow, dpy, evt.xany.window, &left, &right, &top, &bottom); + } + (*env)->CallVoidMethod(env, jwindow, visibleChangedID, JNI_FALSE, JNI_TRUE); + } + break; + + case UnmapNotify: + DBG_PRINT( "X11: event . UnmapNotify call Event %p, Window %p, from_configure %d, child-event: %d\n", + (void*)evt.xunmap.event, (void*)evt.xunmap.window, (int)evt.xunmap.from_configure, + evt.xunmap.event!=evt.xunmap.window); + if( evt.xunmap.event == evt.xunmap.window ) { + // ignore child window notification + (*env)->CallVoidMethod(env, jwindow, visibleChangedID, JNI_FALSE, JNI_FALSE); + } + break; + + case ReparentNotify: + { + jlong parentResult; // 0 if root, otherwise proper value + Window winRoot, winTopParent; + #ifdef VERBOSE_ON + Window oldParentRoot, oldParentTopParent; + Window parentRoot, parentTopParent; + if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.event, &oldParentRoot, &oldParentTopParent) ) { + oldParentRoot=0; oldParentTopParent = 0; + } + if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.parent, &parentRoot, &parentTopParent) ) { + parentRoot=0; parentTopParent = 0; + } + #endif + if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.window, &winRoot, &winTopParent) ) { + winRoot=0; winTopParent = 0; + } + if(evt.xreparent.parent == winRoot) { + parentResult = 0; // our java indicator for root window + } else { + parentResult = (jlong) (intptr_t) evt.xreparent.parent; + } + #ifdef VERBOSE_ON + DBG_PRINT( "X11: event . ReparentNotify: call %d/%d OldParent %p (root %p, top %p), NewParent %p (root %p, top %p), Window %p (root %p, top %p)\n", + evt.xreparent.x, evt.xreparent.y, + (void*)evt.xreparent.event, (void*)oldParentRoot, (void*)oldParentTopParent, + (void*)evt.xreparent.parent, (void*)parentRoot, (void*)parentTopParent, + (void*)evt.xreparent.window, (void*)winRoot, (void*)winTopParent); + #endif + (*env)->CallVoidMethod(env, jwindow, reparentNotifyID, (jlong)evt.xreparent.parent); + } + break; + + // unhandled events .. yet .. + + default: + DBG_PRINT("X11: event . unhandled %d 0x%X call %p\n", (int)evt.type, (unsigned int)evt.type, (void*)evt.xunmap.window); + } + } +} diff --git a/src/newt/native/X11Event.h b/src/newt/native/X11Event.h new file mode 100644 index 000000000..969bcdeed --- /dev/null +++ b/src/newt/native/X11Event.h @@ -0,0 +1,9 @@ + +#ifndef _X11Event_h +#define _X11Event_h + +#include "X11Common.h" + +extern void X11EventPoll(JNIEnv *env, jobject obj, Display *dpy, jlong javaObjectAtom, jlong wmDeleteAtom); + +#endif /* _X11Event_h */ diff --git a/src/newt/native/X11RandR11.c b/src/newt/native/X11RandR11.c new file mode 100644 index 000000000..38d61289b --- /dev/null +++ b/src/newt/native/X11RandR11.c @@ -0,0 +1,371 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#include "X11Screen.h" + +/* + * Class: jogamp_newt_driver_x11_RandR11 + * Method: getAvailableScreenRotations0 + * Signature: (JI)I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR11_getAvailableScreenRotations0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) +{ + Display *dpy = (Display *) (intptr_t) display; + Window root = RootWindow(dpy, (int)scrn_idx); + int num_rotations = 0; + Rotation cur_rotation, rotations_supported; + int rotations[4]; + int major, minor; + + rotations_supported = XRRRotations (dpy, (int)scrn_idx, &cur_rotation); + + if(0 != (rotations_supported & RR_Rotate_0)) { + rotations[num_rotations++] = 0; + } + if(0 != (rotations_supported & RR_Rotate_90)) { + rotations[num_rotations++] = 90; + } + if(0 != (rotations_supported & RR_Rotate_180)) { + rotations[num_rotations++] = 180; + } + if(0 != (rotations_supported & RR_Rotate_270)) { + rotations[num_rotations++] = 270; + } + + jintArray properties = NULL; + + if(num_rotations>0) { + properties = (*env)->NewIntArray(env, num_rotations); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", num_rotations); + } + + // move from the temp structure to the java structure + (*env)->SetIntArrayRegion(env, properties, 0, num_rotations, rotations); + } + + return properties; +} + +/* + * Class: jogamp_newt_driver_x11_RandR11 + * Method: getNumScreenResolution0 + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_RandR11_getNumScreenResolutions0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) +{ + Display *dpy = (Display *) (intptr_t) display; +#ifdef DBG_PERF + struct timespec t0, t1, td; + long td_ms; + timespec_now(&t0); +#endif + +#ifdef DBG_PERF + timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td); + fprintf(stderr, "X11Screen_getNumScreenResolution0.1: %ld ms\n", td_ms); fflush(NULL); +#endif + + int num_sizes; + XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_idx, &num_sizes); //get possible screen resolutions + +#ifdef DBG_PERF + timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td); + fprintf(stderr, "X11Screen_getNumScreenResolution0.2 (XRRSizes): %ld ms\n", td_ms); fflush(NULL); +#endif + + DBG_PRINT("getNumScreenResolutions0: %p:%d -> %d\n", dpy, (int)scrn_idx, num_sizes); + + return num_sizes; +} + +/* + * Class: jogamp_newt_driver_x11_RandR11 + * Method: getScreenResolutions0 + * Signature: (JII)[I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR11_getScreenResolution0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx, jint resMode_idx) +{ + Display *dpy = (Display *) (intptr_t) display; + + int num_sizes; + XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_idx, &num_sizes); //get possible screen resolutions + + if( 0 > resMode_idx || resMode_idx >= num_sizes ) { + NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); + } + + // Fill the properties in temp jint array + int propIndex = 0; + jint prop[4]; + + prop[propIndex++] = xrrs[(int)resMode_idx].width; + prop[propIndex++] = xrrs[(int)resMode_idx].height; + prop[propIndex++] = xrrs[(int)resMode_idx].mwidth; + prop[propIndex++] = xrrs[(int)resMode_idx].mheight; + + jintArray properties = (*env)->NewIntArray(env, 4); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", 4); + } + + // move from the temp structure to the java structure + (*env)->SetIntArrayRegion(env, properties, 0, 4, prop); + + return properties; +} + +/* + * Class: jogamp_newt_driver_x11_RandR11 + * Method: getScreenRates0 + * Signature: (JII)[I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR11_getScreenRates0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx, jint resMode_idx) +{ + Display *dpy = (Display *) (intptr_t) display; + + int num_sizes; + XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_idx, &num_sizes); //get possible screen resolutions + + if( 0 > resMode_idx || resMode_idx >= num_sizes ) { + NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); + } + + int num_rates; + short *rates = XRRRates(dpy, (int)scrn_idx, (int)resMode_idx, &num_rates); + + jint prop[num_rates]; + int i; + for(i=0; i<num_rates; i++) { + prop[i] = (int) rates[i]; + /** fprintf(stderr, "rate[%d, %d, %d/%d]: %d\n", (int)scrn_idx, resMode_idx, i, num_rates, prop[i]); */ + } + + jintArray properties = (*env)->NewIntArray(env, num_rates); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", num_rates); + } + + // move from the temp structure to the java structure + (*env)->SetIntArrayRegion(env, properties, 0, num_rates, prop); + + return properties; +} + +/* + * Class: jogamp_newt_driver_x11_RandR11 + * Method: getScreenConfiguration0 + * Signature: (JI)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_RandR11_getScreenConfiguration0 + (JNIEnv *env, jclass clazz, jlong display, jint screen_idx) +{ + Display *dpy = (Display *) (intptr_t) display; + Window root = RootWindow(dpy, (int)screen_idx); +#ifdef DBG_PERF + struct timespec t0, t1, td; + long td_ms; + timespec_now(&t0); +#endif + +#ifdef DBG_PERF + timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td); + fprintf(stderr, "X11Screen_getScreenConfiguration0.1: %ld ms\n", td_ms); fflush(NULL); +#endif + + // get current resolutions and frequencies + XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root); +#ifdef DBG_PERF + timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td); + fprintf(stderr, "X11Screen_getScreenConfiguration0.2 (XRRGetScreenInfo): %ld ms\n", td_ms); fflush(NULL); +#endif + + return (jlong) (intptr_t) conf; +} + +/* + * Class: jogamp_newt_driver_x11_RandR11 + * Method: freeScreenConfiguration0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_RandR11_freeScreenConfiguration0 + (JNIEnv *env, jclass clazz, jlong screenConfiguration) +{ + XRRFreeScreenConfigInfo( (XRRScreenConfiguration *) (intptr_t) screenConfiguration ); +} + +/* + * Class: jogamp_newt_driver_x11_RandR11 + * Method: getCurrentScreenRate0 + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_RandR11_getCurrentScreenRate0 + (JNIEnv *env, jclass clazz, jlong screenConfiguration) +{ + XRRScreenConfiguration *conf = (XRRScreenConfiguration *) (intptr_t) screenConfiguration; + + short original_rate = XRRConfigCurrentRate(conf); + DBG_PRINT("getCurrentScreenRate0: %d\n", (int)original_rate); + + return (jint) original_rate; +} + +/* + * Class: jogamp_newt_driver_x11_RandR11 + * Method: getCurrentScreenRotation0 + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_RandR11_getCurrentScreenRotation0 + (JNIEnv *env, jclass clazz, jlong screenConfiguration) +{ + XRRScreenConfiguration *conf = (XRRScreenConfiguration *) (intptr_t) screenConfiguration; + Rotation rotation; + + XRRConfigCurrentConfiguration(conf, &rotation); + + return NewtScreen_XRotation2Degree(env, rotation); +} + + +/* + * Class: jogamp_newt_driver_x11_RandR11 + * Method: getCurrentScreenResolutionIndex0 + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_RandR11_getCurrentScreenResolutionIndex0 + (JNIEnv *env, jclass clazz, jlong screenConfiguration) +{ + XRRScreenConfiguration *conf = (XRRScreenConfiguration *) (intptr_t) screenConfiguration; + + short original_rate = XRRConfigCurrentRate(conf); + + Rotation original_rotation; + SizeID original_size_id = XRRConfigCurrentConfiguration(conf, &original_rotation); + + DBG_PRINT("getCurrentScreenResolutionIndex0: %d\n", (int)original_size_id); + return (jint)original_size_id; +} + +/* + * Class: jogamp_newt_driver_x11_RandR11 + * Method: setCurrentScreenModeStart0 + * Signature: (JIJIII)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_RandR11_setCurrentScreenModeStart0 + (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jlong screenConfiguration, jint resMode_idx, jint freq, jint rotation) +{ + Display *dpy = (Display *) (intptr_t) display; + XRRScreenConfiguration *conf = (XRRScreenConfiguration *) (intptr_t) screenConfiguration; + Window root = RootWindow(dpy, (int)screen_idx); + + int num_sizes; + XRRScreenSize *xrrs = XRRSizes(dpy, (int)screen_idx, &num_sizes); //get possible screen resolutions + + if( 0 > resMode_idx || resMode_idx >= num_sizes ) { + NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); + } + + DBG_PRINT("X11Screen.setCurrentScreenMode0: CHANGED TO %d: %d x %d PIXELS, %d Hz, %d degree\n", + resMode_idx, xrrs[resMode_idx].width, xrrs[resMode_idx].height, (int)freq, rotation); + + int xrot = NewtScreen_Degree2XRotation(env, rotation); + + XRRSelectInput (dpy, root, RRScreenChangeNotifyMask); + + XSync(dpy, False); + XRRSetScreenConfigAndRate(dpy, conf, root, (int)resMode_idx, xrot, (short)freq, CurrentTime); + XSync(dpy, False); + + return JNI_TRUE; +} + +/* + * Class: jogamp_newt_driver_x11_RandR11 + * Method: setCurrentScreenModePollEnd0 + * Signature: (JIII)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_RandR11_setCurrentScreenModePollEnd0 + (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jint resMode_idx, jint freq, jint rotation) +{ + Display *dpy = (Display *) (intptr_t) display; + int randr_event_base, randr_error_base; + XEvent evt; + XRRScreenChangeNotifyEvent * scn_event = (XRRScreenChangeNotifyEvent *) &evt; + + int num_sizes; + XRRScreenSize *xrrs = XRRSizes(dpy, (int)screen_idx, &num_sizes); //get possible screen resolutions + XRRScreenConfiguration *conf; + + if( 0 > resMode_idx || resMode_idx >= num_sizes ) { + NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); + } + + XRRQueryExtension(dpy, &randr_event_base, &randr_error_base); + + int done = 0; + int rot; + do { + if ( 0 >= XEventsQueued(dpy, QueuedAfterFlush) ) { + return JNI_FALSE; // not done + } + XNextEvent(dpy, &evt); + + switch (evt.type - randr_event_base) { + case RRScreenChangeNotify: + if(0 < scn_event->rotation ) { + rot = NewtScreen_XRotation2Degree(env, (int)scn_event->rotation); + DBG_PRINT( "XRANDR: event . RRScreenChangeNotify call(1) %p (root %p) resIdx %d rot %d %dx%d\n", + (void*)scn_event->window, (void*)scn_event->root, + (int)scn_event->size_index, rot, + scn_event->width, scn_event->height); + // done = scn_event->size_index == resMode_idx; // not reliable .. + done = rot == rotation && + scn_event->width == xrrs[resMode_idx].width && + scn_event->height == xrrs[resMode_idx].height; + } else { + DBG_PRINT( "XRANDR: event . RRScreenChangeNotify call(0) %p (root %p) resIdx %d %dx%d\n", + (void*)scn_event->window, (void*)scn_event->root, + (int)scn_event->size_index, + scn_event->width, scn_event->height); + } + break; + default: + DBG_PRINT("RANDR: event . unhandled %d 0x%X call %p\n", (int)evt.type, (int)evt.type, (void*)evt.xany.window); + } + XRRUpdateConfiguration(&evt); + } while(!done); + + XSync(dpy, False); + + return done ? JNI_TRUE : JNI_FALSE; +} + diff --git a/src/newt/native/X11RandR13.c b/src/newt/native/X11RandR13.c new file mode 100644 index 000000000..4e92a32b4 --- /dev/null +++ b/src/newt/native/X11RandR13.c @@ -0,0 +1,519 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#include "X11Common.h" + +/* + * Class: jogamp_newt_driver_x11_RandR13 + * Method: getScreenResources0 + * Signature: (JI)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_RandR13_getScreenResources0 + (JNIEnv *env, jclass clazz, jlong display, jint screen_idx) +{ + Display *dpy = (Display *) (intptr_t) display; + Window root = RootWindow(dpy, (int)screen_idx); + + XRRScreenResources *res = XRRGetScreenResourcesCurrent( dpy, root); // 1.3 + // XRRScreenResources *res = XRRGetScreenResources( dpy, root); // 1.2 + + return (jlong) (intptr_t) res; +} + +/* + * Class: jogamp_newt_driver_x11_RandR13 + * Method: freeScreenResources0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_RandR13_freeScreenResources0 + (JNIEnv *env, jclass clazz, jlong screenResources) +{ + XRRScreenResources *resources = (XRRScreenResources *) (intptr_t) screenResources; + if( NULL != resources ) { + XRRFreeScreenResources( resources ); + } +} + +#define SAFE_STRING(s) (NULL==s?"":s) + +static void dumpOutputs(const char *prefix, Display *dpy, XRRScreenResources *resources, int noutput, RROutput * outputs) { + int i, j; + fprintf(stderr, "%s %p: Output count %d\n", prefix, resources, noutput); + for(i=0; i<noutput; i++) { + RROutput output = outputs[i]; + XRROutputInfo * xrrOutputInfo = XRRGetOutputInfo (dpy, resources, output); + fprintf(stderr, " Output[%d]: id %#lx, crtx 0x%X, name %s (%d), %lux%lu, ncrtc %d, .., nmode %d (preferred %d)\n", + i, output, xrrOutputInfo->crtc, SAFE_STRING(xrrOutputInfo->name), xrrOutputInfo->nameLen, xrrOutputInfo->mm_width, xrrOutputInfo->mm_height, + xrrOutputInfo->ncrtc, xrrOutputInfo->nmode, xrrOutputInfo->npreferred); + for(j=0; j<xrrOutputInfo->nmode; j++) { + fprintf(stderr, " Output[%d].Mode[%d].id %#lx\n", i, j, xrrOutputInfo->modes[j]); + } + XRRFreeOutputInfo (xrrOutputInfo); + } +} + +/** Returns vertical refresh rate in hertz */ +static float getVRefresh(XRRModeInfo *mode) { + float rate; + unsigned int vTotal = mode->vTotal; + + if (mode->modeFlags & RR_DoubleScan) { + /* doublescan doubles the number of lines */ + vTotal *= 2; + } + + if (mode->modeFlags & RR_Interlace) { + /* interlace splits the frame into two fields */ + /* the field rate is what is typically reported by monitors */ + vTotal /= 2; + } + + if (mode->hTotal && vTotal) { + rate = ( (float) mode->dotClock / + ( (float) mode->hTotal * (float) vTotal ) + ); + } else { + rate = 0; + } + return rate; +} + + +JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_RandR13_dumpInfo0 + (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jlong screenResources) +{ + Display * dpy = (Display *) (intptr_t) display; + Window root = RootWindow(dpy, (int)screen_idx); + XRRScreenResources *resources = (XRRScreenResources *) (intptr_t) screenResources; + int pos[] = { 0, 0 } ; + int i, j, minWidth, minHeight, maxWidth, maxHeight; + + int vs_width = DisplayWidth(dpy, screen_idx); + int vs_height = DisplayHeight(dpy, screen_idx); + int vs_width_mm = DisplayWidthMM(dpy, screen_idx); + int vs_height_mm = DisplayHeightMM(dpy, screen_idx); + fprintf(stderr, "ScreenVirtualSize: %dx%d %dx%d mm\n", vs_width, vs_height, vs_width_mm, vs_height_mm); + + XRRGetScreenSizeRange (dpy, root, &minWidth, &minHeight, &maxWidth, &maxHeight); + fprintf(stderr, "XRRGetScreenSizeRange: %dx%d .. %dx%d\n", minWidth, minHeight, maxWidth, maxHeight); + + if( NULL == resources ) { + fprintf(stderr, "XRRScreenResources NULL\n"); + return; + } + fprintf(stderr, "XRRScreenResources %p: Crtc count %d\n", resources, resources->ncrtc); + for(i=0; i<resources->ncrtc; i++) { + RRCrtc crtc = resources->crtcs[i]; + XRRCrtcInfo *xrrCrtcInfo = XRRGetCrtcInfo (dpy, resources, crtc); + fprintf(stderr, "Crtc[%d]: %d/%d %dx%d, rot 0x%X, mode.id %#lx\n", + i, xrrCrtcInfo->x, xrrCrtcInfo->y, xrrCrtcInfo->width, xrrCrtcInfo->height, xrrCrtcInfo->rotations, xrrCrtcInfo->mode); + for(j=0; j<xrrCrtcInfo->noutput; j++) { + fprintf(stderr, " Crtc[%d].Output[%d].id %#lx\n", i, j, xrrCrtcInfo->outputs[j]); + } + XRRFreeCrtcInfo(xrrCrtcInfo); + } + + dumpOutputs("XRRScreenResources.outputs", dpy, resources, resources->noutput, resources->outputs); + + fprintf(stderr, "XRRScreenResources %p: Mode count %d\n", resources, resources->nmode); + for(i=0; i<resources->nmode; i++) { + XRRModeInfo *mode = &resources->modes[i]; + + unsigned int dots = mode->hTotal * mode->vTotal; + float refresh = getVRefresh(mode); + fprintf(stderr, "Mode[%d, id %#lx]: %ux%u@%f, name %s\n", i, mode->id, mode->width, mode->height, refresh, SAFE_STRING(mode->name)); + } +} + +/* + * Class: jogamp_newt_driver_x11_RandR13 + * Method: getMonitorDeviceCount0 + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorDeviceCount0 + (JNIEnv *env, jclass clazz, jlong screenResources) +{ + XRRScreenResources *resources = (XRRScreenResources *) (intptr_t) screenResources; + return ( NULL != resources ) ? resources->ncrtc : 0; +} + +/* + * Class: jogamp_newt_driver_x11_RandR13 + * Method: getMonitorInfoHandle0 + * Signature: (JIJI)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorInfoHandle0 + (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jlong screenResources, jint crt_idx) +{ + Display *dpy = (Display *) (intptr_t) display; + Window root = RootWindow(dpy, (int)screen_idx); + XRRScreenResources *resources = (XRRScreenResources *) (intptr_t) screenResources; + + if( NULL == resources || crt_idx >= resources->ncrtc ) { + return 0; + } + RRCrtc crtc = resources->crtcs[crt_idx]; + XRRCrtcInfo *xrrCrtcInfo = XRRGetCrtcInfo (dpy, resources, crtc); + + return (jlong) (intptr_t) xrrCrtcInfo; +} + +/* + * Class: jogamp_newt_driver_x11_RandR13 + * Method: freeMonitorInfoHandle0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_RandR13_freeMonitorInfoHandle0 + (JNIEnv *env, jclass clazz, jlong monitorInfo) +{ + XRRCrtcInfo *xrrCrtcInfo = (XRRCrtcInfo *) (intptr_t) monitorInfo; + if( NULL != xrrCrtcInfo ) { + XRRFreeCrtcInfo( xrrCrtcInfo ); + } +} + +/* + * Class: jogamp_newt_driver_x11_RandR13 + * Method: getAvailableRotations0 + * Signature: (J)I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR13_getAvailableRotations0 + (JNIEnv *env, jclass clazz, jlong monitorInfo) +{ + XRRCrtcInfo *xrrCrtcInfo = (XRRCrtcInfo *) (intptr_t) monitorInfo; + if( NULL == xrrCrtcInfo ) { + return NULL; + } + Rotation rotations_supported = xrrCrtcInfo->rotations; + + int num_rotations = 0; + int rotations[4]; + if(0 != (rotations_supported & RR_Rotate_0)) { + rotations[num_rotations++] = 0; + } + if(0 != (rotations_supported & RR_Rotate_90)) { + rotations[num_rotations++] = 90; + } + if(0 != (rotations_supported & RR_Rotate_180)) { + rotations[num_rotations++] = 180; + } + if(0 != (rotations_supported & RR_Rotate_270)) { + rotations[num_rotations++] = 270; + } + + jintArray properties = NULL; + + if(num_rotations>0) { + properties = (*env)->NewIntArray(env, num_rotations); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", num_rotations); + } + + // move from the temp structure to the java structure + (*env)->SetIntArrayRegion(env, properties, 0, num_rotations, rotations); + } + + return properties; +} + +/* + * Class: jogamp_newt_driver_x11_RandR13 + * Method: getMonitorViewport0 + * Signature: (J)[I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorViewport0 + (JNIEnv *env, jclass clazz, jlong monitorInfo) +{ + XRRCrtcInfo *xrrCrtcInfo = (XRRCrtcInfo *) (intptr_t) monitorInfo; + + if( NULL == xrrCrtcInfo ) { + // n/a + return NULL; + } + + if( None == xrrCrtcInfo->mode || 0 == xrrCrtcInfo->noutput ) { + // disabled + return NULL; + } + + jsize propCount = 4; + jint prop[ propCount ]; + int propIndex = 0; + + prop[propIndex++] = xrrCrtcInfo->x; + prop[propIndex++] = xrrCrtcInfo->y; + prop[propIndex++] = xrrCrtcInfo->width; + prop[propIndex++] = xrrCrtcInfo->height; + + jintArray properties = (*env)->NewIntArray(env, propCount); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", propCount); + } + (*env)->SetIntArrayRegion(env, properties, 0, propCount, prop); + + return properties; +} + +/* + * Class: jogamp_newt_driver_x11_RandR13 + * Method: getMonitorMode0 + * Signature: (JI)[I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorMode0 + (JNIEnv *env, jclass clazz, jlong screenResources, jint mode_idx) +{ + XRRScreenResources *resources = (XRRScreenResources *) (intptr_t) screenResources; + + if( NULL == resources || mode_idx >= resources->nmode ) { + return NULL; + } + + XRRModeInfo *mode = &resources->modes[mode_idx]; + unsigned int dots = mode->hTotal * mode->vTotal; + int refresh = (int) ( getVRefresh(mode) * 100.0f ); // Hz * 100 + int flags = 0; + if (mode->modeFlags & RR_Interlace) { + flags |= FLAG_INTERLACE; + } + if (mode->modeFlags & RR_DoubleScan) { + flags |= FLAG_DOUBLESCAN; + } + + jint prop[ NUM_MONITOR_MODE_PROPERTIES_ALL ]; + int propIndex = 0; + + prop[propIndex++] = NUM_MONITOR_MODE_PROPERTIES_ALL; + prop[propIndex++] = mode->width; + prop[propIndex++] = mode->height; + prop[propIndex++] = 32; // TODO: XRandR > 1.4 may support bpp + prop[propIndex++] = refresh; + prop[propIndex++] = flags; + prop[propIndex++] = mode->id; + prop[propIndex++] = -1; // rotation placeholder + + jintArray properties = (*env)->NewIntArray(env, NUM_MONITOR_MODE_PROPERTIES_ALL); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", NUM_MONITOR_MODE_PROPERTIES_ALL); + } + (*env)->SetIntArrayRegion(env, properties, 0, NUM_MONITOR_MODE_PROPERTIES_ALL, prop); + + return properties; +} + +/* + * Class: jogamp_newt_driver_x11_RandR13 + * Method: getMonitorCurrentMode0 + * Signature: (JJ)[I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorCurrentMode0 + (JNIEnv *env, jclass clazz, jlong screenResources, jlong monitorInfo) +{ + XRRScreenResources *resources = (XRRScreenResources *) (intptr_t) screenResources; + XRRCrtcInfo *xrrCrtcInfo = (XRRCrtcInfo *) (intptr_t) monitorInfo; + + if( NULL == resources || NULL == xrrCrtcInfo ) { + // n/a + return NULL; + } + + if( None == xrrCrtcInfo->mode || 0 == xrrCrtcInfo->noutput ) { + // disabled + return NULL; + } + + int modeId = xrrCrtcInfo->mode; + XRRModeInfo *mode = NULL; + int i; + for(i=0; i<resources->nmode; i++) { + XRRModeInfo *imode = &resources->modes[i]; + if( imode->id == modeId ) { + mode = imode; + break; + } + } + if( NULL == mode ) { + // oops .. + return NULL; + } + + unsigned int dots = mode->hTotal * mode->vTotal; + int refresh = (int) ( getVRefresh(mode) * 100.0f ); // Hz * 100 + int flags = 0; + if (mode->modeFlags & RR_Interlace) { + flags |= FLAG_INTERLACE; + } + if (mode->modeFlags & RR_DoubleScan) { + flags |= FLAG_DOUBLESCAN; + } + + jint prop[ NUM_MONITOR_MODE_PROPERTIES_ALL ]; + int propIndex = 0; + + prop[propIndex++] = NUM_MONITOR_MODE_PROPERTIES_ALL; + prop[propIndex++] = mode->width; + prop[propIndex++] = mode->height; + prop[propIndex++] = 32; // TODO: XRandR > 1.4 may support bpp + prop[propIndex++] = refresh; + prop[propIndex++] = flags; + prop[propIndex++] = mode->id; + prop[propIndex++] = NewtScreen_XRotation2Degree(env, xrrCrtcInfo->rotation); + + jintArray properties = (*env)->NewIntArray(env, NUM_MONITOR_MODE_PROPERTIES_ALL); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", NUM_MONITOR_MODE_PROPERTIES_ALL); + } + (*env)->SetIntArrayRegion(env, properties, 0, NUM_MONITOR_MODE_PROPERTIES_ALL, prop); + + return properties; +} + +/* + * Class: jogamp_newt_driver_x11_RandR13 + * Method: getMonitorDevice0 + * Signature: (JJJJ)[I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorDevice0 + (JNIEnv *env, jclass clazz, jlong display, jlong screenResources, jlong monitorInfo, jint crt_idx) +{ + Display * dpy = (Display *) (intptr_t) display; + XRRScreenResources *resources = (XRRScreenResources *) (intptr_t) screenResources; + XRRCrtcInfo *xrrCrtcInfo = (XRRCrtcInfo *) (intptr_t) monitorInfo; + + if( NULL == resources || NULL == xrrCrtcInfo || crt_idx >= resources->ncrtc ) { + // n/a + return NULL; + } + + if( None == xrrCrtcInfo->mode || 0 == xrrCrtcInfo->noutput ) { + // disabled + return NULL; + } + + RROutput output = xrrCrtcInfo->outputs[0]; + XRROutputInfo * xrrOutputInfo = XRRGetOutputInfo (dpy, resources, output); + int numModes = xrrOutputInfo->nmode; + + jsize propCount = MIN_MONITOR_DEVICE_PROPERTIES - 1 + numModes; + jint prop[ propCount ]; + int propIndex = 0; + + prop[propIndex++] = propCount; + prop[propIndex++] = crt_idx; + prop[propIndex++] = xrrOutputInfo->mm_width; + prop[propIndex++] = xrrOutputInfo->mm_height; + prop[propIndex++] = xrrCrtcInfo->x; // rotated viewport pixel units + prop[propIndex++] = xrrCrtcInfo->y; // rotated viewport pixel units + prop[propIndex++] = xrrCrtcInfo->width; // rotated viewport pixel units + prop[propIndex++] = xrrCrtcInfo->height; // rotated viewport pixel units + prop[propIndex++] = xrrCrtcInfo->x; // rotated viewport window units (same) + prop[propIndex++] = xrrCrtcInfo->y; // rotated viewport window units (same) + prop[propIndex++] = xrrCrtcInfo->width; // rotated viewport window units (same) + prop[propIndex++] = xrrCrtcInfo->height; // rotated viewport window units (same) + prop[propIndex++] = xrrCrtcInfo->mode; // current mode id + prop[propIndex++] = NewtScreen_XRotation2Degree(env, xrrCrtcInfo->rotation); + int i; + for(i=0; i<numModes; i++) { + // avail modes .. + prop[propIndex++] = xrrOutputInfo->modes[i]; + } + + XRRFreeOutputInfo (xrrOutputInfo); + + jintArray properties = (*env)->NewIntArray(env, propCount); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", propCount); + } + (*env)->SetIntArrayRegion(env, properties, 0, propCount, prop); + + return properties; +} + +/* + * Class: jogamp_newt_driver_x11_RandR13 + * Method: setMonitorMode0 + * Signature: (JJJIIIII)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_RandR13_setMonitorMode0 + (JNIEnv *env, jclass clazz, jlong display, jlong screenResources, jlong monitorInfo, jint crt_idx, jint modeId, jint rotation, jint x, jint y) +{ + Display * dpy = (Display *) (intptr_t) display; + XRRScreenResources *resources = (XRRScreenResources *) (intptr_t) screenResources; + XRRCrtcInfo *xrrCrtcInfo = (XRRCrtcInfo *) (intptr_t) monitorInfo; + jboolean res = JNI_FALSE; + + if( NULL == resources || NULL == xrrCrtcInfo || crt_idx >= resources->ncrtc ) { + // n/a + return res; + } + + if( None == xrrCrtcInfo->mode || 0 == xrrCrtcInfo->noutput ) { + // disabled + return res; + } + + if( 0 >= modeId ) { + // oops .. + return res; + } + + if( 0 > x || 0 > y ) { + x = xrrCrtcInfo->x; + y = xrrCrtcInfo->y; + } + + Status status = XRRSetCrtcConfig( dpy, resources, resources->crtcs[crt_idx], CurrentTime, + x, y, modeId, NewtScreen_Degree2XRotation(env, rotation), + xrrCrtcInfo->outputs, xrrCrtcInfo->noutput ); + res = status == RRSetConfigSuccess; + + return res; +} + +/* + * Class: jogamp_newt_driver_x11_RandR13 + * Method: setScreenViewport0 + * Signature: (JIJIIII)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_RandR13_setScreenViewport0 + (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jlong screenResources, jint x, jint y, jint width, jint height) +{ + Display * dpy = (Display *) (intptr_t) display; + Window root = RootWindow(dpy, (int)screen_idx); + XRRScreenResources *resources = (XRRScreenResources *) (intptr_t) screenResources; + jboolean res = JNI_FALSE; + + if( NULL == resources ) { + // n/a + return JNI_FALSE; + } + + XRRSetScreenSize (dpy, root, width, height, DisplayWidthMM(dpy, screen_idx), DisplayHeightMM(dpy, screen_idx)); + return JNI_TRUE; +} + + diff --git a/src/newt/native/X11Screen.c b/src/newt/native/X11Screen.c index 334c39727..152a092c9 100644 --- a/src/newt/native/X11Screen.c +++ b/src/newt/native/X11Screen.c @@ -29,7 +29,7 @@ // #define VERBOSE_ON 1 // #define DBG_PERF 1 -#include "X11Common.h" +#include "X11Screen.h" #ifdef DBG_PERF #include "timespec.h" @@ -74,418 +74,66 @@ JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_ScreenDriver_getHeight0 return (jint) DisplayHeight( dpy, scrn_idx); } -static int showedRandRVersion = 0; - -static Bool NewtScreen_getRANDRVersion(Display *dpy, int *major, int *minor) { - if( 0 == XRRQueryVersion(dpy, major, minor) ) { - return False; - } - if(0 == showedRandRVersion) { - DBG_PRINT("X11 RandR Version %d.%d\n", *major, *minor); - showedRandRVersion = 1; - } - return True; -} - -static Bool NewtScreen_hasRANDR(Display *dpy) { - int major, minor; - return NewtScreen_getRANDRVersion(dpy, &major, &minor); -} - -static int NewtScreen_XRotation2Degree(JNIEnv *env, int xrotation) { - int rot; +int NewtScreen_XRotation2Degree(JNIEnv *env, int xrotation) { + int degree; if(xrotation == RR_Rotate_0) { - rot = 0; + degree = 0; } else if(xrotation == RR_Rotate_90) { - rot = 90; + degree = 90; } else if(xrotation == RR_Rotate_180) { - rot = 180; + degree = 180; } else if(xrotation == RR_Rotate_270) { - rot = 270; + degree = 270; } else { NewtCommon_throwNewRuntimeException(env, "invalid native rotation: %d", xrotation); } - return rot; + return degree; } -/* - * Class: jogamp_newt_driver_x11_ScreenDriver - * Method: getAvailableScreenModeRotations0 - * Signature: (JI)I - */ -JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_ScreenDriver_getAvailableScreenModeRotations0 - (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) -{ - Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)scrn_idx); - int num_rotations = 0; - Rotation cur_rotation, rotations_supported; - int rotations[4]; - int major, minor; - - if(False == NewtScreen_getRANDRVersion(dpy, &major, &minor)) { - fprintf(stderr, "RANDR not available\n"); - return (*env)->NewIntArray(env, 0); - } - - rotations_supported = XRRRotations (dpy, (int)scrn_idx, &cur_rotation); - - if(0 != (rotations_supported & RR_Rotate_0)) { - rotations[num_rotations++] = 0; - } - if(0 != (rotations_supported & RR_Rotate_90)) { - rotations[num_rotations++] = 90; - } - if(0 != (rotations_supported & RR_Rotate_180)) { - rotations[num_rotations++] = 180; +int NewtScreen_Degree2XRotation(JNIEnv *env, int degree) { + int xrot; + if(degree == 0) { + xrot = RR_Rotate_0; } - if(0 != (rotations_supported & RR_Rotate_270)) { - rotations[num_rotations++] = 270; + else if(degree == 90) { + xrot = RR_Rotate_90; } - - jintArray properties = NULL; - - if(num_rotations>0) { - properties = (*env)->NewIntArray(env, num_rotations); - if (properties == NULL) { - NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", num_rotations); - } - - // move from the temp structure to the java structure - (*env)->SetIntArrayRegion(env, properties, 0, num_rotations, rotations); - } - - return properties; -} - -/* - * Class: jogamp_newt_driver_x11_ScreenDriver - * Method: getNumScreenModeResolution0 - * Signature: (JI)I - */ -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_ScreenDriver_getNumScreenModeResolutions0 - (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) -{ - Display *dpy = (Display *) (intptr_t) display; -#ifdef DBG_PERF - struct timespec t0, t1, td; - long td_ms; - timespec_now(&t0); -#endif - - if(False == NewtScreen_hasRANDR(dpy)) { - DBG_PRINT("Java_jogamp_newt_driver_x11_ScreenDriver_getNumScreenModeResolutions0: RANDR not available\n"); - return 0; + else if(degree == 180) { + xrot = RR_Rotate_180; } - -#ifdef DBG_PERF - timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td); - fprintf(stderr, "X11Screen_getNumScreenModeResolution0.1: %ld ms\n", td_ms); fflush(NULL); -#endif - - int num_sizes; - XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_idx, &num_sizes); //get possible screen resolutions - -#ifdef DBG_PERF - timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td); - fprintf(stderr, "X11Screen_getNumScreenModeResolution0.2 (XRRSizes): %ld ms\n", td_ms); fflush(NULL); -#endif - - DBG_PRINT("getNumScreenModeResolutions0: %p:%d -> %d\n", dpy, (int)scrn_idx, num_sizes); - - return num_sizes; -} - -/* - * Class: jogamp_newt_driver_x11_ScreenDriver - * Method: getScreenModeResolutions0 - * Signature: (JII)[I - */ -JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_ScreenDriver_getScreenModeResolution0 - (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx, jint resMode_idx) -{ - Display *dpy = (Display *) (intptr_t) display; - - if(False == NewtScreen_hasRANDR(dpy)) { - DBG_PRINT("Java_jogamp_newt_driver_x11_ScreenDriver_getScreenModeResolution0: RANDR not available\n"); - return (*env)->NewIntArray(env, 0); - } - - int num_sizes; - XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_idx, &num_sizes); //get possible screen resolutions - - if( 0 > resMode_idx || resMode_idx >= num_sizes ) { - NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); - } - - // Fill the properties in temp jint array - int propIndex = 0; - jint prop[4]; - - prop[propIndex++] = xrrs[(int)resMode_idx].width; - prop[propIndex++] = xrrs[(int)resMode_idx].height; - prop[propIndex++] = xrrs[(int)resMode_idx].mwidth; - prop[propIndex++] = xrrs[(int)resMode_idx].mheight; - - jintArray properties = (*env)->NewIntArray(env, 4); - if (properties == NULL) { - NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", 4); + else if(degree == 270) { + xrot = RR_Rotate_270; + } else { + NewtCommon_throwNewRuntimeException(env, "invalid degree: %d", degree); } - - // move from the temp structure to the java structure - (*env)->SetIntArrayRegion(env, properties, 0, 4, prop); - - return properties; + return xrot; } /* * Class: jogamp_newt_driver_x11_ScreenDriver - * Method: getScreenModeRates0 - * Signature: (JII)[I + * Method: GetRandRVersion0 + * Signature: (J)[I */ -JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_ScreenDriver_getScreenModeRates0 - (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx, jint resMode_idx) +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_ScreenDriver_getRandRVersion0 + (JNIEnv *env, jclass clazz, jlong display) { - Display *dpy = (Display *) (intptr_t) display; - - if(False == NewtScreen_hasRANDR(dpy)) { - DBG_PRINT("Java_jogamp_newt_driver_x11_ScreenDriver_getScreenModeRates0: RANDR not available\n"); - return (*env)->NewIntArray(env, 0); - } - - int num_sizes; - XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_idx, &num_sizes); //get possible screen resolutions - - if( 0 > resMode_idx || resMode_idx >= num_sizes ) { - NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); + Display * dpy = (Display *)(intptr_t)display; + jint version[2]; + if( 0 == XRRQueryVersion(dpy, &version[0], &version[1] ) ) { + version[0] = 0; + version[1] = 0; } - - int num_rates; - short *rates = XRRRates(dpy, (int)scrn_idx, (int)resMode_idx, &num_rates); - - jint prop[num_rates]; - int i; - for(i=0; i<num_rates; i++) { - prop[i] = (int) rates[i]; - /** fprintf(stderr, "rate[%d, %d, %d/%d]: %d\n", (int)scrn_idx, resMode_idx, i, num_rates, prop[i]); */ - } - - jintArray properties = (*env)->NewIntArray(env, num_rates); - if (properties == NULL) { - NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", num_rates); + jintArray jversion = (*env)->NewIntArray(env, 2); + if (jversion == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size 2"); } // move from the temp structure to the java structure - (*env)->SetIntArrayRegion(env, properties, 0, num_rates, prop); + (*env)->SetIntArrayRegion(env, jversion, 0, 2, version); - return properties; -} - -/* - * Class: jogamp_newt_driver_x11_ScreenDriver - * Method: getScreenConfiguration0 - * Signature: (JI)J - */ -JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_ScreenDriver_getScreenConfiguration0 - (JNIEnv *env, jclass clazz, jlong display, jint screen_idx) -{ - Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)screen_idx); -#ifdef DBG_PERF - struct timespec t0, t1, td; - long td_ms; - timespec_now(&t0); -#endif - - if(False == NewtScreen_hasRANDR(dpy)) { - DBG_PRINT("Java_jogamp_newt_driver_x11_ScreenDriver_getScreenConfiguration0: RANDR not available\n"); - return 0; - } -#ifdef DBG_PERF - timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td); - fprintf(stderr, "X11Screen_getScreenConfiguration0.1: %ld ms\n", td_ms); fflush(NULL); -#endif - - // get current resolutions and frequencies - XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root); -#ifdef DBG_PERF - timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td); - fprintf(stderr, "X11Screen_getScreenConfiguration0.2 (XRRGetScreenInfo): %ld ms\n", td_ms); fflush(NULL); -#endif - - return (jlong) (intptr_t) conf; -} - -/* - * Class: jogamp_newt_driver_x11_ScreenDriver - * Method: freeScreenConfiguration0 - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_ScreenDriver_freeScreenConfiguration0 - (JNIEnv *env, jclass clazz, jlong screenConfiguration) -{ - XRRFreeScreenConfigInfo( (XRRScreenConfiguration *) (intptr_t) screenConfiguration ); -} - -/* - * Class: jogamp_newt_driver_x11_ScreenDriver - * Method: getCurrentScreenRate0 - * Signature: (J)I - */ -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_ScreenDriver_getCurrentScreenRate0 - (JNIEnv *env, jclass clazz, jlong screenConfiguration) -{ - XRRScreenConfiguration *conf = (XRRScreenConfiguration *) (intptr_t) screenConfiguration; - - short original_rate = XRRConfigCurrentRate(conf); - DBG_PRINT("getCurrentScreenRate0: %d\n", (int)original_rate); - - return (jint) original_rate; -} - -/* - * Class: jogamp_newt_driver_x11_ScreenDriver - * Method: getCurrentScreenRotation0 - * Signature: (J)I - */ -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_ScreenDriver_getCurrentScreenRotation0 - (JNIEnv *env, jclass clazz, jlong screenConfiguration) -{ - XRRScreenConfiguration *conf = (XRRScreenConfiguration *) (intptr_t) screenConfiguration; - Rotation rotation; - - XRRConfigCurrentConfiguration(conf, &rotation); - - return NewtScreen_XRotation2Degree(env, rotation); -} - - -/* - * Class: jogamp_newt_driver_x11_ScreenDriver - * Method: getCurrentScreenResolutionIndex0 - * Signature: (J)I - */ -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_ScreenDriver_getCurrentScreenResolutionIndex0 - (JNIEnv *env, jclass clazz, jlong screenConfiguration) -{ - XRRScreenConfiguration *conf = (XRRScreenConfiguration *) (intptr_t) screenConfiguration; - - short original_rate = XRRConfigCurrentRate(conf); - - Rotation original_rotation; - SizeID original_size_id = XRRConfigCurrentConfiguration(conf, &original_rotation); - - DBG_PRINT("getCurrentScreenResolutionIndex0: %d\n", (int)original_size_id); - return (jint)original_size_id; -} - -/* - * Class: jogamp_newt_driver_x11_ScreenDriver - * Method: setCurrentScreenModeStart0 - * Signature: (JIJIII)Z - */ -JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_ScreenDriver_setCurrentScreenModeStart0 - (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jlong screenConfiguration, jint resMode_idx, jint freq, jint rotation) -{ - Display *dpy = (Display *) (intptr_t) display; - XRRScreenConfiguration *conf = (XRRScreenConfiguration *) (intptr_t) screenConfiguration; - Window root = RootWindow(dpy, (int)screen_idx); - - int num_sizes; - XRRScreenSize *xrrs = XRRSizes(dpy, (int)screen_idx, &num_sizes); //get possible screen resolutions - int rot; - - if( 0 > resMode_idx || resMode_idx >= num_sizes ) { - NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); - } - - switch(rotation) { - case 0: - rot = RR_Rotate_0; - break; - case 90: - rot = RR_Rotate_90; - break; - case 180: - rot = RR_Rotate_180; - break; - case 270: - rot = RR_Rotate_270; - break; - default: - NewtCommon_throwNewRuntimeException(env, "Invalid rotation: %d", rotation); - } - - DBG_PRINT("X11Screen.setCurrentScreenMode0: CHANGED TO %d: %d x %d PIXELS, %d Hz, %d degree\n", - resMode_idx, xrrs[resMode_idx].width, xrrs[resMode_idx].height, (int)freq, rotation); - - XRRSelectInput (dpy, root, RRScreenChangeNotifyMask); - - XSync(dpy, False); - XRRSetScreenConfigAndRate(dpy, conf, root, (int)resMode_idx, rot, (short)freq, CurrentTime); - XSync(dpy, False); - - return JNI_TRUE; -} - -/* - * Class: jogamp_newt_driver_x11_ScreenDriver - * Method: setCurrentScreenModePollEnd0 - * Signature: (J)Z - */ -JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_ScreenDriver_setCurrentScreenModePollEnd0 - (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jint resMode_idx, jint freq, jint rotation) -{ - Display *dpy = (Display *) (intptr_t) display; - int randr_event_base, randr_error_base; - XEvent evt; - XRRScreenChangeNotifyEvent * scn_event = (XRRScreenChangeNotifyEvent *) &evt; - - if(False == NewtScreen_hasRANDR(dpy)) { - DBG_PRINT("Java_jogamp_newt_driver_x11_ScreenDriver_setCurrentScreenModePollEnd0: RANDR not available\n"); - return JNI_FALSE; - } - - int num_sizes; - XRRScreenSize *xrrs = XRRSizes(dpy, (int)screen_idx, &num_sizes); //get possible screen resolutions - XRRScreenConfiguration *conf; - - if( 0 > resMode_idx || resMode_idx >= num_sizes ) { - NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); - } - - XRRQueryExtension(dpy, &randr_event_base, &randr_error_base); - - int done = 0; - int rot; - do { - if ( 0 >= XEventsQueued(dpy, QueuedAfterFlush) ) { - return; - } - XNextEvent(dpy, &evt); - - switch (evt.type - randr_event_base) { - case RRScreenChangeNotify: - rot = NewtScreen_XRotation2Degree(env, (int)scn_event->rotation); - DBG_PRINT( "XRANDR: event . RRScreenChangeNotify call %p (root %p) resIdx %d rot %d %dx%d\n", - (void*)scn_event->window, (void*)scn_event->root, - (int)scn_event->size_index, rot, - scn_event->width, scn_event->height); - // done = scn_event->size_index == resMode_idx; // not reliable .. - done = rot == rotation && - scn_event->width == xrrs[resMode_idx].width && - scn_event->height == xrrs[resMode_idx].height; - break; - default: - DBG_PRINT("RANDR: event . unhandled %d 0x%X call %p\n", (int)evt.type, (int)evt.type, (void*)evt.xany.window); - } - XRRUpdateConfiguration(&evt); - } while(!done); - - XSync(dpy, False); - + return jversion; } diff --git a/src/newt/native/X11Screen.h b/src/newt/native/X11Screen.h new file mode 100644 index 000000000..c81ee05d5 --- /dev/null +++ b/src/newt/native/X11Screen.h @@ -0,0 +1,38 @@ +/** + * Copyright 2013 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#ifndef _X11SCREEN_H +#define _X11SCREEN_H + + +#include "X11Common.h" + +int NewtScreen_XRotation2Degree(JNIEnv *env, int xrotation); +int NewtScreen_Degree2XRotation(JNIEnv *env, int degree); + +#endif /* _X11SCREEN_H */ diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index 59862f463..2cc66c78d 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -98,11 +98,11 @@ static void setJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlon } jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong javaObjectAtom, Bool showWarning) { - Atom actual_type; - int actual_format; + Atom actual_type = 0; + int actual_format = 0; int nitems_32 = ( sizeof(uintptr_t) == 8 ) ? 2 : 1 ; unsigned char * jogl_java_object_data_pp = NULL; - jobject jwindow; + jobject jwindow = 0; { unsigned long nitems= 0; @@ -122,7 +122,9 @@ jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong ja } if(actual_type!=(Atom)javaObjectAtom || nitems<nitems_32 || NULL==jogl_java_object_data_pp) { - XFree(jogl_java_object_data_pp); + if( NULL != jogl_java_object_data_pp ) { + XFree(jogl_java_object_data_pp); + } if(True==showWarning) { fprintf(stderr, "Warning: NEWT X11Window: Fetched invalid Atom NEWT_JAVA_OBJECT window property (res %d) nitems %ld, bytes_after %ld, actual_type %ld, NEWT_JAVA_OBJECT %ld, result 0!\n", res, nitems, bytes_after, (long)actual_type, (long)javaObjectAtom); @@ -189,8 +191,8 @@ static Status NewtWindows_getWindowPositionRelative2Parent (Display *dpy, Window return 0; // Error } static Status NewtWindows_getFrameExtends(Display *dpy, Window window, int *left, int *right, int *top, int *bottom) { - Atom actual_type; - int actual_format; + Atom actual_type = 0; + int actual_format = 0; int nitems_32 = 4; // l, r, t, b unsigned char * frame_extends_data_pp = NULL; @@ -210,7 +212,9 @@ static Status NewtWindows_getFrameExtends(Display *dpy, Window window, int *left } if(nitems<nitems_32 || NULL==frame_extends_data_pp) { - XFree(frame_extends_data_pp); + if( NULL != frame_extends_data_pp ) { + XFree(frame_extends_data_pp); + } // DBG_PRINT( "Warning: NEWT X11Window: Fetched invalid Atom _NET_FRAME_EXTENTS window property (res %d) nitems %ld, bytes_after %ld, actual_type %ld, actual_format %d, _NET_FRAME_EXTENTS %ld, result 0!\n", // res, nitems, bytes_after, (long)actual_type, actual_format, _NET_FRAME_EXTENTS); return 0; // Error, but ok - ie window not mapped @@ -271,18 +275,21 @@ static Bool NewtWindows_hasDecorations (Display *dpy, Window w) { #ifdef DECOR_USE_MWM Atom _MOTIF_WM_HINTS = XInternAtom( dpy, "_MOTIF_WM_HINTS", False ); - unsigned char *wm_data; - Atom wm_type; - int wm_format; - unsigned long wm_nitems, wm_bytes_after; + unsigned char *wm_data = NULL; + Atom wm_type = 0; + int wm_format = 0; + unsigned long wm_nitems = 0, wm_bytes_after = 0; if( Success == XGetWindowProperty(dpy, w, _MOTIF_WM_HINTS, 0, PROP_MWM_HINTS_ELEMENTS, False, AnyPropertyType, &wm_type, &wm_format, &wm_nitems, &wm_bytes_after, &wm_data) ) { - if(wm_type != None) { + if(wm_type != None && NULL != wm_data && wm_nitems >= PROP_MWM_HINTS_ELEMENTS) { // unsigned long mwmhints[PROP_MWM_HINTS_ELEMENTS] = { MWM_HINTS_DECORATIONS, 0, decorated, 0, 0 }; // flags, functions, decorations, input_mode, status unsigned long *hints = (unsigned long *) wm_data; decor = ( 0 != (hints[0] & MWM_HINTS_DECORATIONS) ) && ( 0 != hints[2] ); } + if( NULL != wm_data ) { + XFree(wm_data); + } } #endif @@ -299,9 +306,8 @@ static void NewtWindows_setNormalWindowEWMH (Display *dpy, Window w) { #define _NET_WM_STATE_REMOVE 0 #define _NET_WM_STATE_ADD 1 - -#define _NET_WM_FULLSCREEN ( 1 << 0 ) -#define _NET_WM_ABOVE ( 1 << 1 ) +#define _NET_WM_STATE_FLAG_FULLSCREEN ( 1 << 0 ) +#define _NET_WM_STATE_FLAG_ABOVE ( 1 << 1 ) /** * Set fullscreen using Extended Window Manager Hints (EWMH) @@ -314,101 +320,98 @@ static void NewtWindows_setNormalWindowEWMH (Display *dpy, Window w) { * and resets it when leaving FS. * The same is assumed for the decoration state. */ -static int NewtWindows_isFullscreenEWMHSupported (Display *dpy, Window w) { +static int NewtWindows_getSupportedStackingEWMHFlags(Display *dpy, Window w) { +#ifdef VERBOSE_ON + // Code doesn't work reliable on KDE4 ... Atom _NET_WM_ALLOWED_ACTIONS = XInternAtom( dpy, "_NET_WM_ALLOWED_ACTIONS", False ); Atom _NET_WM_ACTION_FULLSCREEN = XInternAtom( dpy, "_NET_WM_ACTION_FULLSCREEN", False ); Atom _NET_WM_ACTION_ABOVE = XInternAtom( dpy, "_NET_WM_ACTION_ABOVE", False ); - Atom * actions; - Atom type; - unsigned long action_len, remain; - int res = 0, form, i; + Atom * actions = NULL; + Atom type = 0; + unsigned long action_len = 0, remain = 0; + int res = 0, form = 0, i = 0; Status s; if ( Success == (s = XGetWindowProperty(dpy, w, _NET_WM_ALLOWED_ACTIONS, 0, 1024, False, AnyPropertyType, &type, &form, &action_len, &remain, (unsigned char**)&actions)) ) { - for(i=0; i<action_len; i++) { - if(_NET_WM_ACTION_FULLSCREEN == actions[i]) { - DBG_PRINT( "**************** X11: FS EWMH CHECK[%d]: _NET_WM_ACTION_FULLSCREEN (*)\n", i); - res |= _NET_WM_FULLSCREEN ; - } else if(_NET_WM_ACTION_ABOVE == actions[i]) { - DBG_PRINT( "**************** X11: FS EWMH CHECK[%d]: _NET_WM_ACTION_ABOVE (*)\n", i); - res |= _NET_WM_ABOVE ; - } -#ifdef VERBOSE_ON - else { - char * astr = XGetAtomName(dpy, actions[i]); - DBG_PRINT( "**************** X11: FS EWMH CHECK[%d]: %s (unused)\n", i, astr); - XFree(astr); + if( NULL != actions ) { + for(i=0; i<action_len; i++) { + if(_NET_WM_ACTION_FULLSCREEN == actions[i]) { + DBG_PRINT( "**************** X11: FS EWMH CHECK[%d]: _NET_WM_ACTION_FULLSCREEN (*)\n", i); + res |= _NET_WM_STATE_FLAG_FULLSCREEN ; + } else if(_NET_WM_ACTION_ABOVE == actions[i]) { + DBG_PRINT( "**************** X11: FS EWMH CHECK[%d]: _NET_WM_ACTION_ABOVE (*)\n", i); + res |= _NET_WM_STATE_FLAG_ABOVE ; + } + else { + char * astr = XGetAtomName(dpy, actions[i]); + DBG_PRINT( "**************** X11: FS EWMH CHECK[%d]: %s (unused)\n", i, astr); + XFree(astr); + } } -#endif + XFree(actions); } DBG_PRINT( "**************** X11: FS EWMH CHECK: 0x%X\n", res); } else { DBG_PRINT( "**************** X11: FS EWMH CHECK: XGetWindowProperty failed: %d\n", s); } - // above code doesn't work reliable on KDE4 ... - res = _NET_WM_FULLSCREEN | _NET_WM_ABOVE ; - return res; +#endif + return _NET_WM_STATE_FLAG_FULLSCREEN | _NET_WM_STATE_FLAG_ABOVE ; } -static Bool NewtWindows_setFullscreenEWMH (Display *dpy, Window root, Window w, int ewmhFlags, Bool isVisible, Bool enable) { +static Bool NewtWindows_setStackingEWMHFlags (Display *dpy, Window root, Window w, int ewmhFlags, Bool isVisible, Bool enable) { Atom _NET_WM_STATE = XInternAtom( dpy, "_NET_WM_STATE", False ); Atom _NET_WM_STATE_ABOVE = XInternAtom( dpy, "_NET_WM_STATE_ABOVE", False ); Atom _NET_WM_STATE_FULLSCREEN = XInternAtom( dpy, "_NET_WM_STATE_FULLSCREEN", False ); - int ewmhMask = NewtWindows_isFullscreenEWMHSupported(dpy, w); + int ewmhMask = NewtWindows_getSupportedStackingEWMHFlags(dpy, w); + Bool changeFullscreen = 0 != ( ( _NET_WM_STATE_FLAG_FULLSCREEN & ewmhMask ) & ewmhFlags ) ; + Bool changeAbove = 0 != ( ( _NET_WM_STATE_FLAG_ABOVE & ewmhMask ) & ewmhFlags ) ; Bool res = False; if(0 == ewmhMask) { return res; } - if(!isVisible && True==enable) { - Atom types[2]={0}; - int ntypes=0; - - if( 0 != ( ( _NET_WM_FULLSCREEN & ewmhMask ) & ewmhFlags ) ) { - types[ntypes++] = _NET_WM_STATE_FULLSCREEN; - } - if( 0 != ( ( _NET_WM_ABOVE & ewmhMask ) & ewmhFlags ) ) { - types[ntypes++] = _NET_WM_STATE_ABOVE; - } - if(ntypes>0) { - XChangeProperty( dpy, w, _NET_WM_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char *)&types, ntypes); - XSync(dpy, False); - res = True; - } - } else { - if(enable) { - NewtWindows_setCWAbove(dpy, w); - } - XEvent xev; - long mask = SubstructureNotifyMask | SubstructureRedirectMask ; - int i=0; - - memset ( &xev, 0, sizeof(xev) ); - - xev.type = ClientMessage; - xev.xclient.window = w; - xev.xclient.message_type = _NET_WM_STATE; - xev.xclient.format = 32; + // _NET_WM_STATE: fullscreen and/or above + if( changeFullscreen || changeAbove ) { + { + // _NET_WM_STATE as event to root window + XEvent xev; + long mask = SubstructureNotifyMask | SubstructureRedirectMask ; + int i=0; - xev.xclient.data.l[i++] = ( True == enable ) ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE ; - if( 0 != ( ( _NET_WM_FULLSCREEN & ewmhMask ) & ewmhFlags ) ) { - xev.xclient.data.l[i++] = _NET_WM_STATE_FULLSCREEN; - } - if( 0 != ( ( _NET_WM_ABOVE & ewmhMask ) & ewmhFlags ) ) { - xev.xclient.data.l[i++] = _NET_WM_STATE_ABOVE; - } - xev.xclient.data.l[3] = 1; //source indication for normal applications + memset ( &xev, 0, sizeof(xev) ); + + xev.type = ClientMessage; + xev.xclient.window = w; + xev.xclient.message_type = _NET_WM_STATE; + xev.xclient.format = 32; + + xev.xclient.data.l[i++] = enable ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE ; + if( changeFullscreen ) { + xev.xclient.data.l[i++] = _NET_WM_STATE_FULLSCREEN; + } + if( changeAbove ) { + xev.xclient.data.l[i++] = _NET_WM_STATE_ABOVE; + } + xev.xclient.data.l[3] = 1; //source indication for normal applications - if(i>0) { XSendEvent ( dpy, root, False, mask, &xev ); - res = True; } + // Also change _NET_WM_BYPASS_COMPOSITOR! + // A value of 0 indicates no preference. + // A value of 1 hints the compositor to disabling compositing of this window. + // A value of 2 hints the compositor to not disabling compositing of this window + { + Atom _NET_WM_BYPASS_COMPOSITOR = XInternAtom( dpy, "_NET_WM_BYPASS_COMPOSITOR", False ); + unsigned long value = enable ? 1 : 0; + XChangeProperty( dpy, w, _NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&value, 1); + } + XSync(dpy, False); + res = True; } - XSync(dpy, False); - DBG_PRINT( "X11: reconfigureWindow0 FULLSCREEN EWMH ON %d, ewmhMask 0x%X, ewmhFlags 0x%X, visible %d: %d\n", - enable, ewmhMask, ewmhFlags, isVisible, res); + DBG_PRINT( "X11: setStackingEWMHFlags ON %d, changeFullscreen %d, changeAbove %d, visible %d: %d\n", + enable, changeFullscreen, changeAbove, isVisible, res); return res; } @@ -438,7 +441,7 @@ Status NewtWindows_updateInsets(JNIEnv *env, jobject jwindow, Display *dpy, Wind return 0; // Error } -static void NewtWindows_requestFocus (JNIEnv *env, jobject window, Display *dpy, Window w, jboolean force) { +static void NewtWindows_requestFocus (Display *dpy, Window w, Bool force) { XWindowAttributes xwa; Window focus_return; int revert_to_return; @@ -447,7 +450,7 @@ static void NewtWindows_requestFocus (JNIEnv *env, jobject window, Display *dpy, XGetInputFocus(dpy, &focus_return, &revert_to_return); DBG_PRINT( "X11: requestFocus dpy %p,win %p, force %d, hasFocus %d\n", dpy, (void*)w, force, focus_return==w); - if( JNI_TRUE==force || focus_return!=w) { + if( True==force || focus_return!=w) { DBG_PRINT( "X11: XRaiseWindow dpy %p, win %p\n", dpy, (void*)w); XRaiseWindow(dpy, w); NewtWindows_setCWAbove(dpy, w); @@ -504,6 +507,12 @@ static void NewtWindows_setPosSize(Display *dpy, Window w, jint x, jint y, jint } } +static void NewtWindows_setIcon(Display *dpy, Window w, int data_size, const unsigned char * data_ptr) { + Atom _NET_WM_ICON = XInternAtom(dpy, "_NET_WM_ICON", False); + Atom CARDINAL = XInternAtom(dpy, "CARDINAL", False); + XChangeProperty(dpy, w, _NET_WM_ICON, CARDINAL, 32, PropModeReplace, data_ptr, data_size); +} + /* * Class: jogamp_newt_driver_x11_WindowDriver * Method: CreateWindow @@ -512,7 +521,8 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWindow0 (JNIEnv *env, jobject obj, jlong parent, jlong display, jint screen_index, jint visualID, jlong javaObjectAtom, jlong windowDeleteAtom, - jint x, jint y, jint width, jint height, jboolean autoPosition, int flags) + jint x, jint y, jint width, jint height, jboolean autoPosition, int flags, + jint pixelDataSize, jobject pixels, jint pixels_byte_offset, jboolean pixels_is_direct) { Display * dpy = (Display *)(intptr_t)display; Atom wm_delete_atom = (Atom)windowDeleteAtom; @@ -632,12 +642,27 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWindow0 { XEvent event; int left=0, right=0, top=0, bottom=0; + const unsigned char * pixelPtr = NULL; + + // NOTE: MUST BE DIRECT BUFFER, since _NET_WM_ICON Atom uses buffer directly! + DBG_PRINT("X11: CreateWindow icon: size %d, pixels %p, offset %d, direct %d\n", pixelDataSize, (void*)pixels, pixels_byte_offset, pixels_is_direct); + if( 0 < pixelDataSize && NULL != pixels ) { + pixelPtr = (const unsigned char *) ( JNI_TRUE == pixels_is_direct ? + (*env)->GetDirectBufferAddress(env, pixels) : + (*env)->GetPrimitiveArrayCritical(env, pixels, NULL) ); + DBG_PRINT("X11: CreateWindow icon: NIO %p\n", pixelPtr); + NewtWindows_setIcon(dpy, window, (int)pixelDataSize, pixelPtr+pixels_byte_offset); + } XMapWindow(dpy, window); XIfEvent( dpy, &event, WaitForMapNotify, (XPointer) window ); // wait to get proper insets values XSync(dpy, False); + if( JNI_FALSE == pixels_is_direct && NULL != pixelPtr ) { + (*env)->ReleasePrimitiveArrayCritical(env, pixels, (void*)pixelPtr, JNI_ABORT); + } + // send insets before visibility, allowing java code a proper sync point! NewtWindows_updateInsets(env, jwindow, dpy, window, &left, &right, &top, &bottom); (*env)->CallVoidMethod(env, jwindow, visibleChangedID, JNI_FALSE, JNI_TRUE); @@ -657,7 +682,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWindow0 NewtWindows_setPosSize(dpy, window, x, y, width, height); if( TST_FLAG_IS_ALWAYSONTOP(flags) ) { - NewtWindows_setFullscreenEWMH(dpy, root, window, _NET_WM_ABOVE, True, True); + NewtWindows_setStackingEWMHFlags(dpy, root, window, _NET_WM_STATE_FLAG_ABOVE, True, True); } } @@ -671,11 +696,12 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWindow0 * Signature: (JJ)V */ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CloseWindow0 - (JNIEnv *env, jobject obj, jlong display, jlong window, jlong javaObjectAtom, jlong windowDeleteAtom) + (JNIEnv *env, jobject obj, jlong display, jlong window, jlong javaObjectAtom, jlong windowDeleteAtom /*, jlong kbdHandle*/) // XKB disabled for now { Display * dpy = (Display *) (intptr_t) display; Window w = (Window)window; jobject jwindow; + XWindowAttributes xwa; if(dpy==NULL) { NewtCommon_FatalError(env, "invalid display connection.."); @@ -683,51 +709,52 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CloseWindow0 DBG_PRINT( "X11: CloseWindow START dpy %p, win %p\n", (void*)dpy, (void*)w); - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); - jwindow = getJavaWindowProperty(env, dpy, w, javaObjectAtom, True); if(NULL==jwindow) { - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); NewtCommon_throwNewRuntimeException(env, "could not fetch Java Window object, bail out!"); return; } if ( JNI_FALSE == (*env)->IsSameObject(env, jwindow, obj) ) { - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); NewtCommon_throwNewRuntimeException(env, "Internal Error .. Window global ref not the same!"); return; } XSync(dpy, False); + memset(&xwa, 0, sizeof(XWindowAttributes)); + XGetWindowAttributes(dpy, w, &xwa); // prefetch colormap to be destroyed after window destruction XSelectInput(dpy, w, 0); XUnmapWindow(dpy, w); - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); // Drain all events related to this window .. - Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessages0(env, obj, display, javaObjectAtom, windowDeleteAtom); + Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessages0(env, obj, display, javaObjectAtom, windowDeleteAtom /*, kbdHandle */); // XKB disabled for now XDestroyWindow(dpy, w); - XSync(dpy, False); + if( None != xwa.colormap ) { + XFreeColormap(dpy, xwa.colormap); + } + XSync(dpy, True); // discard all events now, no more handler (*env)->DeleteGlobalRef(env, jwindow); DBG_PRINT( "X11: CloseWindow END\n"); } -#if 0 +// #define REPARENT_WAIT_FOR_REPARENT_NOTIFY 1 + +#ifdef REPARENT_WAIT_FOR_REPARENT_NOTIFY static Bool WaitForReparentNotify( Display *dpy, XEvent *event, XPointer arg ) { - return (event->type == ReparentNotify) && (event->xreparent.window == (Window) arg); + Bool res = (event->type == ReparentNotify) && (event->xreparent.window == (Window) arg); + #ifdef VERBOSE_ON + if( event->type == ReparentNotify ) { + DBG_PRINT( "X11.WaitForReparentNotify: Event ReparentNotify: Result %d, exp %p, has %p\n", (int)res, arg, event->xreparent.window); + } else { + DBG_PRINT( "X11.WaitForReparentNotify: Event 0x%X: Result %d, exp %p, has %p\n", (int)event->type, (int)res, arg, event->xreparent.window); + } + #endif + return res; } #endif -/** - * KDE cause lost input focus in fullscreen mode. - * Using 'XGrabKeyboard(..)' would prevent the loss, - * but also would disable WM task switcher etc. - * - * #define FS_GRAB_KEYBOARD 1 - * - */ - /* * Class: jogamp_newt_driver_x11_WindowDriver * Method: reconfigureWindow0 @@ -746,51 +773,60 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo XEvent event; Bool isVisible = !TST_FLAG_CHANGE_VISIBILITY(flags) && TST_FLAG_IS_VISIBLE(flags) ; Bool tempInvisible = ( TST_FLAG_CHANGE_FULLSCREEN(flags) || TST_FLAG_CHANGE_PARENTING(flags) ) && isVisible ; + // Bool tempInvisible = TST_FLAG_CHANGE_PARENTING(flags) && isVisible ; int fsEWMHFlags = 0; if( TST_FLAG_CHANGE_FULLSCREEN(flags) ) { - fsEWMHFlags |= _NET_WM_FULLSCREEN; + if( !TST_FLAG_IS_FULLSCREEN_SPAN(flags) ) { // doesn't work w/ spanning across monitors. See also Bug 770 & Bug 771 + fsEWMHFlags |= _NET_WM_STATE_FLAG_FULLSCREEN; + } if( TST_FLAG_IS_FULLSCREEN(flags) ) { if( TST_FLAG_IS_ALWAYSONTOP(flags) ) { - fsEWMHFlags |= _NET_WM_ABOVE; // fs on, above on - } // else { } // fs on, above off + fsEWMHFlags |= _NET_WM_STATE_FLAG_ABOVE; // fs on, above on + } // else { } // fs on, above off } else if( !TST_FLAG_IS_ALWAYSONTOP(flags) ) { - fsEWMHFlags |= _NET_WM_ABOVE; // fs off, above off - } // else { } // fs off, above on - } - if( TST_FLAG_CHANGE_ALWAYSONTOP(flags) ) { - fsEWMHFlags |= _NET_WM_ABOVE; // toggle above + fsEWMHFlags |= _NET_WM_STATE_FLAG_ABOVE; // fs off, above off + } // else { } // fs off, above on + } else if( TST_FLAG_CHANGE_PARENTING(flags) ) { + // Fix for Unity WM, i.e. _remove_ persistent previous states + fsEWMHFlags |= _NET_WM_STATE_FLAG_FULLSCREEN; // fs off + if( !TST_FLAG_IS_ALWAYSONTOP(flags) ) { + fsEWMHFlags |= _NET_WM_STATE_FLAG_ABOVE; // above off + } + } else if( TST_FLAG_CHANGE_ALWAYSONTOP(flags) ) { + fsEWMHFlags |= _NET_WM_STATE_FLAG_ABOVE; // toggle above } - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 1, 0, 0); - - DBG_PRINT( "X11: reconfigureWindow0 dpy %p, scrn %d, parent %p/%p, win %p, %d/%d %dx%d, parentChange %d, hasParent %d, decorationChange %d, undecorated %d, fullscreenChange %d, fullscreen %d, alwaysOnTopChange %d, alwaysOnTop %d, visibleChange %d, visible %d, tempInvisible %d, fsEWMHFlags %d\n", + DBG_PRINT( "X11: reconfigureWindow0 dpy %p, scrn %d, parent %p/%p, win %p, %d/%d %dx%d, parentChange %d, hasParent %d, decorationChange %d, undecorated %d, fullscreenChange %d, fullscreen %d (span %d), alwaysOnTopChange %d, alwaysOnTop %d, visibleChange %d, visible %d, tempInvisible %d, fsEWMHFlags %d\n", (void*)dpy, screen_index, (void*) jparent, (void*)parent, (void*)w, x, y, width, height, TST_FLAG_CHANGE_PARENTING(flags), TST_FLAG_HAS_PARENT(flags), TST_FLAG_CHANGE_DECORATION(flags), TST_FLAG_IS_UNDECORATED(flags), - TST_FLAG_CHANGE_FULLSCREEN(flags), TST_FLAG_IS_FULLSCREEN(flags), + TST_FLAG_CHANGE_FULLSCREEN(flags), TST_FLAG_IS_FULLSCREEN(flags), TST_FLAG_IS_FULLSCREEN_SPAN(flags), TST_FLAG_CHANGE_ALWAYSONTOP(flags), TST_FLAG_IS_ALWAYSONTOP(flags), - TST_FLAG_CHANGE_VISIBILITY(flags), TST_FLAG_IS_VISIBLE(flags), tempInvisible, fsEWMHFlags); + TST_FLAG_CHANGE_VISIBILITY(flags), TST_FLAG_IS_VISIBLE(flags), + tempInvisible, fsEWMHFlags); - // FS Note: To toggle FS, utilizing the _NET_WM_STATE_FULLSCREEN WM state shall be enough. + // FS Note: To toggle FS, utilizing the _NET_WM_STATE_FULLSCREEN WM state should be enough. // However, we have to consider other cases like reparenting and WM which don't support it. - + #if 0 // Also doesn't work work properly w/ Unity WM if( fsEWMHFlags && !TST_FLAG_CHANGE_PARENTING(flags) && isVisible && + !TST_FLAG_IS_FULLSCREEN_SPAN(flags) && ( TST_FLAG_CHANGE_FULLSCREEN(flags) || TST_FLAG_CHANGE_ALWAYSONTOP(flags) ) ) { Bool enable = TST_FLAG_CHANGE_FULLSCREEN(flags) ? TST_FLAG_IS_FULLSCREEN(flags) : TST_FLAG_IS_ALWAYSONTOP(flags) ; - if( NewtWindows_setFullscreenEWMH(dpy, root, w, fsEWMHFlags, isVisible, enable) ) { - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); - #ifdef FS_GRAB_KEYBOARD - if(TST_FLAG_CHANGE_FULLSCREEN(flags)) { - if(TST_FLAG_IS_FULLSCREEN(flags)) { - XGrabKeyboard(dpy, w, True, GrabModeAsync, GrabModeAsync, CurrentTime); - } else { - XUngrabKeyboard(dpy, CurrentTime); - } - } else if(TST_FLAG_CHANGE_ALWAYSONTOP(flags) && !TST_FLAG_IS_ALWAYSONTOP(flags)) { - XUngrabKeyboard(dpy, CurrentTime); + if( NewtWindows_setStackingEWMHFlags(dpy, root, w, fsEWMHFlags, isVisible, enable) ) { + if ( TST_FLAG_CHANGE_FULLSCREEN(flags) && !TST_FLAG_IS_FULLSCREEN(flags) ) { // FS off - restore decoration + NewtWindows_setDecorations (dpy, w, TST_FLAG_IS_UNDECORATED(flags) ? False : True); } - #endif + DBG_PRINT( "X11: reconfigureWindow0 X (fs.atop.fast)\n"); + return; + } + } + #endif + // Toggle ALWAYSONTOP (only) w/o visibility or window stacking sideffects + if( isVisible && fsEWMHFlags && TST_FLAG_CHANGE_ALWAYSONTOP(flags) && + !TST_FLAG_CHANGE_PARENTING(flags) && !TST_FLAG_CHANGE_FULLSCREEN(flags) ) { + if( NewtWindows_setStackingEWMHFlags(dpy, root, w, fsEWMHFlags, isVisible, TST_FLAG_IS_ALWAYSONTOP(flags)) ) { + DBG_PRINT( "X11: reconfigureWindow0 X (atop.fast)\n"); return; } } @@ -802,21 +838,22 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo // no need to notify the java side .. just temp change } - if( fsEWMHFlags && ( ( TST_FLAG_CHANGE_FULLSCREEN(flags) && !TST_FLAG_IS_FULLSCREEN(flags) ) || - ( TST_FLAG_CHANGE_ALWAYSONTOP(flags) && !TST_FLAG_IS_ALWAYSONTOP(flags) ) ) ) { // FS off - NewtWindows_setFullscreenEWMH(dpy, root, w, fsEWMHFlags, isVisible, False); - #ifdef FS_GRAB_KEYBOARD - XUngrabKeyboard(dpy, CurrentTime); - #endif + if( fsEWMHFlags && ( ( TST_FLAG_CHANGE_FULLSCREEN(flags) && !TST_FLAG_IS_FULLSCREEN(flags) ) || // FS off + ( TST_FLAG_CHANGE_ALWAYSONTOP(flags) && !TST_FLAG_IS_ALWAYSONTOP(flags) ) ) ) { // AlwaysOnTop off + NewtWindows_setStackingEWMHFlags(dpy, root, w, fsEWMHFlags, isVisible, False); } if( TST_FLAG_CHANGE_PARENTING(flags) && !TST_FLAG_HAS_PARENT(flags) ) { // TOP: in -> out DBG_PRINT( "X11: reconfigureWindow0 PARENTING in->out\n"); XReparentWindow( dpy, w, parent, x, y ); // actual reparent call - // XIfEvent( dpy, &event, WaitForReparentNotify, (XPointer) w ); + #ifdef REPARENT_WAIT_FOR_REPARENT_NOTIFY + XIfEvent( dpy, &event, WaitForReparentNotify, (XPointer) w ); + #endif XSync(dpy, False); XSetWMProtocols(dpy, w, &wm_delete_atom, 1); // windowDeleteAtom + // Fix for Unity WM, i.e. _remove_ persistent previous states + NewtWindows_setStackingEWMHFlags(dpy, root, w, fsEWMHFlags, isVisible, False); } if( TST_FLAG_CHANGE_DECORATION(flags) ) { @@ -831,7 +868,9 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo // CHILD: out -> in DBG_PRINT( "X11: reconfigureWindow0 PARENTING out->in\n"); XReparentWindow( dpy, w, parent, x, y ); // actual reparent call - // XIfEvent( dpy, &event, WaitForReparentNotify, (XPointer) w ); + #ifdef REPARENT_WAIT_FOR_REPARENT_NOTIFY + XIfEvent( dpy, &event, WaitForReparentNotify, (XPointer) w ); + #endif XSync(dpy, False); } @@ -840,32 +879,28 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo XMapRaised(dpy, w); XIfEvent( dpy, &event, WaitForMapNotify, (XPointer) w ); // no need to notify the java side .. just temp change - } - - if( TST_FLAG_CHANGE_VISIBILITY(flags) ) { + } else if( TST_FLAG_CHANGE_VISIBILITY(flags) ) { if( TST_FLAG_IS_VISIBLE(flags) ) { DBG_PRINT( "X11: reconfigureWindow0 VISIBLE ON\n"); XMapRaised(dpy, w); + XSync(dpy, False); + // WM may disregard pos/size XConfigureWindow requests for invisible windows! + DBG_PRINT( "X11: reconfigureWindow0 setPosSize.2 %d/%d %dx%d\n", x, y, width, height); + NewtWindows_setPosSize(dpy, w, x, y, width, height); } else { DBG_PRINT( "X11: reconfigureWindow0 VISIBLE OFF\n"); XUnmapWindow(dpy, w); + XSync(dpy, False); } - XSync(dpy, False); } - if( fsEWMHFlags && ( ( TST_FLAG_CHANGE_FULLSCREEN(flags) && TST_FLAG_IS_FULLSCREEN(flags) ) || - ( TST_FLAG_CHANGE_ALWAYSONTOP(flags) && TST_FLAG_IS_ALWAYSONTOP(flags) ) ) ) { // FS on - NewtWindows_setFullscreenEWMH(dpy, root, w, fsEWMHFlags, isVisible, True); - #ifdef FS_GRAB_KEYBOARD - if(TST_FLAG_CHANGE_FULLSCREEN(flags) && TST_FLAG_IS_FULLSCREEN(flags)) { - XGrabKeyboard(dpy, w, True, GrabModeAsync, GrabModeAsync, CurrentTime); - } - #endif + if( fsEWMHFlags && ( ( TST_FLAG_CHANGE_FULLSCREEN(flags) && TST_FLAG_IS_FULLSCREEN(flags) ) || // FS on + ( TST_FLAG_CHANGE_ALWAYSONTOP(flags) && TST_FLAG_IS_ALWAYSONTOP(flags) ) ) ) { // AlwaysOnTop on + NewtWindows_requestFocus (dpy, w, True); + NewtWindows_setStackingEWMHFlags(dpy, root, w, fsEWMHFlags, isVisible, True); } - NewtDisplay_x11ErrorHandlerEnable(env, dpy, 0, 0, 1); - - DBG_PRINT( "X11: reconfigureWindow0 X\n"); + DBG_PRINT( "X11: reconfigureWindow0 X (full)\n"); } /* @@ -876,7 +911,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_reconfigureWindo JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_requestFocus0 (JNIEnv *env, jobject obj, jlong display, jlong window, jboolean force) { - NewtWindows_requestFocus ( env, obj, (Display *) (intptr_t) display, (Window)window, force ) ; + NewtWindows_requestFocus ( (Display *) (intptr_t) display, (Window)window, JNI_TRUE==force?True:False ) ; } /* @@ -943,6 +978,27 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_setTitle0 /* * Class: Java_jogamp_newt_driver_x11_WindowDriver + * Method: setPointerIcon0 + * Signature: (JJILjava/lang/Object;I)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_WindowDriver_setPointerIcon0 + (JNIEnv *env, jclass clazz, jlong display, jlong window, jlong handle) +{ + Display * dpy = (Display *) (intptr_t) display; + Window w = (Window)window; + + if( 0 == handle ) { + DBG_PRINT( "X11: setPointerIcon0: reset\n"); + XUndefineCursor(dpy, w); + } else { + Cursor c = (Cursor) (intptr_t) handle; + DBG_PRINT( "X11: setPointerIcon0: %p\n", (void*)c); + XDefineCursor(dpy, w, c); + } +} + +/* + * Class: Java_jogamp_newt_driver_x11_WindowDriver * Method: setPointerVisible0 * Signature: (JJZ)Z */ diff --git a/src/newt/native/XCBEvent.c b/src/newt/native/XCBEvent.c new file mode 100644 index 000000000..d02d5a4ba --- /dev/null +++ b/src/newt/native/XCBEvent.c @@ -0,0 +1,308 @@ + +#define VERBOSE_ON 1 + +#include "XCBEvent.h" + +#include <xcb/xcb.h> +#include <xcb/xcb_event.h> +#include <xcb/xproto.h> +#include <xcb/xcb_keysyms.h> +#include <X11/Xlib-xcb.h> + +void XCBSetEventQueueOwner(Display *dpy) { + XSetEventQueueOwner(dpy, XCBOwnsEventQueue); +} + +void XCBEventPoll(JNIEnv *env, jobject obj, Display *dpy, jlong javaObjectAtom, jlong wmDeleteAtom) { + int num_events = 100; + xcb_connection_t *conn = NULL; + + if ( NULL == dpy ) { + return; + } + conn = XGetXCBConnection(dpy); + + // Periodically take a break + while( num_events > 0 ) { + jobject jwindow = NULL; + xcb_generic_event_t *evt; + // KeySym keySym = 0; + jint modifiers = 0; + char keyChar = 0; + // char text[255]; + + evt = xcb_poll_for_event(conn); + if(NULL == evt) { + // DBG_PRINT( "X11: DispatchMessages 0x%X - Leave 1\n", dpy); + return; + } + num_events--; + + /*if( 0==evt.xany.window ) { + free(evt); + NewtCommon_throwNewRuntimeException(env, "event window NULL, bail out!"); + return ; + } + + if(dpy!=evt.xany.display) { + free(evt); + NewtCommon_throwNewRuntimeException(env, "wrong display, bail out!"); + return ; + }*/ + + // DBG_PRINT( "X11: DispatchMessages dpy %p, win %p, Event %d\n", (void*)dpy, (void*)evt.xany.window, evt.type); + + // X11WindowDisplayErrorHandlerEnable(1, env); + + // jwindow = X11WindowGetJavaWindowProperty(env, dpy, evt.xany.window, javaObjectAtom, VERBOSE_BOOL); + + //X11WindowDisplayErrorHandlerEnable(0, env); + + /*if(NULL==jwindow) { + fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d for X11 window %p\n", + (void*)dpy, evt.type, (void*)evt.xany.window); + continue; + }*/ + + uint8_t xcb_event_type = evt->response_type & ~0x80; + xcb_window_t event_window = 0; + + switch( xcb_event_type ) { + case XCB_BUTTON_PRESS: + case XCB_BUTTON_RELEASE: + event_window = ((xcb_button_press_event_t *)evt)->event; + modifiers = X11InputState2NewtModifiers(((xcb_button_press_event_t *)evt)->state); + break; + case XCB_MOTION_NOTIFY: + event_window = ((xcb_motion_notify_event_t *)evt)->event; + break; + case XCB_KEY_PRESS: + case XCB_KEY_RELEASE: { + xcb_key_press_event_t *_evt = (xcb_key_press_event_t *)evt; + event_window = _evt->event; + /* + xcb_keycode_t detail = _evt->detail; + if(XLookupString(&evt.xkey,text,255,&keySym,0)==1) { + KeySym lower_return = 0, upper_return = 0; + keyChar=text[0]; + XConvertCase(keySym, &lower_return, &upper_return); + // always return upper case, set modifier masks (SHIFT, ..) + keySym = upper_return; + modifiers = X11InputState2NewtModifiers(evt.xkey.state); + } else { + keyChar=0; + }*/ + } + break; + case XCB_EXPOSE: + event_window = ((xcb_expose_event_t *)evt)->window; + break; + case XCB_MAP_NOTIFY: + event_window = ((xcb_map_notify_event_t *)evt)->window; + break; + case XCB_UNMAP_NOTIFY: + event_window = ((xcb_unmap_notify_event_t *)evt)->window; + break; + } + if(0==event_window) { + fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d, no X11 window associated\n", + (void*)dpy, xcb_event_type); + continue; + } + jwindow = getJavaWindowProperty(env, dpy, event_window, javaObjectAtom, + #ifdef VERBOSE_ON + True + #else + False + #endif + ); + if(NULL==jwindow) { + fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d for X11 window %p\n", + (void*)(intptr_t)dpy, xcb_event_type, (void*)(intptr_t)event_window); + continue; + } + + switch( xcb_event_type ) { + case XCB_BUTTON_PRESS: { + xcb_button_press_event_t *_evt = (xcb_button_press_event_t *)evt; + (*env)->CallVoidMethod(env, jwindow, requestFocusID, JNI_FALSE); + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, + modifiers, + (jint) _evt->event_x, (jint) _evt->event_y, (jint) _evt->state, 0.0f /*rotation*/); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_PRESSED, + modifiers, + (jint) _evt->event_x, (jint) _evt->event_y, (jint) _evt->state, 0.0f /*rotation*/); + #endif + } break; + case XCB_BUTTON_RELEASE: { + xcb_button_release_event_t *_evt = (xcb_button_release_event_t *)evt; + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_RELEASED, + modifiers, + (jint) _evt->event_x, (jint) _evt->event_y, (jint) _evt->state, 0.0f /*rotation*/); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_RELEASED, + modifiers, + (jint) _evt->event_x, (jint) _evt->event_y, (jint) _evt->state, 0.0f /*rotation*/); + #endif + } break; + case XCB_MOTION_NOTIFY: { + xcb_motion_notify_event_t *_evt = (xcb_motion_notify_event_t *)evt; + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_MOVED, + modifiers, + (jint) _evt->event_x, (jint) _evt->event_y, (jint)0, 0.0f /*rotation*/); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_MOVED, + modifiers, + (jint) _evt->event_x, (jint) _evt->event_y, (jint)0, 0.0f /*rotation*/); + #endif + } break; + case XCB_KEY_PRESS: { + xcb_key_press_event_t *_evt = (xcb_key_press_event_t *)evt; + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_PRESSED, + modifiers, X11KeySym2NewtVKey(_evt->state), (jchar) keyChar); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_PRESSED, + modifiers, X11KeySym2NewtVKey(_evt->state), (jchar) keyChar); + #endif + } break; + case XCB_KEY_RELEASE: { + xcb_key_release_event_t *_evt = (xcb_key_release_event_t *)evt; + event_window = ((xcb_key_release_event_t *)evt)->event; + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_RELEASED, + modifiers, X11KeySym2NewtVKey(_evt->state), (jchar) keyChar); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_RELEASED, + modifiers, X11KeySym2NewtVKey(_evt->state), (jchar) keyChar); + #endif + + } break; + /* + case DestroyNotify: + DBG_PRINT( "X11: event . DestroyNotify call %p, parent %p, child-event: %d\n", + (void*)evt.xdestroywindow.window, (void*)evt.xdestroywindow.event, evt.xdestroywindow.window != evt.xdestroywindow.event); + if ( evt.xdestroywindow.window == evt.xdestroywindow.event ) { + // ignore child destroy notification + } + break; + case CreateNotify: + DBG_PRINT( "X11: event . CreateNotify call %p, parent %p, child-event: 1\n", + (void*)evt.xcreatewindow.window, (void*) evt.xcreatewindow.parent); + break; + case ConfigureNotify: + DBG_PRINT( "X11: event . ConfigureNotify call %p (parent %p, above %p) %d/%d %dx%d %d, child-event: %d\n", + (void*)evt.xconfigure.window, (void*)evt.xconfigure.event, (void*)evt.xconfigure.above, + evt.xconfigure.x, evt.xconfigure.y, evt.xconfigure.width, evt.xconfigure.height, + evt.xconfigure.override_redirect, evt.xconfigure.window != evt.xconfigure.event); + if ( evt.xconfigure.window == evt.xconfigure.event ) { + // ignore child window change notification + (*env)->CallVoidMethod(env, jwindow, sizeChangedID, + (jint) evt.xconfigure.width, (jint) evt.xconfigure.height, JNI_FALSE); + (*env)->CallVoidMethod(env, jwindow, positionChangedID, + (jint) evt.xconfigure.x, (jint) evt.xconfigure.y); + } + break; + case ClientMessage: + if (evt.xclient.send_event==True && evt.xclient.data.l[0]==(Atom)wmDeleteAtom) { + DBG_PRINT( "X11: event . ClientMessage call %p type 0x%X !!!\n", + (void*)evt.xclient.window, (unsigned int)evt.xclient.message_type); + (*env)->CallVoidMethod(env, jwindow, windowDestroyNotifyID); + // Called by Window.java: CloseWindow(); + num_events = 0; // end loop in case of destroyed display + } + break; + + case FocusIn: + DBG_PRINT( "X11: event . FocusIn call %p\n", (void*)evt.xvisibility.window); + (*env)->CallVoidMethod(env, jwindow, focusChangedID, JNI_TRUE); + break; + + case FocusOut: + DBG_PRINT( "X11: event . FocusOut call %p\n", (void*)evt.xvisibility.window); + (*env)->CallVoidMethod(env, jwindow, focusChangedID, JNI_FALSE); + break; + */ + + case XCB_EXPOSE: { + xcb_expose_event_t *_evt = (xcb_expose_event_t *)evt; + DBG_PRINT( "X11: event . Expose call %p %d/%d %dx%d count %d\n", (void*)(intptr_t)_evt->window, + _evt->x, _evt->y, _evt->width, _evt->height, _evt->count); + + if (_evt->count == 0 && _evt->width > 0 && _evt->height > 0) { + (*env)->CallVoidMethod(env, jwindow, windowRepaintID, + _evt->x, _evt->y, _evt->width, _evt->height); + } + } break; + + case XCB_MAP_NOTIFY: { + xcb_map_notify_event_t *_evt = (xcb_map_notify_event_t *)evt; + DBG_PRINT( "X11: event . MapNotify call Event %p, Window %p, override_redirect %d, child-event: %d\n", + (void*)(intptr_t)_evt->event, (void*)(intptr_t)_evt->window, (int)_evt->override_redirect, + _evt->event!=_evt->window); + if( _evt->event == _evt->window ) { + // ignore child window notification + (*env)->CallVoidMethod(env, jwindow, visibleChangedID, JNI_TRUE); + } + } break; + + case XCB_UNMAP_NOTIFY: { + xcb_unmap_notify_event_t *_evt = (xcb_unmap_notify_event_t *)evt; + DBG_PRINT( "X11: event . UnmapNotify call Event %p, Window %p, child-event: %d\n", + (void*)(intptr_t)_evt->event, (void*)(intptr_t)_evt->window, + _evt->event!=_evt->window); + if( _evt->event == _evt->window ) { + // ignore child window notification + (*env)->CallVoidMethod(env, jwindow, visibleChangedID, JNI_FALSE); + } + } break; + /* + + case ReparentNotify: + { + jlong parentResult; // 0 if root, otherwise proper value + Window winRoot, winTopParent; + #ifdef VERBOSE_ON + Window oldParentRoot, oldParentTopParent; + Window parentRoot, parentTopParent; + if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.event, &oldParentRoot, &oldParentTopParent) ) { + oldParentRoot=0; oldParentTopParent = 0; + } + if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.parent, &parentRoot, &parentTopParent) ) { + parentRoot=0; parentTopParent = 0; + } + #endif + if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.window, &winRoot, &winTopParent) ) { + winRoot=0; winTopParent = 0; + } + if(evt.xreparent.parent == winRoot) { + parentResult = 0; // our java indicator for root window + } else { + parentResult = (jlong) (intptr_t) evt.xreparent.parent; + } + #ifdef VERBOSE_ON + DBG_PRINT( "X11: event . ReparentNotify: call OldParent %p (root %p, top %p), NewParent %p (root %p, top %p), Window %p (root %p, top %p)\n", + (void*)evt.xreparent.event, (void*)oldParentRoot, (void*)oldParentTopParent, + (void*)evt.xreparent.parent, (void*)parentRoot, (void*)parentTopParent, + (void*)evt.xreparent.window, (void*)winRoot, (void*)winTopParent); + #endif + + (*env)->CallVoidMethod(env, jwindow, windowReparentedID, parentResult); + } + break; + */ + + // unhandled events .. yet .. + + default: + DBG_PRINT("XCB: event . unhandled %d 0x%X call %p\n", (int)xcb_event_type, (unsigned int)xcb_event_type, (void*)(intptr_t)event_window); + } + free(evt); + } +} + + diff --git a/src/newt/native/XCBEvent.h b/src/newt/native/XCBEvent.h new file mode 100644 index 000000000..d70797566 --- /dev/null +++ b/src/newt/native/XCBEvent.h @@ -0,0 +1,10 @@ + +#ifndef _XCBEvent_h +#define _XCBEvent_h + +#include "X11Common.h" + +extern void XCBSetEventQueueOwner(Display *dpy); +extern void XCBEventPoll(JNIEnv *env, jobject obj, Display *dpy, jlong javaObjectAtom, jlong wmDeleteAtom); + +#endif /* _XCBDisplayXCBEvent_h */ diff --git a/src/newt/native/bcm_vc_iv.c b/src/newt/native/bcm_vc_iv.c index e41745e14..ee59f0aa6 100644 --- a/src/newt/native/bcm_vc_iv.c +++ b/src/newt/native/bcm_vc_iv.c @@ -30,28 +30,50 @@ #include <stdio.h> #include <string.h> +/** + * See references in header file. + */ #include "bcm_vc_iv.h" #include "jogamp_newt_driver_bcm_vc_iv_DisplayDriver.h" #include "jogamp_newt_driver_bcm_vc_iv_ScreenDriver.h" #include "jogamp_newt_driver_bcm_vc_iv_WindowDriver.h" -#define VERBOSE_ON 1 +// #define VERBOSE_ON 1 #ifdef VERBOSE_ON - #define DBG_PRINT(...) fprintf(stdout, __VA_ARGS__) + #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) #else #define DBG_PRINT(...) #endif +typedef struct { + DISPMANX_ELEMENT_HANDLE_T handle; // magic BCM EGL position (EGL_DISPMANX_WINDOW_T) + int width; // magic BCM EGL position (EGL_DISPMANX_WINDOW_T) + int height; // magic BCM EGL position (EGL_DISPMANX_WINDOW_T) + int x; + int y; + int32_t layer; +} BCM_ELEMENT_T; + +typedef struct { + DISPMANX_RESOURCE_HANDLE_T handle; + VC_IMAGE_TYPE_T type; + uint32_t native_image_handle; +} BCM_RESOURCE_T; + +typedef struct { + BCM_ELEMENT_T element; + BCM_RESOURCE_T resource; + int hotX, hotY; +} POINTER_ICON_T; + static jmethodID setScreenSizeID = NULL; -static jmethodID windowCreatedID = NULL; static jmethodID sizeChangedID = NULL; +static jmethodID positionChangedID = NULL; static jmethodID visibleChangedID = NULL; static jmethodID windowDestroyNotifyID = NULL; -static jmethodID sendMouseEventID = NULL; -static jmethodID sendKeyEventID = NULL; /** * Display @@ -66,11 +88,210 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_bcm_vc_iv_DisplayDriver_initI return JNI_TRUE; } -JNIEXPORT void JNICALL Java_jogamp_newt_driver_bcm_vc_iv_DisplayDriver_DispatchMessages - (JNIEnv *env, jobject obj) +JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_bcm_vc_iv_DisplayDriver_OpenBCMDisplay0 + (JNIEnv *env, jclass clazz) +{ + DISPMANX_DISPLAY_HANDLE_T dispman_display = vc_dispmanx_display_open( 0 /* LCD */); + DBG_PRINT( "BCM.Display Open %p\n", (void*)(intptr_t)dispman_display); + return (jlong) (intptr_t) dispman_display; +} + +JNIEXPORT void JNICALL Java_jogamp_newt_driver_bcm_vc_iv_DisplayDriver_CloseBCMDisplay0 + (JNIEnv *env, jclass clazz, jlong display) +{ + DISPMANX_DISPLAY_HANDLE_T dispman_display = (DISPMANX_DISPLAY_HANDLE_T) (intptr_t) display; + DBG_PRINT( "BCM.Display Close %p\n", (void*)(intptr_t)dispman_display); + vc_dispmanx_display_close( dispman_display ); +} + + +JNIEXPORT void JNICALL Java_jogamp_newt_driver_bcm_vc_iv_DisplayDriver_DispatchMessages0 + (JNIEnv *env, jclass clazz) { } +static void bcm_moveTo(DISPMANX_ELEMENT_HANDLE_T element, uint32_t layer, int x, int y, int width, int height) { + VC_RECT_T src_rect; + VC_RECT_T dst_rect; + uint32_t change_flags = DISPMANX_ELEMENT_CHANGE_DEST_RECT | DISPMANX_ELEMENT_CHANGE_SRC_RECT; + DISPMANX_RESOURCE_HANDLE_T mask = 0; + DISPMANX_TRANSFORM_T transform = 0; + + uint8_t opacity = 0; // NOP + + dst_rect.x = x; + dst_rect.y = y; + dst_rect.width = width; + dst_rect.height = height; + + src_rect.x = 0; + src_rect.y = 0; + src_rect.width = width << 16; + src_rect.height = height << 16; + + DISPMANX_UPDATE_HANDLE_T dispman_update = vc_dispmanx_update_start( 0 ); + vc_dispmanx_element_change_attributes( dispman_update, + element, + change_flags, + layer, + opacity, + &dst_rect, + &src_rect, + mask, + transform ); + vc_dispmanx_update_submit_sync( dispman_update ); +} + +JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_bcm_vc_iv_DisplayDriver_CreatePointerIcon0 + (JNIEnv *env, jclass clazz, jobject pixels, jint pixels_byte_offset, jboolean pixels_is_direct, jint width, jint height, jint hotX, jint hotY) +{ + if( 0 == pixels ) { + return 0; + } + int32_t success = 0; + VC_RECT_T dst_rect; + VC_RECT_T src_rect; + int x = 0; + int y = 0; + int pitch = width * 4; // RGBA + + const unsigned char * pixelPtr = (const unsigned char *) ( JNI_TRUE == pixels_is_direct ? + (*env)->GetDirectBufferAddress(env, pixels) : + (*env)->GetPrimitiveArrayCritical(env, pixels, NULL) ); + + POINTER_ICON_T * p = calloc(1, sizeof(POINTER_ICON_T)); + p->hotX = hotX; + p->hotY = hotY; + p->element.layer = 2000; + p->element.x = x; + p->element.y = y; + p->element.width = width; + p->element.height = height; + p->resource.type = VC_IMAGE_ARGB8888; /* 32bpp with 8bit alpha at MS byte, with R, G, B (LS byte) */ + p->resource.handle = vc_dispmanx_resource_create( p->resource.type, + width, + height, + &(p->resource.native_image_handle) ); + + dst_rect.x = x; + dst_rect.y = y; + dst_rect.width = width; + dst_rect.height = height; + + vc_dispmanx_resource_write_data( p->resource.handle, + p->resource.type, + pitch, + (void*)(intptr_t)(pixelPtr + pixels_byte_offset), + &dst_rect ); + + if ( JNI_FALSE == pixels_is_direct ) { + (*env)->ReleasePrimitiveArrayCritical(env, pixels, (void*)pixelPtr, JNI_ABORT); + } + + DBG_PRINT( "BCM.Display PointerIcon.Create PI %p, resource %p\n", p, (void*)(intptr_t)p->resource.handle); + return (jlong) (intptr_t) p; +} + +JNIEXPORT void JNICALL Java_jogamp_newt_driver_bcm_vc_iv_DisplayDriver_DestroyPointerIcon0 + (JNIEnv *env, jclass clazz, jlong handle) +{ + POINTER_ICON_T * p = (POINTER_ICON_T *) (intptr_t) handle ; + if( 0 == p ) { + return; + } + + DBG_PRINT( "BCM.Display PointerIcon.Destroy.0 PI %p, resource %p, element %p\n", + p, (void*)(intptr_t)p->resource.handle, (void*)(intptr_t)p->element.handle); + + if( 0 != p->element.handle ) { + DISPMANX_UPDATE_HANDLE_T dispman_update = vc_dispmanx_update_start( 0 ); + vc_dispmanx_element_remove( dispman_update, p->element.handle ); + p->element.handle = 0; + vc_dispmanx_update_submit_sync( dispman_update ); + } + if( 0 != p->resource.handle ) { + vc_dispmanx_resource_delete( p->resource.handle ); + p->resource.handle = 0; + } + free( p ); +} + +JNIEXPORT void JNICALL Java_jogamp_newt_driver_bcm_vc_iv_DisplayDriver_SetPointerIcon0 + (JNIEnv *env, jclass clazz, jlong display, jlong handle, jboolean enable, jint x, jint y) +{ + DISPMANX_DISPLAY_HANDLE_T dispman_display = (DISPMANX_DISPLAY_HANDLE_T) (intptr_t) display; + POINTER_ICON_T * p = (POINTER_ICON_T *) (intptr_t) handle ; + VC_RECT_T dst_rect; + VC_RECT_T src_rect; + + if( 0 == dispman_display || NULL == p || 0 == p->resource.handle ) { + return; + } + + DBG_PRINT( "BCM.Display PointerIcon.Set.0 %p, PI %p, resource %p, element %p - enable %d - %d/%d\n", + (void*)(intptr_t)display, p, (void*)(intptr_t)p->resource.handle, (void*)(intptr_t)p->element.handle, enable, x, y); + + if( enable ) { + if( 0 != p->element.handle ) { + return; + } + + p->element.x = x; + p->element.y = y; + dst_rect.x = p->element.x - p->hotX; + dst_rect.y = p->element.y - p->hotY; + dst_rect.width = p->element.width; + dst_rect.height = p->element.height; + + src_rect.x = 0; + src_rect.y = 0; + src_rect.width = p->element.width << 16; + src_rect.height = p->element.height << 16; + + VC_DISPMANX_ALPHA_T dispman_alpha; + memset(&dispman_alpha, 0x0, sizeof(VC_DISPMANX_ALPHA_T)); + dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FROM_SOURCE ; + dispman_alpha.opacity = 0xFF; + dispman_alpha.mask = 0xFF; + + DISPMANX_UPDATE_HANDLE_T dispman_update = vc_dispmanx_update_start( 0 ); + p->element.handle = vc_dispmanx_element_add ( dispman_update, dispman_display, + p->element.layer, &dst_rect, + p->resource.handle /*src*/, + &src_rect, DISPMANX_PROTECTION_NONE, + &dispman_alpha /*alpha */, 0/*clamp*/, 0/*transform*/); + vc_dispmanx_update_submit_sync( dispman_update ); + } else { + // DISABLE + if( 0 == p->element.handle ) { + return; + } + p->element.x = x; + p->element.y = y; + DISPMANX_UPDATE_HANDLE_T dispman_update = vc_dispmanx_update_start( 0 ); + vc_dispmanx_element_remove( dispman_update, p->element.handle ); + p->element.handle = 0; + vc_dispmanx_update_submit_sync( dispman_update ); + } + DBG_PRINT( "BCM.Display PointerIcon.Set.X %p, PI %p, resource %p, element %p - enable %d - %d/%d\n", + (void*)(intptr_t)display, p, (void*)(intptr_t)p->resource.handle, (void*)(intptr_t)p->element.handle, enable, x, y); +} + +JNIEXPORT void JNICALL Java_jogamp_newt_driver_bcm_vc_iv_DisplayDriver_MovePointerIcon0 + (JNIEnv *env, jclass clazz, jlong handle, jint x, jint y) +{ + POINTER_ICON_T * p = (POINTER_ICON_T *) (intptr_t) handle ; + + if( NULL == p || 0 == p->element.handle ) { + return; + } + DBG_PRINT( "BCM.Display PointerIcon.Move.0 PI %p, resource %p, element %p - %d/%d\n", + p, (void*)(intptr_t)p->resource.handle, (void*)(intptr_t)p->element.handle, x, y); + p->element.x = x; + p->element.y = y; + bcm_moveTo( p->element.handle, p->element.layer, p->element.x - p->hotX, p->element.y - p->hotY, p->element.width, p->element.height); +} + /** * Screen */ @@ -101,8 +322,9 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_bcm_vc_iv_ScreenDriver_initNative if( graphics_get_display_size(0 /* LCD */, &screen_width, &screen_height) >= 0 ) { DBG_PRINT( "BCM.Screen initNative ok %dx%d\n", screen_width, screen_height ); (*env)->CallVoidMethod(env, obj, setScreenSizeID, (jint) screen_width, (jint) screen_height); + } else { + DBG_PRINT( "BCM.Screen initNative failed\n" ); } - DBG_PRINT( "BCM.Screen initNative failed\n" ); } /** @@ -112,18 +334,14 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_bcm_vc_iv_ScreenDriver_initNative JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_bcm_vc_iv_WindowDriver_initIDs (JNIEnv *env, jclass clazz) { - windowCreatedID = (*env)->GetMethodID(env, clazz, "windowCreated", "(J)V"); sizeChangedID = (*env)->GetMethodID(env, clazz, "sizeChanged", "(ZIIZ)V"); + positionChangedID = (*env)->GetMethodID(env, clazz, "positionChanged", "(ZII)V"); visibleChangedID = (*env)->GetMethodID(env, clazz, "visibleChanged", "(ZZ)V"); windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "(Z)Z"); - sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIIII)V"); - sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(IIIC)V"); - if (windowCreatedID == NULL || - sizeChangedID == NULL || + if (sizeChangedID == NULL || + positionChangedID == NULL || visibleChangedID == NULL || - windowDestroyNotifyID == NULL || - sendMouseEventID == NULL || - sendKeyEventID == NULL) { + windowDestroyNotifyID == NULL) { DBG_PRINT( "initIDs failed\n" ); return JNI_FALSE; } @@ -131,15 +349,18 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_bcm_vc_iv_WindowDriver_initID return JNI_TRUE; } -JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_bcm_vc_iv_WindowDriver_CreateWindow - (JNIEnv *env, jobject obj, jint width, jint height) +JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_bcm_vc_iv_WindowDriver_CreateWindow0 + (JNIEnv *env, jobject obj, jlong display, jint layer, jint x, jint y, jint width, jint height, jboolean opaque, jint alphaBits) { int32_t success = 0; VC_RECT_T dst_rect; VC_RECT_T src_rect; - dst_rect.x = 0; - dst_rect.y = 0; + if( 0 == display ) { + return; + } + dst_rect.x = x; + dst_rect.y = y; dst_rect.width = width; dst_rect.height = height; @@ -148,57 +369,95 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_bcm_vc_iv_WindowDriver_CreateWin src_rect.width = width << 16; src_rect.height = height << 16; - DISPMANX_DISPLAY_HANDLE_T dispman_display = vc_dispmanx_display_open( 0 /* LCD */); + VC_DISPMANX_ALPHA_T dispman_alpha; + memset(&dispman_alpha, 0x0, sizeof(VC_DISPMANX_ALPHA_T)); + + if( JNI_TRUE == opaque ) { + dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS ; + dispman_alpha.opacity = 0xFF; + dispman_alpha.mask = 0; + } else { + dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FROM_SOURCE ; + dispman_alpha.opacity = 0xFF; + dispman_alpha.mask = 0xFF; + } + + DISPMANX_DISPLAY_HANDLE_T dispman_display = (DISPMANX_DISPLAY_HANDLE_T) (intptr_t) display; + + DBG_PRINT( "BCM.Display Window.Create.0 %p, %d/%d %dx%d, opaque %d, alphaBits %d, layer %d\n", + (void*)(intptr_t)dispman_display, x, y, width, height, opaque, alphaBits, layer); + + BCM_ELEMENT_T * p = calloc(1, sizeof(BCM_ELEMENT_T)); DISPMANX_UPDATE_HANDLE_T dispman_update = vc_dispmanx_update_start( 0 ); - DISPMANX_ELEMENT_HANDLE_T dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display, - 0/*layer*/, &dst_rect, 0/*src*/, - &src_rect, DISPMANX_PROTECTION_NONE, - 0 /*alpha TODO*/, 0/*clamp*/, 0/*transform*/); - EGL_DISPMANX_WINDOW_T * nativeWindowPtr = calloc(1, sizeof(EGL_DISPMANX_WINDOW_T)); - nativeWindowPtr->element = dispman_element; - nativeWindowPtr->width = width; - nativeWindowPtr->height = height; + p->layer = layer; + p->x = x; + p->y = y; + p->width = width; + p->height = height; + p->handle = vc_dispmanx_element_add ( dispman_update, dispman_display, + p->layer, &dst_rect, 0/*src*/, + &src_rect, DISPMANX_PROTECTION_NONE, + &dispman_alpha /*alpha */, 0/*clamp*/, 0/*transform*/); vc_dispmanx_update_submit_sync( dispman_update ); (*env)->CallVoidMethod(env, obj, visibleChangedID, JNI_FALSE, JNI_TRUE); // FIXME: or defer=true ? - return (jlong) (intptr_t) nativeWindowPtr; -} + DBG_PRINT( "BCM.Display Window.Create.X %p, element %p\n", + (void*)(intptr_t)dispman_display, (void*)(intptr_t)p->handle); -JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_bcm_vc_iv_WindowDriver_RealizeWindow - (JNIEnv *env, jobject obj, jlong window) -{ - return (jlong) (intptr_t) 0; + return (jlong) (intptr_t) p; } -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_bcm_vc_iv_WindowDriver_CloseWindow - (JNIEnv *env, jobject obj, jlong window, jlong juserData) +JNIEXPORT void JNICALL Java_jogamp_newt_driver_bcm_vc_iv_WindowDriver_CloseWindow0 + (JNIEnv *env, jobject obj, jlong display, jlong window) { - EGL_DISPMANX_WINDOW_T * nativeWindowPtr = (EGL_DISPMANX_WINDOW_T *) (intptr_t) window ; - free( nativeWindowPtr ); - return 0; -} + DISPMANX_DISPLAY_HANDLE_T dispman_display = (DISPMANX_DISPLAY_HANDLE_T) (intptr_t) display; + BCM_ELEMENT_T * p = (BCM_ELEMENT_T *) (intptr_t) window ; -/* - * Class: jogamp_newt_driver_bcm_vc_iv_WindowDriver - * Method: setVisible0 - * Signature: (JJZ)V - */ -JNIEXPORT void JNICALL Java_jogamp_newt_driver_bcm_vc_iv_WindowDriver_setVisible0 - (JNIEnv *env, jobject obj, jlong window, jboolean visible) -{ -} + DBG_PRINT( "BCM.Display Window.Close %p, element %p\n", + (void*)(intptr_t)dispman_display, (void*)(intptr_t)p->handle); -JNIEXPORT void JNICALL Java_jogamp_newt_driver_bcm_vc_iv_WindowDriver_setFullScreen0 - (JNIEnv *env, jobject obj, jlong window, jboolean fullscreen) -{ + if( 0 == dispman_display || NULL == p || 0 == p->handle ) { + return; + } + DISPMANX_UPDATE_HANDLE_T dispman_update = vc_dispmanx_update_start( 0 ); + vc_dispmanx_element_remove( dispman_update, p->handle ); + p->handle = 0; + vc_dispmanx_update_submit_sync( dispman_update ); + free( p ); } -JNIEXPORT void JNICALL Java_jogamp_newt_driver_bcm_vc_iv_WindowDriver_setSize0 - (JNIEnv *env, jobject obj, jlong window, jint width, jint height) +JNIEXPORT void JNICALL Java_jogamp_newt_driver_bcm_vc_iv_WindowDriver_reconfigure0 + (JNIEnv *env, jobject obj, jlong window, jint x, jint y, jint width, jint height, jint flags) { - // FIXME RESIZE (*env)->CallVoidMethod(env, obj, sizeChangedID, JNI_FALSE, (jint) width, (jint) height, JNI_FALSE); -} + BCM_ELEMENT_T * p = (BCM_ELEMENT_T *) (intptr_t) window ; + + if( NULL == p || 0 == p->handle ) { + return; + } + /*** + int isVisible = !TST_FLAG_CHANGE_VISIBILITY(flags) && TST_FLAG_IS_VISIBLE(flags) ; + ... + see X11Window.c + */ + int posChanged = p->x != x || p->y != y; + int sizeChanged = p->width != width || p->height != height; + p->x = x; + p->y = y; + p->width = width; + p->height = height; + + DBG_PRINT( "BCM.Display Window.Reconfig %p, element %p - %d/%d %dx%d\n", + p, (void*)(intptr_t)p->handle, p->x, p->y, p->width, p->height); + + bcm_moveTo( p->handle, p->layer, p->x, p->y, p->width, p->height); + if( posChanged ) { + (*env)->CallVoidMethod(env, obj, positionChangedID, JNI_FALSE, x, y); + } + if( sizeChanged ) { + (*env)->CallVoidMethod(env, obj, sizeChangedID, JNI_FALSE, (jint) width, (jint) height, JNI_FALSE); + } +} diff --git a/src/newt/native/bcm_vc_iv.h b/src/newt/native/bcm_vc_iv.h index b43483c10..42189f3d6 100644 --- a/src/newt/native/bcm_vc_iv.h +++ b/src/newt/native/bcm_vc_iv.h @@ -29,6 +29,11 @@ #ifndef BCM_VC_IV_H #define BCM_VC_IV_H +/** + * http://en.wikipedia.org/wiki/VideoCore + * https://github.com/raspberrypi/userland + */ + #ifdef __cplusplus extern "C" { #endif @@ -150,12 +155,6 @@ typedef struct { } DISPMANX_CLAMP_T; -typedef struct { - DISPMANX_ELEMENT_HANDLE_T element; - int width; /* This is necessary because dispmanx elements are not queriable. */ - int height; -} EGL_DISPMANX_WINDOW_T; - typedef struct tag_VC_RECT_T { int32_t x; int32_t y; @@ -163,6 +162,102 @@ typedef struct tag_VC_RECT_T { int32_t height; } VC_RECT_T; +/* Types of image supported. */ +/* Please add any new types to the *end* of this list. Also update + * case_VC_IMAGE_ANY_xxx macros (below), and the vc_image_type_info table in + * vc_image/vc_image_helper.c. + */ +typedef enum +{ + VC_IMAGE_MIN = 0, //bounds for error checking + + VC_IMAGE_RGB565 = 1, + VC_IMAGE_1BPP, + VC_IMAGE_YUV420, + VC_IMAGE_48BPP, + VC_IMAGE_RGB888, + VC_IMAGE_8BPP, + VC_IMAGE_4BPP, // 4bpp palettised image + VC_IMAGE_3D32, /* A separated format of 16 colour/light shorts followed by 16 z values */ + VC_IMAGE_3D32B, /* 16 colours followed by 16 z values */ + VC_IMAGE_3D32MAT, /* A separated format of 16 material/colour/light shorts followed by 16 z values */ + VC_IMAGE_RGB2X9, /* 32 bit format containing 18 bits of 6.6.6 RGB, 9 bits per short */ + VC_IMAGE_RGB666, /* 32-bit format holding 18 bits of 6.6.6 RGB */ + VC_IMAGE_PAL4_OBSOLETE, // 4bpp palettised image with embedded palette + VC_IMAGE_PAL8_OBSOLETE, // 8bpp palettised image with embedded palette + VC_IMAGE_RGBA32, /* RGB888 with an alpha byte after each pixel */ /* xxx: isn't it BEFORE each pixel? */ + VC_IMAGE_YUV422, /* a line of Y (32-byte padded), a line of U (16-byte padded), and a line of V (16-byte padded) */ + VC_IMAGE_RGBA565, /* RGB565 with a transparent patch */ + VC_IMAGE_RGBA16, /* Compressed (4444) version of RGBA32 */ + VC_IMAGE_YUV_UV, /* VCIII codec format */ + VC_IMAGE_TF_RGBA32, /* VCIII T-format RGBA8888 */ + VC_IMAGE_TF_RGBX32, /* VCIII T-format RGBx8888 */ + VC_IMAGE_TF_FLOAT, /* VCIII T-format float */ + VC_IMAGE_TF_RGBA16, /* VCIII T-format RGBA4444 */ + VC_IMAGE_TF_RGBA5551, /* VCIII T-format RGB5551 */ + VC_IMAGE_TF_RGB565, /* VCIII T-format RGB565 */ + VC_IMAGE_TF_YA88, /* VCIII T-format 8-bit luma and 8-bit alpha */ + VC_IMAGE_TF_BYTE, /* VCIII T-format 8 bit generic sample */ + VC_IMAGE_TF_PAL8, /* VCIII T-format 8-bit palette */ + VC_IMAGE_TF_PAL4, /* VCIII T-format 4-bit palette */ + VC_IMAGE_TF_ETC1, /* VCIII T-format Ericsson Texture Compressed */ + VC_IMAGE_BGR888, /* RGB888 with R & B swapped */ + VC_IMAGE_BGR888_NP, /* RGB888 with R & B swapped, but with no pitch, i.e. no padding after each row of pixels */ + VC_IMAGE_BAYER, /* Bayer image, extra defines which variant is being used */ + VC_IMAGE_CODEC, /* General wrapper for codec images e.g. JPEG from camera */ + VC_IMAGE_YUV_UV32, /* VCIII codec format */ + VC_IMAGE_TF_Y8, /* VCIII T-format 8-bit luma */ + VC_IMAGE_TF_A8, /* VCIII T-format 8-bit alpha */ + VC_IMAGE_TF_SHORT,/* VCIII T-format 16-bit generic sample */ + VC_IMAGE_TF_1BPP, /* VCIII T-format 1bpp black/white */ + VC_IMAGE_OPENGL, + VC_IMAGE_YUV444I, /* VCIII-B0 HVS YUV 4:4:4 interleaved samples */ + VC_IMAGE_YUV422PLANAR, /* Y, U, & V planes separately (VC_IMAGE_YUV422 has them interleaved on a per line basis) */ + VC_IMAGE_ARGB8888, /* 32bpp with 8bit alpha at MS byte, with R, G, B (LS byte) */ + VC_IMAGE_XRGB8888, /* 32bpp with 8bit unused at MS byte, with R, G, B (LS byte) */ + + VC_IMAGE_YUV422YUYV, /* interleaved 8 bit samples of Y, U, Y, V */ + VC_IMAGE_YUV422YVYU, /* interleaved 8 bit samples of Y, V, Y, U */ + VC_IMAGE_YUV422UYVY, /* interleaved 8 bit samples of U, Y, V, Y */ + VC_IMAGE_YUV422VYUY, /* interleaved 8 bit samples of V, Y, U, Y */ + + VC_IMAGE_RGBX32, /* 32bpp like RGBA32 but with unused alpha */ + VC_IMAGE_RGBX8888, /* 32bpp, corresponding to RGBA with unused alpha */ + VC_IMAGE_BGRX8888, /* 32bpp, corresponding to BGRA with unused alpha */ + + VC_IMAGE_YUV420SP, /* Y as a plane, then UV byte interleaved in plane with with same pitch, half height */ + + VC_IMAGE_YUV444PLANAR, /* Y, U, & V planes separately 4:4:4 */ + + VC_IMAGE_MAX, //bounds for error checking + VC_IMAGE_FORCE_ENUM_16BIT = 0xffff, +} VC_IMAGE_TYPE_T; + +/** + * From https://github.com/raspberrypi/userland/blob/master/interface/vmcs_host/vc_vchi_dispmanx.h + */ +typedef enum { + DISPMANX_ELEMENT_CHANGE_LAYER = (1<<0), + DISPMANX_ELEMENT_CHANGE_OPACITY = (1<<1), + DISPMANX_ELEMENT_CHANGE_DEST_RECT = (1<<2), + DISPMANX_ELEMENT_CHANGE_SRC_RECT = (1<<3), + DISPMANX_ELEMENT_CHANGE_MASK_RESOURCE = (1<<4), + DISPMANX_ELEMENT_CHANGE_TRANSFORM = (1<<5) +/** + * Not working /validated ! + DISPMANX_ELEMENT_CHANGE_MIN = 0x00, + DISPMANX_ELEMENT_CHANGE_SOURCE = 0x01, + DISPMANX_ELEMENT_INSERT_ABOVE = 0x80, + DISPMANX_ELEMENT_CHANGE_FLAGS = 0x100, + DISPMANX_ELEMENT_CHANGE_NOTHING = 0x200, + DISPMANX_ELEMENT_CHANGE_ALPHA_FLAGS = 0x400, + DISPMANX_ELEMENT_CHANGE_PROTECTION = 0x800, + DISPMANX_ELEMENT_CHANGE_MAX = 0x1000 + */ +} DISPMANX_ELEMENT_CHANGE_T; + + + extern void bcm_host_init(void); extern void bcm_host_deinit(void); @@ -171,15 +266,38 @@ extern int32_t graphics_get_display_size( const uint16_t display_number, uint32_t *height); extern DISPMANX_DISPLAY_HANDLE_T vc_dispmanx_display_open( uint32_t device ); +extern int vc_dispmanx_display_close( DISPMANX_DISPLAY_HANDLE_T display ); + +extern DISPMANX_RESOURCE_HANDLE_T vc_dispmanx_resource_create(VC_IMAGE_TYPE_T type, uint32_t width, uint32_t height, uint32_t *native_image_handle); +extern int vc_dispmanx_resource_write_data( DISPMANX_RESOURCE_HANDLE_T res, VC_IMAGE_TYPE_T src_type, int src_pitch, void * src_address, const VC_RECT_T * rect ); +//extern int vc_dispmanx_resource_write_data_handle( DISPMANX_RESOURCE_HANDLE_T res, VC_IMAGE_TYPE_T src_type, int src_pitch, +// VCHI_MEM_HANDLE_T handle, uint32_t offset, const VC_RECT_T * rect ); +extern int vc_dispmanx_resource_delete( DISPMANX_RESOURCE_HANDLE_T res ); + + + extern DISPMANX_UPDATE_HANDLE_T vc_dispmanx_update_start( int32_t priority ); extern DISPMANX_ELEMENT_HANDLE_T vc_dispmanx_element_add ( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_DISPLAY_HANDLE_T display, int32_t layer, const VC_RECT_T *dest_rect, DISPMANX_RESOURCE_HANDLE_T src, const VC_RECT_T *src_rect, DISPMANX_PROTECTION_T protection, VC_DISPMANX_ALPHA_T *alpha, DISPMANX_CLAMP_T *clamp, DISPMANX_TRANSFORM_T transform ); +extern int vc_dispmanx_element_remove( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_ELEMENT_HANDLE_T element ); + extern int vc_dispmanx_update_submit_sync( DISPMANX_UPDATE_HANDLE_T update ); +//New function added to VCHI to change attributes, set_opacity does not work there. +extern int vc_dispmanx_element_change_attributes( DISPMANX_UPDATE_HANDLE_T update, + DISPMANX_ELEMENT_HANDLE_T element, + uint32_t change_flags, + int32_t layer, + uint8_t opacity, + const VC_RECT_T *dest_rect, + const VC_RECT_T *src_rect, + DISPMANX_RESOURCE_HANDLE_T mask, + DISPMANX_TRANSFORM_T transform ); + #ifdef __cplusplus } #endif |