[gnome-documents] presentation: Show a thumbnail for each display



commit a4a62a077542e794dcb32e82f3a180e425b44b41
Author: Debarshi Ray <debarshir gnome org>
Date:   Mon Sep 29 17:14:46 2014 +0200

    presentation: Show a thumbnail for each display
    
    Based on cc-display-panel.c from gnome-control-center.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=737580

 src/Makefile-lib.am          |    3 +
 src/lib/gd-display-preview.c |  250 ++++++++++++++++++++++++++++++++++++++++++
 src/lib/gd-display-preview.h |   47 ++++++++
 src/presentation.js          |   57 ++++------
 4 files changed, 320 insertions(+), 37 deletions(-)
---
diff --git a/src/Makefile-lib.am b/src/Makefile-lib.am
index 51347b5..33c14d5 100644
--- a/src/Makefile-lib.am
+++ b/src/Makefile-lib.am
@@ -14,6 +14,7 @@ gdprivate_source_h = \
     lib/gd-nav-bar.h \
     lib/gd-bookmark.h \
     lib/gd-bookmarks.h \
+    lib/gd-display-preview.h \
     lib/gd-places-page.h \
     lib/gd-places-bookmarks.h \
     lib/gd-places-links.h \
@@ -26,6 +27,7 @@ gdprivate_source_c = \
     lib/gd-nav-bar.c \
     lib/gd-bookmark.c \
     lib/gd-bookmarks.c \
+    lib/gd-display-preview.c \
     lib/gd-places-page.c \
     lib/gd-places-bookmarks.c \
     lib/gd-places-links.c \
@@ -59,6 +61,7 @@ GdPrivate_1_0_gir_CFLAGS = $(AM_CPPFLAGS) $(gdprivate_cflags)
 GdPrivate_1_0_gir_SCANNERFLAGS = --warn-all --symbol-prefix=gd --identifier-prefix=Gd
 GdPrivate_1_0_gir_INCLUDES = \
    GData-0.0 \
+   GnomeDesktop-3.0 \
    Goa-1.0 \
    Gtk-3.0 \
    EvinceDocument-3.0 \
