diff --git a/extensions/workspace-indicator/Makefile.am b/extensions/workspace-indicator/Makefile.am index 47210de7..66201163 100644 --- a/extensions/workspace-indicator/Makefile.am +++ b/extensions/workspace-indicator/Makefile.am @@ -1,3 +1,5 @@ EXTENSION_ID = workspace-indicator +EXTRA_MODULES = prefs.js + include ../../extension.mk diff --git a/extensions/workspace-indicator/extension.js b/extensions/workspace-indicator/extension.js index e9acbd39..644af8ca 100644 --- a/extensions/workspace-indicator/extension.js +++ b/extensions/workspace-indicator/extension.js @@ -1,3 +1,6 @@ +// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- + +const Gio = imports.gi.Gio; const Meta = imports.gi.Meta; const Clutter = imports.gi.Clutter; const St = imports.gi.St; @@ -16,6 +19,9 @@ const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; +const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences'; +const WORKSPACE_KEY = 'workspace-names'; + const WorkspaceIndicator = new Lang.Class({ Name: 'WorkspaceIndicator.WorkspaceIndicator', Extends: PanelMenu.Button, @@ -43,12 +49,20 @@ const WorkspaceIndicator = new Lang.Class({ //styling this.menu.actor.add_style_class_name('workspace-indicator-shorter'); this.statusLabel.add_style_class_name('panel-workspace-indicator'); + + this._settings = new Gio.Settings({ schema: WORKSPACE_SCHEMA }); + this._settingsChangedId = this._settings.connect('changed::' + WORKSPACE_KEY, Lang.bind(this, this._createWorkspacesSection)); }, destroy: function() { for (let i = 0; i < this._screenSignals.length; i++) global.screen.disconnect(this._screenSignals[i]); + if (this._settingsChangedId) { + this._settings.disconnect(this._settingsChangedId); + this._settingsChangedId = 0; + } + this.parent(); }, diff --git a/extensions/workspace-indicator/prefs.js b/extensions/workspace-indicator/prefs.js new file mode 100644 index 00000000..40a32ac9 --- /dev/null +++ b/extensions/workspace-indicator/prefs.js @@ -0,0 +1,217 @@ +// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- + +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; +const Gtk = imports.gi.Gtk; +const Lang = imports.lang; + +const Gettext = imports.gettext.domain('gnome-shell-extensions'); +const _ = Gettext.gettext; +const N_ = function(e) { return e }; + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); +const Convenience = Me.imports.convenience; + +const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences'; +const WORKSPACE_KEY = 'workspace-names'; + +const WorkspaceNameModel = new GObject.Class({ + Name: 'WorkspaceIndicator.WorkspaceNameModel', + GTypeName: 'WorkspaceNameModel', + Extends: Gtk.ListStore, + + Columns: { + LABEL: 0, + }, + + _init: function(params) { + this.parent(params); + this.set_column_types([GObject.TYPE_STRING]); + + this._settings = new Gio.Settings({ schema: WORKSPACE_SCHEMA }); + //this._settings.connect('changed::workspace-names', Lang.bind(this, this._reloadFromSettings)); + + this._reloadFromSettings(); + + // overriding class closure doesn't work, because GtkTreeModel + // plays tricks with marshallers and class closures + this.connect('row-changed', Lang.bind(this, this._onRowChanged)); + this.connect('row-inserted', Lang.bind(this, this._onRowInserted)); + this.connect('row-deleted', Lang.bind(this, this._onRowDeleted)); + }, + + _reloadFromSettings: function() { + if (this._preventChanges) + return; + this._preventChanges = true; + + print('reloading from settings'); + + let newNames = this._settings.get_strv(WORKSPACE_KEY); + + let i = 0; + let [ok, iter] = this.get_iter_first(); + while (ok && i < newNames.length) { + this.set(iter, [this.Columns.LABEL], [newNames[i]]); + + ok = this.iter_next(iter); + i++; + } + + while (ok) + ok = this.remove(iter); + + for ( ; i < newNames.length; i++) { + iter = this.append(); + this.set(iter, [this.Columns.LABEL], [newNames[i]]); + } + + printerr('three'); + + this._preventChanges = false; + }, + + _onRowChanged: function(self, path, iter) { + if (this._preventChanges) + return; + this._preventChanges = true; + + print('on_row_changed: ' + path.to_string()); + + let index = path.get_indices()[0]; + let names = this._settings.get_strv(WORKSPACE_KEY); + + if (index >= names.length) { + // fill with blanks + for (let i = names.length; i <= index; i++) + names[i] = ''; + } + + names[index] = this.get_value(iter, this.Columns.LABEL); + + this._settings.set_strv(WORKSPACE_KEY, names); + + this._preventChanges = false; + }, + + _onRowInserted: function(self, path, iter) { + if (this._preventChanges) + return; + this._preventChanges = true; + + print('on_row_inserted: ' + path.to_string()); + + let index = path.get_indices()[0]; + let names = this._settings.get_strv(WORKSPACE_KEY); + let label = this.get_value(iter, this.Columns.LABEL) || ''; + names.splice(index, 0, label); + + this._settings.set_strv(WORKSPACE_KEY, names); + + this._preventChanges = false; + }, + + _onRowDeleted: function(self, path) { + if (this._preventChanges) + return; + this._preventChanges = true; + + print('on_row_deleted: ' + path.to_string()); + + let index = path.get_indices()[0]; + let names = this._settings.get_strv(WORKSPACE_KEY); + + if (index >= names.length) + return; + + names.splice(index, 1); + + // compact the array + for (let i = names.length -1; i >= 0 && !names[i]; i++) + names.pop(); + + this._settings.set_strv(WORKSPACE_KEY, names); + + this._preventChanges = false; + }, +}); + +const WorkspaceSettingsWidget = new GObject.Class({ + Name: 'WorkspaceIndicator.WorkspaceSettingsWidget', + GTypeName: 'WorkspaceSettingsWidget', + Extends: Gtk.Grid, + + _init: function(params) { + this.parent(params); + this.margin = 10; + this.orientation = Gtk.Orientation.VERTICAL; + + this.add(new Gtk.Label({ label: _("Workspace names:"), + margin_bottom: 5 })); + + this._store = new WorkspaceNameModel(); + this._treeView = new Gtk.TreeView({ model: this._store, + headers_visible: false, + reorderable: true, + hexpand: true, + vexpand: true + }); + + let column = new Gtk.TreeViewColumn({ title: _("Name") }); + let renderer = new Gtk.CellRendererText({ editable: true }); + renderer.connect('edited', Lang.bind(this, this._cellEdited)); + column.pack_start(renderer, true); + column.add_attribute(renderer, 'text', this._store.Columns.LABEL); + this._treeView.append_column(column); + + this.add(this._treeView); + + let toolbar = new Gtk.Toolbar(); + toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR); + + let newButton = new Gtk.ToolButton({ stock_id: Gtk.STOCK_NEW }); + newButton.connect('clicked', Lang.bind(this, this._newClicked)); + toolbar.add(newButton); + + let delButton = new Gtk.ToolButton({ stock_id: Gtk.STOCK_DELETE }); + delButton.connect('clicked', Lang.bind(this, this._delClicked)); + toolbar.add(delButton); + + this.add(toolbar); + }, + + _cellEdited: function(renderer, path, new_text) { + let [ok, iter] = this._store.get_iter_from_string(path); + + if (ok) + this._store.set(iter, [this._store.Columns.LABEL], [new_text]); + }, + + _newClicked: function() { + let iter = this._store.append(); + let index = this._store.get_path(iter).get_indices()[0]; + + let label = _("Workspace %d").format(index); + this._store.set(iter, [this._store.Columns.LABEL], [label]); + }, + + _delClicked: function() { + let [any, model, iter] = this._treeView.get_selection().get_selected(); + + if (any) + this._store.remove(iter); + } +}); + +function init() { + Convenience.initTranslations(); +} + +function buildPrefsWidget() { + let widget = new WorkspaceSettingsWidget(); + widget.show_all(); + + return widget; +}