From c2d6d46b9ca89cb1c0729ee599c3566d3d1e7cf7 Mon Sep 17 00:00:00 2001 From: Javier Date: Tue, 28 Jan 2014 16:50:47 +0100 Subject: initial import --- libtopmenu-client/topmenu-client.c | 113 +++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 libtopmenu-client/topmenu-client.c (limited to 'libtopmenu-client/topmenu-client.c') 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 +#include + +#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); +} -- cgit v1.2.3