[gnome-shell/wip/aggregate-menu: 53/55] Add a screencast indicator for when we're recording



commit f2b68e0586510dd2de67bc5ff2a9e20e09bdfd8f
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Wed Jul 17 15:26:06 2013 -0400

    Add a screencast indicator for when we're recording
    
    This will replace the indicator painted on the stage right now.
    
    This unfortunately does not work for the recorder triggered by the
    keybinding -- we'll simply replace the in-shell code with a keybinding
    powered by gnome-settings-daemon.

 data/theme/gnome-shell.css |    4 +
 js/Makefile.am             |    1 +
 js/ui/main.js              |    3 +
 js/ui/panel.js             |    2 +
 js/ui/screencast.js        |    9 +++
 js/ui/shellDBus.js         |    2 -
 js/ui/status/screencast.js |   26 ++++++++
 src/shell-recorder.c       |  140 +-------------------------------------------
 8 files changed, 47 insertions(+), 140 deletions(-)
---
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index cc974c7..805a214 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -646,6 +646,10 @@ StScrollBar StButton#vhandle:active {
     icon-size: 32px;
 }
 
+.screencast-indicator {
+    color: #ff0000;
+}
+
 /* Overview */
 
 #overview {
diff --git a/js/Makefile.am b/js/Makefile.am
index 11a1d5f..5eaa6a8 100644
--- a/js/Makefile.am
+++ b/js/Makefile.am
@@ -96,6 +96,7 @@ nobase_dist_js_DATA =         \
        ui/status/rfkill.js     \
        ui/status/volume.js     \
        ui/status/bluetooth.js  \
+       ui/status/screencast.js \
        ui/status/system.js     \
        ui/switcherPopup.js     \
        ui/tweener.js           \
diff --git a/js/ui/main.js b/js/ui/main.js
index 1bd61b7..92e770b 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -28,6 +28,7 @@ const LoginManager = imports.misc.loginManager;
 const LookingGlass = imports.ui.lookingGlass;
 const NotificationDaemon = imports.ui.notificationDaemon;
 const WindowAttentionHandler = imports.ui.windowAttentionHandler;
+const Screencast = imports.ui.screencast;
 const ScreenShield = imports.ui.screenShield;
 const Scripting = imports.ui.scripting;
 const SessionMode = imports.ui.sessionMode;
@@ -59,6 +60,7 @@ let sessionMode = null;
 let shellDBusService = null;
 let shellMountOpDBusService = null;
 let screenSaverDBus = null;
+let screencastService = null;
 let modalCount = 0;
 let keybindingMode = Shell.KeyBindingMode.NONE;
 let modalActorFocusStack = [];