diff --git a/src/lib/gd-display-preview.c b/src/lib/gd-display-preview.c
new file mode 100644
index 0000000..910f760
--- /dev/null
+++ b/src/lib/gd-display-preview.c
@@ -0,0 +1,250 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gd-display-preview.h"
+
+#include <glib.h>
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnome-desktop/gnome-rr.h>
+#include <libgnome-desktop/gnome-bg.h>
+
+struct _GdDisplayPreview {
+        GtkDrawingArea parent_instance;
+        GnomeRROutputInfo *info;
+        gboolean clone;
+        gint width;
+        gint height;
+};
+
+struct _GdDisplayPreviewClass {
+        GtkDrawingAreaClass parent_class;
+};
+
+G_DEFINE_TYPE (GdDisplayPreview, gd_display_preview, GTK_TYPE_DRAWING_AREA);
+
+#define TOP_BAR_HEIGHT 5
+#define DISPLAY_PREVIEW_LIST_HEIGHT  55
+
+enum {
+        PROP_CLONE = 1,
+        PROP_INFO,
+        NUM_PROPERTIES
+};
+
+static gboolean
+gd_display_preview_draw (GtkWidget *widget,
+                         cairo_t   *cr)
+{
+        GdDisplayPreview *self = GD_DISPLAY_PREVIEW (widget);
+        GdkPixbuf *pixbuf;
+        GnomeRRRotation rotation;
+        gboolean active;
+        gint allocated_height;
+        gint allocated_width;
+        gint height;
+        gint width;
+        gint x, y;
+
+        allocated_width = gtk_widget_get_allocated_width (widget);
+        allocated_height = gtk_widget_get_allocated_height (widget);
+        rotation = gnome_rr_output_info_get_rotation (self->info);
+
+        x = y = 0;
+        height = self->height;
+        width = self->width;
+
+        if ((rotation & GNOME_RR_ROTATION_90) || (rotation & GNOME_RR_ROTATION_270)) {
+                gint tmp;
+
+                /* swap width and height */
+                tmp = width;
+                width = height;
+                height = tmp;
+        }
+
+        /* scale to fit allocation */
+        if (width / (double) height < allocated_width / (double) allocated_height) {
+                width = allocated_height * (width / (double) height);
+                height = allocated_height;
+        } else {
+                height = allocated_width * (height / (double) width);
+                width = allocated_width;
+        }
+
+        x = (allocated_width / 2.0) - (width / 2.0);
+        cairo_set_source_rgb (cr, 0, 0, 0);
+        cairo_rectangle (cr, x, y, width, height);
+        cairo_fill (cr);
+
+        if (gnome_rr_output_info_is_active (self->info)) {
+                GdkScreen *screen;
+                GnomeBG *bg;
+                GnomeDesktopThumbnailFactory *factory;
+                GSettings *settings;
+
+                bg = gnome_bg_new ();
+                settings = g_settings_new ("org.gnome.desktop.background");
+                gnome_bg_load_from_preferences (bg, settings);
+
+                factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL);
+                screen = gdk_screen_get_default ();
+
+                pixbuf = gnome_bg_create_thumbnail (bg, factory, screen, width, height);
+
+                g_object_unref (factory);
+                g_object_unref (settings);
+                g_object_unref (bg);
+        } else {
+                pixbuf = NULL;
+        }
+
+        if (gnome_rr_output_info_get_primary (self->info) || self->clone) {
+                y += TOP_BAR_HEIGHT;
+                height -= TOP_BAR_HEIGHT;
+        }
+
+        if (pixbuf != NULL)
+                gdk_cairo_set_source_pixbuf (cr, pixbuf, x + 1, y + 1);
+        else
+                cairo_set_source_rgb (cr, 0.3, 0.3, 0.3);
+
+        cairo_rectangle (cr, x + 1, y + 1, width - 2, height - 2);
+        cairo_fill (cr);
+
+        g_clear_object (&pixbuf);
+
+        return GDK_EVENT_STOP;
+}
+
+static void
+gd_display_preview_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+        GdDisplayPreview *self = GD_DISPLAY_PREVIEW (object);
+
+        switch (prop_id) {
+        case PROP_CLONE:
+                self->clone = g_value_get_boolean (value);
+                break;
+        case PROP_INFO:
+                self->info = g_value_dup_object (value);
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+gd_display_preview_constructed (GObject *object)
+{
+        GdDisplayPreview *self = GD_DISPLAY_PREVIEW (object);
+        gint height;
+        gint width;
+
+        G_OBJECT_CLASS (gd_display_preview_parent_class)->constructed (object);
+
+        if (gnome_rr_output_info_is_active (self->info)) {
+                gnome_rr_output_info_get_geometry (self->info, NULL, NULL, &width, &height);
+        } else {
+                width = gnome_rr_output_info_get_preferred_width (self->info);
+                height = gnome_rr_output_info_get_preferred_height (self->info);
+        }
+
+        gtk_widget_set_size_request (GTK_WIDGET (self),
+                                     DISPLAY_PREVIEW_LIST_HEIGHT * (width / (gdouble) height),
+                                     DISPLAY_PREVIEW_LIST_HEIGHT);
+        self->height = height;
+        self->width = width;
+}
+
+static void
+gd_display_preview_dispose (GObject *object)
+{
+        GdDisplayPreview *self = GD_DISPLAY_PREVIEW (object);
+
+        g_clear_object (&self->info);
+
+        G_OBJECT_CLASS (gd_display_preview_parent_class)->dispose (object);
+}
+
+static void
+gd_display_preview_class_init (GdDisplayPreviewClass *class)
+{
+        GObjectClass *oclass = G_OBJECT_CLASS (class);
+        GtkWidgetClass *wclass = GTK_WIDGET_CLASS (class);
+
+        oclass->constructed = gd_display_preview_constructed;
+        oclass->dispose = gd_display_preview_dispose;
+        oclass->set_property = gd_display_preview_set_property;
+        wclass->draw = gd_display_preview_draw;
+
+        g_object_class_install_property (oclass,
+                                         PROP_CLONE,
+                                         g_param_spec_boolean ("clone",
+                                                               "Clone",
+                                                               "Whether this is part of a cloned 
configuration",
+                                                               FALSE,
+                                                               G_PARAM_CONSTRUCT_ONLY |
+                                                               G_PARAM_WRITABLE |
+                                                               G_PARAM_STATIC_STRINGS));
+
+        g_object_class_install_property (oclass,
+                                         PROP_INFO,
+                                         g_param_spec_object ("info",
+                                                              "GnomeRROutputInfo",
+                                                              "The info describing this display",
+                                                              GNOME_TYPE_RR_OUTPUT_INFO,
+                                                              G_PARAM_CONSTRUCT_ONLY |
+                                                              G_PARAM_WRITABLE |
+                                                              G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gd_display_preview_init (GdDisplayPreview *self)
+{
+}
+
+/**
+ * gd_display_preview_new:
+ * @info:
+ * @clone:
+ *
+ * Creates a new display preview widget.
+ *
+ * Returns: a new #GdDisplayPreview object.
+ **/
+GtkWidget *
+gd_display_preview_new (GnomeRROutputInfo *info,
+                        gboolean           clone)
+{
+        return g_object_new (GD_TYPE_DISPLAY_PREVIEW,
+                             "halign", GTK_ALIGN_CENTER,
+                             "valign", GTK_ALIGN_CENTER,
+                             "clone", clone,
+                             "info", info,
+                             NULL);
+}
diff --git a/src/lib/gd-display-preview.h b/src/lib/gd-display-preview.h
new file mode 100644
index 0000000..9399df2
--- /dev/null
+++ b/src/lib/gd-display-preview.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GD_DISPLAY_PREVIEW_H__
+#define __GD_DISPLAY_PREVIEW_H__
+
+#include <gtk/gtk.h>
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnome-desktop/gnome-rr-config.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdDisplayPreview GdDisplayPreview;
+typedef struct _GdDisplayPreviewClass GdDisplayPreviewClass;
+
+#define GD_TYPE_DISPLAY_PREVIEW            (gd_display_preview_get_type ())
+#define GD_DISPLAY_PREVIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), GD_TYPE_DISPLAY_PREVIEW, 
GdDisplayPreview))
+#define GD_DISPLAY_PREVIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),  GD_TYPE_DISPLAY_PREVIEW, 
GdDisplayPreviewClass))
+#define GD_IS_DISPLAY_PREVIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), GD_TYPE_DISPLAY_PREVIEW))
+#define GD_IS_DISPLAY_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),  GD_TYPE_DISPLAY_PREVIEW))
+#define GD_DISPLAY_PREVIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  GD_TYPE_DISPLAY_PREVIEW, 
GdDisplayPreviewClass))
+
+GType            gd_display_preview_get_type           (void) G_GNUC_CONST;
+
+GtkWidget       *gd_display_preview_new                (GnomeRROutputInfo *info,
+                                                        gboolean           clone);
+
+G_END_DECLS
+
+#endif /* __GD_DISPLAY_PREVIEW_H__ */
diff --git a/src/presentation.js b/src/presentation.js
index 1251ecf..20e5b93 100644
--- a/src/presentation.js
+++ b/src/presentation.js
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Red Hat, Inc.
+ * Copyright (c) 2013, 2014 Red Hat, Inc.
  *
  * Gnome Documents is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by the
