[sushi/wip/cosimoc/no-clutter: 12/50] Don't use Clutter to render the texture



commit 52b839ebea465b4baaa02064ae72865b6c7f9c90
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Mon Apr 3 12:35:21 2017 -0700

    Don't use Clutter to render the texture
    
    This also changes the renderer interface to require a GtkWidget.
    All the renderers have been changed to return a widget.
    
    The image renderer uses a custom widget that allows us to have
    the desired scaling behavior while preserving aspect ratio.

 src/js/ui/fallbackRenderer.js |   4 +-
 src/js/ui/mainWindow.js       |  94 ++++++++++----------------------------
 src/js/ui/spinnerBox.js       |  35 +++------------
 src/js/viewers/audio.js       |   4 +-
 src/js/viewers/evince.js      |   6 +--
 src/js/viewers/font.js        |   7 +--
 src/js/viewers/html.js        |   6 +--
 src/js/viewers/image.js       | 102 ++++++++++++++++++++++++++++++++++++++----
 src/js/viewers/text.js        |   5 +--
 9 files changed, 130 insertions(+), 133 deletions(-)
---
diff --git a/src/js/ui/fallbackRenderer.js b/src/js/ui/fallbackRenderer.js
index 57243a3..9e9bfbe 100644
--- a/src/js/ui/fallbackRenderer.js
+++ b/src/js/ui/fallbackRenderer.js
@@ -97,14 +97,12 @@ var FallbackRenderer = new Lang.Class({
         this._applyLabels();
 
         this._box.show_all();
-        this._actor = new GtkClutter.Actor({ contents: this._box });
-        Utils.alphaGtkWidget(this._actor.get_widget());
 
         callback();
     },
 
     render : function() {
-        return this._actor;
+        return this._box;
     },
 
     _applyLabels : function() {
diff --git a/src/js/ui/mainWindow.js b/src/js/ui/mainWindow.js
index 6123274..a6f11d5 100644
--- a/src/js/ui/mainWindow.js
+++ b/src/js/ui/mainWindow.js
@@ -52,7 +52,7 @@ var MainWindow = new Lang.Class({
         this._isFullScreen = false;
         this._pendingRenderer = null;
         this._renderer = null;
-        this._texture = null;
+        this._view = null;
         this._toolbar = null;
         this._toolbarId = 0;
 
@@ -60,7 +60,6 @@ var MainWindow = new Lang.Class({
 
         this._application = args.application;
         this._createGtkWindow();
-        this._createClutterEmbed();
 
         this.file = null;
     },
@@ -89,29 +88,13 @@ var MainWindow = new Lang.Class({
         this._gtkWindow.connect('realize',
                                 Lang.bind(this, this._onRealize));
 
-        this._embed = new Gtk.Overlay();
-        this._gtkWindow.add(this._embed);
-    },
-
-    _createClutterEmbed : function() {
-        this._clutterEmbed = new GtkClutter.Embed();
-        this._embed.add(this._clutterEmbed);
-
-        this._clutterEmbed.set_receives_default(true);
-        this._clutterEmbed.set_can_default(true);
+        let eventBox = new Gtk.EventBox({ visible_window: false });
+        eventBox.connect('button-press-event',
+                         Lang.bind(this, this._onButtonPressEvent));
+        this._gtkWindow.add(eventBox);
 
-        this._stage = this._clutterEmbed.get_stage();
-        this._stage.set_use_alpha(true);
-        this._stage.set_opacity(0);
-        this._stage.set_color(new Clutter.Color({ red: 0,
-                                                  green: 0,
-                                                  blue: 0,
-                                                  alpha: 255 }));
-
-        this._stage.set_layout_manager(new Clutter.BinLayout());
-
-        this._stage.connect('button-press-event',
-                            Lang.bind(this, this._onButtonPressEvent));
+        this._embed = new Gtk.Overlay();
+        eventBox.add(this._embed);
     },
 
     /**************************************************************************
@@ -143,20 +126,14 @@ var MainWindow = new Lang.Class({
         return false;
     },
 
-    _onButtonPressEvent : function(actor, event) {
-        let stageWin = ClutterGdk.get_stage_window(this._stage);
-        let win_coords = event.get_coords();
-
-        if (event.get_source() == this._texture &&
-            !this._renderer.moveOnClick)
+    _onButtonPressEvent : function(window, event) {
+        if (!this._renderer.moveOnClick)
             return false;
 
-        let root_coords = stageWin.get_root_coords(win_coords[0],
-                                                   win_coords[1]);
-
-        this._gtkWindow.begin_move_drag(event.get_button(),
-                                        root_coords[0],
-                                        root_coords[1],
+        let [, rootX, rootY] = event.get_root_coords();
+        let [, button] = event.get_button();
+        this._gtkWindow.begin_move_drag(button,
+                                        rootX, rootY,
                                         event.get_time());
 
         return false;
@@ -200,27 +177,8 @@ var MainWindow = new Lang.Class({
     },
 
     _positionTexture : function() {
-        let yFactor = 0;
-
-        let textureSize = this._getTextureSize();
         let windowSize = this._getWindowSize();
 
-        if (textureSize[0] < Constants.VIEW_MIN &&
-            textureSize[1] < Constants.VIEW_MIN) {
-            yFactor = 0.52;
-        }
-
-        if (yFactor == 0) {
-            if (this._isFullScreen &&
-               (textureSize[0] > textureSize[1]))
-                yFactor = 0.52;
-            else
-                yFactor = 0.92;
-        }
-
-        this._texture.set_size(textureSize[0], textureSize[1]);
-        this._textureYAlign.factor = yFactor;
-
         if (this._lastWindowSize &&
             windowSize[0] == this._lastWindowSize[0] &&
             windowSize[1] == this._lastWindowSize[1])
@@ -275,28 +233,22 @@ var MainWindow = new Lang.Class({
         this._pendingRenderer = null;
 
         /* generate the texture and toolbar for the new renderer */
-        this._createTexture();
+        this._createView();
         this._createToolbar();
     },
 
-    _createTexture : function() {
-        if (this._texture) {
-            this._texture.destroy();
-            this._texture = null;
+    _createView : function() {
+        if (this._view) {
+            this._view.destroy();
+            this._view = null;
         }
 
-        this._texture = this._renderer.render();
-        this._textureYAlign =
-            new Clutter.AlignConstraint({ source: this._stage,
-                                          factor: 0.5,
-                                          align_axis: Clutter.AlignAxis.Y_AXIS });
-        this._texture.add_constraint(this._textureYAlign);
-        this._texture.add_constraint(
-            new Clutter.BindConstraint({ coordinate: Clutter.BindCoordinate.SIZE,
-                                         source: this._stage }));
+        this._view = this._renderer.render();
+        this._view.expand = true;
+        this._view.show();
 
+        this._embed.add(this._view);
         this.refreshSize();
-        this._stage.add_child(this._texture);
     },
 
     /**************************************************************************
@@ -386,7 +338,7 @@ var MainWindow = new Lang.Class({
     setFile : function(file) {
         this.file = file;
         this._createRenderer(file);
-        this._createTexture();
+        this._createView();
         this._createToolbar();
 
         this._gtkWindow.show_all();
diff --git a/src/js/ui/spinnerBox.js b/src/js/ui/spinnerBox.js
index 32c132e..2d2475f 100644
--- a/src/js/ui/spinnerBox.js
+++ b/src/js/ui/spinnerBox.js
@@ -26,9 +26,7 @@
 const Gettext = imports.gettext.domain('sushi');
 const _ = Gettext.gettext;
 const Gtk = imports.gi.Gtk;
-const GtkClutter = imports.gi.GtkClutter;
 
-const Tweener = imports.ui.tweener;
 const Lang = imports.lang;
 const Mainloop = imports.mainloop;
 
@@ -44,26 +42,20 @@ var SpinnerBox = new Lang.Class({
         this.canFullScreen = false;
         this.moveOnClick = true;
 
-        this._spinnerBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL,
-                                         spacing: 12 });
-        this._spinnerBox.show();
-
         this._spinner = new Gtk.Spinner();
-        this._spinner.show();
         this._spinner.set_size_request(SPINNER_SIZE, SPINNER_SIZE);
-        this._spinnerBox.pack_start(this._spinner, true, true, 0);
 
         this._label = new Gtk.Label();
         this._label.set_text(_("Loading…"));
-        this._label.show();
-        this._spinnerBox.pack_start(this._label, true, true, 0);
 
-        this.actor = new GtkClutter.Actor({ contents: this._spinnerBox });
-        this.actor.set_opacity(0);
+        this._spinnerBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL,
+                                         spacing: 12 });
+        this._spinnerBox.pack_start(this._spinner, true, true, 0);
+        this._spinnerBox.pack_start(this._label, true, true, 0);
     },
 
     render : function() {
-        return this.actor;
+        return this._spinnerBox;
     },
 
     getSizeForAllocation : function() {
@@ -88,24 +80,11 @@ var SpinnerBox = new Lang.Class({
             this._timeoutId = 0;
         }
 
-        Tweener.addTween(this.actor,
-                         { opacity: 0,
-                           time: 0.15,
-                           transition: 'easeOutQuad',
-                           onComplete: function() {
-                               this.actor.destroy();
-                           },
-                           onCompleteScope: this
-                         });
+        this._spinnerBox.destroy();
     },
 
     _onTimeoutCompleted : function() {
         this._timeoutId = 0;
-
-        Tweener.addTween(this.actor,
-                         { opacity: 255,
-                           time: 0.3,
-                           transition: 'easeOutQuad'
-                         });
+        this._spinnerBox.show_all();
     },
 });
diff --git a/src/js/viewers/audio.js b/src/js/viewers/audio.js
index 604b9f1..d6307ab 100644
--- a/src/js/viewers/audio.js
+++ b/src/js/viewers/audio.js
@@ -27,7 +27,6 @@ const GdkPixbuf = imports.gi.GdkPixbuf;
 const Gio = imports.gi.Gio;
 const Gst = imports.gi.Gst;
 const Gtk = imports.gi.Gtk;
-const GtkClutter = imports.gi.GtkClutter;
 const Sushi = imports.gi.Sushi;
 
 const Gettext = imports.gettext.domain('sushi');
@@ -80,13 +79,12 @@ const AudioRenderer = new Lang.Class({
         vbox.pack_start(this._albumLabel, false, false, 0);
 
         this._box.show_all();
-        this._actor = new GtkClutter.Actor({ contents: this._box });
 
         this._callback();
     },
 
     render : function() {
-        return this._actor;
+        return this._box;
     },
 
     _createPlayer : function(file) {
diff --git a/src/js/viewers/evince.js b/src/js/viewers/evince.js
index e1188d5..b93b8f8 100644
--- a/src/js/viewers/evince.js
+++ b/src/js/viewers/evince.js
@@ -26,7 +26,6 @@
 const EvDoc = imports.gi.EvinceDocument;
 const EvView = imports.gi.EvinceView;
 const Gtk = imports.gi.Gtk;
-const GtkClutter = imports.gi.GtkClutter;
 const Sushi = imports.gi.Sushi;
 
 const Gettext = imports.gettext.domain('sushi');
@@ -59,7 +58,7 @@ const EvinceRenderer = new Lang.Class({
     },
 
     render : function() {
-        return this._actor;
+        return this._scrolledWin;
     },
 
     _updatePageLabel : function() {
@@ -91,9 +90,6 @@ const EvinceRenderer = new Lang.Class({
         this._view.set_model(this._model);
         this._scrolledWin.add(this._view);
 
-        this._actor = new GtkClutter.Actor({ contents: this._scrolledWin });
-        this._actor.set_reactive(true);
-
         this._callback();
     },
 
diff --git a/src/js/viewers/font.js b/src/js/viewers/font.js
index 0f3426e..4871f76 100644
--- a/src/js/viewers/font.js
+++ b/src/js/viewers/font.js
@@ -24,11 +24,9 @@
  */
 
 const MimeHandler = imports.ui.mimeHandler;
-const Utils = imports.ui.utils;
 
 const Lang = imports.lang;
 
-const GtkClutter = imports.gi.GtkClutter;
 const Gtk = imports.gi.Gtk;
 const GLib = imports.gi.GLib;
 const Sushi = imports.gi.Sushi;
@@ -50,9 +48,6 @@ const FontRenderer = new Lang.Class({
         this._fontWidget.show();
         this._fontWidget.connect('loaded',
                                  Lang.bind(this, this._onFontLoaded));
-
-        this._fontActor = new GtkClutter.Actor({ contents: this._fontWidget });
-        Utils.alphaGtkWidget(this._fontActor.get_widget());
     },
 
     _onFontLoaded : function() {
@@ -60,7 +55,7 @@ const FontRenderer = new Lang.Class({
     },
 
     render : function() {
-        return this._fontActor;
+        return this._fontWidget;
     },
 
     getSizeForAllocation : function(allocation) {
diff --git a/src/js/viewers/html.js b/src/js/viewers/html.js
index cd70d4f..a26e4a3 100644
--- a/src/js/viewers/html.js
+++ b/src/js/viewers/html.js
@@ -23,7 +23,6 @@
  *
  */
 
-const GtkClutter = imports.gi.GtkClutter;
 const Gtk = imports.gi.Gtk;
 const GLib = imports.gi.GLib;
 const Lang = imports.lang;
@@ -55,14 +54,11 @@ const HTMLRenderer = new Lang.Class({
 
         this._webView.load_uri(file.get_uri());
 
-        this._actor = new GtkClutter.Actor({ contents: this._webView });
-        this._actor.set_reactive(true);
-
         this._callback();
     },
 
     render : function() {
-        return this._actor;
+        return this._webView;
     },
 
     getSizeForAllocation : function(allocation) {
diff --git a/src/js/viewers/image.js b/src/js/viewers/image.js
index 08dc97f..82b4ca5 100644
--- a/src/js/viewers/image.js
+++ b/src/js/viewers/image.js
@@ -23,10 +23,11 @@
  *
  */
 
+const Gdk = imports.gi.Gdk;
 const GdkPixbuf = imports.gi.GdkPixbuf;
-const GtkClutter = imports.gi.GtkClutter;
-const Gtk = imports.gi.Gtk;
 const GLib = imports.gi.GLib;
+const GObject = imports.gi.GObject;
+const Gtk = imports.gi.Gtk;
 
 const Gettext = imports.gettext.domain('sushi');
 const _ = Gettext.gettext;
@@ -36,6 +37,90 @@ const Mainloop = imports.mainloop;
 const MimeHandler = imports.ui.mimeHandler;
 const Utils = imports.ui.utils;
 
+const Image = new Lang.Class({
+    Name: 'Image',
+    Extends: Gtk.DrawingArea,
+    Properties: {
+        'pix': GObject.ParamSpec.object('pix', '', '',
+                                        GObject.ParamFlags.READWRITE,
+                                        GdkPixbuf.Pixbuf)
+    },
+
+    _init: function() {
+        this._pix = null;
+        this._scaledSurface = null;
+
+        this.parent();
+    },
+
+    _ensureScaledPix: function() {
+        let scaleFactor = this.get_scale_factor();
+        let width = this.get_allocated_width() * scaleFactor;
+        let height = this.get_allocated_height() * scaleFactor;
+
+        // Downscale original to fit, if necessary
+        let origWidth = this._pix.get_width();
+        let origHeight = this._pix.get_height();
+
+        let scaleX = width / origWidth;
+        let scaleY = height / origHeight;
+        let scale = Math.min(scaleX, scaleY);
+
+        let newWidth = Math.floor(origWidth * scale);
+        let newHeight = Math.floor(origHeight * scale);
+
+        let scaledWidth = this._scaledSurface ? this._scaledSurface.getWidth() : 0;
+        let scaledHeight = this._scaledSurface ? this._scaledSurface.getHeight() : 0;
+
+        if (newWidth != scaledWidth || newHeight != scaledHeight) {
+            let scaledPixbuf = this._pix.scale_simple(newWidth, newHeight,
+                                                      GdkPixbuf.InterpType.BILINEAR);
+            this._scaledSurface = Gdk.cairo_surface_create_from_pixbuf(scaledPixbuf,
+                                                                       scaleFactor,
+                                                                       this.get_window());
+        }
+    },
+
+    vfunc_get_preferred_width: function() {
+        return [1, this._pix ? this._pix.get_width() : 1];
+    },
+
+    vfunc_get_preferred_height: function() {
+        return [1, this._pix ? this._pix.get_height() : 1];
+    },
+
+    vfunc_size_allocate: function(allocation) {
+        this.parent(allocation);
+        this._ensureScaledPix();
+    },
+
+    vfunc_draw: function(context) {
+        if (!this._scaledSurface)
+            return false;
+
+        let width = this.get_allocated_width();
+        let height = this.get_allocated_height();
+
+        let scaleFactor = this.get_scale_factor();
+        let offsetX = (width - this._scaledSurface.getWidth() / scaleFactor) / 2;
+        let offsetY = (height - this._scaledSurface.getHeight() / scaleFactor) / 2;
+
+        context.setSourceSurface(this._scaledSurface, offsetX, offsetY);
+        context.paint();
+        return false;
+    },
+
+    set pix(p) {
+        this._pix = p;
+        this._scaledSurface = null;
+        this.queue_resize();
+    },
+
+    get pix() {
+        return this._pix;
+    }
+});
+
 const ImageRenderer = new Lang.Class({
     Name: 'ImageRenderer',
 
@@ -58,6 +143,8 @@ const ImageRenderer = new Lang.Class({
     },
 
     _createImageTexture : function(file) {
+        this._texture = new Image();
+
         file.read_async
         (GLib.PRIORITY_DEFAULT, null,
          Lang.bind(this,
@@ -79,9 +166,7 @@ const ImageRenderer = new Lang.Class({
 
              this._iter = anim.get_iter(null);
              let pix = this._iter.get_pixbuf().apply_embedded_orientation();
-
-             this._texture = new GtkClutter.Texture({ keep_aspect_ratio: true });
-             this._texture.set_from_pixbuf(pix);
+             this._texture.pix = pix;
 
              if (!anim.is_static_image())
                  this._startTimeout();
@@ -100,9 +185,10 @@ const ImageRenderer = new Lang.Class({
          }));
     },
 
-    getSizeForAllocation : function(allocation, fullScreen) {
-        let baseSize = this._texture.get_base_size();
-        return Utils.getScaledSize(baseSize, allocation, fullScreen);
+    getSizeForAllocation : function(allocation) {
+        let width = this._texture.pix.get_width();
+        let height = this._texture.pix.get_height();
+        return Utils.getScaledSize([width, height], allocation, false);
     },
 
     _startTimeout : function() {
diff --git a/src/js/viewers/text.js b/src/js/viewers/text.js
index 3a3cea6..1c0cd4a 100644
--- a/src/js/viewers/text.js
+++ b/src/js/viewers/text.js
@@ -26,7 +26,6 @@
 imports.gi.versions.GtkSource = '4';
 
 const Gdk = imports.gi.Gdk;
-const GtkClutter = imports.gi.GtkClutter;
 const Gtk = imports.gi.Gtk;
 const GLib = imports.gi.GLib;
 const GtkSource = imports.gi.GtkSource;
@@ -71,7 +70,7 @@ const TextRenderer = new Lang.Class({
     },
 
     render : function() {
-        return this._actor;
+        return this._scrolledWin;
     },
 
     _onBufferLoaded : function(loader, buffer) {
@@ -103,8 +102,6 @@ const TextRenderer = new Lang.Class({
         this._scrolledWin.add(this._view);
         this._scrolledWin.show_all();
 
-        this._actor = new GtkClutter.Actor({ contents: this._scrolledWin });
-        this._actor.set_reactive(true);
         this._callback();
     },
 


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