From 7b471645f489ff6e50247986386380c370f9a3bf Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Mon, 1 Dec 2008 19:51:43 +0000 Subject: [PATCH] Redo tabs => spaces indentation change to not lose manual indentation Revert most JS changes in commit: Fri Nov 28 20:12:20 2008 +0000 Convert all JS style to be uniform, add Eclipse settings bits Instead, just add 'indent-tabs-mode: nil' to the mode lines and convert tabs to spaces. The indentation no longer exactly matches the Eclipse settings, since they differ in some ways from the style we are trying to achieve. svn path=/trunk/; revision=97 --- js/ui/appdisplay.js | 605 +++++++++++++++++++------------------- js/ui/button.js | 174 +++++------ js/ui/main.js | 106 +++---- js/ui/overlay.js | 650 +++++++++++++++++++++-------------------- js/ui/panel.js | 198 ++++++------- js/ui/run_dialog.js | 183 ++++++------ js/ui/windowmanager.js | 178 +++++------ 7 files changed, 1049 insertions(+), 1045 deletions(-) diff --git a/js/ui/appdisplay.js b/js/ui/appdisplay.js index 5c38d4f82..176b6585c 100644 --- a/js/ui/appdisplay.js +++ b/js/ui/appdisplay.js @@ -1,4 +1,4 @@ -/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ const Signals = imports.signals; const Clutter = imports.gi.Clutter; @@ -10,31 +10,31 @@ const Tidy = imports.gi.Tidy; const Meta = imports.gi.Meta; const Shell = imports.gi.Shell; -//TODO - move this into GConf once we're not a plugin anymore -//but have taken over metacity -//This list is taken from GNOME Online popular applications -//http://online.gnome.org/applications -//but with nautilus removed +// TODO - move this into GConf once we're not a plugin anymore +// but have taken over metacity +// This list is taken from GNOME Online popular applications +// http://online.gnome.org/applications +// but with nautilus removed const DEFAULT_APPLICATIONS = [ - 'mozilla-firefox.desktop', - 'gnome-terminal.desktop', - 'evolution.desktop', - 'evince.desktop', - 'gedit.desktop', - 'mozilla-thunderbird.desktop', - 'totem.desktop', - 'gnome-file-roller.desktop', - 'rhythmbox.desktop', - 'epiphany.desktop', - 'xchat.desktop', - 'openoffice.org-1.9-writer.desktop', - 'emacs.desktop', - 'gnome-system-monitor.desktop', - 'openoffice.org-1.9-calc.desktop', - 'eclipse.desktop', - 'openoffice.org-1.9-impress.desktop', - 'vncviewer.desktop' - ]; + 'mozilla-firefox.desktop', + 'gnome-terminal.desktop', + 'evolution.desktop', + 'evince.desktop', + 'gedit.desktop', + 'mozilla-thunderbird.desktop', + 'totem.desktop', + 'gnome-file-roller.desktop', + 'rhythmbox.desktop', + 'epiphany.desktop', + 'xchat.desktop', + 'openoffice.org-1.9-writer.desktop', + 'emacs.desktop', + 'gnome-system-monitor.desktop', + 'openoffice.org-1.9-calc.desktop', + 'eclipse.desktop', + 'openoffice.org-1.9-impress.desktop', + 'vncviewer.desktop' +]; const APPDISPLAY_NAME_COLOR = new Clutter.Color(); APPDISPLAY_NAME_COLOR.from_pixel(0xffffffff); @@ -49,304 +49,305 @@ const APPDISPLAY_HEIGHT = 50; const APPDISPLAY_PADDING = 4; function AppDisplayItem(node, width) { - this._init(node, width); + this._init(node, width); } AppDisplayItem.prototype = { -_init: function(appinfo, width) { - let me = this; - this._appinfo = appinfo; + _init: function(appinfo, width) { + let me = this; + this._appinfo = appinfo; - let name = appinfo.get_name(); + let name = appinfo.get_name(); - let icontheme = Gtk.IconTheme.get_default(); + let icontheme = Gtk.IconTheme.get_default(); - this._group = new Clutter.Group({reactive: true, - width: width, - height: APPDISPLAY_HEIGHT}); - this._group.connect('button-press-event', function(group, e) { - me.emit('activate'); - return true; - }); - this._bg = new Clutter.Rectangle({ color: APPDISPLAY_BACKGROUND_COLOR, - x: 0, y: 0, width: width, height: APPDISPLAY_HEIGHT }); - this._group.add_actor(this._bg); + this._group = new Clutter.Group({reactive: true, + width: width, + height: APPDISPLAY_HEIGHT}); + this._group.connect('button-press-event', function(group, e) { + me.emit('activate'); + return true; + }); + this._bg = new Clutter.Rectangle({ color: APPDISPLAY_BACKGROUND_COLOR, + x: 0, y: 0, + width: width, height: APPDISPLAY_HEIGHT }); + this._group.add_actor(this._bg); - this._icon = new Clutter.Texture({ width: 48, height: 48, x: 0, y: 0 }); - let gicon = appinfo.get_icon(); - let path = null; - if (gicon != null) { - let iconinfo = icontheme.lookup_by_gicon(gicon, 48, Gtk.IconLookupFlags.NO_SVG); - if (iconinfo) - path = iconinfo.get_filename(); - } + this._icon = new Clutter.Texture({ width: 48, height: 48, x: 0, y: 0 }); + let gicon = appinfo.get_icon(); + let path = null; + if (gicon != null) { + let iconinfo = icontheme.lookup_by_gicon(gicon, 48, Gtk.IconLookupFlags.NO_SVG); + if (iconinfo) + path = iconinfo.get_filename(); + } - if (path) - this._icon.set_from_file(path); - this._group.add_actor(this._icon); + if (path) + this._icon.set_from_file(path); + this._group.add_actor(this._icon); + + let comment = appinfo.get_description(); + let text_width = width - me._icon.width + 4; + this._name = new Clutter.Label({ color: APPDISPLAY_NAME_COLOR, + font_name: "Sans 14px", + width: text_width, + ellipsize: Pango.EllipsizeMode.END, + text: name, + x: this._icon.width + 4, + y: 0}); + this._group.add_actor(this._name); + this._comment = new Clutter.Label({ color: APPDISPLAY_COMMENT_COLOR, + font_name: "Sans 12px", + width: text_width, + ellipsize: Pango.EllipsizeMode.END, + text: comment, + x: this._name.x, + y: this._name.height + 4}) + this._group.add_actor(this._comment); + this.actor = this._group; + }, + launch: function() { + this._appinfo.launch([], null); + }, + appinfo: function () { + return this._appinfo; + }, + markSelected: function(isSelected) { + let color; + if (isSelected) + color = APPDISPLAY_SELECTED_BACKGROUND_COLOR; + else + color = APPDISPLAY_BACKGROUND_COLOR; + this._bg.color = color; + } +}; - let comment = appinfo.get_description(); - let text_width = width - me._icon.width + 4; - this._name = new Clutter.Label({ color: APPDISPLAY_NAME_COLOR, - font_name: "Sans 14px", - width: text_width, - ellipsize: Pango.EllipsizeMode.END, - text: name, - x: this._icon.width + 4, - y: 0}); - this._group.add_actor(this._name); - this._comment = new Clutter.Label({ color: APPDISPLAY_COMMENT_COLOR, - font_name: "Sans 12px", - width: text_width, - ellipsize: Pango.EllipsizeMode.END, - text: comment, - x: this._name.x, - y: this._name.height + 4}) - this._group.add_actor(this._comment); - this.actor = this._group; -}, -launch: function() { - this._appinfo.launch([], null); -}, -appinfo: function () { - return this._appinfo; -}, -markSelected: function(isSelected) { - let color; - if (isSelected) - color = APPDISPLAY_SELECTED_BACKGROUND_COLOR; - else - color = APPDISPLAY_BACKGROUND_COLOR; - this._bg.color = color; -} -} Signals.addSignalMethods(AppDisplayItem.prototype); function AppDisplay(x, y, width, height) { - this._init(x, y, width, height); + this._init(x, y, width, height); } AppDisplay.prototype = { -_init : function(x, y, width, height) { - let me = this; - let global = Shell.Global.get(); - this._search = ''; - this._x = x; - this._y = y; - this._width = width; - this._height = height; - this._appmonitor = new Shell.AppMonitor(); - this._appsStale = true; - this._appmonitor.connect('changed', function(mon) { - me._appsStale = true; - }); - this._grid = new Tidy.Grid({x: x, y: y, width: width, height: height}); - global.stage.add_actor(this._grid); - this._appset = {}; // Map - this._displayed = {} // Map - this._selectedIndex = -1; - this._max_items = this._height / (APPDISPLAY_HEIGHT + APPDISPLAY_PADDING); -}, + _init : function(x, y, width, height) { + let me = this; + let global = Shell.Global.get(); + this._search = ''; + this._x = x; + this._y = y; + this._width = width; + this._height = height; + this._appmonitor = new Shell.AppMonitor(); + this._appsStale = true; + this._appmonitor.connect('changed', function(mon) { + me._appsStale = true; + }); + this._grid = new Tidy.Grid({x: x, y: y, width: width, height: height}); + global.stage.add_actor(this._grid); + this._appset = {}; // Map + this._displayed = {}; // Map + this._selectedIndex = -1; + this._max_items = this._height / (APPDISPLAY_HEIGHT + APPDISPLAY_PADDING); + }, -_refreshCache: function() { - let me = this; + _refreshCache: function() { + let me = this; - if (!this._appsStale) - return; - for (id in this._displayed) - this._displayed[id].destroy(); - this._appset = {}; - this._displayed = {}; - this._selectedIndex = -1; - let apps = Gio.app_info_get_all(); - for (let i = 0; i < apps.length; i++) { - let appinfo = apps[i]; - let appid = appinfo.get_id(); - this._appset[appid] = appinfo; - } - this._appsStale = false; -}, - -_removeItem: function(appid) { - let item = this._displayed[appid]; - let group = item.actor; - group.destroy(); - delete this._displayed[appid]; - -}, - -_removeAll: function() { - for (appid in this._displayed) - this._removeItem(appid); -}, - -_setDefaultList: function() { - this._removeAll(); - let added = 0; - for (let i = 0; i < DEFAULT_APPLICATIONS.length && added < this._max_items; i++) { - let appid = DEFAULT_APPLICATIONS[i]; - let appinfo = this._appset[appid]; - if (appinfo) { - this._filterAdd(appid); - added += 1; - } - } -}, - -_getNDisplayed: function() { - // Is there a better way to do .size() ? - let c = 0; for (i in this._displayed) { c += 1; }; - return c; -}, - -_filterAdd: function(appid) { - let me = this; - - let appinfo = this._appset[appid]; - let name = appinfo.get_name(); - let index = this._getNDisplayed(); - - let appdisplay = new AppDisplayItem(appinfo, this._width); - appdisplay.connect('activate', function() { - appdisplay.launch(); - me.emit('activated'); - }); - let group = appdisplay.actor; - this._grid.add_actor(group); - this._displayed[appid] = appdisplay; -}, - -_filterRemove: function(appid) { - // In the future, do some sort of fade out or other effect here - let item = this._displayed[appid]; - this._removeItem(item); -}, - -_appinfoMatches: function(appinfo, search) { - if (search == null || search == '') - return true; - let name = appinfo.get_name().toLowerCase(); - if (name.indexOf(search) >= 0) - return true; - let description = appinfo.get_description(); - if (description) { - description = description.toLowerCase(); - if (description.indexOf(search) >= 0) - return true; - } - let exec = appinfo.get_executable().toLowerCase(); - if (exec.indexOf(search) >= 0) - return true; - return false; -}, - -_sortApps: function(appids) { - let me = this; - return appids.sort(function (a,b) { - let appA = me._appset[a]; - let appB = me._appset[b]; - return appA.get_name().localeCompare(appB.get_name()); - }); -}, - -_doSearchFilter: function() { - this._removeAll(); - let matchedApps = []; - for (appid in this._appset) { - if (matchedApps.length >= this._max_items) - break; - if (this._displayed[appid]) - continue; - let app = this._appset[appid]; - if (this._appinfoMatches(app, this._search)) - matchedApps.push(appid); - } - this._sortApps(matchedApps); - for (let i = 0; i < matchedApps.length; i++) { - this._filterAdd(matchedApps[i]); - } -}, - -_redisplay: function() { - this._refreshCache(); - if (!this._search) - this._setDefaultList(); - else - this._doSearchFilter(); -}, - -setSearch: function(text) { - this._search = text.toLowerCase(); - this._redisplay(); -}, - -_findDisplayedByIndex: function(index) { - let displayedActors = this._grid.get_children(); - let actor = displayedActors[index]; - return this._findDisplayedByActor(actor); -}, - -_findDisplayedByActor: function(actor) { - for (appid in this._displayed) { - let item = this._displayed[appid]; - if (item.actor == actor) { - return item; + if (!this._appsStale) + return; + for (id in this._displayed) + this._displayed[id].destroy(); + this._appset = {}; + this._displayed = {}; + this._selectedIndex = -1; + let apps = Gio.app_info_get_all(); + for (let i = 0; i < apps.length; i++) { + let appinfo = apps[i]; + let appid = appinfo.get_id(); + this._appset[appid] = appinfo; } - } - return null; -}, + this._appsStale = false; + }, -searchActivate: function() { - if (this._selectedIndex != -1) { - let selected = this._findDisplayedByIndex(this._selectedIndex); - selected.launch(); + _removeItem: function(appid) { + let item = this._displayed[appid]; + let group = item.actor; + group.destroy(); + delete this._displayed[appid]; + }, + + _removeAll: function() { + for (appid in this._displayed) + this._removeItem(appid); + }, + + _setDefaultList: function() { + this._removeAll(); + let added = 0; + for (let i = 0; i < DEFAULT_APPLICATIONS.length && added < this._max_items; i++) { + let appid = DEFAULT_APPLICATIONS[i]; + let appinfo = this._appset[appid]; + if (appinfo) { + this._filterAdd(appid); + added += 1; + } + } + }, + + _getNDisplayed: function() { + // Is there a better way to do .size() ? + let c = 0; for (i in this._displayed) { c += 1; }; + return c; + }, + + _filterAdd: function(appid) { + let me = this; + + let appinfo = this._appset[appid]; + let name = appinfo.get_name(); + let index = this._getNDisplayed(); + + let appdisplay = new AppDisplayItem(appinfo, this._width); + appdisplay.connect('activate', function() { + appdisplay.launch(); + me.emit('activated'); + }); + let group = appdisplay.actor; + this._grid.add_actor(group); + this._displayed[appid] = appdisplay; + }, + + _filterRemove: function(appid) { + // In the future, do some sort of fade out or other effect here + let item = this._displayed[appid]; + this._removeItem(item); + }, + + _appinfoMatches: function(appinfo, search) { + if (search == null || search == '') + return true; + let name = appinfo.get_name().toLowerCase(); + if (name.indexOf(search) >= 0) + return true; + let description = appinfo.get_description(); + if (description) { + description = description.toLowerCase(); + if (description.indexOf(search) >= 0) + return true; + } + let exec = appinfo.get_executable().toLowerCase(); + if (exec.indexOf(search) >= 0) + return true; + return false; + }, + + _sortApps: function(appids) { + let me = this; + return appids.sort(function (a,b) { + let appA = me._appset[a]; + let appB = me._appset[b]; + return appA.get_name().localeCompare(appB.get_name()); + }); + }, + + _doSearchFilter: function() { + this._removeAll(); + let matchedApps = []; + for (appid in this._appset) { + if (matchedApps.length >= this._max_items) + break; + if (this._displayed[appid]) + continue; + let app = this._appset[appid]; + if (this._appinfoMatches(app, this._search)) + matchedApps.push(appid); + } + this._sortApps(matchedApps); + for (let i = 0; i < matchedApps.length; i++) { + this._filterAdd(matchedApps[i]); + } + }, + + _redisplay: function() { + this._refreshCache(); + if (!this._search) + this._setDefaultList(); + else + this._doSearchFilter(); + }, + + setSearch: function(text) { + this._search = text.toLowerCase(); + this._redisplay(); + }, + + _findDisplayedByIndex: function(index) { + let displayedActors = this._grid.get_children(); + let actor = displayedActors[index]; + return this._findDisplayedByActor(actor); + }, + + _findDisplayedByActor: function(actor) { + for (appid in this._displayed) { + let item = this._displayed[appid]; + if (item.actor == actor) { + return item; + } + } + return null; + }, + + searchActivate: function() { + if (this._selectedIndex != -1) { + let selected = this._findDisplayedByIndex(this._selectedIndex); + selected.launch(); + this.emit('activated'); + return; + } + let displayedActors = this._grid.get_children(); + if (displayedActors.length != 1) + return; + let selectedActor = displayedActors[0]; + let selectedMenuItem = this._findDisplayedByActor(selectedActor); + selectedMenuItem.launch(); this.emit('activated'); - return; - } - let displayedActors = this._grid.get_children(); - if (displayedActors.length != 1) - return; - let selectedActor = displayedActors[0]; - let selectedMenuItem = this._findDisplayedByActor(selectedActor); - selectedMenuItem.launch(); - this.emit('activated'); -}, + }, -_selectIndex: function(index) { - if (this._selectedIndex != -1) { - let prev = this._findDisplayedByIndex(this._selectedIndex); - log("demarking " + prev); - prev.markSelected(false); + _selectIndex: function(index) { + if (this._selectedIndex != -1) { + let prev = this._findDisplayedByIndex(this._selectedIndex); + log("demarking " + prev); + prev.markSelected(false); + } + this._selectedIndex = index; + let item = this._findDisplayedByIndex(index); + log("marking " + item); + item.markSelected(true); + }, + + selectUp: function() { + let prev = this._selectedIndex-1; + if (prev < 0) + return; + this._selectIndex(prev); + }, + + selectDown: function() { + let next = this._selectedIndex+1; + let nDisplayed = this._getNDisplayed(); + if (next >= nDisplayed) + return; + this._selectIndex(next); + }, + + show: function() { + this._redisplay(); + this._grid.show(); + }, + + hide: function() { + this._grid.hide(); } - this._selectedIndex = index; - let item = this._findDisplayedByIndex(index); - log("marking " + item); - item.markSelected(true); -}, +}; -selectUp: function() { - let prev = this._selectedIndex-1; - if (prev < 0) - return; - this._selectIndex(prev); -}, - -selectDown: function() { - let next = this._selectedIndex+1; - let nDisplayed = this._getNDisplayed(); - if (next >= nDisplayed) - return; - this._selectIndex(next); -}, - -show: function() { - this._redisplay(); - this._grid.show(); -}, - -hide: function() { - this._grid.hide(); -} -} Signals.addSignalMethods(AppDisplay.prototype); - diff --git a/js/ui/button.js b/js/ui/button.js index a56f0e2dc..7076ca024 100644 --- a/js/ui/button.js +++ b/js/ui/button.js @@ -1,4 +1,4 @@ -/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ const Clutter = imports.gi.Clutter; const Tweener = imports.tweener.tweener; @@ -9,7 +9,7 @@ DEFAULT_BUTTON_COLOR.from_pixel(0xeeddccff); const DEFAULT_PRESSED_BUTTON_COLOR = new Clutter.Color(); DEFAULT_PRESSED_BUTTON_COLOR.from_pixel(0xccbbaaff); -//Time for animation making the button darker +// Time for animation making the button darker const ANIMATION_TIME = 0.3; const NO_OPACITY = 0; @@ -23,95 +23,95 @@ function Button(text, buttonColor, pressedButtonColor, staysPressed, minWidth, m } Button.prototype = { -_init : function(text, buttonColor, pressedButtonColor, staysPressed, minWidth, minHeight) { - let me = this; - this._buttonColor = buttonColor - if (buttonColor == null) - this._buttonColor = DEFAULT_BUTTON_COLOR; + _init : function(text, buttonColor, pressedButtonColor, staysPressed, minWidth, minHeight) { + let me = this; - this._pressedButtonColor = pressedButtonColor - if (pressedButtonColor == null) - this._pressedButtonColor = DEFAULT_PRESSED_BUTTON_COLOR; + this._buttonColor = buttonColor + if (buttonColor == null) + this._buttonColor = DEFAULT_BUTTON_COLOR; - if (staysPressed == null) - staysPressed = false; - if (minWidth == null) - minWidth = 0; - if (minHeight == null) - minHeight = 0; + this._pressedButtonColor = pressedButtonColor + if (pressedButtonColor == null) + this._pressedButtonColor = DEFAULT_PRESSED_BUTTON_COLOR; - // if staysPressed is true, this.active will be true past the first release of a button, untill a subsequent one (the button - // is unpressed) or untill release() is called explicitly - this._active = false; - this._isBetweenPressAndRelease = false; - this._mouseIsOverButton = false; + if (staysPressed == null) + staysPressed = false; + if (minWidth == null) + minWidth = 0; + if (minHeight == null) + minHeight = 0; - this.button = new Clutter.Group({reactive: true}); - this._background = new Clutter.Rectangle({ color: this._buttonColor}); - this._pressedBackground = new Clutter.Rectangle({ color: this._pressedButtonColor, opacity: NO_OPACITY}); - this._label = new Clutter.Label({ font_name: "Sans Bold 16px", - text: text}); - this._label.set_position(5, 5); - let backgroundWidth = Math.max(this._label.get_width()+10, minWidth); - let backgroundHeight = Math.max(this._label.get_height()+10, minHeight); - this._background.set_width(backgroundWidth) - this._background.set_height(backgroundHeight) - this._pressedBackground.set_width(backgroundWidth) - this._pressedBackground.set_height(backgroundHeight) - this.button.add_actor(this._background); - this.button.add_actor(this._pressedBackground); - this.button.add_actor(this._label); - this.button.connect('button-press-event', - function(o, event) { - me._isBetweenPressAndRelease = true; - Tweener.addTween(me._pressedBackground, - { time: ANIMATION_TIME, - opacity: FULL_OPACITY, - transition: "linear" - }); - return false; - }); - this.button.connect('button-release-event', - function(o, event) { - me._isBetweenPressAndRelease = false; - if (!staysPressed || me._active) { - me.release(); - } else { - me._active = true; - } - return false; - }); - this.button.connect('enter-event', - function(o, event) { - me._mouseIsOverButton = true; - if (!me._active) { - Tweener.removeTweens(me._pressedBackground); - me._pressedBackground.set_opacity(PARTIAL_OPACITY); - } - return false; - }); - this.button.connect('leave-event', - function(o, event) { - me._isBetweenPressAndRelease = false; - me._mouseIsOverButton = false; - if (!me._active) { - Tweener.removeTweens(me._pressedBackground); - me._pressedBackground.set_opacity(NO_OPACITY); - } - return false; - }); -}, - -release : function() { - if (!this._isBetweenPressAndRelease) { + // if staysPressed is true, this.active will be true past the first release of a button, untill a subsequent one (the button + // is unpressed) or untill release() is called explicitly this._active = false; - Tweener.removeTweens(this._pressedBackground); - if (this._mouseIsOverButton) { - this._pressedBackground.set_opacity(PARTIAL_OPACITY); - } else { - this._pressedBackground.set_opacity(NO_OPACITY); + this._isBetweenPressAndRelease = false; + this._mouseIsOverButton = false; + + this.button = new Clutter.Group({reactive: true}); + this._background = new Clutter.Rectangle({ color: this._buttonColor}); + this._pressedBackground = new Clutter.Rectangle({ color: this._pressedButtonColor, opacity: NO_OPACITY}); + this._label = new Clutter.Label({ font_name: "Sans Bold 16px", + text: text}); + this._label.set_position(5, 5); + let backgroundWidth = Math.max(this._label.get_width()+10, minWidth); + let backgroundHeight = Math.max(this._label.get_height()+10, minHeight); + this._background.set_width(backgroundWidth) + this._background.set_height(backgroundHeight) + this._pressedBackground.set_width(backgroundWidth) + this._pressedBackground.set_height(backgroundHeight) + this.button.add_actor(this._background); + this.button.add_actor(this._pressedBackground); + this.button.add_actor(this._label); + this.button.connect('button-press-event', + function(o, event) { + me._isBetweenPressAndRelease = true; + Tweener.addTween(me._pressedBackground, + { time: ANIMATION_TIME, + opacity: FULL_OPACITY, + transition: "linear" + }); + return false; + }); + this.button.connect('button-release-event', + function(o, event) { + me._isBetweenPressAndRelease = false; + if (!staysPressed || me._active) { + me.release(); + } else { + me._active = true; + } + return false; + }); + this.button.connect('enter-event', + function(o, event) { + me._mouseIsOverButton = true; + if (!me._active) { + Tweener.removeTweens(me._pressedBackground); + me._pressedBackground.set_opacity(PARTIAL_OPACITY); + } + return false; + }); + this.button.connect('leave-event', + function(o, event) { + me._isBetweenPressAndRelease = false; + me._mouseIsOverButton = false; + if (!me._active) { + Tweener.removeTweens(me._pressedBackground); + me._pressedBackground.set_opacity(NO_OPACITY); + } + return false; + }); + }, + + release : function() { + if (!this._isBetweenPressAndRelease) { + this._active = false; + Tweener.removeTweens(this._pressedBackground); + if (this._mouseIsOverButton) { + this._pressedBackground.set_opacity(PARTIAL_OPACITY); + } else { + this._pressedBackground.set_opacity(NO_OPACITY); + } } } -} -} - +}; diff --git a/js/ui/main.js b/js/ui/main.js index dde716829..8928a1469 100644 --- a/js/ui/main.js +++ b/js/ui/main.js @@ -1,4 +1,4 @@ -/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ const Clutter = imports.gi.Clutter; const Shell = imports.gi.Shell; @@ -18,67 +18,67 @@ let overlay = null; let run_dialog = null; let wm = null; -//The "FrameTicker" object is an object used to feed new frames to Tweener -//so it can update values and redraw. The default frame ticker for -//Tweener just uses a simple timeout at a fixed frame rate and has no idea -//of "catching up" by dropping frames. - -//We substitute it with custom frame ticker here that connects Tweener to -//a Clutter.TimeLine. Now, Clutter.Timeline itself isn't a whole lot more -//sophisticated than a simple timeout at a fixed frame rate, but at least -//it knows how to drop frames. (See HippoAnimationManager for a more -//sophisticated view of continous time updates; even better is to pay -//attention to the vertical vblank and sync to that when possible.) - +// The "FrameTicker" object is an object used to feed new frames to Tweener +// so it can update values and redraw. The default frame ticker for +// Tweener just uses a simple timeout at a fixed frame rate and has no idea +// of "catching up" by dropping frames. +// +// We substitute it with custom frame ticker here that connects Tweener to +// a Clutter.TimeLine. Now, Clutter.Timeline itself isn't a whole lot more +// sophisticated than a simple timeout at a fixed frame rate, but at least +// it knows how to drop frames. (See HippoAnimationManager for a more +// sophisticated view of continous time updates; even better is to pay +// attention to the vertical vblank and sync to that when possible.) +// function ClutterFrameTicker() { this._init(); } ClutterFrameTicker.prototype = { -TARGET_FRAME_RATE : 60, + TARGET_FRAME_RATE : 60, -_init : function() { - // We don't have a finite duration; tweener will tell us to stop - // when we need to stop, so use 1000 seconds as "infinity" - this._timeline = new Clutter.Timeline({ fps: this.TARGET_FRAME_RATE, - duration: 1000*1000 }); - this._frame = 0; + _init : function() { + // We don't have a finite duration; tweener will tell us to stop + // when we need to stop, so use 1000 seconds as "infinity" + this._timeline = new Clutter.Timeline({ fps: this.TARGET_FRAME_RATE, + duration: 1000*1000 }); + this._frame = 0; - let me = this; - this._timeline.connect('new-frame', + let me = this; + this._timeline.connect('new-frame', function(timeline, frame) { - me._onNewFrame(frame); - }); -}, + me._onNewFrame(frame); + }); + }, -_onNewFrame : function(frame) { - // Unfortunately the interface to to send a new frame to tweener - // is a simple "next frame" and there is no provision for signaling - // that frames have been skipped or just telling it the new time. - // But what it actually does internally is just: - // - // _currentTime += 1000/_ticker.FRAME_RATE; - // - // So by dynamically adjusting the value of FRAME_RATE we can trick - // it into dealing with dropped frames. + _onNewFrame : function(frame) { + // Unfortunately the interface to to send a new frame to tweener + // is a simple "next frame" and there is no provision for signaling + // that frames have been skipped or just telling it the new time. + // But what it actually does internally is just: + // + // _currentTime += 1000/_ticker.FRAME_RATE; + // + // So by dynamically adjusting the value of FRAME_RATE we can trick + // it into dealing with dropped frames. - let delta = frame - this._frame; - if (delta == 0) - this.FRAME_RATE = this.TARGET_FRAME_RATE; - else - this.FRAME_RATE = this.TARGET_FRAME_RATE / delta; - this._frame = frame; - this.emit('prepare-frame'); -}, + let delta = frame - this._frame; + if (delta == 0) + this.FRAME_RATE = this.TARGET_FRAME_RATE; + else + this.FRAME_RATE = this.TARGET_FRAME_RATE / delta; + this._frame = frame; + this.emit('prepare-frame'); + }, -start : function() { - this._timeline.start(); -}, + start : function() { + this._timeline.start(); + }, -stop : function() { - this._timeline.stop(); - this._frame = 0; -} + stop : function() { + this._timeline.stop(); + this._frame = 0; + } }; Signals.addSignalMethods(ClutterFrameTicker.prototype); @@ -121,9 +121,9 @@ function start() { wm = new WindowManager.WindowManager(); } -//Used to go into a mode where all keyboard and mouse input goes to -//the stage. Returns true if we successfully grabbed the keyboard and -//went modal, false otherwise +// Used to go into a mode where all keyboard and mouse input goes to +// the stage. Returns true if we successfully grabbed the keyboard and +// went modal, false otherwise function startModal() { let global = Shell.Global.get(); diff --git a/js/ui/overlay.js b/js/ui/overlay.js index ee300cc3c..488cc5783 100644 --- a/js/ui/overlay.js +++ b/js/ui/overlay.js @@ -1,4 +1,4 @@ -/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ const Signals = imports.signals; const Mainloop = imports.mainloop; @@ -23,27 +23,27 @@ SIDESHOW_SEARCH_BG_COLOR.from_pixel(0xffffffff); const SIDESHOW_TEXT_COLOR = new Clutter.Color(); SIDESHOW_TEXT_COLOR.from_pixel(0xffffffff); -//Time for initial animation going into overlay mode +// Time for initial animation going into overlay mode const ANIMATION_TIME = 0.5; -//How much to scale the desktop down by in overlay mode +// How much to scale the desktop down by in overlay mode const DESKTOP_SCALE = 0.75; -//Windows are slightly translucent in the overlay mode +// Windows are slightly translucent in the overlay mode const WINDOW_OPACITY = 0.9 * 255; -//Define a layout scheme for small window counts. For larger -//counts we fall back to an algorithm. We need more schemes here -//unless we have a really good algorithm. - -//Each triplet is [xCenter, yCenter, scale] where the scale -//is relative to the width of the desktop. +// Define a layout scheme for small window counts. For larger +// counts we fall back to an algorithm. We need more schemes here +// unless we have a really good algorithm. +// +// Each triplet is [xCenter, yCenter, scale] where the scale +// is relative to the width of the desktop. const POSITIONS = { - 1: [[0.5, 0.5, 0.8]], - 2: [[0.25, 0.5, 0.4], [0.75, 0.5, 0.4]], - 3: [[0.25, 0.25, 0.33], [0.75, 0.25, 0.33], [0.5, 0.75, 0.33]], - 4: [[0.25, 0.25, 0.33], [0.75, 0.25, 0.33], [0.75, 0.75, 0.33], [0.25, 0.75, 0.33]], - 5: [[0.165, 0.25, 0.28], [0.495, 0.25, 0.28], [0.825, 0.25, 0.28], [0.25, 0.75, 0.4], [0.75, 0.75, 0.4]] + 1: [[0.5, 0.5, 0.8]], + 2: [[0.25, 0.5, 0.4], [0.75, 0.5, 0.4]], + 3: [[0.25, 0.25, 0.33], [0.75, 0.25, 0.33], [0.5, 0.75, 0.33]], + 4: [[0.25, 0.25, 0.33], [0.75, 0.25, 0.33], [0.75, 0.75, 0.33], [0.25, 0.75, 0.33]], + 5: [[0.165, 0.25, 0.28], [0.495, 0.25, 0.28], [0.825, 0.25, 0.28], [0.25, 0.75, 0.4], [0.75, 0.75, 0.4]] }; function Sideshow(width) { @@ -51,95 +51,95 @@ function Sideshow(width) { } Sideshow.prototype = { -_init : function(width) { - let me = this; + _init : function(width) { + let me = this; - let global = Shell.Global.get(); - this._group = new Clutter.Group(); - this._group.hide(); - global.stage.add_actor(this._group); - let icontheme = Gtk.IconTheme.get_default(); - let rect = new Clutter.Rectangle({ color: SIDESHOW_SEARCH_BG_COLOR, - x: SIDESHOW_PAD, - y: Panel.PANEL_HEIGHT + SIDESHOW_PAD, - width: width, - height: 24}); - this._group.add_actor(rect); + let global = Shell.Global.get(); + this._group = new Clutter.Group(); + this._group.hide(); + global.stage.add_actor(this._group); + let icontheme = Gtk.IconTheme.get_default(); + let rect = new Clutter.Rectangle({ color: SIDESHOW_SEARCH_BG_COLOR, + x: SIDESHOW_PAD, + y: Panel.PANEL_HEIGHT + SIDESHOW_PAD, + width: width, + height: 24}); + this._group.add_actor(rect); - let searchIconTexture = new Clutter.Texture({ x: SIDESHOW_PAD + 2, - y: rect.y + 2 }); - let searchIconPath = icontheme.lookup_icon('gtk-find', 16, 0).get_filename(); - searchIconTexture.set_from_file(searchIconPath); - this._group.add_actor(searchIconTexture); + let searchIconTexture = new Clutter.Texture({ x: SIDESHOW_PAD + 2, + y: rect.y + 2 }); + let searchIconPath = icontheme.lookup_icon('gtk-find', 16, 0).get_filename(); + searchIconTexture.set_from_file(searchIconPath); + this._group.add_actor(searchIconTexture); - this._searchEntry = new Clutter.Entry({ - font_name: "Sans 14px", - x: searchIconTexture.x - + searchIconTexture.width + 4, - y: searchIconTexture.y, - width: rect.width - (searchIconTexture.x), - height: searchIconTexture.height}); - this._group.add_actor(this._searchEntry); - global.stage.set_key_focus(this._searchEntry); - this._searchQueued = false; - this._searchActive = false; - this._searchEntry.connect('notify::text', function (se, prop) { - if (me._searchQueued) - return; - Mainloop.timeout_add(250, function() { - let text = me._searchEntry.text; - me._searchQueued = false; - me._searchActive = text != ''; - me._appdisplay.setSearch(text); + this._searchEntry = new Clutter.Entry({ + font_name: "Sans 14px", + x: searchIconTexture.x + + searchIconTexture.width + 4, + y: searchIconTexture.y, + width: rect.width - (searchIconTexture.x), + height: searchIconTexture.height}); + this._group.add_actor(this._searchEntry); + global.stage.set_key_focus(this._searchEntry); + this._searchQueued = false; + this._searchActive = false; + this._searchEntry.connect('notify::text', function (se, prop) { + if (me._searchQueued) + return; + Mainloop.timeout_add(250, function() { + let text = me._searchEntry.text; + me._searchQueued = false; + me._searchActive = text != ''; + me._appdisplay.setSearch(text); + return false; + }); + }); + this._searchEntry.connect('activate', function (se) { + if (!me._searchActive) + return false; + me._appdisplay.searchActivate(); + return true; + }); + this._searchEntry.connect('key-press-event', function (se, e) { + let code = e.get_code(); + log("code: " + code); + if (code == 111) { + me._appdisplay.selectUp(); + return true; + } else if (code == 116) { + me._appdisplay.selectDown(); + return true; + } return false; }); - }); - this._searchEntry.connect('activate', function (se) { - if (!me._searchActive) - return false; - me._appdisplay.searchActivate(); - return true; - }); - this._searchEntry.connect('key-press-event', function (se, e) { - let code = e.get_code(); - log("code: " + code); - if (code == 111) { - me._appdisplay.selectUp(); - return true; - } else if (code == 116) { - me._appdisplay.selectDown(); - return true; - } - return false; - }); - let appsText = new Clutter.Label({ color: SIDESHOW_TEXT_COLOR, - font_name: "Sans Bold 14px", - text: "Applications", - x: SIDESHOW_PAD, - y: this._searchEntry.y + this._searchEntry.height + 10, - height: 16}); - this._group.add_actor(appsText); + let appsText = new Clutter.Label({ color: SIDESHOW_TEXT_COLOR, + font_name: "Sans Bold 14px", + text: "Applications", + x: SIDESHOW_PAD, + y: this._searchEntry.y + this._searchEntry.height + 10, + height: 16}); + this._group.add_actor(appsText); - let menuY = appsText.y + appsText.height + 6; - this._appdisplay = new AppDisplay.AppDisplay(SIDESHOW_PAD, - menuY, width, global.screen_height - menuY); + let menuY = appsText.y + appsText.height + 6; + this._appdisplay = new AppDisplay.AppDisplay(SIDESHOW_PAD, + menuY, width, global.screen_height - menuY); - /* Proxy the activated signal */ - this._appdisplay.connect('activated', function(appdisplay) { - me.emit('activated'); - }); -}, + /* Proxy the activated signal */ + this._appdisplay.connect('activated', function(appdisplay) { + me.emit('activated'); + }); + }, -show: function() { - this._group.show(); - this._appdisplay.show(); -}, + show: function() { + this._group.show(); + this._appdisplay.show(); + }, -hide: function() { - this._group.hide(); - this._appdisplay.hide(); -} + hide: function() { + this._group.hide(); + this._appdisplay.hide(); + } }; Signals.addSignalMethods(Sideshow.prototype); @@ -148,252 +148,254 @@ function Overlay() { } Overlay.prototype = { -_init : function() { - let me = this; + _init : function() { + let me = this; - let global = Shell.Global.get(); + let global = Shell.Global.get(); - this._group = new Clutter.Group(); - this.visible = false; + this._group = new Clutter.Group(); + this.visible = false; - let background = new Clutter.Rectangle({ color: OVERLAY_BACKGROUND_COLOR, - reactive: true, - x: 0, - y: Panel.PANEL_HEIGHT, - width: global.screen_width, - height: global.screen_width - Panel.PANEL_HEIGHT }); - this._group.add_actor(background); + let background = new Clutter.Rectangle({ color: OVERLAY_BACKGROUND_COLOR, + reactive: true, + x: 0, + y: Panel.PANEL_HEIGHT, + width: global.screen_width, + height: global.screen_width - Panel.PANEL_HEIGHT }); + this._group.add_actor(background); - this._group.hide(); - global.overlay_group.add_actor(this._group); + this._group.hide(); + global.overlay_group.add_actor(this._group); this._windowClones = []; - // TODO - recalculate everything when desktop size changes - this._recalculateSize(); + // TODO - recalculate everything when desktop size changes + this._recalculateSize(); - this._sideshow = new Sideshow(this._desktopX - 10); - this._sideshow.connect('activated', function(sideshow) { - // TODO - have some sort of animation/effect while - // transitioning to the new app. We definitely need - // startup-notification integration at least. - me._deactivate(); - }); -}, + this._sideshow = new Sideshow(this._desktopX - 10); + this._sideshow.connect('activated', function(sideshow) { + // TODO - have some sort of animation/effect while + // transitioning to the new app. We definitely need + // startup-notification integration at least. + me._deactivate(); + }); + }, -_recalculateSize: function () { - let global = Shell.Global.get(); - let screenWidth = global.screen_width; - let screenHeight = global.screen_height; - // The desktop windows are shown on top of a scaled down version of the - // desktop. This is positioned at the right side of the screen - this._desktopWidth = screenWidth * DESKTOP_SCALE; - this._desktopHeight = screenHeight * DESKTOP_SCALE; - this._desktopX = screenWidth - this._desktopWidth - 10; - this._desktopY = Panel.PANEL_HEIGHT + (screenHeight - this._desktopHeight - Panel.PANEL_HEIGHT) / 2; -}, + _recalculateSize: function () { + let global = Shell.Global.get(); + let screenWidth = global.screen_width; + let screenHeight = global.screen_height; + // The desktop windows are shown on top of a scaled down version of the + // desktop. This is positioned at the right side of the screen + this._desktopWidth = screenWidth * DESKTOP_SCALE; + this._desktopHeight = screenHeight * DESKTOP_SCALE; + this._desktopX = screenWidth - this._desktopWidth - 10; + this._desktopY = Panel.PANEL_HEIGHT + (screenHeight - this._desktopHeight - Panel.PANEL_HEIGHT) / 2; + }, -show : function() { - if (this.visible) - return; - this.visible = true; + show : function() { + if (this.visible) + return; - let global = Shell.Global.get(); + this.visible = true; - let windows = global.get_windows(); - let desktopWindow = null; + let global = Shell.Global.get(); - this._recalculateSize(); + let windows = global.get_windows(); + let desktopWindow = null; - for (let i = 0; i < windows.length; i++) - if (windows[i].get_window_type() == Meta.WindowType.DESKTOP) - desktopWindow = windows[i]; + this._recalculateSize(); - // If a file manager is displaying desktop icons, there will be a desktop window. - // This window will have the size of the whole desktop. When such window is not present - // (e.g. when the preference for showing icons on the desktop is disabled by the user - // or we are running inside a Xephyr window), we should create a desktop rectangle - // to serve as the background. - if (desktopWindow) - this._createDesktopClone(desktopWindow); - else - this._createDesktopRectangle(); + for (let i = 0; i < windows.length; i++) + if (windows[i].get_window_type() == Meta.WindowType.DESKTOP) + desktopWindow = windows[i]; - // Count the total number of windows so we know what layout scheme to use - let numberOfWindows = 0; - for (let i = 0; i < windows.length; i++) { - let w = windows[i]; - if (w == desktopWindow || w.is_override_redirect()) - continue; + // If a file manager is displaying desktop icons, there will be a desktop window. + // This window will have the size of the whole desktop. When such window is not present + // (e.g. when the preference for showing icons on the desktop is disabled by the user + // or we are running inside a Xephyr window), we should create a desktop rectangle + // to serve as the background. + if (desktopWindow) + this._createDesktopClone(desktopWindow); + else + this._createDesktopRectangle(); - numberOfWindows++; + // Count the total number of windows so we know what layout scheme to use + let numberOfWindows = 0; + for (let i = 0; i < windows.length; i++) { + let w = windows[i]; + if (w == desktopWindow || w.is_override_redirect()) + continue; + + numberOfWindows++; + } + + // Now create actors for all the desktop windows. Do it in + // reverse order so that the active actor ends up on top + let windowIndex = 0; + for (let i = windows.length - 1; i >= 0; i--) { + let w = windows[i]; + if (w == desktopWindow || w.is_override_redirect()) + continue; + this._createWindowClone(w, numberOfWindows - windowIndex - 1, numberOfWindows); + + windowIndex++; + } + + this._sideshow.show(); + + // All the the actors in the window group are completely obscured, + // hiding the group holding them while the overlay is displayed greatly + // increases performance of the overlay especially when there are many + // windows visible. + // + // If we switched to displaying the actors in the overlay rather than + // clones of them, this would obviously no longer be necessary. + global.window_group.hide() + this._group.show(); + }, + + hide : function() { + if (!this.visible) + return; + + let global = Shell.Global.get(); + + this.visible = false; + global.window_group.show() + this._group.hide(); + + for (let i = 0; i < this._windowClones.length; i++) { + this._windowClones[i].destroy(); + } + + this._sideshow.hide(); + + this._windowClones = []; + }, + + _createDesktopClone : function(w) { + let clone = new Clutter.CloneTexture({ parent_texture: w.get_texture(), + reactive: true, + x: 0, + y: 0 }); + this._addDesktop(clone); + }, + + _createDesktopRectangle : function() { + let global = Shell.Global.get(); + // In the case when we have a desktop window from the file manager, its height is + // full-screen, i.e. it includes the height of the panel, so we should not subtract + // the height of the panel from global.screen_height here either to have them show + // up identically. + // We are also using (0,0) coordinates in both cases which makes the background + // window animate out from behind the panel. + let desktopRectangle = new Clutter.Rectangle({ color: global.stage.color, + reactive: true, + x: 0, + y: 0, + width: global.screen_width, + height: global.screen_height }); + this._addDesktop(desktopRectangle); + }, + + _addDesktop : function(desktop) { + let me = this; + + this._windowClones.push(desktop); + this._group.add_actor(desktop); + + // Since the right side only moves a little bit (the width of padding + // we add) it looks less jittery to put the anchor there. + desktop.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST); + Tweener.addTween(desktop, + { x: this._desktopX + this._desktopWidth, + y: this._desktopY, + scale_x: DESKTOP_SCALE, + scale_y: DESKTOP_SCALE, + time: ANIMATION_TIME, + transition: "easeOutQuad" + }); + + desktop.connect("button-press-event", + function() { + me._deactivate(); + }); + }, + + // windowIndex == 0 => top in stacking order + _computeWindowPosition : function(windowIndex, numberOfWindows) { + if (numberOfWindows in POSITIONS) + return POSITIONS[numberOfWindows][windowIndex]; + + // If we don't have a predefined scheme for this window count, overlap the windows + // along the diagonal of the desktop (improve this!) + let fraction = Math.sqrt(1/numberOfWindows); + + // The top window goes at the lower right - this is different from the + // fixed position schemes where the windows are in "reading order" + // and the top window goes at the upper left. + let pos = (numberOfWindows - windowIndex - 1) / (numberOfWindows - 1); + let xCenter = (fraction / 2) + (1 - fraction) * pos; + let yCenter = xCenter; + + return [xCenter, yCenter, fraction]; + }, + + _createWindowClone : function(w, windowIndex, numberOfWindows) { + let me = this; + + // We show the window using "clones" of the texture .. separate + // actors that mirror the original actors for the window. For + // animation purposes, it may be better to actually move the + // original actors about instead. + + let clone = new Clutter.CloneTexture({ parent_texture: w.get_texture(), + reactive: true, + x: w.x, + y: w.y }); + + let [xCenter, yCenter, fraction] = this._computeWindowPosition(windowIndex, numberOfWindows); + + let desiredSize = this._desktopWidth * fraction; + + xCenter = this._desktopX + xCenter * this._desktopWidth; + yCenter = this._desktopY + yCenter * this._desktopHeight; + + let size = clone.width; + if (clone.height > size) + size = clone.height; + + // Never scale up + let scale = desiredSize / size; + if (scale > 1) + scale = 1; + + this._group.add_actor(clone); + this._windowClones.push(clone); + + Tweener.addTween(clone, + { x: xCenter - 0.5 * scale * w.width, + y: yCenter - 0.5 * scale * w.height, + scale_x: scale, + scale_y: scale, + time: ANIMATION_TIME, + opacity: WINDOW_OPACITY, + transition: "easeOutQuad" + }); + + clone.connect("button-press-event", + function(clone, event) { + me._activateWindow(w, event.get_time()); + }); + }, + + _activateWindow : function(w, time) { + this._deactivate(); + w.get_meta_window().activate(time); + }, + + _deactivate : function() { + Main.hide_overlay(); } - - // Now create actors for all the desktop windows. Do it in - // reverse order so that the active actor ends up on top - let windowIndex = 0; - for (let i = windows.length - 1; i >= 0; i--) { - let w = windows[i]; - if (w == desktopWindow || w.is_override_redirect()) - continue; - this._createWindowClone(w, numberOfWindows - windowIndex - 1, numberOfWindows); - - windowIndex++; - } - - this._sideshow.show(); - - // All the the actors in the window group are completely obscured, - // hiding the group holding them while the overlay is displayed greatly - // increases performance of the overlay especially when there are many - // windows visible. - // - // If we switched to displaying the actors in the overlay rather than - // clones of them, this would obviously no longer be necessary. - global.window_group.hide() - this._group.show(); -}, - -hide : function() { - if (!this.visible) - return; - let global = Shell.Global.get(); - - this.visible = false; - global.window_group.show() - this._group.hide(); - - for (let i = 0; i < this._windowClones.length; i++) { - this._windowClones[i].destroy(); - } - - this._sideshow.hide(); - - this._windowClones = []; -}, - -_createDesktopClone : function(w) { - let clone = new Clutter.CloneTexture({ parent_texture: w.get_texture(), - reactive: true, - x: 0, - y: 0 }); - this._addDesktop(clone); -}, - -_createDesktopRectangle : function() { - let global = Shell.Global.get(); - // In the case when we have a desktop window from the file manager, its height is - // full-screen, i.e. it includes the height of the panel, so we should not subtract - // the height of the panel from global.screen_height here either to have them show - // up identically. - // We are also using (0,0) coordinates in both cases which makes the background - // window animate out from behind the panel. - let desktopRectangle = new Clutter.Rectangle({ color: global.stage.color, - reactive: true, - x: 0, - y: 0, - width: global.screen_width, - height: global.screen_height }); - this._addDesktop(desktopRectangle); -}, - -_addDesktop : function(desktop) { - let me = this; - - this._windowClones.push(desktop); - this._group.add_actor(desktop); - - // Since the right side only moves a little bit (the width of padding - // we add) it looks less jittery to put the anchor there. - desktop.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST); - Tweener.addTween(desktop, - { x: this._desktopX + this._desktopWidth, - y: this._desktopY, - scale_x: DESKTOP_SCALE, - scale_y: DESKTOP_SCALE, - time: ANIMATION_TIME, - transition: "easeOutQuad" - }); - - desktop.connect("button-press-event", - function() { - me._deactivate(); - }); -}, - -//windowIndex == 0 => top in stacking order -_computeWindowPosition : function(windowIndex, numberOfWindows) { - if (numberOfWindows in POSITIONS) - return POSITIONS[numberOfWindows][windowIndex]; - - // If we don't have a predefined scheme for this window count, overlap the windows - // along the diagonal of the desktop (improve this!) - let fraction = Math.sqrt(1/numberOfWindows); - - // The top window goes at the lower right - this is different from the - // fixed position schemes where the windows are in "reading order" - // and the top window goes at the upper left. - let pos = (numberOfWindows - windowIndex - 1) / (numberOfWindows - 1); - let xCenter = (fraction / 2) + (1 - fraction) * pos; - let yCenter = xCenter; - - return [xCenter, yCenter, fraction]; -}, - -_createWindowClone : function(w, windowIndex, numberOfWindows) { - let me = this; - - // We show the window using "clones" of the texture .. separate - // actors that mirror the original actors for the window. For - // animation purposes, it may be better to actually move the - // original actors about instead. - - let clone = new Clutter.CloneTexture({ parent_texture: w.get_texture(), - reactive: true, - x: w.x, - y: w.y }); - - let [xCenter, yCenter, fraction] = this._computeWindowPosition(windowIndex, numberOfWindows); - - let desiredSize = this._desktopWidth * fraction; - - xCenter = this._desktopX + xCenter * this._desktopWidth; - yCenter = this._desktopY + yCenter * this._desktopHeight; - - let size = clone.width; - if (clone.height > size) - size = clone.height; - - // Never scale up - let scale = desiredSize / size; - if (scale > 1) - scale = 1; - - this._group.add_actor(clone); - this._windowClones.push(clone); - - Tweener.addTween(clone, - { x: xCenter - 0.5 * scale * w.width, - y: yCenter - 0.5 * scale * w.height, - scale_x: scale, - scale_y: scale, - time: ANIMATION_TIME, - opacity: WINDOW_OPACITY, - transition: "easeOutQuad" - }); - - clone.connect("button-press-event", - function(clone, event) { - me._activateWindow(w, event.get_time()); - }); -}, - -_activateWindow : function(w, time) { - this._deactivate(); - w.get_meta_window().activate(time); -}, - -_deactivate : function() { - Main.hide_overlay(); -} }; diff --git a/js/ui/panel.js b/js/ui/panel.js index 71801b0f5..2c37a7dd8 100644 --- a/js/ui/panel.js +++ b/js/ui/panel.js @@ -1,4 +1,4 @@ -/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ const Clutter = imports.gi.Clutter; const Mainloop = imports.mainloop; @@ -21,123 +21,123 @@ function Panel() { } Panel.prototype = { -_init : function() { - let global = Shell.Global.get(); + _init : function() { + let global = Shell.Global.get(); - this._group = new Clutter.Group(); + this._group = new Clutter.Group(); - let background = new Clutter.Rectangle({ color: PANEL_BACKGROUND_COLOR, - reactive: true, - width: global.screen_width+2, - height: PANEL_HEIGHT+1, - border_width: 1}); - background.set_position(-1, -1); - this._group.add_actor(background); + let background = new Clutter.Rectangle({ color: PANEL_BACKGROUND_COLOR, + reactive: true, + width: global.screen_width+2, + height: PANEL_HEIGHT+1, + border_width: 1}); + background.set_position(-1, -1); + this._group.add_actor(background); - this.button = new Button.Button("Activities", PANEL_BACKGROUND_COLOR, PRESSED_BUTTON_BACKGROUND_COLOR, true, null, PANEL_HEIGHT-1); + this.button = new Button.Button("Activities", PANEL_BACKGROUND_COLOR, PRESSED_BUTTON_BACKGROUND_COLOR, true, null, PANEL_HEIGHT-1); - this._group.add_actor(this.button.button); + this._group.add_actor(this.button.button); - this._grid = new Tidy.Grid({ height: TRAY_HEIGHT, - valign: 0.5, - end_align: true, - column_gap: 2 }) - this._group.add_actor(this._grid); + this._grid = new Tidy.Grid({ height: TRAY_HEIGHT, + valign: 0.5, + end_align: true, + column_gap: 2 }) + this._group.add_actor(this._grid); - this._clock = new Clutter.Label({ font_name: "Sans Bold 16px", - text: "" }); - this._grid.add_actor(this._clock); + this._clock = new Clutter.Label({ font_name: "Sans Bold 16px", + text: "" }); + this._grid.add_actor(this._clock); - // Setting the anchor point at top right (north east) makes that portion of the - // grid positioned at the position specified below. - this._grid.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST); - this._grid.set_position(global.screen_width - 2, (PANEL_HEIGHT - TRAY_HEIGHT) / 2); + // Setting the anchor point at top right (north east) makes that portion of the + // grid positioned at the position specified below. + this._grid.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST); + this._grid.set_position(global.screen_width - 2, (PANEL_HEIGHT - TRAY_HEIGHT) / 2); - this._traymanager = new Shell.TrayManager({ bg_color: PANEL_BACKGROUND_COLOR }); - let me = this; - // the anchor point needs to be updated each time the height/width of the content might have changed, because - // it doesn't get updated on its own - this._traymanager.connect('tray-icon-added', + this._traymanager = new Shell.TrayManager({ bg_color: PANEL_BACKGROUND_COLOR }); + let me = this; + // the anchor point needs to be updated each time the height/width of the content might have changed, because + // it doesn't get updated on its own + this._traymanager.connect('tray-icon-added', function(o, icon) { - me._grid.add_actor(icon); - /* bump the clock back to the end */ - me._grid.remove_actor(me._clock); - me._grid.add_actor(me._clock); - me._grid.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST); - }); - this._traymanager.connect('tray-icon-removed', + me._grid.add_actor(icon); + /* bump the clock back to the end */ + me._grid.remove_actor(me._clock); + me._grid.add_actor(me._clock); + me._grid.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST); + }); + this._traymanager.connect('tray-icon-removed', function(o, icon) { - me._grid.remove_actor(icon); - me._grid.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST); - }); - this._traymanager.manage_stage(global.stage); + me._grid.remove_actor(icon); + me._grid.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST); + }); + this._traymanager.manage_stage(global.stage); - // TODO: decide what to do with the rest of the panel in the overlay mode (make it fade-out, become non-reactive, etc.) - // We get into the overlay mode on button-press-event as opposed to button-release-event because eventually we'll probably - // have the overlay act like a menu that allows the user to release the mouse on the activity the user wants - // to switch to. - this.button.button.connect('button-press-event', + // TODO: decide what to do with the rest of the panel in the overlay mode (make it fade-out, become non-reactive, etc.) + // We get into the overlay mode on button-press-event as opposed to button-release-event because eventually we'll probably + // have the overlay act like a menu that allows the user to release the mouse on the activity the user wants + // to switch to. + this.button.button.connect('button-press-event', function(o, event) { - if (Main.overlay.visible) - Main.hide_overlay(); - else - Main.show_overlay(); + if (Main.overlay.visible) + Main.hide_overlay(); + else + Main.show_overlay(); - return true; - }); + return true; + }); - this._setStruts(); - global.screen.connect('notify::n-workspaces', + this._setStruts(); + global.screen.connect('notify::n-workspaces', function() { - me._setStruts(); - }); + me._setStruts(); + }); - global.stage.add_actor(this._group); + global.stage.add_actor(this._group); - this._updateClock(); - this._startClock(); -}, + this._updateClock(); + this._startClock(); + }, -// Struts determine the area along each side of the screen that is reserved -// and not available to applications -_setStruts: function() { - let global = Shell.Global.get(); + // Struts determine the area along each side of the screen that is reserved + // and not available to applications + _setStruts: function() { + let global = Shell.Global.get(); - let struts = [ - new Meta.Strut({ - rect: { - x: 0, - y: 0, - width: global.screen_width, - height: PANEL_HEIGHT - }, - side: Meta.Direction.TOP - }) - ]; + let struts = [ + new Meta.Strut({ + rect: { + x: 0, + y: 0, + width: global.screen_width, + height: PANEL_HEIGHT + }, + side: Meta.Direction.TOP + }) + ]; - let screen = global.screen; - for (let i = 0; i < screen.n_workspaces; i++) { - let workspace = screen.get_workspace_by_index(i); - workspace.set_builtin_struts(struts); + let screen = global.screen; + for (let i = 0; i < screen.n_workspaces; i++) { + let workspace = screen.get_workspace_by_index(i); + workspace.set_builtin_struts(struts); + } + }, + + _startClock: function() { + let me = this; + // TODO: this makes the clock updated every 60 seconds, but not necessarily on the minute, so it is inaccurate + Mainloop.timeout_add_seconds(60, + function() { + me._updateClock(); + return true; + }); + }, + + _updateClock: function() { + this._clock.set_text(new Date().toLocaleFormat("%H:%M")); + return true; + }, + + overlayHidden: function() { + this.button.release(); } -}, - -_startClock: function() { - let me = this; - // TODO: this makes the clock updated every 60 seconds, but not necessarily on the minute, so it is inaccurate - Mainloop.timeout_add_seconds(60, - function() { - me._updateClock(); - return true; - }); -}, - -_updateClock: function() { - this._clock.set_text(new Date().toLocaleFormat("%H:%M")); - return true; -}, - -overlayHidden: function() { - this.button.release(); -} }; diff --git a/js/ui/run_dialog.js b/js/ui/run_dialog.js index 25e0b91c4..fdfd36a8c 100644 --- a/js/ui/run_dialog.js +++ b/js/ui/run_dialog.js @@ -1,4 +1,4 @@ -/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ const Signals = imports.signals; const Shell = imports.gi.Shell; @@ -23,110 +23,111 @@ function RunDialog() { }; RunDialog.prototype = { - _init : function() { - let global = Shell.Global.get(); + _init : function() { + let global = Shell.Global.get(); - // All actors are inside _group. We create it initially - // hidden then show it in show() - this._group = new Clutter.Group({ visible: false }); - global.stage.add_actor(this._group); + // All actors are inside _group. We create it initially + // hidden then show it in show() + this._group = new Clutter.Group({ visible: false }); + global.stage.add_actor(this._group); - this._overlay = new Clutter.Rectangle({ color: OVERLAY_COLOR, - width: global.screen_width, - height: global.screen_height, - border_width: 0, - reactive: true }); - this._group.add_actor(this._overlay); + this._overlay = new Clutter.Rectangle({ color: OVERLAY_COLOR, + width: global.screen_width, + height: global.screen_height, + border_width: 0, + reactive: true }); + this._group.add_actor(this._overlay); - let boxGroup = new Clutter.Group(); - boxGroup.set_position((global.screen_width - BOX_WIDTH) / 2, - (global.screen_height - BOX_HEIGHT) / 2); - this._group.add_actor(boxGroup); + let boxGroup = new Clutter.Group(); + boxGroup.set_position((global.screen_width - BOX_WIDTH) / 2, + (global.screen_height - BOX_HEIGHT) / 2); + this._group.add_actor(boxGroup); - let box = new Clutter.Rectangle({ color: BOX_BACKGROUND_COLOR, - reactive: false, - width: BOX_WIDTH, - height: BOX_HEIGHT, - border_width: 0 }); - boxGroup.add_actor(box); + let box = new Clutter.Rectangle({ color: BOX_BACKGROUND_COLOR, + reactive: false, + width: BOX_WIDTH, + height: BOX_HEIGHT, + border_width: 0 }); + boxGroup.add_actor(box); - let label = new Clutter.Label({ color: BOX_TEXT_COLOR, - font_name: '18px Sans', - text: 'Please enter a command:' }); - label.set_position(6, 6); - boxGroup.add_actor(label); + let label = new Clutter.Label({ color: BOX_TEXT_COLOR, + font_name: '18px Sans', + text: 'Please enter a command:' }); + label.set_position(6, 6); + boxGroup.add_actor(label); - this._entry = new Clutter.Entry({ color: BOX_TEXT_COLOR, - font_name: '20px Sans Bold', - reactive: true, - text: '', - entry_padding: 0, - width: BOX_WIDTH - 12, - height: BOX_HEIGHT - 12 }); - // TODO: Implement relative positioning using Tidy. - this._entry.set_position(6, 30); - boxGroup.add_actor(this._entry); + this._entry = new Clutter.Entry({ color: BOX_TEXT_COLOR, + font_name: '20px Sans Bold', + reactive: true, + text: '', + entry_padding: 0, + width: BOX_WIDTH - 12, + height: BOX_HEIGHT - 12 }); + // TODO: Implement relative positioning using Tidy. + this._entry.set_position(6, 30); + boxGroup.add_actor(this._entry); - let me = this; + let me = this; - this._entry.connect('activate', function (o, e) { - me.hide(); - me._run(o.get_text()); - return false; - }); - -}, - -_run : function(command) { - if (command) { - var p = new Shell.Process({'args' : [command]}); - try { - p.run(); - } catch (e) { - // TODO: Give the user direct feedback. - log('Could not run command ' + command + '.'); - } - } - - this.emit('run'); -}, - -show : function() { - let me = this; - if (this._group.visible) // Already shown - return false; - - if (!Main.startModal()) - return false; - - this._group.show_all(); - - this._entry.connect('key-press-event', function(o, e) { - if (e.get_code() == 9) { + this._entry.connect('activate', function (o, e) { me.hide(); - me.emit('cancel'); - return true; - } else + me._run(o.get_text()); return false; - }); + }); - let global = Shell.Global.get(); - global.stage.set_key_focus(this._entry); + }, - return true; -}, + _run : function(command) { + if (command) { + var p = new Shell.Process({'args' : [command]}); + try { + p.run(); + } catch (e) { + // TODO: Give the user direct feedback. + log('Could not run command ' + command + '.'); + } + } -hide : function() { - if (!this._group.visible) - return; + this.emit('run'); + }, - this._group.hide(); - Main.endModal(); -}, + show : function() { + let me = this; -destroy : function(){ - this.hide(); - this._group.destroy(); -} + if (this._group.visible) // Already shown + return false; + + if (!Main.startModal()) + return false; + + this._group.show_all(); + + this._entry.connect('key-press-event', function(o, e) { + if (e.get_code() == 9) { + me.hide(); + me.emit('cancel'); + return true; + } else + return false; + }); + + let global = Shell.Global.get(); + global.stage.set_key_focus(this._entry); + + return true; + }, + + hide : function() { + if (!this._group.visible) + return; + + this._group.hide(); + Main.endModal(); + }, + + destroy : function(){ + this.hide(); + this._group.destroy(); + } }; Signals.addSignalMethods(RunDialog.prototype); diff --git a/js/ui/windowmanager.js b/js/ui/windowmanager.js index 90dd579fc..3cb1bf5fa 100644 --- a/js/ui/windowmanager.js +++ b/js/ui/windowmanager.js @@ -1,4 +1,4 @@ -/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ const Clutter = imports.gi.Clutter; const Mainloop = imports.mainloop; @@ -15,111 +15,111 @@ function WindowManager() { } WindowManager.prototype = { -_init : function() { - let me = this; + _init : function() { + let me = this; - this._global = Shell.Global.get(); - this._shellwm = this._global.window_manager; + this._global = Shell.Global.get(); + this._shellwm = this._global.window_manager; - this._switchData = null; - this._shellwm.connect('switch-workspace', + this._switchData = null; + this._shellwm.connect('switch-workspace', function(o, from, to, direction) { - let actors = me._shellwm.get_switch_workspace_actors(); - me.switchWorkspace(actors, from, to, direction); - }); - this._shellwm.connect('kill-switch-workspace', + let actors = me._shellwm.get_switch_workspace_actors(); + me.switchWorkspace(actors, from, to, direction); + }); + this._shellwm.connect('kill-switch-workspace', function(o) { - me.switchWorkspaceDone(); - }); -}, + me.switchWorkspaceDone(); + }); + }, -switchWorkspace : function(windows, from, to, direction) { - /* @direction is the direction that the "camera" moves, so the - * screen contents have to move one screen's worth in the - * opposite direction. - */ - let xDest = 0, yDest = 0; + switchWorkspace : function(windows, from, to, direction) { + /* @direction is the direction that the "camera" moves, so the + * screen contents have to move one screen's worth in the + * opposite direction. + */ + let xDest = 0, yDest = 0; - if (direction == Meta.MotionDirection.UP || + if (direction == Meta.MotionDirection.UP || direction == Meta.MotionDirection.UP_LEFT || direction == Meta.MotionDirection.UP_RIGHT) - yDest = this._global.screen_height; - else if (direction == Meta.MotionDirection.DOWN || + yDest = this._global.screen_height; + else if (direction == Meta.MotionDirection.DOWN || direction == Meta.MotionDirection.DOWN_LEFT || direction == Meta.MotionDirection.DOWN_RIGHT) - yDest = -this._global.screen_height; + yDest = -this._global.screen_height; - if (direction == Meta.MotionDirection.LEFT || + if (direction == Meta.MotionDirection.LEFT || direction == Meta.MotionDirection.UP_LEFT || direction == Meta.MotionDirection.DOWN_LEFT) - xDest = this._global.screen_width; - else if (direction == Meta.MotionDirection.RIGHT || - direction == Meta.MotionDirection.UP_RIGHT || - direction == Meta.MotionDirection.DOWN_RIGHT) - xDest = -this._global.screen_width; + xDest = this._global.screen_width; + else if (direction == Meta.MotionDirection.RIGHT || + direction == Meta.MotionDirection.UP_RIGHT || + direction == Meta.MotionDirection.DOWN_RIGHT) + xDest = -this._global.screen_width; - let switchData = {}; - this._switchData = switchData; - switchData.inGroup = new Clutter.Group(); - switchData.outGroup = new Clutter.Group(); - switchData.windows = []; + let switchData = {}; + this._switchData = switchData; + switchData.inGroup = new Clutter.Group(); + switchData.outGroup = new Clutter.Group(); + switchData.windows = []; - let wgroup = this._global.window_group; - wgroup.add_actor(switchData.inGroup); - wgroup.add_actor(switchData.outGroup); + let wgroup = this._global.window_group; + wgroup.add_actor(switchData.inGroup); + wgroup.add_actor(switchData.outGroup); - for (let i = 0; i < windows.length; i++) { - let window = windows[i]; - if (window.get_workspace() == from) { - switchData.windows.push({ window: window, - parent: window.get_parent() }); - window.reparent(switchData.outGroup); - } else if (window.get_workspace() == to) { - switchData.windows.push({ window: window, - parent: window.get_parent() }); - window.reparent(switchData.inGroup); - window.show_all(); + for (let i = 0; i < windows.length; i++) { + let window = windows[i]; + if (window.get_workspace() == from) { + switchData.windows.push({ window: window, + parent: window.get_parent() }); + window.reparent(switchData.outGroup); + } else if (window.get_workspace() == to) { + switchData.windows.push({ window: window, + parent: window.get_parent() }); + window.reparent(switchData.inGroup); + window.show_all(); + } } + + switchData.inGroup.set_position(-xDest, -yDest); + switchData.inGroup.raise_top(); + + Tweener.addTween(switchData.outGroup, + { x: xDest, + y: yDest, + time: SWITCH_ANIMATION_TIME, + transition: "easeOutBack", + onComplete: this.switchWorkspaceDone + }); + Tweener.addTween(switchData.inGroup, + { x: 0, + y: 0, + time: SWITCH_ANIMATION_TIME, + transition: "easeOutBack" + }); + }, + + switchWorkspaceDone : function() { + let switchData = this._switchData; + if (!switchData) + return; + this._switchData = null; + + for (let i = 0; i < switchData.windows.length; i++) { + let w = switchData.windows[i]; + if (w.window.get_parent() == switchData.outGroup) { + w.window.reparent(w.parent); + w.window.hide(); + } else + w.window.reparent(w.parent); + } + Tweener.removeTweens(switchData.inGroup); + Tweener.removeTweens(switchData.outGroup); + switchData.inGroup.destroy(); + switchData.outGroup.destroy(); + + this._shellwm.completed_switch_workspace(); } - switchData.inGroup.set_position(-xDest, -yDest); - switchData.inGroup.raise_top(); - - Tweener.addTween(switchData.outGroup, - { x: xDest, - y: yDest, - time: SWITCH_ANIMATION_TIME, - transition: "easeOutBack", - onComplete: this.switchWorkspaceDone - }); - Tweener.addTween(switchData.inGroup, - { x: 0, - y: 0, - time: SWITCH_ANIMATION_TIME, - transition: "easeOutBack" - }); -}, - -switchWorkspaceDone : function() { - let switchData = this._switchData; - if (!switchData) - return; - this._switchData = null; - - for (let i = 0; i < switchData.windows.length; i++) { - let w = switchData.windows[i]; - if (w.window.get_parent() == switchData.outGroup) { - w.window.reparent(w.parent); - w.window.hide(); - } else - w.window.reparent(w.parent); - } - Tweener.removeTweens(switchData.inGroup); - Tweener.removeTweens(switchData.outGroup); - switchData.inGroup.destroy(); - switchData.outGroup.destroy(); - - this._shellwm.completed_switch_workspace(); -} - };