@@ -151,6 +153,7 @@ function _initializeUI() {
     // working until it's updated.
     uiGroup = layoutManager.uiGroup;
 
+    screencastService = new Screencast.ScreencastService();
     xdndHandler = new XdndHandler.XdndHandler();
     ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
     osdWindow = new OsdWindow.OsdWindow();
diff --git a/js/ui/panel.js b/js/ui/panel.js
index eac083e..59d231b 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -865,7 +865,9 @@ const AggregateMenu = new Lang.Class({
         this._volume = new imports.ui.status.volume.Indicator();
         this._brightness = new imports.ui.status.brightness.Indicator();
         this._system = new imports.ui.status.system.Indicator();
+        this._screencast = new imports.ui.status.screencast.Indicator();
 
+        this._indicators.add_child(this._screencast.indicators);
         this._indicators.add_child(this._network.indicators);
         this._indicators.add_child(this._bluetooth.indicators);
         this._indicators.add_child(this._rfkill.indicators);
diff --git a/js/ui/screencast.js b/js/ui/screencast.js
index 307cab0..61dc692 100644
--- a/js/ui/screencast.js
+++ b/js/ui/screencast.js
@@ -4,6 +4,7 @@ const Gio = imports.gi.Gio;
 const GLib = imports.gi.GLib;
 const Lang = imports.lang;
 const Shell = imports.gi.Shell;
+const Signals = imports.signals;
 
 const Hash = imports.misc.hash;
 const Main = imports.ui.main;
@@ -44,6 +45,10 @@ const ScreencastService = new Lang.Class({
         Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
     },
 
+    get isRecording() {
+        return this._recorders.size() > 0;
+    },
+
     _ensureRecorderForSender: function(sender) {
         let recorder = this._recorders.get(sender);
         if (!recorder) {
@@ -52,6 +57,7 @@ const ScreencastService = new Lang.Class({
                 Gio.bus_watch_name(Gio.BusType.SESSION, sender, 0, null,
                                    Lang.bind(this, this._onNameVanished));
             this._recorders.set(sender, recorder);
+            this.emit('updated');
         }
         return recorder;
     },
@@ -62,6 +68,7 @@ const ScreencastService = new Lang.Class({
 
         for (let sender in this._recorders.keys())
             this._recorders.delete(sender);
+        this.emit('updated');
     },
 
     _onNameVanished: function(connection, name) {
@@ -76,6 +83,7 @@ const ScreencastService = new Lang.Class({
         Gio.bus_unwatch_name(recorder._watchNameId);
         recorder.close();
         this._recorders.delete(sender);
+        this.emit('updated');
 
         return true;
     },
@@ -137,3 +145,4 @@ const ScreencastService = new Lang.Class({
         invocation.return_value(GLib.Variant.new('(b)', [success]));
     }
 });
+Signals.addSignalMethods(ScreencastService.prototype);
diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js
index 0099978..78a9c5b 100644
--- a/js/ui/shellDBus.js
+++ b/js/ui/shellDBus.js
@@ -12,7 +12,6 @@ const ExtensionDownloader = imports.ui.extensionDownloader;
 const ExtensionUtils = imports.misc.extensionUtils;
 const Hash = imports.misc.hash;
 const Main = imports.ui.main;
-const Screencast = imports.ui.screencast;
 const Screenshot = imports.ui.screenshot;
 
 const GnomeShellIface = <interface name="org.gnome.Shell">
@@ -73,7 +72,6 @@ const GnomeShell = new Lang.Class({
         this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
 
         this._extensionsService = new GnomeShellExtensions();
-        this._screencastService = new Screencast.ScreencastService();
         this._screenshotService = new Screenshot.ScreenshotService();
 
         this._grabbedAccelerators = new Hash.Map();
diff --git a/js/ui/status/screencast.js b/js/ui/status/screencast.js
new file mode 100644
index 0000000..7a35ff0
--- /dev/null
+++ b/js/ui/status/screencast.js
@@ -0,0 +1,26 @@
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+
+const Lang = imports.lang;
+
+const Main = imports.ui.main;
+const PanelMenu = imports.ui.panelMenu;
+
+const Indicator = new Lang.Class({
+    Name: 'ScreencastIndicator',
+    Extends: PanelMenu.SystemIndicator,
+
+    _init: function() {
+        this.parent();
+
+        this._indicator = this._addIndicator();
+        this._indicator.icon_name = 'media-record-symbolic';
+        this._indicator.add_style_class_name('screencast-indicator');
+        this._sync();
+
+        Main.screencastService.connect('updated', Lang.bind(this, this._sync));
+    },
+
+    _sync: function() {
+        this._indicator.visible = Main.screencastService.isRecording;
+    },
+});
diff --git a/src/shell-recorder.c b/src/shell-recorder.c
index eb0d447..6b2bdfa 100644
--- a/src/shell-recorder.c
+++ b/src/shell-recorder.c
@@ -69,16 +69,12 @@ struct _ShellRecorder {
 
   int xinput_opcode;
 
-  CoglHandle recording_icon; /* icon shown while playing */
-
   GSettings *a11y_settings;
   gboolean draw_cursor;
   cairo_surface_t *cursor_image;
   int cursor_hot_x;
   int cursor_hot_y;
 
-  gboolean only_paint; /* Used to temporarily suppress recording */
-
   int framerate;
   char *pipeline_description;
   char *file_template;
@@ -170,57 +166,6 @@ G_DEFINE_TYPE(ShellRecorder, shell_recorder, G_TYPE_OBJECT);
  */
 #define DEFAULT_MEMORY_TARGET (512*1024)
 
-/* Create an emblem to show at the lower-left corner of the stage while
- * recording. The emblem is drawn *after* we record the frame so doesn't
- * show up in the frame.
- */
-static CoglHandle
-create_recording_icon (void)
-{
-  cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 32, 32);
-  cairo_t *cr;
-  cairo_pattern_t *pat;
-  CoglHandle texture;
-
-  cr = cairo_create (surface);
-
-  /* clear to transparent */
-  cairo_save (cr);
-  cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
-  cairo_paint (cr);
-  cairo_restore (cr);
-
-  /* radial "glow" */
-  pat = cairo_pattern_create_radial (16, 16, 6,
-                                     16, 16, 14);
-  cairo_pattern_add_color_stop_rgba (pat, 0.0,
-                                     1, 0, 0, 1); /* opaque red */
-  cairo_pattern_add_color_stop_rgba (pat, 1.0,
-                                     1, 0, 0, 0); /* transparent red */
-
-  cairo_set_source (cr, pat);
-  cairo_paint (cr);
-  cairo_pattern_destroy (pat);
-
-  /* red circle */
-  cairo_arc (cr, 16, 16, 8,
-             0, 2 * M_PI);
-  cairo_set_source_rgb (cr, 1, 0, 0);
-  cairo_fill (cr);
-
-  cairo_destroy (cr);
-
-  texture = cogl_texture_new_from_data (32, 32,
-                                        COGL_TEXTURE_NONE,
-                                        CLUTTER_CAIRO_FORMAT_ARGB32,
-                                        COGL_PIXEL_FORMAT_ANY,
-                                        cairo_image_surface_get_stride (surface),
-                                        cairo_image_surface_get_data (surface));
-  cairo_surface_destroy (surface);
-
-  return texture;
-}
-
 static guint
 get_memory_target (void)
 {
@@ -278,7 +223,6 @@ shell_recorder_init (ShellRecorder *recorder)
 
   recorder->gdk_screen = gdk_screen_get_default ();
 
-  recorder->recording_icon = create_recording_icon ();
   recorder->memory_target = get_memory_target();
 
   recorder->a11y_settings = g_settings_new (A11Y_APPS_SCHEMA);
@@ -303,8 +247,6 @@ shell_recorder_finalize (GObject  *object)
   recorder_set_pipeline (recorder, NULL);
   recorder_set_file_template (recorder, NULL);
 
-  cogl_handle_unref (recorder->recording_icon);
-
   g_clear_object (&recorder->a11y_settings);
 
   G_OBJECT_CLASS (shell_recorder_parent_class)->finalize (object);
@@ -340,20 +282,7 @@ recorder_update_memory_used (ShellRecorder *recorder,
     }
 
   if (memory_used != recorder->memory_used)
-    {
-      recorder->memory_used = memory_used;
-      if (repaint)
-        {
-          /* In other cases we just queue a redraw even if we only need
-           * to repaint and not redraw a frame, but having changes in
-           * memory usage cause frames to be painted and memory used
-           * seems like a bad idea.
-           */
-          recorder->only_paint = TRUE;
-          clutter_stage_ensure_redraw (recorder->stage);
-          recorder->only_paint = FALSE;
-        }
-    }
+    recorder->memory_used = memory_used;
 }
 
 /* Timeout used to avoid not drawing for more than MAXIMUM_PAUSE_TIME
@@ -475,56 +404,6 @@ recorder_draw_cursor (ShellRecorder *recorder,
   gst_buffer_unmap (buffer, &info);
 }
 
-/* Draw an overlay indicating how much of the target memory is used
- * for buffering frames.
- */
-static void
-recorder_draw_buffer_meter (ShellRecorder *recorder)
-{
-  int fill_level;
-  GdkRectangle primary_monitor;
-  float rects[16];
-
-  gdk_screen_get_monitor_workarea (recorder->gdk_screen,
-                                   gdk_screen_get_primary_monitor (recorder->gdk_screen),
-                                   &primary_monitor);
-
-  recorder_update_memory_used (recorder, FALSE);
-
-  /* As the buffer gets more full, we go from green, to yellow, to red */
-  if (recorder->memory_used > (recorder->memory_target * 3) / 4)
-    cogl_set_source_color4f (1, 0, 0, 1);
-  else if (recorder->memory_used > recorder->memory_target / 2)
-    cogl_set_source_color4f (1, 1, 0, 1);
-  else
-    cogl_set_source_color4f (0, 1, 0, 1);
-
-  fill_level = MIN (60, (recorder->memory_used * 60) / recorder->memory_target);
-
-  /* A hollow rectangle filled from the left to fill_level */
-  rects[0] = primary_monitor.x + primary_monitor.width - 64;
-  rects[1] = primary_monitor.y + primary_monitor.height - 10;
-  rects[2] = primary_monitor.x + primary_monitor.width - 2;
-  rects[3] = primary_monitor.y + primary_monitor.height - 9;
-
-  rects[4] = primary_monitor.x + primary_monitor.width - 64;
-  rects[5] = primary_monitor.y + primary_monitor.height - 9;
-  rects[6] = primary_monitor.x + primary_monitor.width - (63 - fill_level);
-  rects[7] = primary_monitor.y + primary_monitor.height - 3;
-
-  rects[8] = primary_monitor.x + primary_monitor.width - 3;
-  rects[9] = primary_monitor.y + primary_monitor.height - 9;
-  rects[10] = primary_monitor.x + primary_monitor.width - 2;
-  rects[11] = primary_monitor.y + primary_monitor.height - 3;
-
-  rects[12] = primary_monitor.x + primary_monitor.width - 64;
-  rects[13] = primary_monitor.y + primary_monitor.height - 3;
-  rects[14] = primary_monitor.x + primary_monitor.width - 2;
-  rects[15] = primary_monitor.y + primary_monitor.height - 2;
-
-  cogl_rectangles (rects, 4);
-}
-
 /* We want to time-stamp each frame based on the actual time it was
  * recorded. We probably should use the pipeline clock rather than
  * gettimeofday(): that would be needed to get sync'ed audio correct.
@@ -608,22 +487,7 @@ recorder_on_stage_paint (ClutterActor  *actor,
                          ShellRecorder *recorder)
 {
   if (recorder->state == RECORDER_STATE_RECORDING)
-    {
-      GdkRectangle primary_monitor;
-
-      gdk_screen_get_monitor_workarea (recorder->gdk_screen,
-                                       gdk_screen_get_primary_monitor (recorder->gdk_screen),
-                                       &primary_monitor);
-      if (!recorder->only_paint)
-        recorder_record_frame (recorder);
-
-      cogl_set_source_texture (recorder->recording_icon);
-      cogl_rectangle (primary_monitor.x + primary_monitor.width - 32, primary_monitor.y + 
primary_monitor.height - 42,
-                      primary_monitor.x + primary_monitor.width,      primary_monitor.y + 
primary_monitor.height - 10);
-    }
-
-  if (recorder->state == RECORDER_STATE_RECORDING || recorder->memory_used != 0)
-    recorder_draw_buffer_meter (recorder);
+    recorder_record_frame (recorder);
 }
 
 static void


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