diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/actionGroups/actionGroup.vala | 23 | ||||
-rw-r--r-- | src/actionGroups/clipboardGroup.vala | 124 | ||||
-rw-r--r-- | src/actionGroups/groupRegistry.vala | 31 | ||||
-rw-r--r-- | src/actionGroups/windowListGroup.vala | 54 | ||||
-rw-r--r-- | src/actionGroups/workspaceWindowListGroup.vala | 145 | ||||
-rw-r--r-- | src/deamon.vala | 90 | ||||
-rw-r--r-- | src/gui/aboutWindow.vala | 1 | ||||
-rw-r--r-- | src/gui/newSliceWindow.vala | 55 | ||||
-rw-r--r-- | src/gui/preferencesWindow.vala | 38 | ||||
-rw-r--r-- | src/gui/themeList.vala | 3 | ||||
-rw-r--r-- | src/pies/defaultConfig.vala | 4 | ||||
-rw-r--r-- | src/pies/load.vala | 11 | ||||
-rw-r--r-- | src/pies/save.vala | 2 | ||||
-rwxr-xr-x | src/renderers/pieWindow.vala | 1 | ||||
-rw-r--r-- | src/themes/theme.vala | 46 | ||||
-rw-r--r-- | src/utilities/config.vala | 2 | ||||
-rw-r--r-- | src/utilities/paths.vala | 22 |
17 files changed, 408 insertions, 244 deletions
diff --git a/src/actionGroups/actionGroup.vala b/src/actionGroups/actionGroup.vala index 8bbcde4..85488ad 100644 --- a/src/actionGroups/actionGroup.vala +++ b/src/actionGroups/actionGroup.vala @@ -56,6 +56,20 @@ public class ActionGroup : GLib.Object { public virtual void on_remove() {} ///////////////////////////////////////////////////////////////////// + /// This one is called, when the ActionGroup is saved. + ///////////////////////////////////////////////////////////////////// + + public virtual void on_save(Xml.TextWriter writer) { + writer.write_attribute("type", GroupRegistry.descriptions[this.get_type().name()].id); + } + + ///////////////////////////////////////////////////////////////////// + /// This one is called, when the ActionGroup is loaded. + ///////////////////////////////////////////////////////////////////// + + public virtual void on_load(Xml.Node* data) {} + + ///////////////////////////////////////////////////////////////////// /// Adds a new Action to the group. ///////////////////////////////////////////////////////////////////// @@ -76,8 +90,9 @@ public class ActionGroup : GLib.Object { ///////////////////////////////////////////////////////////////////// public void disable_quickactions() { - foreach (var action in actions) + foreach (var action in actions) { action.is_quickaction = false; + } } ///////////////////////////////////////////////////////////////////// @@ -85,9 +100,11 @@ public class ActionGroup : GLib.Object { ///////////////////////////////////////////////////////////////////// public bool has_quickaction() { - foreach (var action in actions) - if (action.is_quickaction) + foreach (var action in actions) { + if (action.is_quickaction) { return true; + } + } return false; } diff --git a/src/actionGroups/clipboardGroup.vala b/src/actionGroups/clipboardGroup.vala index ad18740..58409de 100644 --- a/src/actionGroups/clipboardGroup.vala +++ b/src/actionGroups/clipboardGroup.vala @@ -25,34 +25,78 @@ namespace GnomePie { public class ClipboardGroup : ActionGroup { ///////////////////////////////////////////////////////////////////// - /// - ///////////////////////////////////////////////////////////////////// private class ClipboardItem : GLib.Object { - public string name { get; private set; } - public string icon { get; private set; } + public string name { get; protected set; } + public string icon { get; protected set; } + + protected Gtk.Clipboard clipboard { get; set; } + protected static Key paste_key = new Key.from_string("<Control>v"); + + public virtual void paste() {} + } - private Gtk.SelectionData contents; + ///////////////////////////////////////////////////////////////////// - public ClipboardItem(Gtk.SelectionData contents) { - this.contents = contents.copy(); - this.name = this.contents.get_text() ?? ""; - this.icon = "edit-paste"; + private class TextClipboardItem : ClipboardItem { + + public TextClipboardItem(Gtk.Clipboard clipboard) { + GLib.Object(clipboard : clipboard, + name : clipboard.wait_for_text(), + icon : "edit-paste"); + + // check whether a file has been copied and search for a cool icon + var first_line = this.name.substring(0, this.name.index_of("\n")); + var file = GLib.File.new_for_path(first_line); + + if (file.query_exists()) { + try { + var info = file.query_info("standard::icon", 0); + this.icon = Icon.get_icon_name(info.get_icon()); + } catch (Error e) { + warning("Failed to generate icon for ClipboardGroupItem."); + } + } } - public void paste() { - debug(name); + public override void paste() { + clipboard.set_text(name, name.length); + paste_key.press(); } } - public ClipboardGroup(string parent_id) { - GLib.Object(parent_id : parent_id); + ///////////////////////////////////////////////////////////////////// + + private class ImageClipboardItem : ClipboardItem { + + private Gdk.Pixbuf image { get; set; } + + public ImageClipboardItem(Gtk.Clipboard clipboard) { + GLib.Object(clipboard : clipboard, + name : _("Image data"), + icon : "image-viewer"); + this.image = clipboard.wait_for_image(); + } + + public override void paste() { + clipboard.set_image(image); + paste_key.press(); + } } ///////////////////////////////////////////////////////////////////// + /// The maximum remembered items of the clipboard. + ///////////////////////////////////////////////////////////////////// + + public int max_items {get; set; default=8; } + ///////////////////////////////////////////////////////////////////// + public ClipboardGroup(string parent_id) { + GLib.Object(parent_id : parent_id); + } + ///////////////////////////////////////////////////////////////////// /// Used to register this type of ActionGroup. It sets the display /// name for this ActionGroup, it's icon name and the string used in @@ -74,12 +118,7 @@ public class ClipboardGroup : ActionGroup { private Gtk.Clipboard clipboard; - - ///////////////////////////////////////////////////////////////////// - /// The maximum remembered items of the clipboard. - ///////////////////////////////////////////////////////////////////// - - private static const int max_items = 6; + private bool ignore_next_change = false; private Gee.ArrayList<ClipboardItem?> items; @@ -89,26 +128,61 @@ public class ClipboardGroup : ActionGroup { this.clipboard.owner_change.connect(this.on_change); } + ///////////////////////////////////////////////////////////////////// + /// This one is called, when the ActionGroup is saved. + ///////////////////////////////////////////////////////////////////// + + public override void on_save(Xml.TextWriter writer) { + base.on_save(writer); + writer.write_attribute("max_items", this.max_items.to_string()); + } + + ///////////////////////////////////////////////////////////////////// + /// This one is called, when the ActionGroup is loaded. + ///////////////////////////////////////////////////////////////////// + + public override void on_load(Xml.Node* data) { + for (Xml.Attr* attribute = data->properties; attribute != null; attribute = attribute->next) { + string attr_name = attribute->name.down(); + string attr_content = attribute->children->content; + + if (attr_name == "max_items") { + this.max_items = int.parse(attr_content); + } + } + } + private void on_change() { + if (ignore_next_change) { + ignore_next_change = false; + return; + } + if (this.clipboard.wait_is_text_available()) { - this.clipboard.request_contents(Gdk.Atom.intern("text/plain", false), this.add_item); + if (clipboard.wait_for_text() != null) { + add_item(new TextClipboardItem(this.clipboard)); + } + } else if (this.clipboard.wait_is_image_available()) { + add_item(new ImageClipboardItem(this.clipboard)); } } - private void add_item(Gtk.Clipboard c, Gtk.SelectionData contents) { - var new_item = new ClipboardItem(contents); + private void add_item(ClipboardItem item) { - if (this.items.size == ClipboardGroup.max_items) + // remove one item if there are too many + if (this.items.size == this.max_items) { this.items.remove_at(0); + } - this.items.add(new_item); + this.items.add(item); // update slices this.delete_all(); - for (int i=0; i<this.items.size; ++i) { + for (int i=this.items.size-1; i>=0; --i) { var action = new SigAction(items[i].name, items[i].icon, i.to_string()); action.activated.connect(() => { + ignore_next_change = true; this.items[int.parse(action.real_command)].paste(); }); this.add_action(action); diff --git a/src/actionGroups/groupRegistry.vala b/src/actionGroups/groupRegistry.vala index ebf34ba..c97cf95 100644 --- a/src/actionGroups/groupRegistry.vala +++ b/src/actionGroups/groupRegistry.vala @@ -57,6 +57,10 @@ public class GroupRegistry : GLib.Object { types.add(typeof(BookmarkGroup).name()); descriptions.set(typeof(BookmarkGroup).name(), type_description); + type_description = ClipboardGroup.register(); + types.add(typeof(ClipboardGroup).name()); + descriptions.set(typeof(ClipboardGroup).name(), type_description); + type_description = DevicesGroup.register(); types.add(typeof(DevicesGroup).name()); descriptions.set(typeof(DevicesGroup).name(), type_description); @@ -72,10 +76,6 @@ public class GroupRegistry : GLib.Object { type_description = WindowListGroup.register(); types.add(typeof(WindowListGroup).name()); descriptions.set(typeof(WindowListGroup).name(), type_description); - - type_description = WorkspaceWindowListGroup.register(); - types.add(typeof(WorkspaceWindowListGroup).name()); - descriptions.set(typeof(WorkspaceWindowListGroup).name(), type_description); } ///////////////////////////////////////////////////////////////////// @@ -84,12 +84,23 @@ public class GroupRegistry : GLib.Object { public static ActionGroup? create_group(string type_id, string parent_id) { switch (type_id) { - case "bookmarks": return new BookmarkGroup(parent_id); - case "devices": return new DevicesGroup(parent_id); - case "menu": return new MenuGroup(parent_id); - case "session": return new SessionGroup(parent_id); - case "window_list": return new WindowListGroup(parent_id); - case "workspace_window_list": return new WorkspaceWindowListGroup(parent_id); + case "bookmarks": + return new BookmarkGroup(parent_id); + case "clipboard": + return new ClipboardGroup(parent_id); + case "devices": + return new DevicesGroup(parent_id); + case "menu": + return new MenuGroup(parent_id); + case "session": + return new SessionGroup(parent_id); + case "window_list": + return new WindowListGroup(parent_id); + // deprecated + case "workspace_window_list": + var group = new WindowListGroup(parent_id); + group.current_workspace_only = true; + return group; } return null; diff --git a/src/actionGroups/windowListGroup.vala b/src/actionGroups/windowListGroup.vala index 1560f5f..69029a7 100644 --- a/src/actionGroups/windowListGroup.vala +++ b/src/actionGroups/windowListGroup.vala @@ -38,6 +38,8 @@ public class WindowListGroup : ActionGroup { return description; } + public bool current_workspace_only { get; set; default=false; } + ///////////////////////////////////////////////////////////////////// /// Two members needed to avoid useless, frequent changes of the /// stored Actions. @@ -65,22 +67,50 @@ public class WindowListGroup : ActionGroup { this.screen.window_opened.connect(reload); this.screen.window_closed.connect(reload); + this.screen.active_workspace_changed.connect(reload); - this.load(); + this.update(); + } + + ///////////////////////////////////////////////////////////////////// + /// This one is called, when the ActionGroup is saved. + ///////////////////////////////////////////////////////////////////// + + public override void on_save(Xml.TextWriter writer) { + base.on_save(writer); + writer.write_attribute("current_workspace_only", this.current_workspace_only.to_string()); + } + + ///////////////////////////////////////////////////////////////////// + /// This one is called, when the ActionGroup is loaded. + ///////////////////////////////////////////////////////////////////// + + public override void on_load(Xml.Node* data) { + for (Xml.Attr* attribute = data->properties; attribute != null; attribute = attribute->next) { + string attr_name = attribute->name.down(); + string attr_content = attribute->children->content; + + if (attr_name == "current_workspace_only") { + this.current_workspace_only = bool.parse(attr_content); + } + } } ///////////////////////////////////////////////////////////////////// /// Loads all currently opened windows and creates actions for them. ///////////////////////////////////////////////////////////////////// - private void load() { + private void update() { unowned GLib.List<Wnck.Window?> windows = this.screen.get_windows(); var matcher = Bamf.Matcher.get_default(); foreach (var window in windows) { if (window.get_window_type() == Wnck.WindowType.NORMAL - && !window.is_skip_pager() && !window.is_skip_tasklist()) { + && !window.is_skip_pager() && !window.is_skip_tasklist() + && (!current_workspace_only || (window.get_workspace() != null + && window.get_workspace() == this.screen.get_active_workspace()))) { + var application = window.get_application(); var bamf_app = matcher.get_application_for_xid((uint32)window.get_xid()); @@ -102,17 +132,18 @@ public class WindowListGroup : ActionGroup { if (win.get_workspace() != null) { //select the workspace - if (win.get_workspace() != win.get_screen().get_active_workspace()) + if (win.get_workspace() != win.get_screen().get_active_workspace()) { win.get_workspace().activate(time_stamp); + } - //select the viewport inside the wprkspace + //select the viewport inside the workspace if (!win.is_in_viewport(win.get_workspace()) ) { int xp, yp, widthp, heightp, scx, scy, nx, ny, wx, wy; win.get_geometry (out xp, out yp, out widthp, out heightp); - scx= win.get_screen().get_width(); - scy= win.get_screen().get_height(); - wx= win.get_workspace().get_viewport_x(); - wy= win.get_workspace().get_viewport_y(); + scx = win.get_screen().get_width(); + scy = win.get_screen().get_height(); + wx = win.get_workspace().get_viewport_x(); + wy = win.get_workspace().get_viewport_y(); if (scx > 0 && scy > 0) { nx= ((wx+xp) / scx) * scx; ny= ((wy+yp) / scy) * scy; @@ -121,8 +152,9 @@ public class WindowListGroup : ActionGroup { } } - if (win.is_minimized()) + if (win.is_minimized()) { win.unminimize(time_stamp); + } win.activate_transient(time_stamp); }); @@ -147,7 +179,7 @@ public class WindowListGroup : ActionGroup { // reload this.delete_all(); - this.load(); + this.update(); this.changing = false; return false; diff --git a/src/actionGroups/workspaceWindowListGroup.vala b/src/actionGroups/workspaceWindowListGroup.vala deleted file mode 100644 index 42a4863..0000000 --- a/src/actionGroups/workspaceWindowListGroup.vala +++ /dev/null @@ -1,145 +0,0 @@ -///////////////////////////////////////////////////////////////////////// -// Copyright (c) 2011-2015 by Simon Schneegans -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or (at -// your option) any later version. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -///////////////////////////////////////////////////////////////////////// - -namespace GnomePie { - -///////////////////////////////////////////////////////////////////// -/// This group displays a list of all running application windows of -/// the current workspace. -///////////////////////////////////////////////////////////////////// - -public class WorkspaceWindowListGroup : ActionGroup { - - ///////////////////////////////////////////////////////////////////// - /// Used to register this type of ActionGroup. It sets the display - /// name for this ActionGroup, it's icon name and the string used in - /// the pies.conf file for this kind of ActionGroups. - ///////////////////////////////////////////////////////////////////// - - public static GroupRegistry.TypeDescription register() { - var description = new GroupRegistry.TypeDescription(); - description.name = _("Group: Window List for current workspace"); - description.icon = "preferences-system-windows"; - description.description = _("Shows a Slice for each of your opened windows on the current workspace."); - description.id = "workspace_window_list"; - return description; - } - - ///////////////////////////////////////////////////////////////////// - /// Two members needed to avoid useless, frequent changes of the - /// stored Actions. - ///////////////////////////////////////////////////////////////////// - - private bool changing = false; - private bool changed_again = false; - - private Wnck.Screen screen; - - ///////////////////////////////////////////////////////////////////// - /// C'tor, initializes all members. - ///////////////////////////////////////////////////////////////////// - - public WorkspaceWindowListGroup(string parent_id) { - GLib.Object(parent_id : parent_id); - } - - ///////////////////////////////////////////////////////////////////// - /// Loads all windows. - ///////////////////////////////////////////////////////////////////// - - construct { - this.screen = Wnck.Screen.get_default(); - - this.screen.window_opened.connect(reload); - this.screen.window_closed.connect(reload); - this.screen.active_workspace_changed.connect(reload); - - this.load(); - } - - ///////////////////////////////////////////////////////////////////// - /// Loads all currently opened windows and creates actions for them. - ///////////////////////////////////////////////////////////////////// - - private void load() { - unowned GLib.List<Wnck.Window?> windows = this.screen.get_windows(); - - var matcher = Bamf.Matcher.get_default(); - - foreach (var window in windows) { - if (window.get_window_type() == Wnck.WindowType.NORMAL - && !window.is_skip_pager() && !window.is_skip_tasklist() - && window.get_workspace() != null - && window.get_workspace() == this.screen.get_active_workspace()) { - - var application = window.get_application(); - var bamf_app = matcher.get_application_for_xid((uint32)window.get_xid()); - - string name = window.get_name(); - - if (name.length > 30) - name = name.substring(0, 30) + "..."; - - var action = new SigAction( - name, - (bamf_app == null) ? application.get_icon_name().down() : bamf_app.get_icon(), - "%lu".printf(window.get_xid()) - ); - action.activated.connect((time_stamp) => { - Wnck.Screen.get_default().force_update(); - - var xid = (X.Window)uint64.parse(action.real_command); - var win = Wnck.Window.get(xid); - - if (win.is_minimized()) - win.unminimize(time_stamp); - - win.activate_transient(time_stamp); - }); - this.add_action(action); - } - } - } - - ///////////////////////////////////////////////////////////////////// - /// Reloads all running applications. - ///////////////////////////////////////////////////////////////////// - - private void reload() { - // avoid too frequent changes... - if (!this.changing) { - this.changing = true; - Timeout.add(500, () => { - if (this.changed_again) { - this.changed_again = false; - return true; - } - - // reload - this.delete_all(); - this.load(); - - this.changing = false; - return false; - }); - } else { - this.changed_again = true; - } - } -} - -} diff --git a/src/deamon.vala b/src/deamon.vala index f4e1aeb..5430a09 100644 --- a/src/deamon.vala +++ b/src/deamon.vala @@ -38,12 +38,18 @@ public class Deamon : GLib.Application { public static bool disable_header_bar = false; public static bool disable_stack_switcher = false; + + ///////////////////////////////////////////////////////////////////// + /// true if init_pies() has been called already + ///////////////////////////////////////////////////////////////////// + private bool initialized = false; + ///////////////////////////////////////////////////////////////////// /// The beginning of everything. ///////////////////////////////////////////////////////////////////// public static int main(string[] args) { - version = "0.6.6"; + version = "0.6.7"; // disable overlay scrollbar --- hacky workaround for black / // transparent background @@ -81,15 +87,20 @@ public class Deamon : GLib.Application { ///////////////////////////////////////////////////////////////////// private const GLib.OptionEntry[] options = { - { "open", 'o', 0, GLib.OptionArg.STRING, out open_pie, + { "open", 'o', 0, GLib.OptionArg.STRING, + out open_pie, "Open the Pie with the given ID", "ID" }, - { "reset", 'r', 0, GLib.OptionArg.NONE, out reset, + { "reset", 'r', 0, GLib.OptionArg.NONE, + out reset, "Reset all options to default values" }, - { "no-header-bar", 'b', 0, GLib.OptionArg.NONE, out disable_header_bar, + { "no-header-bar", 'b', 0, GLib.OptionArg.NONE, + out disable_header_bar, "Disables the usage of GTK.HeaderBar" }, - { "no-stack-switcher", 's', 0, GLib.OptionArg.NONE, out disable_stack_switcher, + { "no-stack-switcher", 's', 0, GLib.OptionArg.NONE, + out disable_stack_switcher, "Disables the usage of GTK.StackSwitcher" }, - { "print-ids", 'p', 0, GLib.OptionArg.NONE, out print_ids, + { "print-ids", 'p', 0, GLib.OptionArg.NONE, + out print_ids, "Prints all Pie names with their according IDs" }, { null } }; @@ -103,31 +114,27 @@ public class Deamon : GLib.Application { Object(application_id: "org.gnome.gnomepie", flags: GLib.ApplicationFlags.HANDLES_COMMAND_LINE); - message("Welcome to Gnome-Pie " + version + "!"); - // init locale support Intl.bindtextdomain("gnomepie", Paths.locales); Intl.textdomain("gnomepie"); - // init toolkits and static stuff - ActionRegistry.init(); - GroupRegistry.init(); - - PieManager.init(); - - // initialize icon cache - Icon.init(); - // connect SigHandlers Posix.signal(Posix.SIGINT, sig_handler); Posix.signal(Posix.SIGTERM, sig_handler); this.startup.connect(()=>{ + message("Welcome to Gnome-Pie " + version + "!"); + + this.init_pies(); // launch the indicator this.indicator = new Indicator(); + if (open_pie != null && open_pie != "") { + PieManager.open_pie(open_pie); + } + // finished loading... so run the prog! message("Started happily..."); hold(); @@ -138,7 +145,9 @@ public class Deamon : GLib.Application { /// Call handle_command_line on program launch. ///////////////////////////////////////////////////////////////////// - protected override bool local_command_line(ref unowned string[] args, out int exit_status) { + protected override bool local_command_line( + ref unowned string[] args, out int exit_status) { + exit_status = 0; // copy command line @@ -173,6 +182,26 @@ public class Deamon : GLib.Application { GLib.Application.get_default().release(); } + ///////////////////////////////////////////////////////////////////// + /// Print a nifty message when the prog is killed. + ///////////////////////////////////////////////////////////////////// + + private void init_pies() { + if (!this.initialized) { + + // init static stuff + ActionRegistry.init(); + GroupRegistry.init(); + + // load all pies + PieManager.init(); + + // initialize icon cache + Icon.init(); + + this.initialized = true; + } + } ///////////////////////////////////////////////////////////////////// /// Handles command line parameters. @@ -188,7 +217,9 @@ public class Deamon : GLib.Application { context.parse(ref args); } catch(GLib.OptionError error) { warning(error.message); - message("Run '%s' to launch Gnome-Pie or run '%s --help' to see a full list of available command line options.\n", args[0], args[0]); + message("Run '%s' to launch Gnome-Pie or run '%s --help' to" + + " see a full list of available command line options.\n", + args[0], args[0]); } if (reset) { @@ -199,22 +230,29 @@ public class Deamon : GLib.Application { message("Removed file \"%s\"", Paths.settings); } + // do not notify the already running instance (if any) return true; } - if (open_pie != null && open_pie != "") { - PieManager.open_pie(open_pie); - open_pie = ""; - } else if (called_from_remote) { - this.indicator.show_preferences(); - } - if (print_ids) { + this.init_pies(); PieManager.print_ids(); print_ids = false; + + // do not notify the already running instance (if any) return true; } + + if (called_from_remote) { + if (open_pie != null && open_pie != "") { + PieManager.open_pie(open_pie); + } else { + this.indicator.show_preferences(); + } + } + + // notify the already running instance (if any) return false; } } diff --git a/src/gui/aboutWindow.vala b/src/gui/aboutWindow.vala index 896d2ba..fd38c8c 100644 --- a/src/gui/aboutWindow.vala +++ b/src/gui/aboutWindow.vala @@ -47,6 +47,7 @@ public class AboutWindow: Gtk.AboutDialog { "Moo <hazap@hotmail.com> (LT)", "Gabriel Dubatti <gdubatti@gmail.com> (ES)", "Grégoire Bellon-Gervais <greggbg@gmail.com> (FR)", + "Raphaël Rochet <raphael@rri.fr> (FR)", "Alex Maxime <cad.maxime@gmail.com> (FR)", "Eugene Roskin <pams@imail.ru> (RU)", "Ting Zhou <tzhou@haverford.edu> (ZH-CN)", diff --git a/src/gui/newSliceWindow.vala b/src/gui/newSliceWindow.vala index 6066e57..89294b5 100644 --- a/src/gui/newSliceWindow.vala +++ b/src/gui/newSliceWindow.vala @@ -57,11 +57,15 @@ public class NewSliceWindow : GLib.Object { private Gtk.Box hotkey_box = null; private Gtk.Box uri_box = null; private Gtk.Box quickaction_box = null; + private Gtk.Box clipboard_box = null; + private Gtk.Box workspace_only_box = null; private Gtk.Image icon = null; private Gtk.Entry name_entry = null; private Gtk.Entry command_entry = null; private Gtk.Entry uri_entry = null; - private Gtk.CheckButton quickaction_checkbutton = null; + private Gtk.Switch quickaction_checkbutton = null; + private Gtk.Switch workspace_only_checkbutton = null; + private Gtk.Scale clipboard_slider = null; ///////////////////////////////////////////////////////////////////// /// Two custom widgets. For Pie and hotkey selection respectively. @@ -116,16 +120,25 @@ public class NewSliceWindow : GLib.Object { this.hotkey_box.hide(); this.uri_box.hide(); this.quickaction_box.hide(); + this.workspace_only_box.hide(); + this.clipboard_box.hide(); this.current_type = type; switch (type) { - case "bookmarks": case "clipboard": case "devices": - case "menu": case "session": case "window_list": - case "workspace_window_list": + case "bookmarks": case "devices": + case "menu": case "session": this.no_options_box.show(); this.set_icon(icon); break; + case "window_list": + this.workspace_only_box.show(); + this.set_icon(icon); + break; + case "clipboard": + this.clipboard_box.show(); + this.set_icon(icon); + break; case "app": this.name_box.show(); this.command_box.show(); @@ -183,11 +196,18 @@ public class NewSliceWindow : GLib.Object { this.name_entry = builder.get_object("name-entry") as Gtk.Entry; this.uri_entry = builder.get_object("uri-entry") as Gtk.Entry; this.command_entry = builder.get_object("command-entry") as Gtk.Entry; - this.quickaction_checkbutton = builder.get_object("quick-action-checkbutton") as Gtk.CheckButton; - + this.quickaction_checkbutton = builder.get_object("quick-action-checkbutton") as Gtk.Switch; this.quickaction_box = builder.get_object("quickaction-box") as Gtk.Box; this.icon = builder.get_object("icon") as Gtk.Image; + this.workspace_only_checkbutton = builder.get_object("workspace-only-checkbutton") as Gtk.Switch; + this.workspace_only_box = builder.get_object("workspace-only-box") as Gtk.Box; + + this.clipboard_box = builder.get_object("clipboard-box") as Gtk.Box; + this.clipboard_slider = (builder.get_object("clipboard-scale") as Gtk.Scale); + clipboard_slider.set_range(2, 24); + clipboard_slider.set_value(8); + this.icon_button.clicked.connect(on_icon_button_clicked); var scroll_area = builder.get_object("slice-scrolledwindow") as Gtk.ScrolledWindow; @@ -273,6 +293,15 @@ public class NewSliceWindow : GLib.Object { } else { type = GroupRegistry.descriptions[group.get_type().name()].id; + switch (type) { + case "clipboard": + this.clipboard_slider.set_value((group as ClipboardGroup).max_items); + break; + case "window_list": + this.workspace_only_checkbutton.active = (group as WindowListGroup).current_workspace_only; + break; + + } this.select_type(type); } } @@ -314,13 +343,19 @@ public class NewSliceWindow : GLib.Object { switch (this.current_type) { case "bookmarks": group = new BookmarkGroup(this.current_id); break; - case "clipboard": group = new ClipboardGroup(this.current_id); break; case "devices": group = new DevicesGroup(this.current_id); break; case "menu": group = new MenuGroup(this.current_id); break; case "session": group = new SessionGroup(this.current_id); break; - case "window_list": group = new WindowListGroup(this.current_id); break; - case "workspace_window_list": group = new WorkspaceWindowListGroup(this.current_id); break; - + case "clipboard": + var g = new ClipboardGroup(this.current_id); + g.max_items = (int)this.clipboard_slider.get_value(); + group = g; + break; + case "window_list": + var g = new WindowListGroup(this.current_id); + g.current_workspace_only = this.workspace_only_checkbutton.active; + group = g; + break; case "app": group = new ActionGroup(this.current_id); group.add_action(new AppAction(this.name_entry.text, this.current_icon, diff --git a/src/gui/preferencesWindow.vala b/src/gui/preferencesWindow.vala index d671501..09d8a3c 100644 --- a/src/gui/preferencesWindow.vala +++ b/src/gui/preferencesWindow.vala @@ -43,6 +43,7 @@ public class PreferencesWindow : GLib.Object { private Gtk.EventBox? preview_background = null; private Gtk.Button? remove_pie_button = null; private Gtk.Button? edit_pie_button = null; + private Gtk.Button? theme_delete_button = null; private ThemeList? theme_list = null; private Gtk.ToggleButton? indicator = null; @@ -149,6 +150,11 @@ public class PreferencesWindow : GLib.Object { } else { this.captions.sensitive = false; } + if (Config.global.theme.is_local()) { + this.theme_delete_button.sensitive = true; + } else { + this.theme_delete_button.sensitive = false; + } }); scroll_area = builder.get_object("theme-scrolledwindow") as Gtk.ScrolledWindow; @@ -164,6 +170,8 @@ public class PreferencesWindow : GLib.Object { (builder.get_object("theme-export-button") as Gtk.Button).clicked.connect(on_export_theme_button_clicked); (builder.get_object("theme-import-button") as Gtk.Button).clicked.connect(on_import_theme_button_clicked); + this.theme_delete_button = (builder.get_object("theme-delete-button") as Gtk.Button); + this.theme_delete_button.clicked.connect(on_delete_theme_button_clicked); this.autostart = (builder.get_object("autostart-checkbox") as Gtk.ToggleButton); this.autostart.toggled.connect(on_autostart_toggled); @@ -230,7 +238,7 @@ public class PreferencesWindow : GLib.Object { _("You can support the development of Gnome-Pie by donating via %s.").printf("<a href='https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=X65SUVC4ZTQSC'>Paypal</a>"), _("Translating Gnome-Pie to your language is easy. Translations are managed at %s.").printf("<a href='https://translate.zanata.org/zanata/iteration/view/gnome-pie/develop'>Zanata</a>"), _("It's easy to create new themes for Gnome-Pie. Read the <a href='%s'>Tutorial</a> online.").printf("http://simmesimme.github.io/lessons/2015/04/26/themes-for-gnome-pie/"), - _("It's usually a good practive to have at most twelve slices per pie."), + _("It's usually a good practice to have at most twelve slices per pie."), _("You can export themes you created and share them with the community!"), _("The source code of Gnome-Pie is available on %s.").printf("<a href='https://github.com/Simmesimme/Gnome-Pie'>Github</a>"), _("Bugs can be reported at %s!").printf("<a href='https://github.com/Simmesimme/Gnome-Pie/issues'>Github</a>"), @@ -284,6 +292,12 @@ public class PreferencesWindow : GLib.Object { this.captions.sensitive = false; } + if (Config.global.theme.is_local()) { + this.theme_delete_button.sensitive = true; + } else { + this.theme_delete_button.sensitive = false; + } + if (!Deamon.disable_stack_switcher) { this.stack.set_visible_child_full("2", Gtk.StackTransitionType.NONE); } else { @@ -427,6 +441,28 @@ public class PreferencesWindow : GLib.Object { } ///////////////////////////////////////////////////////////////////// + /// Deleted the slected theme. + ///////////////////////////////////////////////////////////////////// + + private void on_delete_theme_button_clicked(Gtk.Button button) { + + var dialog = new Gtk.MessageDialog((Gtk.Window)this.window.get_toplevel(), Gtk.DialogFlags.MODAL, + Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, + _("Do you really want to delete the selected theme from %s?").printf(Config.global.theme.directory)); + + dialog.response.connect((response) => { + if (response == Gtk.ResponseType.YES) { + Paths.delete_directory(Config.global.theme.directory); + Config.global.load_themes(""); + this.theme_list.reload(); + } + }); + + dialog.run(); + dialog.destroy(); + } + + ///////////////////////////////////////////////////////////////////// /// Shows or hides the indicator. ///////////////////////////////////////////////////////////////////// diff --git a/src/gui/themeList.vala b/src/gui/themeList.vala index 46ae876..e6ecb3c 100644 --- a/src/gui/themeList.vala +++ b/src/gui/themeList.vala @@ -105,7 +105,8 @@ class ThemeList : Gtk.TreeView { data.set(current, DataPos.ICON, theme.preview_icon.to_pixbuf()); data.set(current, DataPos.NAME, GLib.Markup.escape_text(theme.name)+"\n" + "<span font-size='x-small'>" + GLib.Markup.escape_text(theme.description) - + "</span>"); + + " - <i>"+GLib.Markup.escape_text(_("by")+" "+theme.author) + + "</i></span>"); if(theme == Config.global.theme) { get_selection().select_iter(current); } diff --git a/src/pies/defaultConfig.vala b/src/pies/defaultConfig.vala index e446c2b..8763a1d 100644 --- a/src/pies/defaultConfig.vala +++ b/src/pies/defaultConfig.vala @@ -62,6 +62,10 @@ namespace Pies { window.add_action(new KeyAction(_("Maximize"), "view-fullscreen", "<Alt>F10")); window.add_action(new KeyAction(_("Restore"), "view-restore", "<Alt>F5")); + // add a pie with window list group + var alt_tab = PieManager.create_persistent_pie("Alt Tab", "dock", new Trigger.from_string("<Control><Alt>T")); + alt_tab.add_group(new WindowListGroup(alt_tab.id)); + // save the configuration to file Pies.save(); } diff --git a/src/pies/load.vala b/src/pies/load.vala index 7402094..0dfb423 100644 --- a/src/pies/load.vala +++ b/src/pies/load.vala @@ -192,17 +192,14 @@ namespace Pies { string attr_name = attribute->name.down(); string attr_content = attribute->children->content; - switch (attr_name) { - case "type": - type = attr_content; - break; - default: - warning("Invalid attribute \"" + attr_name + "\" in <group> element in pies.conf!"); - break; + if (attr_name == "type") { + type = attr_content; + break; } } ActionGroup group = GroupRegistry.create_group(type, pie.id); + group.on_load(slice); if (group != null) pie.add_group(group); } diff --git a/src/pies/save.vala b/src/pies/save.vala index 9760cce..efb3fb6 100644 --- a/src/pies/save.vala +++ b/src/pies/save.vala @@ -72,7 +72,7 @@ namespace Pies { } } else { writer.start_element("group"); - writer.write_attribute("type", GroupRegistry.descriptions[group.get_type().name()].id); + group.on_save(writer); writer.end_element(); slice_count += group.actions.size; diff --git a/src/renderers/pieWindow.vala b/src/renderers/pieWindow.vala index c1d70b7..5accb15 100755 --- a/src/renderers/pieWindow.vala +++ b/src/renderers/pieWindow.vala @@ -445,6 +445,7 @@ public class PieWindow : Gtk.Window { if (Gdk.keyval_name(key) == "Escape") this.cancel(); else if (Gdk.keyval_name(key) == "Return") this.activate_slice(time_stamp); + else if (Gdk.keyval_name(key) == "KP_Enter") this.activate_slice(time_stamp); else if (!PieManager.get_is_turbo(this.renderer.id)) { if (Gdk.keyval_name(key) == "Up") this.renderer.select_up(); else if (Gdk.keyval_name(key) == "Down") this.renderer.select_down(); diff --git a/src/themes/theme.vala b/src/themes/theme.vala index 98e8994..2e256f9 100644 --- a/src/themes/theme.vala +++ b/src/themes/theme.vala @@ -87,14 +87,44 @@ public class Theme : GLib.Object { this.active_slice_layers.clear(); this.inactive_slice_layers.clear(); + if (!GLib.File.new_for_path(this.directory).query_exists()) { + return false; + } + + string config_file = this.directory + "/theme.xml"; + + if (!GLib.File.new_for_path(config_file).query_exists()) { + try { + // detect whether theme is one directory deeper + string child; + bool success = false; + + // load global themes + var d = Dir.open(this.directory); + while ((child = d.read_name()) != null && !success) { + config_file = this.directory + "/" + child + "/theme.xml"; + if (GLib.File.new_for_path(config_file).query_exists()) { + this.directory = this.directory + "/" + child; + success = true; + } + } + + if (!success) { + return false; + } + } catch (Error e) { + warning (e.message); + return false; + } + } + this.preview_icon = new Icon(this.directory + "/preview.png", 36); Xml.Parser.init(); - string path = this.directory + "/theme.xml"; - Xml.Doc* themeXML = Xml.Parser.parse_file(path); + Xml.Doc* themeXML = Xml.Parser.parse_file(config_file); if (themeXML == null) { - warning("Failed to add theme: \"" + path + "\" not found!"); + warning("Failed to add theme: \"" + config_file + "\" not found!"); return false; } @@ -151,6 +181,7 @@ public class Theme : GLib.Object { } } + ///////////////////////////////////////////////////////////////////// /// Loads all images of the theme. ///////////////////////////////////////////////////////////////////// @@ -165,6 +196,15 @@ public class Theme : GLib.Object { } ///////////////////////////////////////////////////////////////////// + /// Returns true if the theme is installed to the local themes + /// directory. + ///////////////////////////////////////////////////////////////////// + + public bool is_local() { + return this.directory.has_prefix(Paths.local_themes); + } + + ///////////////////////////////////////////////////////////////////// /// The following methods parse specific parts of the theme file. /// Nothing special here, just some boring code. ///////////////////////////////////////////////////////////////////// diff --git a/src/utilities/config.vala b/src/utilities/config.vala index 5dedddb..74bbcbb 100644 --- a/src/utilities/config.vala +++ b/src/utilities/config.vala @@ -57,7 +57,7 @@ public class Config : GLib.Object { public int activation_range { get; set; default = 200; } public int max_visible_slices { get; set; default = 24; } public bool show_indicator { get; set; default = true; } - public bool show_captions { get; set; default = true; } + public bool show_captions { get; set; default = false; } public bool search_by_string { get; set; default = true; } public bool auto_start { get; set; default = false; } public int showed_news { get; set; default = 0; } diff --git a/src/utilities/paths.vala b/src/utilities/paths.vala index 96bce0a..7bdd642 100644 --- a/src/utilities/paths.vala +++ b/src/utilities/paths.vala @@ -108,6 +108,28 @@ public class Paths : GLib.Object { public static string executable { get; private set; default=""; } ///////////////////////////////////////////////////////////////////// + /// Deletes a directory recursively from disk. Use with care :) + ///////////////////////////////////////////////////////////////////// + + public static void delete_directory(string directory) { + try { + var d = Dir.open(directory); + string name; + while ((name = d.read_name()) != null) { + string path = Path.build_filename(directory, name); + if (FileUtils.test(path, FileTest.IS_DIR)) { + delete_directory(path); + } else { + FileUtils.remove(path); + } + } + DirUtils.remove(directory); + } catch (Error e) { + warning (e.message); + } + } + + ///////////////////////////////////////////////////////////////////// /// Initializes all values above. ///////////////////////////////////////////////////////////////////// |