aboutsummaryrefslogtreecommitdiff
path: root/libtopmenu-client
diff options
context:
space:
mode:
Diffstat (limited to 'libtopmenu-client')
-rw-r--r--libtopmenu-client/Makefile.am8
-rw-r--r--libtopmenu-client/topmenu-appmenubar.c86
-rw-r--r--libtopmenu-client/topmenu-appmenubar.h38
-rw-r--r--libtopmenu-client/topmenu-client.c113
-rw-r--r--libtopmenu-client/topmenu-client.h13
-rw-r--r--libtopmenu-client/topmenu-menubar-proxy.h44
-rw-r--r--libtopmenu-client/topmenu-monitor.c163
-rw-r--r--libtopmenu-client/topmenu-monitor.h39
8 files changed, 504 insertions, 0 deletions
diff --git a/libtopmenu-client/Makefile.am b/libtopmenu-client/Makefile.am
new file mode 100644
index 0000000..b57343b
--- /dev/null
+++ b/libtopmenu-client/Makefile.am
@@ -0,0 +1,8 @@
+lib_LTLIBRARIES = libtopmenu-client.la
+libtopmenu_client_la_SOURCES = topmenu-client.c topmenu-client.h \
+ topmenu-monitor.c topmenu-monitor.h \
+ topmenu-appmenubar.c topmenu-appmenubar.h
+libtopmenu_client_la_CPPFLAGS = $(GTK_CFLAGS) -DG_LOG_DOMAIN=\"topmenu-client\"
+libtopmenu_client_la_LIBADD = $(GTK_LIBS)
+
+include_HEADERS = topmenu-client.h topmenu-monitor.h topmenu-appmenubar.h
diff --git a/libtopmenu-client/topmenu-appmenubar.c b/libtopmenu-client/topmenu-appmenubar.c
new file mode 100644
index 0000000..7d94cf5
--- /dev/null
+++ b/libtopmenu-client/topmenu-appmenubar.c
@@ -0,0 +1,86 @@
+#include "topmenu-appmenubar.h"
+
+G_DEFINE_TYPE(TopMenuAppMenuBar, topmenu_app_menu_bar, GTK_TYPE_MENU_BAR)
+
+enum {
+ PROP_0,
+ PROP_APP_MENU,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL };
+
+static void topmenu_app_menu_bar_get_property(GObject *obj, guint property_id, GValue *value, GParamSpec *pspec)
+{
+ TopMenuAppMenuBar *self = TOPMENU_APP_MENU_BAR(obj);
+ switch (property_id) {
+ case PROP_APP_MENU:
+ g_value_set_object(value, topmenu_app_menu_bar_get_app_menu(self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
+ }
+}
+
+static void topmenu_app_menu_bar_set_property(GObject *obj, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+ TopMenuAppMenuBar *self = TOPMENU_APP_MENU_BAR(obj);
+ switch (property_id) {
+ case PROP_APP_MENU:
+ topmenu_app_menu_bar_set_app_menu(self, g_value_get_object(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
+ }
+}
+
+static void topmenu_app_menu_bar_class_init(TopMenuAppMenuBarClass *klass)
+{
+ GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+ obj_class->get_property = topmenu_app_menu_bar_get_property;
+ obj_class->set_property = topmenu_app_menu_bar_set_property;
+
+ properties[PROP_APP_MENU] = g_param_spec_object("app-menu",
+ "Application menu",
+ "The application menu (shown under the application name)",
+ GTK_TYPE_MENU,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
+
+ g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
+
+ gtk_rc_parse_string (
+ "style \"app-menubar-style\"\n"
+ "{\n"
+ " GtkMenuBar::shadow-type = none\n"
+ " GtkMenuBar::internal-padding = 0\n"
+ "}\n"
+ "class \"TopMenuAppMenuBar\" style \"app-menubar-style\"");
+}
+
+static void topmenu_app_menu_bar_init(TopMenuAppMenuBar *self)
+{
+ self->app_menu_item = GTK_MENU_ITEM(gtk_menu_item_new_with_label(g_get_application_name()));
+ GtkLabel *app_label = GTK_LABEL(gtk_bin_get_child(GTK_BIN(self->app_menu_item)));
+ PangoAttrList *app_label_attr = pango_attr_list_new();
+ pango_attr_list_insert(app_label_attr, pango_attr_weight_new(PANGO_WEIGHT_BOLD));
+ gtk_label_set_attributes(app_label, app_label_attr);
+ pango_attr_list_unref(app_label_attr);
+ gtk_widget_show(GTK_WIDGET(self->app_menu_item));
+
+ gtk_menu_shell_prepend(GTK_MENU_SHELL(self), GTK_WIDGET(self->app_menu_item));
+}
+
+TopMenuAppMenuBar *topmenu_app_menu_bar_new(void)
+{
+ return TOPMENU_APP_MENU_BAR(g_object_new(TOPMENU_TYPE_APP_MENU_BAR, NULL));
+}
+
+void topmenu_app_menu_bar_set_app_menu(TopMenuAppMenuBar *self, GtkWidget *menu)
+{
+ gtk_menu_item_set_submenu(self->app_menu_item, GTK_WIDGET(menu));
+}
+
+GtkWidget *topmenu_app_menu_bar_get_app_menu(TopMenuAppMenuBar *self)
+{
+ return gtk_menu_item_get_submenu(self->app_menu_item);
+}
diff --git a/libtopmenu-client/topmenu-appmenubar.h b/libtopmenu-client/topmenu-appmenubar.h
new file mode 100644
index 0000000..e2e1344
--- /dev/null
+++ b/libtopmenu-client/topmenu-appmenubar.h
@@ -0,0 +1,38 @@
+#ifndef _TOPMENU_APPMENUBAR_H_
+#define _TOPMENU_APPMENUBAR_H_
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define TOPMENU_TYPE_APP_MENU_BAR topmenu_app_menu_bar_get_type()
+#define TOPMENU_APP_MENU_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TOPMENU_TYPE_APP_MENU_BAR, TopMenuAppMenuBar))
+#define TOPMENU_IS_APP_MENU_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TOPMENU_TYPE_APP_MENU_BAR))
+#define TOPMENU_APP_MENU_BAR_CLASS(c) (G_TYPE_CHECK_CLASS_CAST((c), TOPMENU_TYPE_APP_MENU_BAR, TopMenuAppMenuBarClass))
+#define TOPMENU_IS_APP_MENU_BAR_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE((c), TOPMENU_TYPE_APP_MENU_BAR))
+#define TOPMENU_APP_MENU_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TOPMENU_TYPE_APP_MENU_BAR, TopMenuAppMenuBarClass))
+
+typedef struct _TopMenuAppMenuBar TopMenuAppMenuBar;
+typedef struct _TopMenuAppMenuBarClass TopMenuAppMenuBarClass;
+
+struct _TopMenuAppMenuBar
+{
+ GtkMenuBar parent_instance;
+ GtkMenuItem *app_menu_item;
+};
+
+struct _TopMenuAppMenuBarClass
+{
+ GtkMenuBarClass parent_class;
+};
+
+GType topmenu_app_menu_bar_get_type(void);
+
+TopMenuAppMenuBar *topmenu_app_menu_bar_new(void);
+
+void topmenu_app_menu_bar_set_app_menu(TopMenuAppMenuBar *self, GtkWidget *menu);
+GtkWidget *topmenu_app_menu_bar_get_app_menu(TopMenuAppMenuBar *self);
+
+G_END_DECLS
+
+#endif /* _TOPMENU_APP_MENU_BAR_H_ */
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)&gtk_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);
+}
diff --git a/libtopmenu-client/topmenu-client.h b/libtopmenu-client/topmenu-client.h
new file mode 100644
index 0000000..f65eb69
--- /dev/null
+++ b/libtopmenu-client/topmenu-client.h
@@ -0,0 +1,13 @@
+#ifndef _TOPMENU_CLIENT_H_
+#define _TOPMENU_CLIENT_H_
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void topmenu_client_connect_window_widget(GdkWindow *window, GtkWidget *widget);
+void topmenu_client_disconnect_window(GdkWindow *window);
+
+G_END_DECLS
+
+#endif
diff --git a/libtopmenu-client/topmenu-menubar-proxy.h b/libtopmenu-client/topmenu-menubar-proxy.h
new file mode 100644
index 0000000..e601e04
--- /dev/null
+++ b/libtopmenu-client/topmenu-menubar-proxy.h
@@ -0,0 +1,44 @@
+#ifndef _TOPMENU_MENUBAR_PROXY_H_
+#define _TOPMENU_MENUBAR_PROXY_H_
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define TOPMENU_TYPE_MENUBAR_PROXY topmenu_menubar_proxy_get_type()
+#define TOPMENU_MENUBAR_PROXY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TOPMENU_TYPE_MENUBAR_PROXY, TopMenuMenuBarProxy))
+#define TOPMENU_IS_MENUBAR_PROXY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TOPMENU_TYPE_MENUBAR_PROXY))
+#define TOPMENU_MENUBAR_PROXY_CLASS(c) (G_TYPE_CHECK_CLASS_CAST((c), TOPMENU_TYPE_MENUBAR_PROXY, TopMenuMenuBarProxyClass))
+#define TOPMENU_IS_MENUBAR_PROXY_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE((c), TOPMENU_TYPE_MENUBAR_PROXY))
+#define TOPMENU_MENUBAR_PROXY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TOPMENU_TYPE_MENUBAR_PROXY, TopMenuMenuBarProxyClass))
+
+typedef struct _TopMenuMenuBarProxy TopMenuMenuBarProxy;
+typedef struct _TopMenuMenuBarProxyClass TopMenuMenuBarProxyClass;
+typedef struct _TopMenuMenuBarProxyPrivate TopMenuMenuBarProxyPrivate;
+
+struct _TopMenuMenuBarProxy
+{
+ GtkMenuBar parent_instance;
+ TopMenuMenuBarProxyPrivate *priv;
+ GtkMenuItem *app_menu_item;
+ GtkMenu *app_menu;
+};
+
+struct _TopMenuMenuBarProxyClass
+{
+ GtkMenuBarClass parent_class;
+};
+
+GType topmenu_menubar_proxy_get_type(void);
+
+TopMenuMenuBarProxy *topmenu_menubar_proxy_new(void);
+
+void topmenu_menubar_proxy_add_menu(TopMenuMenuBarProxy *self, GtkMenuShell *shell);
+void topmenu_menubar_proxy_remove_menu(TopMenuMenuBarProxy *self, GtkMenuShell *shell);
+
+typedef enum _MenuItemRole MenuItemRole;
+void topmenu_menubar_proxy_add_app_menu_item(TopMenuMenuBarProxy *self, GtkMenuItem *item, MenuItemRole role);
+
+G_END_DECLS
+
+#endif /* _TOPMENU_MENUBAR_PROXY_H_ */
diff --git a/libtopmenu-client/topmenu-monitor.c b/libtopmenu-client/topmenu-monitor.c
new file mode 100644
index 0000000..abd7522
--- /dev/null
+++ b/libtopmenu-client/topmenu-monitor.c
@@ -0,0 +1,163 @@
+#include <X11/Xatom.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+#include "../global.h"
+
+#include "topmenu-monitor.h"
+
+struct _TopMenuMonitorPrivate
+{
+ GdkAtom atom_selection;
+ GtkClipboard *selection;
+ GdkWindow *cur_server;
+};
+
+enum {
+ PROP_0,
+ PROP_AVAILABLE,
+ N_PROPERTIES
+};
+
+G_DEFINE_TYPE(TopMenuMonitor, topmenu_monitor, G_TYPE_OBJECT)
+
+#define TOPMENU_MONITOR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), TOPMENU_TYPE_MONITOR, TopMenuMonitorPrivate))
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL };
+
+static void topmenu_monitor_update(TopMenuMonitor *self);
+
+static void handle_clipboard_owner_change(GtkClipboard *clipboard, GdkEvent *event, TopMenuMonitor *self)
+{
+ topmenu_monitor_update(self);
+}
+
+static GdkFilterReturn handle_cur_server_event(GdkXEvent *xevent, GdkEvent *event, gpointer data)
+{
+ XEvent *e = (XEvent*)xevent;
+ if (e->type == DestroyNotify) {
+ g_debug("Current server has been destroyed");
+ TopMenuMonitor *self = TOPMENU_MONITOR(data);
+ if (self->priv->cur_server &&
+ GDK_WINDOW_XWINDOW(self->priv->cur_server) == e->xdestroywindow.window) {
+ topmenu_monitor_update(self);
+ }
+ }
+ return GDK_FILTER_CONTINUE;
+}
+
+static void topmenu_monitor_set_cur_server(TopMenuMonitor *self, GdkWindow *window)
+{
+ if (self->priv->cur_server == window) {
+ // Nothing to do
+ return;
+ }
+ g_debug("Setting current server to 0x%lx", GDK_WINDOW_XWINDOW(window));
+ if (self->priv->cur_server) {
+ gdk_window_remove_filter(window, handle_cur_server_event, self);
+ gdk_window_unref(self->priv->cur_server);
+ self->priv->cur_server = 0;
+ }
+ if (window) {
+ gdk_window_set_events(window, gdk_window_get_events(window) | GDK_STRUCTURE_MASK);
+ gdk_window_add_filter(window, handle_cur_server_event, self);
+ self->priv->cur_server = window;
+ }
+ if (self->priv->cur_server && !self->available) {
+ // Signal availability
+ self->available = TRUE;
+ g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_AVAILABLE]);
+ } else if (!self->priv->cur_server && self->available) {
+ // Signal no availability
+ self->available = FALSE;
+ g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_AVAILABLE]);
+ }
+}
+
+static void topmenu_monitor_update(TopMenuMonitor *self)
+{
+ GdkScreen *screen = gdk_screen_get_default();
+ GdkDisplay *display = gdk_screen_get_display(screen);
+
+ Display *xdpy = GDK_DISPLAY_XDISPLAY(display);
+ Atom atom = gdk_x11_atom_to_xatom_for_display(display, self->priv->atom_selection);
+
+ Window xwin = XGetSelectionOwner(xdpy, atom);
+
+ if (xwin) {
+ GdkWindow *window = gdk_x11_window_foreign_new_for_display(display, xwin);
+ topmenu_monitor_set_cur_server(self, window);
+ } else {
+ topmenu_monitor_set_cur_server(self, NULL);
+ }
+}
+
+static void topmenu_monitor_get_property(GObject *obj, guint property_id, GValue *value, GParamSpec *pspec)
+{
+ TopMenuMonitor *self = TOPMENU_MONITOR(obj);
+ switch (property_id) {
+ case PROP_AVAILABLE:
+ g_value_set_boolean(value, self->available);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
+ }
+}
+
+static void topmenu_monitor_dispose(GObject *obj)
+{
+ TopMenuMonitor *self = TOPMENU_MONITOR(obj);
+ if (self->priv->cur_server) {
+ gdk_window_remove_filter(self->priv->cur_server,
+ handle_cur_server_event, self);
+ gdk_window_unref(self->priv->cur_server);
+ self->priv->cur_server = 0;
+ }
+ self->priv->selection = NULL;
+ G_OBJECT_CLASS(topmenu_monitor_parent_class)->dispose(obj);
+}
+
+static void topmenu_monitor_class_init(TopMenuMonitorClass *klass)
+{
+ GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+ obj_class->get_property = topmenu_monitor_get_property;
+ obj_class->dispose = topmenu_monitor_dispose;
+
+ properties[PROP_AVAILABLE] = g_param_spec_boolean("available",
+ "TopMenu's availability",
+ "Set to TRUE whether a TopMenu server is currently available",
+ FALSE,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
+ g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
+
+ g_type_class_add_private(klass, sizeof(TopMenuMonitorPrivate));
+}
+
+static void topmenu_monitor_init(TopMenuMonitor *self)
+{
+ self->priv = TOPMENU_MONITOR_GET_PRIVATE(self);
+ self->available = FALSE;
+
+ self->priv->atom_selection = gdk_atom_intern_static_string(ATOM_TOPMENU_SERVER_SELECTION);
+ self->priv->selection = gtk_clipboard_get(self->priv->atom_selection);
+ self->priv->cur_server = NULL;
+
+ g_signal_connect_object(self->priv->selection, "owner-change",
+ G_CALLBACK(handle_clipboard_owner_change), self, 0);
+
+ topmenu_monitor_update(self);
+}
+
+TopMenuMonitor * topmenu_monitor_get_instance()
+{
+ static TopMenuMonitor *instance = NULL;
+ if (!instance) {
+ instance = TOPMENU_MONITOR(g_object_new(TOPMENU_TYPE_MONITOR, NULL));
+ }
+ return instance;
+}
+
+gboolean topmenu_monitor_is_topmenu_available(TopMenuMonitor * self)
+{
+ return self->available;
+}
diff --git a/libtopmenu-client/topmenu-monitor.h b/libtopmenu-client/topmenu-monitor.h
new file mode 100644
index 0000000..afd066c
--- /dev/null
+++ b/libtopmenu-client/topmenu-monitor.h
@@ -0,0 +1,39 @@
+#ifndef _TOPMENU_MONITOR_H_
+#define _TOPMENU_MONITOR_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define TOPMENU_TYPE_MONITOR topmenu_monitor_get_type()
+#define TOPMENU_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TOPMENU_TYPE_MONITOR, TopMenuMonitor))
+#define TOPMENU_IS_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TOPMENU_TYPE_MONITOR))
+#define TOPMENU_MONITOR_CLASS(c) (G_TYPE_CHECK_CLASS_CAST((c), TOPMENU_TYPE_MONITOR, TopMenuMonitorClass))
+#define TOPMENU_IS_MONITOR_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE((c), TOPMENU_TYPE_MONITOR))
+#define TOPMENU_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TOPMENU_TYPE_MONITOR, TopMenuMonitorClass))
+
+typedef struct _TopMenuMonitor TopMenuMonitor;
+typedef struct _TopMenuMonitorClass TopMenuMonitorClass;
+typedef struct _TopMenuMonitorPrivate TopMenuMonitorPrivate;
+
+struct _TopMenuMonitor
+{
+ GObject parent_instance;
+ TopMenuMonitorPrivate *priv;
+ gboolean available;
+};
+
+struct _TopMenuMonitorClass
+{
+ GObjectClass parent_class;
+};
+
+GType topmenu_monitor_get_type(void);
+
+TopMenuMonitor * topmenu_monitor_get_instance(void);
+
+gboolean topmenu_monitor_is_topmenu_available(TopMenuMonitor * self);
+
+G_END_DECLS
+
+#endif /* _TOPMENU_MONITOR_H_ */