diff options
Diffstat (limited to 'libmate-desktop/mate-rr-labeler.c')
-rw-r--r-- | libmate-desktop/mate-rr-labeler.c | 135 |
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); |