aboutsummaryrefslogtreecommitdiff
path: root/libtopmenu-server
diff options
context:
space:
mode:
Diffstat (limited to 'libtopmenu-server')
-rw-r--r--libtopmenu-server/Makefile.am8
-rw-r--r--libtopmenu-server/topmenu-server.c20
-rw-r--r--libtopmenu-server/topmenu-widget.c92
-rw-r--r--libtopmenu-server/topmenu-widget.h7
4 files changed, 98 insertions, 29 deletions
diff --git a/libtopmenu-server/Makefile.am b/libtopmenu-server/Makefile.am
index b910248..7830b11 100644
--- a/libtopmenu-server/Makefile.am
+++ b/libtopmenu-server/Makefile.am
@@ -2,15 +2,15 @@ if GTK3
lib_LTLIBRARIES = libtopmenu-server-gtk3.la
libtopmenu_server_gtk3_la_SOURCES = topmenu-server.c topmenu-server.h topmenu-widget.c topmenu-widget.h
-libtopmenu_server_gtk3_la_CPPFLAGS = $(GTK_CFLAGS) $(WNCK3_CFLAGS) -DG_LOG_DOMAIN=\"topmenu-server\"
-libtopmenu_server_gtk3_la_LIBADD = $(GTK_LIBS) $(WNCK3_LIBS)
+libtopmenu_server_gtk3_la_CPPFLAGS = $(GTK_CFLAGS) $(WNCK3_CFLAGS) -I../libtopmenu-common -DG_LOG_DOMAIN=\"topmenu-server\"
+libtopmenu_server_gtk3_la_LIBADD = $(GTK_LIBS) $(WNCK3_LIBS) ../libtopmenu-common/libtopmenu-common-gtk3.la
else
lib_LTLIBRARIES = libtopmenu-server-gtk2.la
libtopmenu_server_gtk2_la_SOURCES = topmenu-server.c topmenu-server.h topmenu-widget.c topmenu-widget.h
-libtopmenu_server_gtk2_la_CPPFLAGS = $(GTK_CFLAGS) $(WNCK1_CFLAGS) $(MATEWNCK_CFLAGS) -DG_LOG_DOMAIN=\"topmenu-server\"
-libtopmenu_server_gtk2_la_LIBADD = $(GTK_LIBS) $(WNCK1_LIBS) $(MATEWNCK_LIBS)
+libtopmenu_server_gtk2_la_CPPFLAGS = $(GTK_CFLAGS) $(WNCK1_CFLAGS) $(MATEWNCK_CFLAGS) -I../libtopmenu-common -DG_LOG_DOMAIN=\"topmenu-server\"
+libtopmenu_server_gtk2_la_LIBADD = $(GTK_LIBS) $(WNCK1_LIBS) $(MATEWNCK_LIBS) ../libtopmenu-common/libtopmenu-common-gtk2.la
endif
diff --git a/libtopmenu-server/topmenu-server.c b/libtopmenu-server/topmenu-server.c
index 1e94398..7e5f3f7 100644
--- a/libtopmenu-server/topmenu-server.c
+++ b/libtopmenu-server/topmenu-server.c
@@ -17,21 +17,29 @@
* along with TopMenu. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <math.h>
+#include <string.h>
+#include <X11/Xatom.h>
#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <cairo-xlib.h>
#include "topmenu-server.h"
#include "../global.h"
static GdkAtom selection_atom = GDK_NONE;
+static GdkAtom background_atom = GDK_NONE;
static GtkClipboard *selection_clipboard = NULL;
static GList *server_widgets = NULL;
+static G_DEFINE_QUARK(topmenu-server-stub, server_stub)
+
static void handle_selection_owner_change(GtkClipboard *clipboard, GdkEvent *event, gpointer user_data);
static void init_selection_monitor()
{
- if (!selection_clipboard || selection_atom == GDK_NONE) {
+ if (!selection_clipboard || selection_atom == GDK_NONE || background_atom == GDK_NONE) {
selection_atom = gdk_atom_intern_static_string(ATOM_TOPMENU_SERVER_SELECTION);
selection_clipboard = gtk_clipboard_get(selection_atom);
// Used to monitor the current owner of the server selection
@@ -45,7 +53,7 @@ static GdkWindow *get_front_server_stub()
{
if (server_widgets) {
GtkWidget *widget = server_widgets->data;
- gpointer data = g_object_get_data(G_OBJECT(widget), OBJECT_DATA_KEY_SERVER_STUB);
+ gpointer data = g_object_get_qdata(G_OBJECT(widget), server_stub_quark());
g_return_val_if_fail(data, NULL);
return GDK_WINDOW(data);
} else {
@@ -78,14 +86,14 @@ void topmenu_server_register_server_widget(GtkWidget *widget)
init_selection_monitor();
- g_return_if_fail(g_object_get_data(G_OBJECT(widget), OBJECT_DATA_KEY_SERVER_STUB) == NULL);
+ g_return_if_fail(g_object_get_qdata(G_OBJECT(widget), server_stub_quark()) == NULL);
GdkWindowAttr stub_attr = { 0 };
stub_attr.wclass = GDK_INPUT_ONLY;
stub_attr.override_redirect = TRUE;
GdkWindow *stub = gdk_window_new(window, &stub_attr, GDK_WA_NOREDIR);
- g_object_set_data_full(G_OBJECT(widget), OBJECT_DATA_KEY_SERVER_STUB, stub,
+ g_object_set_qdata_full(G_OBJECT(widget), server_stub_quark(), stub,
(GDestroyNotify) &gdk_window_destroy);
server_widgets = g_list_prepend(server_widgets, widget);
@@ -94,9 +102,9 @@ void topmenu_server_register_server_widget(GtkWidget *widget)
void topmenu_server_unregister_server_widget(GtkWidget *widget)
{
- g_return_if_fail(g_object_get_data(G_OBJECT(widget), OBJECT_DATA_KEY_SERVER_STUB) != NULL);
+ g_return_if_fail(g_object_get_qdata(G_OBJECT(widget), server_stub_quark()) != NULL);
server_widgets = g_list_remove_all(server_widgets, widget);
- gpointer data = g_object_steal_data(G_OBJECT(widget), OBJECT_DATA_KEY_SERVER_STUB);
+ gpointer data = g_object_steal_qdata(G_OBJECT(widget), server_stub_quark());
GdkWindow *stub = GDK_WINDOW(data);
gdk_window_destroy(stub);
}
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();
diff --git a/libtopmenu-server/topmenu-widget.h b/libtopmenu-server/topmenu-widget.h
index 7d9ee05..73663ad 100644
--- a/libtopmenu-server/topmenu-widget.h
+++ b/libtopmenu-server/topmenu-widget.h
@@ -26,6 +26,10 @@
#include <gtk/gtkx.h>
#endif
+#include <gdk/gdkx.h>
+
+#include <topmenu-background.h>
+
G_BEGIN_DECLS
#define TOPMENU_TYPE_WIDGET topmenu_widget_get_type()
@@ -46,6 +50,7 @@ struct _TopMenuWidget
TopMenuWidgetPrivate *priv;
GtkSocket *socket;
+ TopMenuBackground *background;
};
struct _TopMenuWidgetClass
@@ -53,7 +58,7 @@ struct _TopMenuWidgetClass
GtkBinClass parent_class;
};
-GType topmenu_widget_get_type(void);
+GType topmenu_widget_get_type(void) G_GNUC_CONST;
GtkWidget *topmenu_widget_new(void);