@@ -72,7 +72,8 @@ const PresentationWindow = new Lang.Class({
     },
 
     setOutput: function(output) {
-        this.window.move(output.x, output.y);
+        let [x, y, width, height] = output.get_geometry();
+        this.window.move(x, y);
     },
 
     _createView: function() {
@@ -125,6 +126,8 @@ const PresentationOutputChooser = new Lang.Class({
     },
 
     _populateList: function() {
+        let sizeGroup = new Gtk.SizeGroup({ mode: Gtk.SizeGroupMode.HORIZONTAL });
+
         for (let i = 0; i < this._outputs.list.length; i++) {
             let row = new Gtk.Grid({ orientation: Gtk.Orientation.HORIZONTAL,
                                      column_spacing: 12,
@@ -132,10 +135,13 @@ const PresentationOutputChooser = new Lang.Class({
             this._box.add(row);
 
             let output = this._outputs.list[i];
-            let markup = '<b>' + output.display_name + '</b>';
-            let label = new Gtk.Label({ label: markup,
-                                        use_markup: true });
             row.output = output;
+
+            let preview = new GdPrivate.DisplayPreview({ info: output, clone: this._outputs.clone });
+            sizeGroup.add_widget(preview);
+            row.add(preview);
+
+            let label = new Gtk.Label({ label: output.get_display_name() });
             row.add(label);
 
             if (this._outputs.list.length > 1) {
@@ -144,9 +150,9 @@ const PresentationOutputChooser = new Lang.Class({
                 if (this._outputs.clone)
                     // Translators: "Mirrored" describes when both displays show the same view
                     status = _("Mirrored");
-                else if (output.is_primary)
+                else if (output.get_primary())
                     status = _("Primary");
-                else if (!output.is_active)
+                else if (!output.is_active())
                     status = _("Off");
                 else
                     status = _("Secondary");
@@ -195,19 +201,6 @@ const PresentationOutputChooser = new Lang.Class({
 });
 Signals.addSignalMethods(PresentationOutputChooser.prototype);
 
-const PresentationOutput = new Lang.Class({
-    Name: 'PresentationOutput',
-    _init: function() {
-        this.id = null;
-        this.name = null;
-        this.display_name = null;
-        this.is_active = false;
-        this.is_primary = false;
-        this.x = 0;
-        this.y = 0;
-    }
-});
-
 const PresentationOutputs = new Lang.Class({
     Name: 'PresentationOutputs',
 
@@ -220,6 +213,7 @@ const PresentationOutputs = new Lang.Class({
 
         this._config = GnomeDesktop.RRConfig.new_current(this._screen);
         this.clone = this._config.get_clone();
+        this._infos = this._config.get_outputs();
 
         this.load();
     },
@@ -229,27 +223,16 @@ const PresentationOutputs = new Lang.Class({
     },
 
     load: function() {
-        this._outputs = this._screen.list_outputs();
         this.list = [];
-        for (let idx in this._outputs) {
-            let output = this._outputs[idx];
-
-            let out = new PresentationOutput();
-            out.name = output.get_name();
-            out.display_name = output.get_display_name();
-            out.is_primary = output.get_is_primary();
-
-            if (output.get_crtc())
-                out.is_active = true;
-
-            let [x, y] = output.get_position();
-            out.x = x;
-            out.y = y;
+        for (let idx in this._infos) {
+            let info = this._infos[idx];
+            let name = info.get_name();
+            let output = this._screen.get_output_by_name(name);
 
             if (output.is_builtin_display())
-                this.list.unshift(out);
+                this.list.unshift(info);
             else
-                this.list.push(out);
+                this.list.push(info);
         }
     }
 });


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]