aboutsummaryrefslogtreecommitdiff
path: root/libtopmenu-server/topmenu-widget.c
diff options
context:
space:
mode:
Diffstat (limited to 'libtopmenu-server/topmenu-widget.c')
-rw-r--r--libtopmenu-server/topmenu-widget.c92
1 files changed, 74 insertions, 18 deletions
diff --git a/libtopmenu-server/topmenu-widget.c b/libtopmenu-server/topmenu-widget.c
index 9d80ff2..5d13a6a 100644
--- a/libtopmenu-server/topmenu-widget.c
+++ b/libtopmenu-server/topmenu-widget.c
@@ -42,10 +42,17 @@
#include <libmatewnck/libmatewnck.h>
#endif
+enum _TopMenuWidgetAtoms
+{
+ ATOM_WINDOW,
+ ATOM_BACKGROUND_CHANGE,
+ ATOM_TRANSIENT_FOR,
+ N_ATOMS
+};
+
struct _TopMenuWidgetPrivate
{
- Atom atom_window;
- Atom atom_transient_for;
+ Atom atoms[N_ATOMS];
GQueue followed_windows;
#ifdef HAVE_WNCK
WnckScreen *wnck_screen;
@@ -176,7 +183,8 @@ static Window topmenu_widget_get_any_app_window_with_menu(TopMenuWidget *self, W
for (i = g_list_last(windows); i; i = g_list_previous(i)) {
if (i->data != w && wnck_window_get_application(i->data) == app) {
Window candidate = wnck_window_get_xid(i->data);
- Window menu_window = read_window_property(dpy, candidate, self->priv->atom_window);
+ Window menu_window = read_window_property(dpy, candidate,
+ self->priv->atoms[ATOM_WINDOW]);
if (menu_window) {
return candidate;
}
@@ -198,7 +206,8 @@ static Window topmenu_widget_get_any_app_window_with_menu(TopMenuWidget *self, W
for (i = g_list_last(windows); i; i = g_list_previous(i)) {
if (i->data != w && matewnck_window_get_application(i->data) == app) {
Window candidate = matewnck_window_get_xid(i->data);
- Window menu_window = read_window_property(dpy, candidate, self->priv->atom_window);
+ Window menu_window = read_window_property(dpy, candidate,
+ self->priv->atoms[ATOM_WINDOW]);
if (menu_window) {
return candidate;
}
@@ -208,6 +217,37 @@ static Window topmenu_widget_get_any_app_window_with_menu(TopMenuWidget *self, W
return None;
}
+static Window topmenu_widget_get_current_topmenu_window(TopMenuWidget *self)
+{
+ g_return_val_if_fail(self->socket, None);
+ GdkWindow *cur = gtk_socket_get_plug_window(self->socket);
+ if (cur) {
+ return GDK_WINDOW_XID(cur);
+ } else {
+ return None;
+ }
+}
+
+static void topmenu_widget_send_background(TopMenuWidget *self, Window window)
+{
+ Display *dpy = topmenu_widget_get_display(self);
+ g_return_if_fail(dpy);
+
+ XEvent e;
+ XClientMessageEvent *msg = &e.xclient;
+ msg->type = ClientMessage;
+ msg->display = dpy;
+ msg->window = window;
+ msg->message_type = self->priv->atoms[ATOM_BACKGROUND_CHANGE];
+ topmenu_background_fill_client_message(self->background, msg);
+
+ g_debug("sending current background to window 0x%lx", window);
+
+ if (XSendEvent(dpy, window, False, 0, &e) == 0) {
+ g_warning("sending background message failed");
+ }
+}
+
static void topmenu_widget_embed_topmenu_window(TopMenuWidget *self, Window window)
{
g_return_if_fail(self->socket);
@@ -244,6 +284,7 @@ static void topmenu_widget_embed_topmenu_window(TopMenuWidget *self, Window wind
if (window) {
g_debug("Embedding window 0x%lx", window);
+ topmenu_widget_send_background(self, window);
gtk_socket_add_id(self->socket, window);
}
}
@@ -254,7 +295,8 @@ static gboolean topmenu_widget_try_window(TopMenuWidget *self, Window window)
g_return_val_if_fail(dpy, FALSE);
g_return_val_if_fail(window, FALSE);
- Window menu_window = read_window_property(dpy, window, self->priv->atom_window);
+ Window menu_window = read_window_property(dpy, window,
+ self->priv->atoms[ATOM_WINDOW]);
if (menu_window) {
topmenu_widget_embed_topmenu_window(self, menu_window);
return TRUE;
@@ -335,11 +377,16 @@ static void topmenu_widget_set_followed_window(TopMenuWidget *self, Window windo
if (window) {
// Initialize atoms now
- if (self->priv->atom_window == None) {
- self->priv->atom_window = XInternAtom(dpy, ATOM_TOPMENU_WINDOW, False);
- }
- if (self->priv->atom_transient_for) {
- self->priv->atom_transient_for = XInternAtom(dpy, "WM_TRANSIENT_FOR", False);
+ if (self->priv->atoms[0] == None) {
+ static const char *atom_names[] = {
+ ATOM_TOPMENU_WINDOW,
+ ATOM_TOPMENU_BACKGROUND_CHANGE,
+ "WM_TRANSIENT_FOR",
+ NULL
+ };
+ if (!XInternAtoms(dpy, (char**) atom_names, N_ATOMS, False, self->priv->atoms)) {
+ g_warning("Could not intern all atoms");
+ }
}
// Start by checking the active window
@@ -360,9 +407,7 @@ static void topmenu_widget_set_followed_window(TopMenuWidget *self, Window windo
static void handle_socket_realize(GtkSocket *socket, TopMenuWidget *self)
{
- // Workaround a "bug workaround" where GtkSocket will not select ButtonPress
- // events
- g_warn_if_fail(gtk_widget_get_realized(GTK_WIDGET(socket)));
+ // GtkSocket does not select ButtonPress events
gtk_widget_add_events(GTK_WIDGET(socket),
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
}
@@ -374,6 +419,16 @@ static gboolean handle_socket_plug_removed(GtkSocket *socket, TopMenuWidget *sel
return TRUE; // Do not destroy the socket
}
+static void handle_background_changed(TopMenuBackground *background, TopMenuWidget *self)
+{
+ g_debug("background has changed");
+ topmenu_background_apply(background, GTK_WIDGET(self->socket));
+ Window cur = topmenu_widget_get_current_topmenu_window(self);
+ if (cur != None) {
+ topmenu_widget_send_background(self, cur);
+ }
+}
+
#ifdef HAVE_WNCK
static void handle_active_wnck_window_changed(WnckScreen *screen, WnckWindow *prev_window, TopMenuWidget *self)
{
@@ -410,8 +465,8 @@ static GdkFilterReturn handle_gdk_event(GdkXEvent *xevent, GdkEvent *event, gpoi
XEvent *e = (XEvent*) xevent;
if (e->type == PropertyNotify &&
- (e->xproperty.atom == self->priv->atom_transient_for ||
- e->xproperty.atom == self->priv->atom_window)) {
+ (e->xproperty.atom == self->priv->atoms[ATOM_TRANSIENT_FOR] ||
+ e->xproperty.atom == self->priv->atoms[ATOM_WINDOW])) {
// One of the properties we are interested in changed.
// See if it's one of the windows we're following.
if (g_queue_find(&self->priv->followed_windows,
@@ -480,7 +535,7 @@ static void topmenu_widget_size_request(GtkWidget *widget, GtkRequisition *requi
if (self->socket) {
gtk_widget_size_request(GTK_WIDGET(self->socket), requisition);
}
-}
+}
#endif
static void topmenu_widget_dispose(GObject *obj)
@@ -534,8 +589,9 @@ static void topmenu_widget_init(TopMenuWidget *self)
G_CALLBACK(handle_socket_realize), self);
g_signal_connect(self->socket, "plug-removed",
G_CALLBACK(handle_socket_plug_removed), self);
- self->priv->atom_window = None;
- self->priv->atom_transient_for = None;
+ self->background = topmenu_background_new();
+ g_signal_connect(self->background, "changed",
+ G_CALLBACK(handle_background_changed), self);
g_queue_init(&self->priv->followed_windows);
#ifdef HAVE_WNCK
self->priv->wnck_screen = wnck_screen_get_default();