| /* gtkcomponentpeer.c -- Native implementation of GtkComponentPeer |
| Copyright (C) 1998, 1999, 2002, 2004, 2006 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| #include "gtkpeer.h" |
| #include "gnu_java_awt_peer_gtk_GtkComponentPeer.h" |
| |
| #include <gtk/gtkprivate.h> |
| |
| #define AWT_DEFAULT_CURSOR 0 |
| #define AWT_CROSSHAIR_CURSOR 1 |
| #define AWT_TEXT_CURSOR 2 |
| #define AWT_WAIT_CURSOR 3 |
| #define AWT_SW_RESIZE_CURSOR 4 |
| #define AWT_SE_RESIZE_CURSOR 5 |
| #define AWT_NW_RESIZE_CURSOR 6 |
| #define AWT_NE_RESIZE_CURSOR 7 |
| #define AWT_N_RESIZE_CURSOR 8 |
| #define AWT_S_RESIZE_CURSOR 9 |
| #define AWT_W_RESIZE_CURSOR 10 |
| #define AWT_E_RESIZE_CURSOR 11 |
| #define AWT_HAND_CURSOR 12 |
| #define AWT_MOVE_CURSOR 13 |
| |
| /* FIXME: use gtk-double-click-time, gtk-double-click-distance */ |
| #define MULTI_CLICK_TIME 250 |
| /* as opposed to a MULTI_PASS_TIME :) */ |
| |
| #define AWT_MOUSE_CLICKED 500 |
| #define AWT_MOUSE_PRESSED 501 |
| #define AWT_MOUSE_RELEASED 502 |
| #define AWT_MOUSE_MOVED 503 |
| #define AWT_MOUSE_ENTERED 504 |
| #define AWT_MOUSE_EXITED 505 |
| #define AWT_MOUSE_DRAGGED 506 |
| #define AWT_MOUSE_WHEEL 507 |
| |
| #define AWT_WHEEL_UNIT_SCROLL 0 |
| |
| #define AWT_FOCUS_GAINED 1004 |
| #define AWT_FOCUS_LOST 1005 |
| |
| static GtkWidget *find_fg_color_widget (GtkWidget *widget); |
| static GtkWidget *find_bg_color_widget (GtkWidget *widget); |
| static GtkWidget *get_widget (GtkWidget *widget); |
| |
| static jmethodID postMouseEventID; |
| static jmethodID postMouseWheelEventID; |
| static jmethodID postExposeEventID; |
| static jmethodID postFocusEventID; |
| |
| void |
| cp_gtk_component_init_jni (void) |
| { |
| jclass gtkcomponentpeer; |
| |
| gtkcomponentpeer = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(), |
| "gnu/java/awt/peer/gtk/GtkComponentPeer"); |
| |
| postMouseEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkcomponentpeer, |
| "postMouseEvent", "(IJIIIIZ)V"); |
| |
| postMouseWheelEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), |
| gtkcomponentpeer, |
| "postMouseWheelEvent", |
| "(IJIIIIZIII)V"); |
| |
| postExposeEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkcomponentpeer, |
| "postExposeEvent", "(IIII)V"); |
| |
| postFocusEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkcomponentpeer, |
| "postFocusEvent", "(IZ)V"); |
| } |
| |
| static gboolean component_button_press_cb (GtkWidget *widget, |
| GdkEventButton *event, |
| jobject peer); |
| static gboolean component_button_release_cb (GtkWidget *widget, |
| GdkEventButton *event, |
| jobject peer); |
| static gboolean component_motion_notify_cb (GtkWidget *widget, |
| GdkEventMotion *event, |
| jobject peer); |
| static gboolean component_scroll_cb (GtkWidget *widget, |
| GdkEventScroll *event, |
| jobject peer); |
| static gboolean component_enter_notify_cb (GtkWidget *widget, |
| GdkEventCrossing *event, |
| jobject peer); |
| static gboolean component_leave_notify_cb (GtkWidget *widget, |
| GdkEventCrossing *event, |
| jobject peer); |
| static gboolean component_expose_cb (GtkWidget *widget, |
| GdkEventExpose *event, |
| jobject peer); |
| static gboolean component_focus_in_cb (GtkWidget *widget, |
| GdkEventFocus *event, |
| jobject peer); |
| static gboolean component_focus_out_cb (GtkWidget *widget, |
| GdkEventFocus *event, |
| jobject peer); |
| |
| static jint |
| button_to_awt_mods (int button) |
| { |
| switch (button) |
| { |
| case 1: |
| return AWT_BUTTON1_DOWN_MASK | AWT_BUTTON1_MASK; |
| case 2: |
| return AWT_BUTTON2_DOWN_MASK | AWT_BUTTON2_MASK; |
| case 3: |
| return AWT_BUTTON3_DOWN_MASK | AWT_BUTTON3_MASK; |
| } |
| |
| return 0; |
| } |
| |
| jint |
| cp_gtk_state_to_awt_mods (guint state) |
| { |
| jint result = 0; |
| |
| if (state & GDK_SHIFT_MASK) |
| result |= (AWT_SHIFT_DOWN_MASK | AWT_SHIFT_MASK); |
| if (state & GDK_CONTROL_MASK) |
| result |= (AWT_CTRL_DOWN_MASK | AWT_CTRL_MASK); |
| if (state & GDK_MOD1_MASK) |
| result |= (AWT_ALT_DOWN_MASK | AWT_ALT_MASK); |
| |
| return result; |
| } |
| |
| static jint |
| state_to_awt_mods_with_button_states (guint state) |
| { |
| jint result = 0; |
| |
| if (state & GDK_SHIFT_MASK) |
| result |= AWT_SHIFT_DOWN_MASK | AWT_SHIFT_MASK; |
| if (state & GDK_CONTROL_MASK) |
| result |= AWT_CTRL_DOWN_MASK | AWT_CTRL_MASK; |
| if (state & GDK_MOD1_MASK) |
| result |= AWT_ALT_DOWN_MASK | AWT_ALT_MASK; |
| if (state & GDK_BUTTON1_MASK) |
| result |= AWT_BUTTON1_DOWN_MASK | AWT_BUTTON1_MASK; |
| if (state & GDK_BUTTON2_MASK) |
| result |= AWT_BUTTON2_DOWN_MASK; |
| if (state & GDK_BUTTON3_MASK) |
| result |= AWT_BUTTON3_DOWN_MASK; |
| |
| return result; |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetCursor |
| (JNIEnv *env, jobject obj, jint type, jobject image, jint x, jint y) |
| { |
| gdk_threads_enter (); |
| |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetCursorUnlocked |
| (env, obj, type, image, x, y); |
| |
| gdk_threads_leave (); |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetCursorUnlocked |
| (JNIEnv *env, jobject obj, jint type, jobject image, jint x, jint y) |
| { |
| void *ptr; |
| GtkWidget *widget; |
| GdkWindow *win; |
| GdkCursorType gdk_cursor_type; |
| GdkCursor *gdk_cursor; |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| switch (type) |
| { |
| case AWT_CROSSHAIR_CURSOR: |
| gdk_cursor_type = GDK_CROSSHAIR; |
| break; |
| case AWT_TEXT_CURSOR: |
| gdk_cursor_type = GDK_XTERM; |
| break; |
| case AWT_WAIT_CURSOR: |
| gdk_cursor_type = GDK_WATCH; |
| break; |
| case AWT_SW_RESIZE_CURSOR: |
| gdk_cursor_type = GDK_BOTTOM_LEFT_CORNER; |
| break; |
| case AWT_SE_RESIZE_CURSOR: |
| gdk_cursor_type = GDK_BOTTOM_RIGHT_CORNER; |
| break; |
| case AWT_NW_RESIZE_CURSOR: |
| gdk_cursor_type = GDK_TOP_LEFT_CORNER; |
| break; |
| case AWT_NE_RESIZE_CURSOR: |
| gdk_cursor_type = GDK_TOP_RIGHT_CORNER; |
| break; |
| case AWT_N_RESIZE_CURSOR: |
| gdk_cursor_type = GDK_TOP_SIDE; |
| break; |
| case AWT_S_RESIZE_CURSOR: |
| gdk_cursor_type = GDK_BOTTOM_SIDE; |
| break; |
| case AWT_W_RESIZE_CURSOR: |
| gdk_cursor_type = GDK_LEFT_SIDE; |
| break; |
| case AWT_E_RESIZE_CURSOR: |
| gdk_cursor_type = GDK_RIGHT_SIDE; |
| break; |
| case AWT_HAND_CURSOR: |
| gdk_cursor_type = GDK_HAND2; |
| break; |
| case AWT_MOVE_CURSOR: |
| gdk_cursor_type = GDK_FLEUR; |
| break; |
| default: |
| gdk_cursor_type = GDK_LEFT_PTR; |
| } |
| |
| widget = get_widget(GTK_WIDGET(ptr)); |
| |
| win = widget->window; |
| if ((widget->window) == NULL) |
| win = GTK_WIDGET(ptr)->window; |
| |
| if (image == NULL) |
| gdk_cursor = gdk_cursor_new (gdk_cursor_type); |
| else |
| gdk_cursor |
| = gdk_cursor_new_from_pixbuf (gdk_drawable_get_display (win), |
| cp_gtk_image_get_pixbuf (env, image), |
| x, y); |
| |
| gdk_window_set_cursor (win, gdk_cursor); |
| gdk_cursor_unref (gdk_cursor); |
| |
| /* Make sure the cursor is replaced on screen. */ |
| gdk_flush(); |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetParent |
| (JNIEnv *env, jobject obj, jobject parent) |
| { |
| void *ptr; |
| void *parent_ptr; |
| GtkWidget *widget; |
| GtkWidget *parent_widget; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| parent_ptr = NSA_GET_PTR (env, parent); |
| |
| widget = GTK_WIDGET (ptr); |
| parent_widget = get_widget(GTK_WIDGET (parent_ptr)); |
| |
| if (widget->parent == NULL) |
| { |
| if (GTK_IS_WINDOW (parent_widget)) |
| { |
| GList *children = gtk_container_get_children |
| (GTK_CONTAINER (parent_widget)); |
| |
| if (GTK_IS_MENU_BAR (children->data)) |
| gtk_fixed_put (GTK_FIXED (children->next->data), widget, 0, 0); |
| else |
| gtk_fixed_put (GTK_FIXED (children->data), widget, 0, 0); |
| } |
| else |
| if (GTK_IS_SCROLLED_WINDOW (parent_widget)) |
| { |
| gtk_scrolled_window_add_with_viewport |
| (GTK_SCROLLED_WINDOW (parent_widget), widget); |
| gtk_viewport_set_shadow_type (GTK_VIEWPORT (widget->parent), |
| GTK_SHADOW_NONE); |
| |
| } |
| else |
| { |
| if (widget->parent == NULL) |
| gtk_fixed_put (GTK_FIXED (parent_widget), widget, 0, 0); |
| } |
| } |
| |
| gdk_threads_leave (); |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetSensitive |
| (JNIEnv *env, jobject obj, jboolean sensitive) |
| { |
| void *ptr; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| gtk_widget_set_sensitive (get_widget(GTK_WIDGET (ptr)), sensitive); |
| |
| gdk_threads_leave (); |
| } |
| |
| JNIEXPORT jboolean JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetHasFocus |
| (JNIEnv *env, jobject obj) |
| { |
| void *ptr; |
| jboolean retval; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| retval = GTK_WIDGET_HAS_FOCUS((GTK_WIDGET (ptr))); |
| |
| gdk_threads_leave (); |
| |
| return retval; |
| } |
| |
| JNIEXPORT jboolean JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetCanFocus |
| (JNIEnv *env, jobject obj) |
| { |
| void *ptr; |
| jboolean retval; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| retval = GTK_WIDGET_CAN_FOCUS((GTK_WIDGET (ptr))); |
| |
| gdk_threads_leave (); |
| |
| return retval; |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetRequestFocus |
| (JNIEnv *env, jobject obj) |
| { |
| void *ptr; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| gtk_widget_grab_focus (get_widget(GTK_WIDGET (ptr))); |
| |
| gdk_threads_leave (); |
| } |
| |
| /* |
| * Translate a Java KeyEvent object into a GdkEventKey event, then |
| * pass it to the GTK main loop for processing. |
| */ |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetDispatchKeyEvent |
| (JNIEnv *env, jobject obj, jint id, jlong when, jint mods, |
| jint keyCode, jint keyLocation) |
| { |
| void *ptr; |
| GdkEvent *event = NULL; |
| GdkKeymapKey *keymap_keys = NULL; |
| gint n_keys = 0; |
| guint lookup_keyval = 0; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| if (id == AWT_KEY_PRESSED) |
| event = gdk_event_new (GDK_KEY_PRESS); |
| else if (id == AWT_KEY_RELEASED) |
| event = gdk_event_new (GDK_KEY_RELEASE); |
| else |
| { |
| gdk_threads_leave (); |
| /* Don't send AWT KEY_TYPED events to GTK. */ |
| return; |
| } |
| |
| if (GTK_IS_BUTTON (ptr)) |
| event->key.window = GTK_BUTTON (get_widget(GTK_WIDGET (ptr)))->event_window; |
| else if (GTK_IS_SCROLLED_WINDOW (get_widget(GTK_WIDGET (ptr)))) |
| event->key.window = GTK_WIDGET (GTK_SCROLLED_WINDOW (get_widget(GTK_WIDGET (ptr)))->container.child)->window; |
| else |
| event->key.window = get_widget(GTK_WIDGET (ptr))->window; |
| |
| event->key.send_event = 0; |
| event->key.time = (guint32) when; |
| |
| if (mods & AWT_SHIFT_DOWN_MASK) |
| event->key.state |= GDK_SHIFT_MASK; |
| if (mods & AWT_CTRL_DOWN_MASK) |
| event->key.state |= GDK_CONTROL_MASK; |
| if (mods & AWT_ALT_DOWN_MASK) |
| event->key.state |= GDK_MOD1_MASK; |
| |
| /* This hack is needed because the AWT has no notion of num lock. |
| It infers numlock state from the only Java virtual keys that are |
| affected by it. */ |
| if (keyCode == VK_NUMPAD9 |
| || keyCode == VK_NUMPAD8 |
| || keyCode == VK_NUMPAD7 |
| || keyCode == VK_NUMPAD6 |
| || keyCode == VK_NUMPAD5 |
| || keyCode == VK_NUMPAD4 |
| || keyCode == VK_NUMPAD3 |
| || keyCode == VK_NUMPAD2 |
| || keyCode == VK_NUMPAD1 |
| || keyCode == VK_NUMPAD0 |
| || keyCode == VK_DECIMAL) |
| event->key.state |= GDK_MOD2_MASK; |
| |
| /* These values don't need to be filled in since GTK doesn't use |
| them. */ |
| event->key.length = 0; |
| event->key.string = NULL; |
| |
| lookup_keyval = cp_gtk_awt_keycode_to_keysym (keyCode, keyLocation); |
| |
| if (!gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), |
| lookup_keyval, |
| &keymap_keys, |
| &n_keys)) |
| { |
| /* No matching keymap entry was found. */ |
| g_printerr ("No matching keymap entries were found\n"); |
| gdk_threads_leave (); |
| return; |
| } |
| |
| /* Note: if n_keys > 1 then there are multiple hardware keycodes |
| that translate to lookup_keyval. We arbitrarily choose the first |
| hardware keycode from the list returned by |
| gdk_keymap_get_entries_for_keyval. */ |
| |
| event->key.hardware_keycode = keymap_keys[0].keycode; |
| event->key.group = keymap_keys[0].group; |
| |
| g_free (keymap_keys); |
| |
| if (!gdk_keymap_translate_keyboard_state (gdk_keymap_get_default (), |
| event->key.hardware_keycode, |
| event->key.state, |
| event->key.group, |
| &event->key.keyval, |
| NULL, NULL, NULL)) |
| { |
| /* No matching keyval was found. */ |
| g_printerr ("No matching keyval was found\n"); |
| gdk_threads_leave (); |
| return; |
| } |
| |
| /* keyevent = (GdkEventKey *) event; */ |
| /* g_printerr ("generated event: sent: %d time: %d state: %d keyval: %d length: %d string: %s hardware_keycode: %d group: %d\n", keyevent->send_event, keyevent->time, keyevent->state, keyevent->keyval, keyevent->length, keyevent->string, keyevent->hardware_keycode, keyevent->group); */ |
| |
| /* We already received the original key event on the window itself, |
| so we don't want to resend it. */ |
| if (!GTK_IS_WINDOW (ptr)) |
| { |
| if (GTK_IS_SCROLLED_WINDOW (get_widget(GTK_WIDGET (ptr)))) |
| gtk_widget_event (GTK_WIDGET (GTK_SCROLLED_WINDOW (get_widget(GTK_WIDGET (ptr)))->container.child), event); |
| else |
| gtk_widget_event (get_widget(GTK_WIDGET (ptr)), event); |
| } |
| |
| gdk_threads_leave (); |
| } |
| |
| /* |
| * Find the origin of a widget's window. |
| */ |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWindowGetLocationOnScreen |
| (JNIEnv * env, jobject obj, jintArray jpoint) |
| { |
| void *ptr; |
| jint *point; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| point = (*env)->GetIntArrayElements (env, jpoint, 0); |
| |
| gdk_window_get_root_origin (get_widget(GTK_WIDGET (ptr))->window, point, point+1); |
| |
| (*env)->ReleaseIntArrayElements(env, jpoint, point, 0); |
| |
| gdk_threads_leave (); |
| } |
| |
| /* |
| * Find the origin of a widget |
| */ |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetGetLocationOnScreen |
| (JNIEnv * env, jobject obj, jintArray jpoint) |
| { |
| void *ptr; |
| jint *point; |
| GtkWidget *widget; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| point = (*env)->GetIntArrayElements (env, jpoint, 0); |
| |
| widget = get_widget(GTK_WIDGET (ptr)); |
| while(gtk_widget_get_parent(widget) != NULL) |
| widget = gtk_widget_get_parent(widget); |
| gdk_window_get_position (GTK_WIDGET(widget)->window, point, point+1); |
| |
| *point += GTK_WIDGET(ptr)->allocation.x; |
| *(point+1) += GTK_WIDGET(ptr)->allocation.y; |
| |
| (*env)->ReleaseIntArrayElements(env, jpoint, point, 0); |
| |
| gdk_threads_leave (); |
| } |
| |
| /* |
| * Find this widget's current size. |
| */ |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetGetDimensions |
| (JNIEnv *env, jobject obj, jintArray jdims) |
| { |
| void *ptr; |
| jint *dims; |
| GtkRequisition requisition; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| dims = (*env)->GetIntArrayElements (env, jdims, 0); |
| dims[0] = dims[1] = 0; |
| |
| gtk_widget_size_request (get_widget(GTK_WIDGET (ptr)), &requisition); |
| |
| dims[0] = requisition.width; |
| dims[1] = requisition.height; |
| |
| (*env)->ReleaseIntArrayElements (env, jdims, dims, 0); |
| |
| gdk_threads_leave (); |
| } |
| |
| /* |
| * Find this widget's preferred size. |
| */ |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetGetPreferredDimensions |
| (JNIEnv *env, jobject obj, jintArray jdims) |
| { |
| void *ptr; |
| jint *dims; |
| GtkRequisition current_req; |
| GtkRequisition natural_req; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| dims = (*env)->GetIntArrayElements (env, jdims, 0); |
| dims[0] = dims[1] = 0; |
| |
| /* Widgets that extend GtkWindow such as GtkFileChooserDialog may have |
| a default size. These values seem more useful then the natural |
| requisition values, particularly for GtkFileChooserDialog. */ |
| if (GTK_IS_WINDOW (get_widget(GTK_WIDGET (ptr)))) |
| { |
| gint width, height; |
| gtk_window_get_default_size (GTK_WINDOW (get_widget(GTK_WIDGET (ptr))), &width, &height); |
| |
| dims[0] = width; |
| dims[1] = height; |
| } |
| else |
| { |
| /* Save the widget's current size request. */ |
| gtk_widget_size_request (get_widget(GTK_WIDGET (ptr)), ¤t_req); |
| |
| /* Get the widget's "natural" size request. */ |
| gtk_widget_set_size_request (get_widget(GTK_WIDGET (ptr)), -1, -1); |
| gtk_widget_size_request (get_widget(GTK_WIDGET (ptr)), &natural_req); |
| |
| /* Reset the widget's size request. */ |
| gtk_widget_set_size_request (get_widget(GTK_WIDGET (ptr)), |
| current_req.width, current_req.height); |
| |
| dims[0] = natural_req.width; |
| dims[1] = natural_req.height; |
| } |
| |
| (*env)->ReleaseIntArrayElements (env, jdims, dims, 0); |
| |
| gdk_threads_leave (); |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_setNativeBounds |
| (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height) |
| { |
| GtkWidget *widget; |
| void *ptr; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| widget = GTK_WIDGET (ptr); |
| |
| /* We assume that -1 is a width or height and not a request for the |
| widget's natural size. */ |
| width = width < 0 ? 0 : width; |
| height = height < 0 ? 0 : height; |
| |
| if (GTK_IS_VIEWPORT (widget->parent)) |
| gtk_widget_set_size_request (widget, width, height); |
| else |
| { |
| if (!(width == 0 && height == 0)) |
| { |
| gtk_widget_set_size_request (widget, width, height); |
| if (widget->parent != NULL) |
| gtk_fixed_move (GTK_FIXED (widget->parent), widget, x, y); |
| } |
| } |
| |
| gdk_threads_leave (); |
| } |
| |
| JNIEXPORT jintArray JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetGetBackground |
| (JNIEnv *env, jobject obj) |
| { |
| void *ptr; |
| jintArray array; |
| int *rgb; |
| GdkColor bg; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| bg = GTK_WIDGET (ptr)->style->bg[GTK_STATE_NORMAL]; |
| |
| array = (*env)->NewIntArray (env, 3); |
| |
| rgb = (*env)->GetIntArrayElements (env, array, NULL); |
| /* convert color data from 16 bit values down to 8 bit values */ |
| rgb[0] = bg.red >> 8; |
| rgb[1] = bg.green >> 8; |
| rgb[2] = bg.blue >> 8; |
| (*env)->ReleaseIntArrayElements (env, array, rgb, 0); |
| |
| gdk_threads_leave (); |
| |
| return array; |
| } |
| |
| JNIEXPORT jintArray JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetGetForeground |
| (JNIEnv *env, jobject obj) |
| { |
| void *ptr; |
| jintArray array; |
| jint *rgb; |
| GdkColor fg; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| fg = get_widget(GTK_WIDGET (ptr))->style->fg[GTK_STATE_NORMAL]; |
| |
| array = (*env)->NewIntArray (env, 3); |
| |
| rgb = (*env)->GetIntArrayElements (env, array, NULL); |
| /* convert color data from 16 bit values down to 8 bit values */ |
| rgb[0] = fg.red >> 8; |
| rgb[1] = fg.green >> 8; |
| rgb[2] = fg.blue >> 8; |
| (*env)->ReleaseIntArrayElements (env, array, rgb, 0); |
| |
| gdk_threads_leave (); |
| |
| return array; |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetBackground |
| (JNIEnv *env, jobject obj, jint red, jint green, jint blue) |
| { |
| GdkColor normal_color; |
| GdkColor active_color; |
| GtkWidget *widget; |
| void *ptr; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| normal_color.red = (red / 255.0) * 65535; |
| normal_color.green = (green / 255.0) * 65535; |
| normal_color.blue = (blue / 255.0) * 65535; |
| |
| /* This calculation only approximates the active colors produced by |
| Sun's AWT. */ |
| active_color.red = 0.85 * (red / 255.0) * 65535; |
| active_color.green = 0.85 * (green / 255.0) * 65535; |
| active_color.blue = 0.85 * (blue / 255.0) * 65535; |
| |
| widget = find_bg_color_widget (GTK_WIDGET (ptr)); |
| |
| gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, &normal_color); |
| gtk_widget_modify_bg (widget, GTK_STATE_ACTIVE, &active_color); |
| gtk_widget_modify_bg (widget, GTK_STATE_PRELIGHT, &normal_color); |
| |
| gdk_threads_leave (); |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetForeground |
| (JNIEnv *env, jobject obj, jint red, jint green, jint blue) |
| { |
| GdkColor color; |
| GtkWidget *widget; |
| void *ptr; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| color.red = (red / 255.0) * 65535; |
| color.green = (green / 255.0) * 65535; |
| color.blue = (blue / 255.0) * 65535; |
| |
| widget = find_fg_color_widget (GTK_WIDGET (ptr)); |
| |
| gtk_widget_modify_fg (widget, GTK_STATE_NORMAL, &color); |
| gtk_widget_modify_fg (widget, GTK_STATE_ACTIVE, &color); |
| gtk_widget_modify_fg (widget, GTK_STATE_PRELIGHT, &color); |
| |
| gdk_threads_leave (); |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_realize (JNIEnv *env, jobject obj) |
| { |
| void *ptr; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| gtk_widget_realize (GTK_WIDGET (ptr)); |
| |
| gdk_threads_leave (); |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_setVisibleNative |
| (JNIEnv *env, jobject obj, jboolean visible) |
| { |
| gdk_threads_enter(); |
| |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_setVisibleNativeUnlocked |
| (env, obj, visible); |
| |
| gdk_threads_leave(); |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_setVisibleNativeUnlocked |
| (JNIEnv *env, jobject obj, jboolean visible) |
| { |
| void *ptr; |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| if (visible) |
| gtk_widget_show (GTK_WIDGET (ptr)); |
| else |
| gtk_widget_hide (GTK_WIDGET (ptr)); |
| } |
| |
| JNIEXPORT jboolean JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_isEnabled |
| (JNIEnv *env, jobject obj) |
| { |
| void *ptr; |
| jboolean ret_val; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| ret_val = GTK_WIDGET_IS_SENSITIVE (get_widget(GTK_WIDGET (ptr))); |
| |
| gdk_threads_leave (); |
| |
| return ret_val; |
| } |
| |
| JNIEXPORT jboolean JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_modalHasGrab |
| (JNIEnv *env __attribute__((unused)), jclass clazz __attribute__((unused))) |
| { |
| GtkWidget *widget; |
| jboolean retval; |
| |
| gdk_threads_enter (); |
| |
| widget = gtk_grab_get_current (); |
| retval = (widget && GTK_IS_WINDOW (widget) && GTK_WINDOW (widget)->modal); |
| |
| gdk_threads_leave (); |
| |
| return retval; |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_connectSignals |
| (JNIEnv *env, jobject obj) |
| { |
| void *ptr; |
| jobject *gref; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| gref = NSA_GET_GLOBAL_REF (env, obj); |
| |
| cp_gtk_component_connect_signals (ptr, gref); |
| |
| gdk_threads_leave (); |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkComponentPeer_setNativeEventMask |
| (JNIEnv *env, jobject obj) |
| { |
| void *ptr; |
| |
| gdk_threads_enter (); |
| |
| ptr = NSA_GET_PTR (env, obj); |
| |
| gtk_widget_add_events (get_widget(GTK_WIDGET (ptr)), |
| GDK_POINTER_MOTION_MASK |
| | GDK_BUTTON_MOTION_MASK |
| | GDK_BUTTON_PRESS_MASK |
| | GDK_BUTTON_RELEASE_MASK |
| | GDK_KEY_PRESS_MASK |
| | GDK_KEY_RELEASE_MASK |
| | GDK_ENTER_NOTIFY_MASK |
| | GDK_LEAVE_NOTIFY_MASK |
| | GDK_STRUCTURE_MASK |
| | GDK_KEY_PRESS_MASK |
| | GDK_FOCUS_CHANGE_MASK); |
| |
| gdk_threads_leave (); |
| } |
| |
| static GtkWidget * |
| get_widget (GtkWidget *widget) |
| { |
| GtkWidget *w; |
| |
| if (GTK_IS_EVENT_BOX (widget)) |
| w = gtk_bin_get_child (GTK_BIN(widget)); |
| else |
| w = widget; |
| |
| return w; |
| } |
| |
| /* FIXME: these functions should be implemented by overridding the |
| appropriate GtkComponentPeer methods. */ |
| static GtkWidget * |
| find_fg_color_widget (GtkWidget *widget) |
| { |
| GtkWidget *fg_color_widget; |
| |
| if (GTK_IS_EVENT_BOX (widget) |
| || (GTK_IS_BUTTON (widget) |
| && !GTK_IS_COMBO_BOX (widget))) |
| fg_color_widget = gtk_bin_get_child (GTK_BIN(widget)); |
| else |
| fg_color_widget = widget; |
| |
| return fg_color_widget; |
| } |
| |
| static GtkWidget * |
| find_bg_color_widget (GtkWidget *widget) |
| { |
| GtkWidget *bg_color_widget; |
| |
| bg_color_widget = widget; |
| |
| return bg_color_widget; |
| } |
| |
| void |
| cp_gtk_component_connect_expose_signals (GObject *ptr, jobject *gref) |
| { |
| g_signal_connect (G_OBJECT (ptr), "expose-event", |
| G_CALLBACK (component_expose_cb), *gref); |
| } |
| |
| void |
| cp_gtk_component_connect_focus_signals (GObject *ptr, jobject *gref) |
| { |
| g_signal_connect (G_OBJECT (ptr), "focus-in-event", |
| G_CALLBACK (component_focus_in_cb), *gref); |
| |
| g_signal_connect (G_OBJECT (ptr), "focus-out-event", |
| G_CALLBACK (component_focus_out_cb), *gref); |
| } |
| |
| void |
| cp_gtk_component_connect_mouse_signals (GObject *ptr, jobject *gref) |
| { |
| g_signal_connect (G_OBJECT (ptr), "button-press-event", |
| G_CALLBACK (component_button_press_cb), *gref); |
| |
| g_signal_connect (G_OBJECT (ptr), "button-release-event", |
| G_CALLBACK (component_button_release_cb), *gref); |
| |
| g_signal_connect (G_OBJECT (ptr), "enter-notify-event", |
| G_CALLBACK (component_enter_notify_cb), *gref); |
| |
| g_signal_connect (G_OBJECT (ptr), "leave-notify-event", |
| G_CALLBACK (component_leave_notify_cb), *gref); |
| |
| g_signal_connect (G_OBJECT (ptr), "motion-notify-event", |
| G_CALLBACK (component_motion_notify_cb), *gref); |
| |
| g_signal_connect (G_OBJECT (ptr), "scroll-event", |
| G_CALLBACK (component_scroll_cb), *gref); |
| } |
| |
| void |
| cp_gtk_component_connect_signals (GObject *ptr, jobject *gref) |
| { |
| cp_gtk_component_connect_expose_signals (ptr, gref); |
| cp_gtk_component_connect_focus_signals (ptr, gref); |
| cp_gtk_component_connect_mouse_signals (ptr, gref); |
| } |
| |
| /* These variables are used to keep track of click counts. The AWT |
| allows more than a triple click to occur but GTK doesn't report |
| more-than-triple clicks. Also used for keeping track of scroll events.*/ |
| static jint click_count = 1; |
| static guint32 button_click_time = 0; |
| static GdkWindow *button_window = NULL; |
| static guint button_number_direction = -1; |
| static int hasBeenDragged; |
| |
| static gboolean |
| component_button_press_cb (GtkWidget *widget __attribute__((unused)), |
| GdkEventButton *event, |
| jobject peer) |
| { |
| /* Ignore double and triple click events. */ |
| if (event->type == GDK_2BUTTON_PRESS |
| || event->type == GDK_3BUTTON_PRESS) |
| return FALSE; |
| |
| if ((event->time < (button_click_time + MULTI_CLICK_TIME)) |
| && (event->window == button_window) |
| && (event->button == button_number_direction)) |
| click_count++; |
| else |
| click_count = 1; |
| |
| button_click_time = event->time; |
| button_window = event->window; |
| button_number_direction = event->button; |
| |
| (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, |
| postMouseEventID, |
| AWT_MOUSE_PRESSED, |
| (jlong)event->time, |
| cp_gtk_state_to_awt_mods (event->state) |
| | button_to_awt_mods (event->button), |
| (jint)event->x, |
| (jint)event->y, |
| click_count, |
| (event->button == 3) ? JNI_TRUE : |
| JNI_FALSE); |
| |
| hasBeenDragged = FALSE; |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| component_button_release_cb (GtkWidget *widget __attribute__((unused)), |
| GdkEventButton *event, |
| jobject peer) |
| { |
| int width, height; |
| |
| (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, |
| postMouseEventID, |
| AWT_MOUSE_RELEASED, |
| (jlong)event->time, |
| cp_gtk_state_to_awt_mods (event->state) |
| | button_to_awt_mods (event->button), |
| (jint)event->x, |
| (jint)event->y, |
| click_count, |
| JNI_FALSE); |
| |
| /* Generate an AWT click event only if the release occured in the |
| window it was pressed in, and the mouse has not been dragged since |
| the last time it was pressed. */ |
| gdk_drawable_get_size (event->window, &width, &height); |
| if (! hasBeenDragged |
| && event->x >= 0 |
| && event->y >= 0 |
| && event->x <= width |
| && event->y <= height) |
| { |
| (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, |
| postMouseEventID, |
| AWT_MOUSE_CLICKED, |
| (jlong)event->time, |
| cp_gtk_state_to_awt_mods (event->state) |
| | button_to_awt_mods (event->button), |
| (jint)event->x, |
| (jint)event->y, |
| click_count, |
| JNI_FALSE); |
| } |
| return FALSE; |
| } |
| |
| static gboolean |
| component_motion_notify_cb (GtkWidget *widget __attribute__((unused)), |
| GdkEventMotion *event, |
| jobject peer) |
| { |
| if (event->state & (GDK_BUTTON1_MASK |
| | GDK_BUTTON2_MASK |
| | GDK_BUTTON3_MASK |
| | GDK_BUTTON4_MASK |
| | GDK_BUTTON5_MASK)) |
| { |
| (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, |
| postMouseEventID, |
| AWT_MOUSE_DRAGGED, |
| (jlong)event->time, |
| state_to_awt_mods_with_button_states (event->state), |
| (jint)event->x, |
| (jint)event->y, |
| 0, |
| JNI_FALSE); |
| |
| hasBeenDragged = TRUE; |
| } |
| else |
| { |
| (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, postMouseEventID, |
| AWT_MOUSE_MOVED, |
| (jlong)event->time, |
| cp_gtk_state_to_awt_mods (event->state), |
| (jint)event->x, |
| (jint)event->y, |
| 0, |
| JNI_FALSE); |
| } |
| return FALSE; |
| } |
| |
| static gboolean |
| component_scroll_cb (GtkWidget *widget __attribute__((unused)), |
| GdkEventScroll *event, |
| jobject peer) |
| { |
| int rotation; |
| /** Record click count for specific direction. */ |
| if ((event->time < (button_click_time + MULTI_CLICK_TIME)) |
| && (event->window == button_window) |
| && (event->direction == button_number_direction)) |
| click_count++; |
| else |
| click_count = 1; |
| |
| button_click_time = event->time; |
| button_window = event->window; |
| button_number_direction = event->direction; |
| |
| if (event->direction == GDK_SCROLL_UP |
| || event->direction == GDK_SCROLL_LEFT) |
| rotation = -1; |
| else |
| rotation = 1; |
| |
| (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, |
| postMouseWheelEventID, |
| AWT_MOUSE_WHEEL, |
| (jlong)event->time, |
| cp_gtk_state_to_awt_mods (event->state), |
| (jint)event->x, |
| (jint)event->y, |
| click_count, |
| JNI_FALSE, |
| AWT_WHEEL_UNIT_SCROLL, |
| 1 /* amount */, |
| rotation); |
| return FALSE; |
| } |
| |
| static gboolean |
| component_enter_notify_cb (GtkWidget *widget __attribute__((unused)), |
| GdkEventCrossing *event, |
| jobject peer) |
| { |
| /* We are not interested in enter events that are due to |
| grab/ungrab and not to actually crossing boundaries */ |
| if (event->mode == GDK_CROSSING_NORMAL) |
| { |
| (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, postMouseEventID, |
| AWT_MOUSE_ENTERED, |
| (jlong)event->time, |
| state_to_awt_mods_with_button_states (event->state), |
| (jint)event->x, |
| (jint)event->y, |
| 0, |
| JNI_FALSE); |
| } |
| return FALSE; |
| } |
| |
| static gboolean |
| component_leave_notify_cb (GtkWidget *widget __attribute__((unused)), |
| GdkEventCrossing *event, |
| jobject peer) |
| { |
| /* We are not interested in leave events that are due to |
| grab/ungrab and not to actually crossing boundaries */ |
| if (event->mode == GDK_CROSSING_NORMAL) |
| { |
| (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, |
| postMouseEventID, |
| AWT_MOUSE_EXITED, |
| (jlong)event->time, |
| state_to_awt_mods_with_button_states (event->state), |
| (jint)event->x, |
| (jint)event->y, |
| 0, |
| JNI_FALSE); |
| } |
| return FALSE; |
| } |
| |
| static gboolean |
| component_expose_cb (GtkWidget *widget __attribute__((unused)), |
| GdkEventExpose *event, |
| jobject peer) |
| { |
| (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, |
| postExposeEventID, |
| (jint)event->area.x, |
| (jint)event->area.y, |
| (jint)event->area.width, |
| (jint)event->area.height); |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| component_focus_in_cb (GtkWidget *widget __attribute((unused)), |
| GdkEventFocus *event __attribute((unused)), |
| jobject peer) |
| { |
| (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, |
| postFocusEventID, |
| AWT_FOCUS_GAINED, |
| JNI_FALSE); |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| component_focus_out_cb (GtkWidget *widget __attribute((unused)), |
| GdkEventFocus *event __attribute((unused)), |
| jobject peer) |
| { |
| (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, |
| postFocusEventID, |
| AWT_FOCUS_LOST, |
| JNI_FALSE); |
| |
| return FALSE; |
| } |