summaryrefslogtreecommitdiff
path: root/libmate-desktop/mate-rr-labeler.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmate-desktop/mate-rr-labeler.c')
-rw-r--r--libmate-desktop/mate-rr-labeler.c135
1 files changed, 132 insertions, 3 deletions
diff --git a/libmate-desktop/mate-rr-labeler.c b/libmate-desktop/mate-rr-labeler.c
index f19c2ce..c649f81 100644
--- a/libmate-desktop/mate-rr-labeler.c
+++ b/libmate-desktop/mate-rr-labeler.c
@@ -1,4 +1,6 @@
-/* mate-rr-labeler.c - Utility to label monitors to identify them
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * mate-rr-labeler.c - Utility to label monitors to identify them
* while they are being configured.
*
* Copyright 2008, Novell, Inc.
@@ -30,6 +32,12 @@
#include "libmateui/mate-rr-labeler.h"
#include <gtk/gtk.h>
+#include <X11/Xproto.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <gdk/gdkx.h>
+
struct _MateRRLabeler {
GObject parent;
@@ -39,6 +47,9 @@ struct _MateRRLabeler {
GdkColor *palette;
GtkWidget **windows;
+
+ GdkScreen *screen;
+ Atom workarea_atom;
};
struct _MateRRLabelerClass {
@@ -48,11 +59,105 @@ struct _MateRRLabelerClass {
G_DEFINE_TYPE (MateRRLabeler, mate_rr_labeler, G_TYPE_OBJECT);
static void mate_rr_labeler_finalize (GObject *object);
+static void create_label_windows (MateRRLabeler *labeler);
+
+static gboolean
+get_work_area (MateRRLabeler *labeler,
+ GdkRectangle *rect)
+{
+ Atom workarea;
+ Atom type;
+ Window win;
+ int format;
+ gulong num;
+ gulong leftovers;
+ gulong max_len = 4 * 32;
+ guchar *ret_workarea;
+ long *workareas;
+ int result;
+ int disp_screen;
+ Display *display;
+
+ display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (labeler->screen));
+ workarea = XInternAtom (display, "_NET_WORKAREA", True);
+
+ disp_screen = GDK_SCREEN_XNUMBER (labeler->screen);
+
+ /* Defaults in case of error */
+ rect->x = 0;
+ rect->y = 0;
+ rect->width = gdk_screen_get_width (labeler->screen);
+ rect->height = gdk_screen_get_height (labeler->screen);
+
+ if (workarea == None)
+ return FALSE;
+
+ win = XRootWindow (display, disp_screen);
+ result = XGetWindowProperty (display,
+ win,
+ workarea,
+ 0,
+ max_len,
+ False,
+ AnyPropertyType,
+ &type,
+ &format,
+ &num,
+ &leftovers,
+ &ret_workarea);
+
+ if (result != Success
+ || type == None
+ || format == 0
+ || leftovers
+ || num % 4) {
+ return FALSE;
+ }
+
+ workareas = (long *) ret_workarea;
+ rect->x = workareas[disp_screen * 4];
+ rect->y = workareas[disp_screen * 4 + 1];
+ rect->width = workareas[disp_screen * 4 + 2];
+ rect->height = workareas[disp_screen * 4 + 3];
+
+ XFree (ret_workarea);
+
+ return TRUE;
+}
+
+static GdkFilterReturn
+screen_xevent_filter (GdkXEvent *xevent,
+ GdkEvent *event,
+ MateRRLabeler *labeler)
+{
+ XEvent *xev;
+
+ xev = (XEvent *) xevent;
+
+ if (xev->type == PropertyNotify &&
+ xev->xproperty.atom == labeler->workarea_atom) {
+ /* update label positions */
+ mate_rr_labeler_hide (labeler);
+ create_label_windows (labeler);
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
static void
mate_rr_labeler_init (MateRRLabeler *labeler)
{
- /* nothing */
+ GdkWindow *gdkwindow;
+
+ labeler->workarea_atom = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
+ "_NET_WORKAREA",
+ True);
+
+ labeler->screen = gdk_screen_get_default ();
+ /* code is not really designed to handle multiple screens so *shrug* */
+ gdkwindow = gdk_screen_get_root_window (labeler->screen);
+ gdk_window_add_filter (gdkwindow, (GdkFilterFunc) screen_xevent_filter, labeler);
+ gdk_window_set_events (gdkwindow, gdk_window_get_events (gdkwindow) | GDK_PROPERTY_CHANGE_MASK);
}
static void
@@ -69,9 +174,13 @@ static void
mate_rr_labeler_finalize (GObject *object)
{
MateRRLabeler *labeler;
+ GdkWindow *gdkwindow;
labeler = MATE_RR_LABELER (object);
+ gdkwindow = gdk_screen_get_root_window (labeler->screen);
+ gdk_window_remove_filter (gdkwindow, (GdkFilterFunc) screen_xevent_filter, labeler);
+
/* We don't destroy the labeler->config (a MateRRConfig*) here; let our
* caller do that instead.
*/
@@ -185,6 +294,26 @@ label_window_expose_event_cb (GtkWidget *widget, GdkEventExpose *event, gpointer
return FALSE;
}
+static void
+position_window (MateRRLabeler *labeler,
+ GtkWidget *window,
+ int x,
+ int y)
+{
+ GdkRectangle workarea;
+ GdkRectangle monitor;
+ int monitor_num;
+
+ get_work_area (labeler, &workarea);
+ monitor_num = gdk_screen_get_monitor_at_point (labeler->screen, x, y);
+ gdk_screen_get_monitor_geometry (labeler->screen,
+ monitor_num,
+ &monitor);
+ gdk_rectangle_intersect (&monitor, &workarea, &workarea);
+
+ gtk_window_move (GTK_WINDOW (window), workarea.x, workarea.y);
+}
+
static GtkWidget *
create_label_window (MateRRLabeler *labeler, MateOutputInfo *output, GdkColor *color)
{
@@ -239,7 +368,7 @@ create_label_window (MateRRLabeler *labeler, MateOutputInfo *output, GdkColor *c
gtk_container_add (GTK_CONTAINER (window), widget);
/* Should we center this at the top edge of the monitor, instead of using the upper-left corner? */
- gtk_window_move (GTK_WINDOW (window), output->x, output->y);
+ position_window (labeler, window, output->x, output->y);
gtk_widget_show_all (window);