[gnome-shell-extensions/wip/window-list: 1/13] window-list: New extension
- From: Florian MÃllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell-extensions/wip/window-list: 1/13] window-list: New extension
- Date: Fri, 25 Jan 2013 02:14:07 +0000 (UTC)
commit f93e896ced8479384decb621f3fe8a1d3bc5de11
Author: Florian MÃllner <fmuellner gnome org>
Date: Fri Nov 9 22:43:30 2012 +0100
window-list: New extension
configure.ac | 5 +-
extensions/window-list/Makefile.am | 3 +
extensions/window-list/extension.js | 270 +++++++++++++++++++++++++++++++
extensions/window-list/metadata.json.in | 10 ++
extensions/window-list/stylesheet.css | 63 +++++++
5 files changed, 349 insertions(+), 2 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 536ba3d..9ac1e1a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -27,7 +27,7 @@ fi
AC_SUBST([SHELL_VERSION])
dnl keep this in alphabetic order
-CLASSIC_EXTENSIONS="apps-menu places-menu alternate-tab default-min-max launch-new-instance static-workspaces"
+CLASSIC_EXTENSIONS="apps-menu places-menu alternate-tab default-min-max launch-new-instance static-workspaces window-list"
DEFAULT_EXTENSIONS="$CLASSIC_EXTENSIONS alternative-status-menu drive-menu windowsNavigator workspace-indicator"
ALL_EXTENSIONS="$DEFAULT_EXTENSIONS auto-move-windows example native-window-placement systemMonitor user-theme xrandr-indicator"
AC_SUBST(CLASSIC_EXTENSIONS, [$CLASSIC_EXTENSIONS])
@@ -71,7 +71,7 @@ for e in $enable_extensions; do
[AC_MSG_WARN([gnome-desktop-3.0 not found, disabling xrandr-indicator])])
;;
dnl keep this in alphabetic order
- alternate-tab|alternative-status-menu|apps-menu|auto-move-windows|default-min-max|drive-menu|example|launch-new-instance|native-window-placement|places-menu|static-workspaces|user-theme|windowsNavigator|workspace-indicator)
+ alternate-tab|alternative-status-menu|apps-menu|auto-move-windows|default-min-max|drive-menu|example|launch-new-instance|native-window-placement|places-menu|static-workspaces|user-theme|window-list|windowsNavigator|workspace-indicator)
ENABLED_EXTENSIONS="$ENABLED_EXTENSIONS $e"
;;
*)
@@ -97,6 +97,7 @@ AC_CONFIG_FILES([
extensions/static-workspaces/Makefile
extensions/systemMonitor/Makefile
extensions/user-theme/Makefile
+ extensions/window-list/Makefile
extensions/windowsNavigator/Makefile
extensions/workspace-indicator/Makefile
extensions/xrandr-indicator/Makefile
diff --git a/extensions/window-list/Makefile.am b/extensions/window-list/Makefile.am
new file mode 100644
index 0000000..48a1028
--- /dev/null
+++ b/extensions/window-list/Makefile.am
@@ -0,0 +1,3 @@
+EXTENSION_ID = window-list
+
+include ../../extension.mk
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
new file mode 100644
index 0000000..c603628
--- /dev/null
+++ b/extensions/window-list/extension.js
@@ -0,0 +1,270 @@
+const Clutter = imports.gi.Clutter;
+const Meta = imports.gi.Meta;
+const St = imports.gi.St;
+
+const Lang = imports.lang;
+const Main = imports.ui.main;
+const MessageTray = imports.ui.messageTray;
+
+const WindowButton = new Lang.Class({
+ Name: 'WindowButton',
+
+ _init: function(metaWindow) {
+ this.metaWindow = metaWindow;
+
+ let box = new St.BoxLayout();
+ this.actor = new St.Button({ style_class: 'window-button',
+ child: box });
+ this.actor._delegate = this;
+
+ let textureCache = St.TextureCache.get_default();
+ let icon = textureCache.bind_pixbuf_property(this.metaWindow, "icon");
+ box.add(new St.Bin({ style_class: 'window-button-icon', child: icon }));
+
+ this._label = new St.Label({ text: metaWindow.title });
+ box.add(this._label);
+
+ this.actor.connect('clicked', Lang.bind(this, this._onClicked));
+ this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
+
+ this._switchWorkspaceId =
+ global.window_manager.connect('switch-workspace',
+ Lang.bind(this, this._updateVisibility));
+ this._updateVisibility();
+
+ this._notifyTitleId =
+ this.metaWindow.connect('notify::title',
+ Lang.bind(this, function() {
+ this._label.text = this.metaWindow.title;
+ }));
+ this._notifyMinimizedId =
+ this.metaWindow.connect('notify::minimized',
+ Lang.bind(this, this._updateStyle));
+ this._notifyFocusId =
+ global.display.connect('notify::focus-window',
+ Lang.bind(this, this._updateStyle));
+ this._updateStyle();
+ },
+
+ _onClicked: function() {
+ if (global.display.focus_window == this.metaWindow)
+ this.metaWindow.minimize();
+ else
+ this.metaWindow.activate(global.get_current_time());
+ },
+
+ _updateStyle: function() {
+ if (this.metaWindow.minimized)
+ this.actor.add_style_class_name('minimized');
+ else
+ this.actor.remove_style_class_name('minimized');
+
+ if (global.display.focus_window == this.metaWindow)
+ this.actor.add_style_class_name('focused');
+ else
+ this.actor.remove_style_class_name('focused');
+ },
+
+ _updateVisibility: function() {
+ let workspace = global.screen.get_active_workspace();
+ this.actor.visible = this.metaWindow.located_on_workspace(workspace);
+ },
+
+ _onDestroy: function() {
+ global.window_manager.disconnect(this._switchWorkspaceId);
+ this.metaWindow.disconnect(this._notifyTitleId);
+ this.metaWindow.disconnect(this._notifyMinimizedId);
+ global.display.disconnect(this._notifyFocusId);
+ }
+});
+
+
+const TrayButton = new Lang.Class({
+ Name: 'TrayButton',
+
+ _init: function() {
+ let icon = new St.Icon({ icon_name: 'dialog-information-symbolic',
+ style_class: 'system-status-icon' });
+ this.actor = new St.Button({ style_class: 'tray-button',
+ child: icon });
+ this.actor.set_x_align(Clutter.ActorAlign.END);
+ this.actor.set_x_expand(true);
+ this.actor.set_y_expand(true);
+
+ this.actor.connect('clicked', Lang.bind(this,
+ function() {
+ if (Main.messageTray._trayState == MessageTray.State.HIDDEN)
+ Main.messageTray.toggle();
+ }));
+ this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
+
+ this._trayItemCount = 0;
+ Main.messageTray.getSummaryItems().forEach(Lang.bind(this,
+ function(item) {
+ this._itemAdded(Main.messageTray, item);
+ }));
+ this._itemAddedId =
+ Main.messageTray.connect('summary-item-added',
+ Lang.bind(this, this._itemAdded));
+ this._updateVisibility();
+ },
+
+ _itemAdded: function(tray, item) {
+ item.source._windowListDestroyId = item.source.connect('destroy', Lang.bind(this, this._itemRemoved));
+ this._trayItemCount++;
+ this._updateVisibility();
+ },
+
+ _itemRemoved: function(item) {
+ item.disconnect(item._windowListDestroyId);
+ delete item._windowListDestroyId;
+ this._trayItemCount--;
+ this.actor.checked = false;
+ this._updateVisibility();
+ },
+
+ _updateVisibility: function() {
+ this.actor.visible = this._trayItemCount > 0;
+ },
+
+ _onDestroy: function() {
+ Main.messageTray.disconnect(this._itemAddedId);
+ }
+});
+
+
+const WindowList = new Lang.Class({
+ Name: 'WindowList',
+
+ _init: function() {
+ this.actor = new St.Widget({ name: 'panel',
+ reactive: true,
+ layout_manager: new Clutter.BinLayout()});
+ this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
+
+ this._windowList = new St.BoxLayout({ style_class: 'window-list',
+ x_align: Clutter.ActorAlign.START,
+ x_expand: true,
+ y_expand: true });
+ this.actor.add_actor(this._windowList);
+
+ this._trayButton = new TrayButton();
+ this.actor.add_actor(this._trayButton.actor);
+
+ Main.layoutManager.addChrome(this.actor, { affectsStruts: true,
+ trackFullscreen: true });
+
+ this._monitorsChangedId =
+ Main.layoutManager.connect('monitors-changed',
+ Lang.bind(this, this._updatePosition));
+ this._updatePosition();
+
+ this._nWorkspacesChangedId =
+ global.screen.connect('notify::n-workspaces',
+ Lang.bind(this, this._onWorkspacesChanged));
+ this._onWorkspacesChanged();
+
+ this._overviewShowingId =
+ Main.overview.connect('showing', Lang.bind(this, function() {
+ this.actor.hide();
+ }));
+
+ this._overviewHidingId =
+ Main.overview.connect('hiding', Lang.bind(this, function() {
+ this.actor.show();
+ }));
+
+ let windows = Meta.get_window_actors(global.screen);
+ for (let i = 0; i < windows.length; i++)
+ this._onWindowAdded(null, windows[i].metaWindow);
+ },
+
+ _updatePosition: function() {
+ let monitor = Main.layoutManager.primaryMonitor;
+ this.actor.width = monitor.width;
+ this.actor.set_position(monitor.x, monitor.y + monitor.height - this.actor.height);
+ },
+
+ _onWindowAdded: function(ws, win) {
+ let button = new WindowButton(win);
+ this._windowList.add(button.actor, { y_fill: true });
+ },
+
+ _onWindowRemoved: function(ws, win) {
+ let children = this._windowList.get_children();
+ for (let i = 0; i < children.length; i++) {
+ if (children[i]._delegate.metaWindow == win) {
+ children[i].destroy();
+ return;
+ }
+ }
+ },
+
+ _onWorkspacesChanged: function() {
+ let numWorkspaces = global.screen.n_workspaces;
+ for (let i = 0; i < numWorkspaces; i++) {
+ let workspace = global.screen.get_workspace_by_index(i);
+ if (workspace._windowAddedId)
+ workspace.disconnect(workspace._windowAddedId);
+ if (workspace._windowRemovedId)
+ workspace.disconnect(workspace._windowRemovedId);
+ workspace._windowAddedId =
+ workspace.connect('window-added',
+ Lang.bind(this, this._onWindowAdded));
+ workspace._windowRemovedId =
+ workspace.connect('window-removed',
+ Lang.bind(this, this._onWindowRemoved));
+ }
+ },
+
+ _onDestroy: function() {
+ Main.layoutManager.disconnect(this._monitorsChangedId);
+ this._monitorsChangedId = 0;
+
+ global.screen.disconnect(this._nWorkspacesChangedId);
+ this._nWorkspacesChangedId = 0;
+
+ Main.overview.disconnect(this._overviewShowingId);
+ Main.overview.disconnect(this._overviewHidingId);
+ }
+});
+
+let windowList;
+let injections = {};
+
+function init() {
+}
+
+function enable() {
+ windowList = new WindowList();
+
+ injections['_trayDwellTimeout'] = MessageTray.MessageTray.prototype._trayDwellTimeout;
+ MessageTray.MessageTray.prototype._trayDwellTimeout = function() {
+ return false;
+ };
+
+ injections['_tween'] = MessageTray.MessageTray.prototype._tween;
+ MessageTray.MessageTray.prototype._tween = function(actor, statevar, value, params) {
+ if (statevar == '_trayState' && !Main.overview.visible) {
+ let anchorY = windowList.actor.height;
+ actor.anchor_y = anchorY;
+ }
+ injections['_tween'].call(Main.messageTray, actor, statevar, value, params);
+ };
+ injections['_onTrayHidden'] = MessageTray.MessageTray.prototype._onTrayHidden;
+ MessageTray.MessageTray.prototype._onTrayHidden = function() {
+ this.actor.anchor_y = 0;
+ injections['_onTrayHidden'].call(Main.messageTray);
+ };
+}
+
+function disable() {
+ if (!windowList)
+ return;
+
+ windowList.actor.destroy();
+ windowList = null;
+
+ for (prop in injections)
+ MessageTray.MessageTray.prototype[prop] = injections[prop];
+}
diff --git a/extensions/window-list/metadata.json.in b/extensions/window-list/metadata.json.in
new file mode 100644
index 0000000..ebfaed6
--- /dev/null
+++ b/extensions/window-list/metadata.json.in
@@ -0,0 +1,10 @@
+{
+"extension-id": "@extension_id@",
+"uuid": "@uuid@",
+"settings-schema": "@gschemaname@",
+"gettext-domain": "@gettext_domain@",
+"name": "Window List",
+"description": "Display a window list at the bottom of the screen",
+"shell-version": [ "@shell_current@" ],
+"url": "@url@"
+}
diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css
new file mode 100644
index 0000000..dae184a
--- /dev/null
+++ b/extensions/window-list/stylesheet.css
@@ -0,0 +1,63 @@
+.window-list {
+ spacing: 2px;
+ font-size: 10pt;
+}
+
+.window-button {
+ padding: 1px;
+}
+
+.window-button:first-child:ltr {
+ padding-left: 2px;
+}
+
+.window-button:last-child:rtl {
+ padding-right: 2px;
+}
+
+.window-button > StWidget {
+ width: 250px;
+ color: #bbb;
+ background-color: black;
+ border-radius: 4px;
+ padding: 2px 6px;
+ box-shadow: inset 1px 1px 4px rgba(255,255,255,0.5);
+ text-shadow: 1px 1px 4px rgba(0,0,0,0.8);
+ spacing: 4px;
+}
+
+.window-button:hover > StWidget {
+ color: white;
+ background-color: #1f1f1f;
+}
+
+.window-button:active > StWidget {
+ box-shadow: inset 2px 2px 4px rgba(255,255,255,0.5);
+}
+
+.window-button.focused > StWidget {
+ color: white;
+ box-shadow: inset 1px 1px 4px rgba(255,255,255,0.7);
+}
+
+.window-button.focused:active > StWidget {
+ box-shadow: inset 2px 2px 4px rgba(255,255,255,0.7);
+}
+
+.window-button.minimized > StWidget {
+ color: #666;
+ box-shadow: inset -1px -1px 4px rgba(255,255,255,0.5);
+}
+
+.window-button.minimized:active > StWidget {
+ box-shadow: inset -2px -2px 4px rgba(255,255,255,0.5);
+}
+
+.window-button-icon {
+ width: 16px;
+ height: 16px;
+}
+
+.tray-button {
+ padding: 1px 1px 1px 4px;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]