diff options
author | Javier <dev.git@javispedro.com> | 2014-01-28 16:50:47 +0100 |
---|---|---|
committer | Javier <dev.git@javispedro.com> | 2014-01-28 16:50:47 +0100 |
commit | c2d6d46b9ca89cb1c0729ee599c3566d3d1e7cf7 (patch) | |
tree | 7e1e2285437816c06ac884d68284d854413cf41e /libtopmenu-client/topmenu-client.c | |
download | topmenu-gtk-c2d6d46b9ca89cb1c0729ee599c3566d3d1e7cf7.tar.gz topmenu-gtk-c2d6d46b9ca89cb1c0729ee599c3566d3d1e7cf7.zip |
initial import
Diffstat (limited to 'libtopmenu-client/topmenu-client.c')
-rw-r--r-- | libtopmenu-client/topmenu-client.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/libtopmenu-client/topmenu-client.c b/libtopmenu-client/topmenu-client.c new file mode 100644 index 0000000..63e27bc --- /dev/null +++ b/libtopmenu-client/topmenu-client.c @@ -0,0 +1,113 @@ +#include <X11/Xatom.h> +#include <gdk/gdkx.h> + +#include "../global.h" + +#include "topmenu-client.h" + +#define OBJECT_DATA_KEY_PLUG "topmenu-plug" + +static gboolean handle_plug_delete(GtkPlug *plug, GdkEvent *event, GdkWindow *window) +{ + return TRUE; // Prevent deletion of plug window +} + +static gboolean handle_widget_button_event(GtkWidget *widget, GdkEvent *event, GtkPlug *plug) +{ + if (event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE) { + return FALSE; + } + if (event->button.button == 1) { + return FALSE; + } + + GdkWindow *socket = gtk_plug_get_socket_window(plug); + if (socket) { + GdkScreen *screen = gdk_window_get_screen(socket); + GdkWindow *root = gdk_screen_get_root_window(screen); + Display *dpy = GDK_WINDOW_XDISPLAY(socket); + Window xwin = GDK_WINDOW_XWINDOW(socket); + + if (event->type == GDK_BUTTON_PRESS) { + gdk_display_pointer_ungrab(gtk_widget_get_display(widget), + GDK_CURRENT_TIME); + } + + XEvent e; + long mask = event->type == GDK_BUTTON_PRESS ? ButtonPressMask : ButtonReleaseMask; + e.type = event->type == GDK_BUTTON_PRESS ? ButtonPress : ButtonRelease; + e.xbutton.window = xwin; + e.xbutton.display = dpy; + e.xbutton.root = GDK_WINDOW_XWINDOW(root); + e.xbutton.time = event->button.time; + e.xbutton.button = event->button.button; + e.xbutton.state = event->button.state; + e.xbutton.x = event->button.x; + e.xbutton.y = event->button.y; + e.xbutton.x_root = event->button.x_root; + e.xbutton.y_root = event->button.y_root; + e.xbutton.same_screen = True; + + gdk_error_trap_push(); + XSendEvent(dpy, xwin, True, mask, &e); + g_debug("Forwarding button %d %s event to 0x%lx", + e.xbutton.button, + event->type == GDK_BUTTON_PRESS ? "press" : "release", + xwin); + gdk_flush(); + gdk_error_trap_pop(); + + return TRUE; + } + + return FALSE; +} + +void topmenu_client_connect_window_widget(GdkWindow *window, GtkWidget *widget) +{ + Display *display = GDK_WINDOW_XDISPLAY(window); + + if (g_object_get_data(G_OBJECT(window), OBJECT_DATA_KEY_PLUG)) { + topmenu_client_disconnect_window(window); + } + + Window xwin = GDK_WINDOW_XID(window); + GtkPlug *plug = GTK_PLUG(gtk_plug_new(0)); + gtk_container_add(GTK_CONTAINER(plug), widget); + g_signal_connect_object(plug, "delete-event", + G_CALLBACK(handle_plug_delete), window, 0); + g_signal_connect_object(widget, "button-press-event", + G_CALLBACK(handle_widget_button_event), plug, 0); + g_signal_connect_object(widget, "button-release-event", + G_CALLBACK(handle_widget_button_event), plug, 0); + gtk_widget_show(GTK_WIDGET(plug)); + + Window plug_xwin = gtk_plug_get_id(plug); + + Atom atom = XInternAtom(display, ATOM_TOPMENU_WINDOW, False); + + XChangeProperty(display, xwin, atom, + XA_WINDOW, 32, PropModeReplace, + (unsigned char*)&plug_xwin, 1); + + g_object_set_data_full(G_OBJECT(window), OBJECT_DATA_KEY_PLUG, plug, (GDestroyNotify)>k_widget_destroy); +} + +void topmenu_client_disconnect_window(GdkWindow *window) +{ + Display *display = GDK_WINDOW_XDISPLAY(window); + + gpointer window_data = g_object_steal_data(G_OBJECT(window), OBJECT_DATA_KEY_PLUG); + g_return_if_fail(window_data); + + Window xwin = GDK_WINDOW_XID(window); + + GtkPlug *plug = GTK_PLUG(window_data); + g_return_if_fail(plug); + + Atom atom = XInternAtom(display, ATOM_TOPMENU_WINDOW, False); + + XDeleteProperty(display, xwin, atom); + + g_object_unref(plug); +} |