gnu_java_awt_peer_gtk_GtkWindowPeer.c [plain text]
#include "gtkpeer.h"
#include "gnu_java_awt_peer_gtk_GtkWindowPeer.h"
#include <gdk/gdkprivate.h>
#include <gdk/gdkx.h>
#include <X11/Xatom.h>
static void window_get_frame_extents (GtkWidget *window,
int *top, int *left,
int *bottom, int *right);
static void request_frame_extents (GtkWidget *window);
static Bool property_notify_predicate (Display *display,
XEvent *xevent,
XPointer arg);
static void window_delete_cb (GtkWidget *widget, GdkEvent *event,
jobject peer);
static void window_destroy_cb (GtkWidget *widget, GdkEvent *event,
jobject peer);
static void window_show_cb (GtkWidget *widget, jobject peer);
static void window_active_state_change_cb (GtkWidget *widget,
GParamSpec *pspec,
jobject peer);
static void window_focus_state_change_cb (GtkWidget *widget,
GParamSpec *pspec,
jobject peer);
static gboolean window_focus_in_cb (GtkWidget * widget,
GdkEventFocus *event,
jobject peer);
static gboolean window_focus_out_cb (GtkWidget * widget,
GdkEventFocus *event,
jobject peer);
static gboolean window_window_state_cb (GtkWidget *widget,
GdkEvent *event,
jobject peer);
static jint window_get_new_state (GtkWidget *widget);
static gboolean window_property_changed_cb (GtkWidget *widget,
GdkEventProperty *event,
jobject peer);
static void realize_cb (GtkWidget *widget, jobject peer);
union extents_union
{
guchar **gu_extents;
unsigned long **extents;
};
union atom_list_union
{
guchar **gu_extents;
Atom **atom_list;
};
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkWindowPeer_create
(JNIEnv *env, jobject obj, jint type, jboolean decorated, jobject parent)
{
GtkWidget *window_widget;
GtkWindow *window;
void *window_parent;
GtkWidget *fixed;
NSA_SET_GLOBAL_REF (env, obj);
gdk_threads_enter ();
window_widget = gtk_window_new (GTK_WINDOW_TOPLEVEL);
window = GTK_WINDOW (window_widget);
if (parent)
{
window_parent = NSA_GET_PTR (env, parent);
gtk_window_set_transient_for (window, GTK_WINDOW(window_parent));
}
gtk_window_set_decorated (window, decorated);
gtk_window_set_type_hint (window, type);
gtk_window_group_add_window (global_gtk_window_group, window);
fixed = gtk_fixed_new ();
gtk_container_add (GTK_CONTAINER (window_widget), fixed);
gtk_widget_show (fixed);
gdk_threads_leave ();
NSA_SET_PTR (env, obj, window_widget);
}
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkWindowPeer_gtkWindowSetTitle
(JNIEnv *env, jobject obj, jstring title)
{
const char *c_title;
void *ptr;
ptr = NSA_GET_PTR (env, obj);
c_title = (*env)->GetStringUTFChars (env, title, NULL);
gdk_threads_enter ();
gtk_window_set_title (GTK_WINDOW (ptr), c_title);
gdk_threads_leave ();
(*env)->ReleaseStringUTFChars (env, title, c_title);
}
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkWindowPeer_gtkWindowSetResizable
(JNIEnv *env, jobject obj, jboolean resizable)
{
void *ptr;
ptr = NSA_GET_PTR (env, obj);
gdk_threads_enter ();
gtk_window_set_policy (GTK_WINDOW (ptr), resizable, resizable, FALSE);
gdk_threads_leave ();
}
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkWindowPeer_gtkWindowSetModal
(JNIEnv *env, jobject obj, jboolean modal)
{
void *ptr;
ptr = NSA_GET_PTR (env, obj);
gdk_threads_enter ();
gtk_window_set_modal (GTK_WINDOW (ptr), modal);
gdk_threads_leave ();
}
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSetVisible
(JNIEnv *env, jobject obj, jboolean visible)
{
void *ptr;
ptr = NSA_GET_PTR (env, obj);
gdk_threads_enter ();
if (visible)
gtk_widget_show (GTK_WIDGET (ptr));
else
gtk_widget_hide (GTK_WIDGET (ptr));
XFlush (GDK_DISPLAY ());
gdk_threads_leave ();
}
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkWindowPeer_connectSignals
(JNIEnv *env, jobject obj)
{
void *ptr;
jobject *gref;
ptr = NSA_GET_PTR (env, obj);
gref = NSA_GET_GLOBAL_REF (env, obj);
gdk_threads_enter ();
g_signal_connect (G_OBJECT (ptr), "event",
G_CALLBACK (pre_event_handler), *gref);
g_signal_connect (G_OBJECT (ptr), "delete-event",
G_CALLBACK (window_delete_cb), *gref);
g_signal_connect (G_OBJECT (ptr), "destroy-event",
G_CALLBACK (window_destroy_cb), *gref);
g_signal_connect (G_OBJECT (ptr), "show",
G_CALLBACK (window_show_cb), *gref);
g_signal_connect (G_OBJECT (ptr), "notify::is-active",
G_CALLBACK (window_active_state_change_cb), *gref);
g_signal_connect (G_OBJECT (ptr), "notify::has-toplevel-focus",
G_CALLBACK (window_focus_state_change_cb), *gref);
g_signal_connect (G_OBJECT (ptr), "focus-in-event",
G_CALLBACK (window_focus_in_cb), *gref);
g_signal_connect (G_OBJECT (ptr), "focus-out-event",
G_CALLBACK (window_focus_out_cb), *gref);
g_signal_connect (G_OBJECT (ptr), "window-state-event",
G_CALLBACK (window_window_state_cb), *gref);
g_signal_connect (G_OBJECT (ptr), "property-notify-event",
G_CALLBACK (window_property_changed_cb), *gref);
g_signal_connect_after (G_OBJECT (ptr), "realize",
G_CALLBACK (realize_cb), *gref);
g_signal_connect_after (G_OBJECT (ptr), "realize",
G_CALLBACK (connect_awt_hook_cb), *gref);
gdk_threads_leave ();
}
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkWindowPeer_toBack (JNIEnv *env,
jobject obj)
{
void *ptr;
ptr = NSA_GET_PTR (env, obj);
gdk_threads_enter ();
gdk_window_lower (GTK_WIDGET (ptr)->window);
gdk_flush ();
gdk_threads_leave ();
}
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkWindowPeer_toFront (JNIEnv *env,
jobject obj)
{
void *ptr;
ptr = NSA_GET_PTR (env, obj);
gdk_threads_enter ();
gdk_window_raise (GTK_WIDGET (ptr)->window);
gdk_flush ();
gdk_threads_leave ();
}
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkWindowPeer_setBoundsCallback
(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
jobject window, jint x, jint y, jint width, jint height)
{
(*gdk_env())->CallVoidMethod (gdk_env(), window, setBoundsCallbackID,
x, y, width, height);
}
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkWindowPeer_setSize
(JNIEnv *env, jobject obj, jint width, jint height)
{
void *ptr = NSA_GET_PTR (env, obj);
width = (width < 1) ? 1 : width;
height = (height < 1) ? 1 : height;
gdk_threads_enter ();
gtk_widget_set_size_request (GTK_WIDGET(ptr), width, height);
gdk_threads_leave ();
}
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSetBounds
(JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height)
{
void *ptr = NSA_GET_PTR (env, obj);
width = (width < 1) ? 1 : width;
height = (height < 1) ? 1 : height;
gdk_threads_enter ();
gtk_window_move (GTK_WINDOW(ptr), x, y);
if (GTK_WIDGET (ptr)->window != NULL)
gdk_window_move (GTK_WIDGET (ptr)->window, x, y);
gtk_widget_set_size_request (GTK_WIDGET(ptr), width, height);
gtk_window_resize (GTK_WINDOW (ptr), width, height);
gdk_threads_leave ();
}
static void
window_get_frame_extents (GtkWidget *window,
int *top, int *left, int *bottom, int *right)
{
unsigned long *extents = NULL;
union extents_union gu_ex;
*top = 23;
*left = 6;
*bottom = 6;
*right = 6;
request_frame_extents (window);
gu_ex.extents = &extents;
if (gdk_property_get (window->window,
gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE),
gdk_atom_intern ("CARDINAL", FALSE),
0,
sizeof (unsigned long) * 4,
FALSE,
NULL,
NULL,
NULL,
gu_ex.gu_extents))
{
*left = extents [0];
*right = extents [1];
*top = extents [2];
*bottom = extents [3];
}
}
static Atom extents_atom = 0;
static void
request_frame_extents (GtkWidget *window)
{
const char *request_str = "_NET_REQUEST_FRAME_EXTENTS";
GdkAtom request_extents = gdk_atom_intern (request_str, FALSE);
if (gdk_net_wm_supports (request_extents))
{
GdkDisplay *display = gtk_widget_get_display (window);
Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
GdkWindow *root_window = gdk_get_default_root_window ();
Window xroot_window = GDK_WINDOW_XID (root_window);
Atom extents_request_atom =
gdk_x11_get_xatom_by_name_for_display (display, request_str);
XEvent xevent;
XEvent notify_xevent;
unsigned long window_id = GDK_WINDOW_XID (GDK_DRAWABLE(window->window));
if (!extents_atom)
{
const char *extents_str = "_NET_FRAME_EXTENTS";
extents_atom =
gdk_x11_get_xatom_by_name_for_display (display, extents_str);
}
xevent.xclient.type = ClientMessage;
xevent.xclient.message_type = extents_request_atom;
xevent.xclient.display = xdisplay;
xevent.xclient.window = window_id;
xevent.xclient.format = 32;
xevent.xclient.data.l[0] = 0;
xevent.xclient.data.l[1] = 0;
xevent.xclient.data.l[2] = 0;
xevent.xclient.data.l[3] = 0;
xevent.xclient.data.l[4] = 0;
XSendEvent (xdisplay, xroot_window, False,
(SubstructureRedirectMask | SubstructureNotifyMask),
&xevent);
XIfEvent(xdisplay, ¬ify_xevent,
property_notify_predicate, (XPointer) &window_id);
}
}
static Bool
property_notify_predicate (Display *xdisplay __attribute__((unused)),
XEvent *event,
XPointer window_id)
{
unsigned long *window = (unsigned long *) window_id;
if (event->xany.type == PropertyNotify
&& event->xany.window == *window
&& event->xproperty.atom == extents_atom)
return True;
else
return False;
}
static void
window_delete_cb (GtkWidget *widget __attribute__((unused)),
GdkEvent *event __attribute__((unused)),
jobject peer)
{
gdk_threads_leave ();
(*gdk_env())->CallVoidMethod (gdk_env(), peer,
postWindowEventID,
(jint) AWT_WINDOW_CLOSING,
(jobject) NULL, (jint) 0);
gdk_threads_enter ();
}
static void
window_destroy_cb (GtkWidget *widget __attribute__((unused)),
GdkEvent *event __attribute__((unused)),
jobject peer)
{
gdk_threads_leave ();
(*gdk_env())->CallVoidMethod (gdk_env(), peer,
postWindowEventID,
(jint) AWT_WINDOW_CLOSED,
(jobject) NULL, (jint) 0);
gdk_threads_enter ();
}
static void
window_show_cb (GtkWidget *widget __attribute__((unused)),
jobject peer)
{
gdk_threads_leave ();
(*gdk_env())->CallVoidMethod (gdk_env(), peer,
postWindowEventID,
(jint) AWT_WINDOW_OPENED,
(jobject) NULL, (jint) 0);
gdk_threads_enter ();
}
static void
window_active_state_change_cb (GtkWidget *widget __attribute__((unused)),
GParamSpec *pspec __attribute__((unused)),
jobject peer __attribute__((unused)))
{
#if 0
gdk_threads_leave ();
if (GTK_WINDOW (widget)->is_active)
(*gdk_env())->CallVoidMethod (gdk_env(), peer,
postWindowEventID,
(jint) AWT_WINDOW_GAINED_FOCUS,
(jobject) NULL, (jint) 0);
else
(*gdk_env())->CallVoidMethod (gdk_env(), peer,
postWindowEventID,
(jint) AWT_WINDOW_DEACTIVATED,
(jobject) NULL, (jint) 0);
gdk_threads_enter ();
#endif
}
static void
window_focus_state_change_cb (GtkWidget *widget,
GParamSpec *pspec __attribute__((unused)),
jobject peer)
{
gdk_threads_leave ();
if (GTK_WINDOW (widget)->has_toplevel_focus)
(*gdk_env())->CallVoidMethod (gdk_env(), peer,
postWindowEventID,
(jint) AWT_WINDOW_ACTIVATED,
(jobject) NULL, (jint) 0);
else
(*gdk_env())->CallVoidMethod (gdk_env(), peer,
postWindowEventID,
(jint) AWT_WINDOW_DEACTIVATED,
(jobject) NULL, (jint) 0);
gdk_threads_enter ();
}
static gboolean
window_focus_in_cb (GtkWidget * widget __attribute__((unused)),
GdkEventFocus *event __attribute__((unused)),
jobject peer)
{
gdk_threads_leave ();
(*gdk_env())->CallVoidMethod (gdk_env(), peer,
postWindowEventID,
(jint) AWT_WINDOW_GAINED_FOCUS,
(jobject) NULL, (jint) 0);
gdk_threads_enter ();
return FALSE;
}
static gboolean
window_focus_out_cb (GtkWidget * widget __attribute__((unused)),
GdkEventFocus *event __attribute__((unused)),
jobject peer)
{
gdk_threads_leave ();
(*gdk_env())->CallVoidMethod (gdk_env(), peer,
postWindowEventID,
(jint) AWT_WINDOW_LOST_FOCUS,
(jobject) NULL, (jint) 0);
gdk_threads_enter ();
return FALSE;
}
static gboolean
window_window_state_cb (GtkWidget *widget,
GdkEvent *event,
jobject peer)
{
jint new_state;
if (event->window_state.changed_mask & GDK_WINDOW_STATE_ICONIFIED)
{
if (event->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED)
{
gdk_threads_leave ();
(*gdk_env())->CallVoidMethod (gdk_env(), peer,
postWindowEventID,
(jint) AWT_WINDOW_ICONIFIED,
(jobject) NULL, (jint) 0);
gdk_threads_enter ();
}
else
{
gdk_threads_leave ();
(*gdk_env())->CallVoidMethod (gdk_env(), peer,
postWindowEventID,
(jint) AWT_WINDOW_DEICONIFIED,
(jobject) NULL, (jint) 0);
gdk_threads_enter ();
}
}
new_state = AWT_FRAME_STATE_NORMAL;
if (event->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED)
new_state |= AWT_FRAME_STATE_ICONIFIED;
new_state |= window_get_new_state (widget);
gdk_threads_leave ();
(*gdk_env())->CallVoidMethod (gdk_env(), peer,
postWindowEventID,
(jint) AWT_WINDOW_STATE_CHANGED,
(jobject) NULL, new_state);
gdk_threads_enter ();
return TRUE;
}
static jint
window_get_new_state (GtkWidget *widget)
{
GdkDisplay *display = gtk_widget_get_display(widget);
jint new_state = AWT_FRAME_STATE_NORMAL;
Atom type;
gint format;
gulong atom_count;
gulong bytes_after;
Atom *atom_list = NULL;
union atom_list_union alu;
gulong i;
alu.atom_list = &atom_list;
XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
GDK_WINDOW_XID (widget->window),
gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
0, G_MAXLONG, False, XA_ATOM, &type, &format, &atom_count,
&bytes_after, alu.gu_extents);
if (type != None)
{
Atom maxvert = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_VERT");
Atom maxhorz = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ");
i = 0;
while (i < atom_count)
{
if (atom_list[i] == maxhorz)
new_state |= AWT_FRAME_STATE_MAXIMIZED_HORIZ;
else if (atom_list[i] == maxvert)
new_state |= AWT_FRAME_STATE_MAXIMIZED_VERT;
++i;
}
XFree (atom_list);
}
return new_state;
}
static gboolean
window_property_changed_cb (GtkWidget *widget __attribute__((unused)),
GdkEventProperty *event,
jobject peer)
{
unsigned long *extents;
union extents_union gu_ex;
gu_ex.extents = &extents;
if (gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE) == event->atom
&& gdk_property_get (event->window,
gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE),
gdk_atom_intern ("CARDINAL", FALSE),
0,
sizeof (unsigned long) * 4,
FALSE,
NULL,
NULL,
NULL,
gu_ex.gu_extents))
{
gdk_threads_leave ();
(*gdk_env())->CallVoidMethod (gdk_env(), peer,
postInsetsChangedEventID,
(jint) extents[2],
(jint) extents[0],
(jint) extents[3],
(jint) extents[1]);
gdk_threads_enter ();
}
return FALSE;
}
static void
realize_cb (GtkWidget *widget, jobject peer)
{
jint top = 0;
jint left = 0;
jint bottom = 0;
jint right = 0;
jint width = 0;
jint height = 0;
width = (*gdk_env())->CallIntMethod (gdk_env(), peer, windowGetWidthID);
height = (*gdk_env())->CallIntMethod (gdk_env(), peer, windowGetHeightID);
window_get_frame_extents (widget, &top, &left, &bottom, &right);
(*gdk_env())->CallVoidMethod (gdk_env(), peer,
postInsetsChangedEventID,
top, left, bottom, right);
gtk_window_set_default_size (GTK_WINDOW (widget),
MAX (1, width - left - right),
MAX (1, height - top - bottom));
gtk_widget_set_size_request (widget,
MAX (1, width - left - right),
MAX (1, height - top - bottom));
gtk_window_resize (GTK_WINDOW (widget),
MAX (1, width - left - right),
MAX (1, height - top - bottom));
}