diff options
Diffstat (limited to 'libmate-desktop/mate-rr-labeler.c')
-rw-r--r-- | libmate-desktop/mate-rr-labeler.c | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/libmate-desktop/mate-rr-labeler.c b/libmate-desktop/mate-rr-labeler.c new file mode 100644 index 0000000..fe9a50c --- /dev/null +++ b/libmate-desktop/mate-rr-labeler.c @@ -0,0 +1,317 @@ +/* mate-rr-labeler.c - Utility to label monitors to identify them + * while they are being configured. + * + * Copyright 2008, Novell, Inc. + * + * This file is part of the Mate Library. + * + * The Mate Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The Mate Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Mate Library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Federico Mena-Quintero <[email protected]> + */ + +#define MATE_DESKTOP_USE_UNSTABLE_API + +#include <config.h> +#include <glib/gi18n-lib.h> +#include "libmateui/mate-rr-labeler.h" +#include <gtk/gtk.h> + +struct _MateRRLabeler { + GObject parent; + + MateRRConfig *config; + + int num_outputs; + + GdkColor *palette; + GtkWidget **windows; +}; + +struct _MateRRLabelerClass { + GObjectClass parent_class; +}; + +G_DEFINE_TYPE (MateRRLabeler, mate_rr_labeler, G_TYPE_OBJECT); + +static void mate_rr_labeler_finalize (GObject *object); + +static void +mate_rr_labeler_init (MateRRLabeler *labeler) +{ + /* nothing */ +} + +static void +mate_rr_labeler_class_init (MateRRLabelerClass *class) +{ + GObjectClass *object_class; + + object_class = (GObjectClass *) class; + + object_class->finalize = mate_rr_labeler_finalize; +} + +static void +mate_rr_labeler_finalize (GObject *object) +{ + MateRRLabeler *labeler; + + labeler = MATE_RR_LABELER (object); + + /* We don't destroy the labeler->config (a MateRRConfig*) here; let our + * caller do that instead. + */ + + if (labeler->windows != NULL) { + mate_rr_labeler_hide (labeler); + g_free (labeler->windows); + labeler->windows = NULL; + } + + g_free (labeler->palette); + labeler->palette = NULL; + + G_OBJECT_CLASS (mate_rr_labeler_parent_class)->finalize (object); +} + +static int +count_outputs (MateRRConfig *config) +{ + int i; + + for (i = 0; config->outputs[i] != NULL; i++) + ; + + return i; +} + +static void +make_palette (MateRRLabeler *labeler) +{ + /* The idea is that we go around an hue color wheel. We want to start + * at red, go around to green/etc. and stop at blue --- because magenta + * is evil. Eeeeek, no magenta, please! + * + * Purple would be nice, though. Remember that we are watered down + * (i.e. low saturation), so that would be like Like berries with cream. + * Mmmmm, berries. + */ + double start_hue; + double end_hue; + int i; + + g_assert (labeler->num_outputs > 0); + + labeler->palette = g_new (GdkColor, labeler->num_outputs); + + start_hue = 0.0; /* red */ + end_hue = 2.0/3; /* blue */ + + for (i = 0; i < labeler->num_outputs; i++) { + double h, s, v; + double r, g, b; + + h = start_hue + (end_hue - start_hue) / labeler->num_outputs * i; + s = 1.0 / 3; + v = 1.0; + + gtk_hsv_to_rgb (h, s, v, &r, &g, &b); + + labeler->palette[i].red = (int) (65535 * r + 0.5); + labeler->palette[i].green = (int) (65535 * g + 0.5); + labeler->palette[i].blue = (int) (65535 * b + 0.5); + } +} + +#define LABEL_WINDOW_EDGE_THICKNESS 2 +#define LABEL_WINDOW_PADDING 12 + +static gboolean +label_window_expose_event_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data) +{ + cairo_t *cr; + GdkColor *color; + GtkAllocation allocation; + + color = g_object_get_data (G_OBJECT (widget), "color"); + gtk_widget_get_allocation (widget, &allocation); + + cr = gdk_cairo_create (gtk_widget_get_window (widget)); + + /* edge outline */ + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_rectangle (cr, + LABEL_WINDOW_EDGE_THICKNESS / 2.0, + LABEL_WINDOW_EDGE_THICKNESS / 2.0, + allocation.width - LABEL_WINDOW_EDGE_THICKNESS, + allocation.height - LABEL_WINDOW_EDGE_THICKNESS); + cairo_set_line_width (cr, LABEL_WINDOW_EDGE_THICKNESS); + cairo_stroke (cr); + + /* fill */ + + gdk_cairo_set_source_color (cr, color); + cairo_rectangle (cr, + LABEL_WINDOW_EDGE_THICKNESS, + LABEL_WINDOW_EDGE_THICKNESS, + allocation.width - LABEL_WINDOW_EDGE_THICKNESS * 2, + allocation.height - LABEL_WINDOW_EDGE_THICKNESS * 2); + cairo_fill (cr); + + cairo_destroy (cr); + + return FALSE; +} + +static GtkWidget * +create_label_window (MateRRLabeler *labeler, MateOutputInfo *output, GdkColor *color) +{ + GtkWidget *window; + GtkWidget *widget; + char *str; + const char *display_name; + GdkColor black = { 0, 0, 0, 0 }; + + window = gtk_window_new (GTK_WINDOW_POPUP); + gtk_widget_set_app_paintable (window, TRUE); + + gtk_container_set_border_width (GTK_CONTAINER (window), LABEL_WINDOW_PADDING + LABEL_WINDOW_EDGE_THICKNESS); + + /* This is semi-dangerous. The color is part of the labeler->palette + * array. Note that in mate_rr_labeler_finalize(), we are careful to + * free the palette only after we free the windows. + */ + g_object_set_data (G_OBJECT (window), "color", color); + + g_signal_connect (window, "expose-event", + G_CALLBACK (label_window_expose_event_cb), labeler); + + if (labeler->config->clone) { + /* Keep this string in sync with mate-control-center/capplets/display/xrandr-capplet.c:get_display_name() */ + + /* Translators: this is the feature where what you see on your laptop's + * screen is the same as your external monitor. Here, "Mirror" is being + * used as an adjective, not as a verb. For example, the Spanish + * translation could be "Pantallas en Espejo", *not* "Espejar Pantallas". + */ + display_name = _("Mirror Screens"); + } else + display_name = output->display_name; + + str = g_strdup_printf ("<b>%s</b>", display_name); + widget = gtk_label_new (NULL); + gtk_label_set_markup (GTK_LABEL (widget), str); + g_free (str); + + /* Make the label explicitly black. We don't want it to follow the + * theme's colors, since the label is always shown against a light + * pastel background. See bgo#556050 + */ + gtk_widget_modify_fg (widget, gtk_widget_get_state (widget), &black); + + 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); + + gtk_widget_show_all (window); + + return window; +} + +static void +create_label_windows (MateRRLabeler *labeler) +{ + int i; + gboolean created_window_for_clone; + + labeler->windows = g_new (GtkWidget *, labeler->num_outputs); + + created_window_for_clone = FALSE; + + for (i = 0; i < labeler->num_outputs; i++) { + if (!created_window_for_clone && labeler->config->outputs[i]->on) { + labeler->windows[i] = create_label_window (labeler, labeler->config->outputs[i], labeler->palette + i); + + if (labeler->config->clone) + created_window_for_clone = TRUE; + } else + labeler->windows[i] = NULL; + } +} + +static void +setup_from_config (MateRRLabeler *labeler) +{ + labeler->num_outputs = count_outputs (labeler->config); + + make_palette (labeler); + + create_label_windows (labeler); +} + +MateRRLabeler * +mate_rr_labeler_new (MateRRConfig *config) +{ + MateRRLabeler *labeler; + + g_return_val_if_fail (config != NULL, NULL); + + labeler = g_object_new (MATE_TYPE_RR_LABELER, NULL); + labeler->config = config; + + setup_from_config (labeler); + + return labeler; +} + +void +mate_rr_labeler_hide (MateRRLabeler *labeler) +{ + int i; + + g_return_if_fail (MATE_IS_RR_LABELER (labeler)); + + for (i = 0; i < labeler->num_outputs; i++) + if (labeler->windows[i] != NULL) { + gtk_widget_destroy (labeler->windows[i]); + labeler->windows[i] = NULL; + } +} + +void +mate_rr_labeler_get_color_for_output (MateRRLabeler *labeler, MateOutputInfo *output, GdkColor *color_out) +{ + int i; + + g_return_if_fail (MATE_IS_RR_LABELER (labeler)); + g_return_if_fail (output != NULL); + g_return_if_fail (color_out != NULL); + + for (i = 0; i < labeler->num_outputs; i++) + if (labeler->config->outputs[i] == output) { + *color_out = labeler->palette[i]; + return; + } + + g_warning ("trying to get the color for unknown MateOutputInfo %p; returning magenta!", output); + + color_out->red = 0xffff; + color_out->green = 0; + color_out->blue = 0xffff; +} |