From 98f3ef2689de06e8ab8b46a91acfa7dd2056a3a6 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Mon, 5 Mar 2012 12:19:59 +0100 Subject: Imported Upstream version 0.5.1 --- src/actionGroups/devicesGroup.vala | 12 +-- src/actionGroups/menuGroup.vala | 15 +--- src/actions/actionRegistry.vala | 27 ++---- src/actions/pieAction.vala | 10 ++- src/deamon.vala | 21 ++++- src/gui/aboutWindow.vala | 5 +- src/gui/newSliceWindow.vala | 1 + src/gui/piePreview.vala | 3 + src/gui/settingsWindow.vala | 38 ++++++++- src/gui/themeList.vala | 12 +++ src/gui/triggerSelectButton.vala | 4 +- src/images/icon.vala | 18 ++++ src/images/renderedText.vala | 81 +++++++++++------- src/images/themedIcon.vala | 129 +++++++++++----------------- src/pies/load.vala | 2 + src/pies/pieManager.vala | 21 ++++- src/pies/save.vala | 15 ++++ src/renderers/pieRenderer.vala | 42 +++++++--- src/renderers/pieWindow.vala | 23 +++++ src/renderers/sliceRenderer.vala | 32 +++++-- src/themes/sliceLayer.vala | 50 +++++++++-- src/themes/theme.vala | 61 +++++++++++++- src/utilities/config.vala | 5 ++ src/utilities/logger.vala | 168 ++++++++++++++++++++++++++++++------- src/utilities/paths.vala | 44 +++++++++- 25 files changed, 609 insertions(+), 230 deletions(-) (limited to 'src') diff --git a/src/actionGroups/devicesGroup.vala b/src/actionGroups/devicesGroup.vala index dee6a6e..d3892fe 100644 --- a/src/actionGroups/devicesGroup.vala +++ b/src/actionGroups/devicesGroup.vala @@ -87,17 +87,9 @@ public class DevicesGroup : ActionGroup { // add all other devices foreach(var mount in this.monitor.get_mounts()) { // get icon - var icon_names = mount.get_icon().to_string().split(" "); + var icon = mount.get_icon(); - string icon = ""; - foreach (var icon_name in icon_names) { - if (Gtk.IconTheme.get_default().has_icon(icon_name)) { - icon = icon_name; - break; - } - } - - this.add_action(new UriAction(mount.get_name(), icon, mount.get_root().get_uri())); + this.add_action(new UriAction(mount.get_name(), Icon.get_icon_name(icon), mount.get_root().get_uri())); } } diff --git a/src/actionGroups/menuGroup.vala b/src/actionGroups/menuGroup.vala index 247376d..26a2662 100644 --- a/src/actionGroups/menuGroup.vala +++ b/src/actionGroups/menuGroup.vala @@ -131,18 +131,11 @@ public class MenuGroup : ActionGroup { if (type == GMenu.TreeItemType.DIRECTORY && !item.get_directory().get_is_nodisplay()) { // create a MenuGroup for sub menus - string[] icons = item.get_directory().get_icon().to_string().split(" "); - string final_icon = "application-default-icon"; - // search for available icons - foreach (var icon in icons) { - if (Gtk.IconTheme.get_default().has_icon(icon)) { - final_icon = icon; - break; - } - } - - var sub_menu = PieManager.create_dynamic_pie(item.get_directory().get_name(), final_icon); + // get icon + var icon = item.get_directory().get_icon(); + + var sub_menu = PieManager.create_dynamic_pie(item.get_directory().get_name(), Icon.get_icon_name(icon)); var group = new MenuGroup.sub_menu(sub_menu.id); group.add_action(new PieAction(parent_id, true)); group.load_contents(item.get_directory(), sub_menu.id); diff --git a/src/actions/actionRegistry.vala b/src/actions/actionRegistry.vala index 135e90c..705c06c 100644 --- a/src/actions/actionRegistry.vala +++ b/src/actions/actionRegistry.vala @@ -137,15 +137,8 @@ public class ActionRegistry : GLib.Object { return new_for_desktop_file(file.get_parse_name()); // search for an appropriate icon - var gicon = info.get_icon(); - string[] icons = gicon.to_string().split(" "); - - foreach (var icon in icons) { - if (Gtk.IconTheme.get_default().has_icon(icon)) { - final_icon = icon; - break; - } - } + var icon = info.get_icon(); + final_icon = Icon.get_icon_name(icon); } catch (GLib.Error e) { warning(e.message); @@ -167,19 +160,11 @@ public class ActionRegistry : GLib.Object { /// A helper method which creates an AppAction for given AppInfo. ///////////////////////////////////////////////////////////////////// - public static Action? new_for_app_info(GLib.AppInfo info) { - string[] icons = info.get_icon().to_string().split(" "); - string final_icon = "application-default-icon"; - - // search for available icons - foreach (var icon in icons) { - if (Gtk.IconTheme.get_default().has_icon(icon)) { - final_icon = icon; - break; - } - } + public static Action? new_for_app_info(GLib.AppInfo info) { + // get icon + var icon = info.get_icon(); - return new AppAction(info.get_display_name() , final_icon, info.get_commandline()); + return new AppAction(info.get_display_name(), Icon.get_icon_name(icon), info.get_commandline()); } ///////////////////////////////////////////////////////////////////// diff --git a/src/actions/pieAction.vala b/src/actions/pieAction.vala index 5b2c81d..faf7aca 100644 --- a/src/actions/pieAction.vala +++ b/src/actions/pieAction.vala @@ -58,13 +58,17 @@ public class PieAction : Action { public override string name { get { var referee = PieManager.all_pies[real_command]; - if (referee != null) - return referee.name; + if (referee != null) { + owned_name = "↪" + referee.name; + return owned_name; + } return ""; } protected set {} } + private string owned_name; + ///////////////////////////////////////////////////////////////////// /// Returns the icon of the referenced Pie. ///////////////////////////////////////////////////////////////////// @@ -92,7 +96,7 @@ public class PieAction : Action { ///////////////////////////////////////////////////////////////////// public override void activate() { - PieManager.open_pie(real_command); + PieManager.open_pie(real_command, true); } } diff --git a/src/deamon.vala b/src/deamon.vala index ceecf1b..b622028 100644 --- a/src/deamon.vala +++ b/src/deamon.vala @@ -24,16 +24,26 @@ namespace GnomePie { ///////////////////////////////////////////////////////////////////////// public class Deamon : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// The current version of Gnome-Pie + ///////////////////////////////////////////////////////////////////// + + public static string version; ///////////////////////////////////////////////////////////////////// /// The beginning of everything. ///////////////////////////////////////////////////////////////////// public static int main(string[] args) { + version = "0.5.1"; + Logger.init(); Gdk.threads_init(); Gtk.init(ref args); Paths.init(); + + message("Welcome to Gnome-Pie " + version + "!"); // create the Deamon and run it var deamon = new GnomePie.Deamon(); @@ -90,6 +100,9 @@ public class Deamon : GLib.Object { message("Removed file \"%s\"", Paths.pie_config); if (GLib.FileUtils.remove(Paths.settings) == 0) message("Removed file \"%s\"", Paths.settings); + + Logger.stats("LAUNCH RESET"); + return; } @@ -107,11 +120,17 @@ public class Deamon : GLib.Object { var data = new Unique.MessageData(); data.set_text(open_pie, open_pie.length); app.send_message(Unique.Command.ACTIVATE, data); + + Logger.stats("LAUNCH PIE " + open_pie); + return; } message("Gnome-Pie is already running. Sending request to open config menu."); app.send_message(Unique.Command.ACTIVATE, null); + + Logger.stats("LAUNCH CONFIG"); + return; } @@ -139,7 +158,6 @@ public class Deamon : GLib.Object { PieManager.init(); Icon.init(); - ThemedIcon.init(); // launch the indicator this.indicator = new Indicator(); @@ -150,6 +168,7 @@ public class Deamon : GLib.Object { // finished loading... so run the prog! message("Started happily..."); + Logger.stats("LAUNCH " + version); // open pie if neccessary if (open_pie != null) PieManager.open_pie(open_pie); diff --git a/src/gui/aboutWindow.vala b/src/gui/aboutWindow.vala index 2df8c46..6c5820b 100644 --- a/src/gui/aboutWindow.vala +++ b/src/gui/aboutWindow.vala @@ -42,7 +42,8 @@ public class AboutWindow: Gtk.AboutDialog { "Magnun Leno (PT-BR)", "Kim Boram (KO)", "Eduardo Anabalon (ES)", - "Gregoire Bellon-Gervais (FR)", + "Grégoire Bellon-Gervais (FR)", + "Alex Maxime (FR)", "Eugene Roskin (RU)" }; @@ -68,7 +69,7 @@ public class AboutWindow: Gtk.AboutDialog { logo_icon_name: "gnome-pie", website: "http://www.simonschneegans.de/?page_id=12", website_label: "www.gnome-pie.simonschneegans.de", - version: "0.4.2" + version: Deamon.version ); } } diff --git a/src/gui/newSliceWindow.vala b/src/gui/newSliceWindow.vala index 7bd6340..ade6432 100644 --- a/src/gui/newSliceWindow.vala +++ b/src/gui/newSliceWindow.vala @@ -258,6 +258,7 @@ public class NewSliceWindow : GLib.Object { break; case "key": this.current_custom_icon = action.icon; + this.current_hotkey = action.real_command; this.key_select.set_trigger(new Trigger.from_string(action.real_command)); break; case "pie": diff --git a/src/gui/piePreview.vala b/src/gui/piePreview.vala index 5745fcb..4963bb2 100644 --- a/src/gui/piePreview.vala +++ b/src/gui/piePreview.vala @@ -111,6 +111,9 @@ class PiePreview : Gtk.DrawingArea { this.new_slice_window.on_select.connect((new_action, as_new_slice, at_position) => { var pie = PieManager.all_pies[this.current_id]; + debug(new_action.actions[0].name); + debug(new_action.actions[0].real_command); + if (new_action.has_quickaction()) renderer.disable_quickactions(); diff --git a/src/gui/settingsWindow.vala b/src/gui/settingsWindow.vala index 1eaa0b4..0e7af20 100644 --- a/src/gui/settingsWindow.vala +++ b/src/gui/settingsWindow.vala @@ -32,6 +32,7 @@ public class SettingsWindow : GLib.Object { private ThemeList? theme_list = null; private Gtk.ToggleButton? indicator = null; private Gtk.ToggleButton? autostart = null; + private Gtk.ToggleButton? captions = null; ///////////////////////////////////////////////////////////////////// /// C'tor creates, the dialog. @@ -47,6 +48,14 @@ public class SettingsWindow : GLib.Object { this.window = builder.get_object("window") as Gtk.Dialog; this.theme_list = new ThemeList(); + this.theme_list.on_select_new.connect(() => { + this.captions.active = Config.global.show_captions; + if (Config.global.theme.has_slice_captions) { + this.captions.sensitive = true; + } else { + this.captions.sensitive = false; + } + }); var scroll_area = builder.get_object("theme-scrolledwindow") as Gtk.ScrolledWindow; scroll_area.add(this.theme_list); @@ -59,6 +68,9 @@ public class SettingsWindow : GLib.Object { this.indicator = (builder.get_object("indicator-checkbox") as Gtk.ToggleButton); this.indicator.toggled.connect(on_indicator_toggled); + this.captions = (builder.get_object("captions-checkbox") as Gtk.ToggleButton); + this.captions.toggled.connect(on_captions_toggled); + var scale_slider = (builder.get_object("scale-hscale") as Gtk.HScale); scale_slider.set_range(0.5, 2.0); scale_slider.set_increments(0.05, 0.25); @@ -108,8 +120,15 @@ public class SettingsWindow : GLib.Object { public void show() { this.indicator.active = Config.global.show_indicator; - this.autostart.active = Config.global.auto_start; - + this.autostart.active = Config.global.auto_start; + this.captions.active = Config.global.show_captions; + + if (Config.global.theme.has_slice_captions) { + this.captions.sensitive = true; + } else { + this.captions.sensitive = false; + } + this.window.show_all(); } @@ -119,6 +138,12 @@ public class SettingsWindow : GLib.Object { private void on_close_button_clicked() { this.window.hide(); + + Logger.stats("SETTINGS " + Config.global.theme.name + + (this.indicator.active ? " INDICATOR" : "") + + (this.autostart.active ? " AUTOSTART" : "") + + (this.captions.active ? " CAPTIONS" : "") + + " %f".printf(Config.global.global_scale)); } ///////////////////////////////////////////////////////////////////// @@ -169,6 +194,15 @@ public class SettingsWindow : GLib.Object { var check = check_box as Gtk.CheckButton; Config.global.show_indicator = check.active; } + + ///////////////////////////////////////////////////////////////////// + /// Shows or hides the captions of Slices. + ///////////////////////////////////////////////////////////////////// + + private void on_captions_toggled(Gtk.ToggleButton check_box) { + var check = check_box as Gtk.CheckButton; + Config.global.show_captions = check.active; + } } } diff --git a/src/gui/themeList.vala b/src/gui/themeList.vala index 7aaecc6..1c038a9 100644 --- a/src/gui/themeList.vala +++ b/src/gui/themeList.vala @@ -23,6 +23,15 @@ namespace GnomePie { class ThemeList : Gtk.TreeView { + ///////////////////////////////////////////////////////////////////// + /// This signal gets emitted, when a new theme is selected by the + /// user. This new theme is applied automatically, with this signal + /// actions may be triggered which should be executed AFTER the + /// change to a new theme. + ///////////////////////////////////////////////////////////////////// + + public signal void on_select_new(); + ///////////////////////////////////////////////////////////////////// /// The currently selected row. ///////////////////////////////////////////////////////////////////// @@ -69,6 +78,9 @@ class ThemeList : Gtk.TreeView { Timeout.add(10, () => { int index = int.parse(data.get_path(active).to_string()); Config.global.theme = Config.global.themes[index]; + + this.on_select_new(); + Config.global.theme.load(); Config.global.theme.load_images(); return false; diff --git a/src/gui/triggerSelectButton.vala b/src/gui/triggerSelectButton.vala index eeb37e2..fd8505a 100644 --- a/src/gui/triggerSelectButton.vala +++ b/src/gui/triggerSelectButton.vala @@ -132,8 +132,8 @@ public class TriggerSelectButton : Gtk.ToggleButton { if (this.active) { Gtk.Allocation rect; this.get_allocation(out rect); - if (event.x < rect.x || event.x > rect.x + rect.width - || event.y < rect.y || event.y > rect.y + rect.height) { + if (event.x < 0 || event.x > rect.width + || event.y < 0 || event.y > rect.height) { this.cancel(); return true; diff --git a/src/images/icon.vala b/src/images/icon.vala index 81eb2d9..e942e7c 100644 --- a/src/images/icon.vala +++ b/src/images/icon.vala @@ -74,6 +74,24 @@ public class Icon : Image { return base.width(); } + ///////////////////////////////////////////////////////////////////// + /// Returns the icon name for a given GLib.Icon. + ///////////////////////////////////////////////////////////////////// + + public static string get_icon_name(GLib.Icon? icon) { + if (icon != null) { + var icon_names = icon.to_string().split(" "); + + foreach (var icon_name in icon_names) { + if (Gtk.IconTheme.get_default().has_icon(icon_name)) { + return icon_name; + } + } + } + + return ""; + } + ///////////////////////////////////////////////////////////////////// /// Returns the filename for a given system icon. ///////////////////////////////////////////////////////////////////// diff --git a/src/images/renderedText.vala b/src/images/renderedText.vala index 41146d6..e99d26a 100644 --- a/src/images/renderedText.vala +++ b/src/images/renderedText.vala @@ -50,39 +50,60 @@ public class RenderedText : Image { public void render_text(string text, int width, int height, string font, Color color, double scale) { - + this.surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, width, height); - var ctx = this.context(); - - // set the color - ctx.set_source_rgb(color.r, color.g, color.g); - - var layout = Pango.cairo_create_layout(ctx); - layout.set_width(Pango.units_from_double(width)); - - var font_description = Pango.FontDescription.from_string(font); - font_description.set_size((int)(font_description.get_size() * scale)); - - layout.set_font_description(font_description); - layout.set_text(text, -1); - - // add newlines at the end of each line, in order to allow ellipsizing - string broken_string = ""; - foreach (var line in layout.get_lines()) { - broken_string = broken_string.concat(text.substring(line.start_index, line.length), "\n"); + if (text != "") { + + var ctx = this.context(); + + // set the color + ctx.set_source_rgb(color.r, color.g, color.g); + + var layout = Pango.cairo_create_layout(ctx); + layout.set_width(Pango.units_from_double(width)); + + var font_description = Pango.FontDescription.from_string(font); + font_description.set_size((int)(font_description.get_size() * scale)); + + layout.set_font_description(font_description); + layout.set_text(text, -1); + + // add newlines at the end of each line, in order to allow ellipsizing + string broken_string = ""; + var lines = layout.get_lines().copy(); + + foreach (var line in lines) { + + string next_line = text.substring(line.start_index, line.length); + + if (broken_string == "") { + broken_string = next_line; + } else if (next_line != "") { + // test whether the addition of a line would cause the height to become too large + string broken_string_tmp = broken_string + "\n" + next_line; + + layout.set_text(broken_string_tmp, -1); + Pango.Rectangle extents; + layout.get_pixel_extents(null, out extents); + + if (extents.height > height) broken_string = broken_string + next_line; + else broken_string = broken_string_tmp; + } + } + + layout.set_text(broken_string, -1); + + layout.set_ellipsize(Pango.EllipsizeMode.END); + layout.set_alignment(Pango.Alignment.CENTER); + + Pango.Rectangle extents; + layout.get_pixel_extents(null, out extents); + ctx.move_to(0, (int)(0.5*(height - extents.height))); + + Pango.cairo_update_layout(ctx, layout); + Pango.cairo_show_layout(ctx, layout); } - layout.set_text(broken_string, broken_string.length-1); - - layout.set_ellipsize(Pango.EllipsizeMode.END); - layout.set_alignment(Pango.Alignment.CENTER); - - Pango.Rectangle extents; - layout.get_pixel_extents(null, out extents); - ctx.move_to(0, (int)(0.5*(height - extents.height))); - - Pango.cairo_update_layout(ctx, layout); - Pango.cairo_show_layout(ctx, layout); } ///////////////////////////////////////////////////////////////////// diff --git a/src/images/themedIcon.vala b/src/images/themedIcon.vala index 6c904a6..f816e0f 100644 --- a/src/images/themedIcon.vala +++ b/src/images/themedIcon.vala @@ -23,54 +23,12 @@ namespace GnomePie { ///////////////////////////////////////////////////////////////////////// public class ThemedIcon : Image { - - ///////////////////////////////////////////////////////////////////// - /// A cache which stores loaded icon. The key is the icon name. When - /// the users icon theme or the theme of Gnome-Pie changes, these - /// cahces are cleared. - ///////////////////////////////////////////////////////////////////// - - private static Gee.HashMap active_cache { private get; private set; } - private static Gee.HashMap inactive_cache { private get; private set; } - - ///////////////////////////////////////////////////////////////////// - /// Initializes the caches. - ///////////////////////////////////////////////////////////////////// - - public static void init() { - clear_cache(); - - Config.global.notify["theme"].connect(() => { - clear_cache(); - }); - - Gtk.IconTheme.get_default().changed.connect(() => { - clear_cache(); - }); - } - - ///////////////////////////////////////////////////////////////////// - /// Clears the cache. - ///////////////////////////////////////////////////////////////////// - - public static void clear_cache() { - active_cache = new Gee.HashMap(); - inactive_cache = new Gee.HashMap(); - } ///////////////////////////////////////////////////////////////////// /// Paint a slice icon according to the current theme. ///////////////////////////////////////////////////////////////////// - public ThemedIcon(string icon_name, bool active) { - // check cache - var current_cache = active ? active_cache : inactive_cache; - var cached = current_cache.get(icon_name); - - if (cached != null) { - this.surface = cached; - return; - } + public ThemedIcon(string caption, string icon_name, bool active) { // get layers for the desired slice type var layers = active ? Config.global.theme.active_slice_layers : Config.global.theme.inactive_slice_layers; @@ -78,7 +36,8 @@ public class ThemedIcon : Image { // get max size int size = 1; foreach (var layer in layers) { - if (layer.image.width() > size) size = layer.image.width(); + if (layer.image != null && layer.image.width() > size) + size = layer.image.width(); } this.surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, size, size); @@ -86,7 +45,8 @@ public class ThemedIcon : Image { // get size of icon layer int icon_size = size; foreach (var layer in layers) { - if (layer.is_icon) icon_size = layer.image.width(); + if (layer.image != null && layer.layer_type == SliceLayer.Type.ICON) + icon_size = layer.image.width(); } Image icon; @@ -104,49 +64,54 @@ public class ThemedIcon : Image { // now render all layers on top of each other foreach (var layer in layers) { - if (layer.colorize) { - ctx.push_group(); - } - - if (layer.is_icon) { + if (layer.visibility == SliceLayer.Visibility.ANY || + (Config.global.show_captions == (layer.visibility == SliceLayer.Visibility.WITH_CAPTION))) { - ctx.push_group(); - - layer.image.paint_on(ctx); - - ctx.set_operator(Cairo.Operator.IN); - - if (layer.image.width() != icon_size) { - if (icon_name.contains("/")) - icon = new Image.from_file_at_size(icon_name, layer.image.width(), layer.image.width()); - else - icon = new Icon(icon_name,layer.image.width()); + if (layer.colorize) { + ctx.push_group(); } - - icon.paint_on(ctx); + + if (layer.layer_type == SliceLayer.Type.ICON) { + ctx.push_group(); + + layer.image.paint_on(ctx); + + ctx.set_operator(Cairo.Operator.IN); + + if (layer.image.width() != icon_size) { + if (icon_name.contains("/")) + icon = new Image.from_file_at_size(icon_name, layer.image.width(), layer.image.width()); + else + icon = new Icon(icon_name,layer.image.width()); + } + + icon.paint_on(ctx); - ctx.pop_group_to_source(); - ctx.paint(); - ctx.set_operator(Cairo.Operator.OVER); - - } else { - layer.image.paint_on(ctx); - } - - // colorize the whole layer if neccasary - if (layer.colorize) { - ctx.set_operator(Cairo.Operator.ATOP); - ctx.set_source_rgb(color.r, color.g, color.b); - ctx.paint(); + ctx.pop_group_to_source(); + ctx.paint(); + ctx.set_operator(Cairo.Operator.OVER); + + } else if (layer.layer_type == SliceLayer.Type.CAPTION) { + Image text = new RenderedText(caption, layer.width, layer.height, layer.font, layer.color, Config.global.global_scale); + ctx.translate(0, layer.position); + text.paint_on(ctx); + ctx.translate(0, -layer.position); + } else if (layer.layer_type == SliceLayer.Type.FILE) { + layer.image.paint_on(ctx); + } - ctx.set_operator(Cairo.Operator.OVER); - ctx.pop_group_to_source(); - ctx.paint(); + // colorize the whole layer if neccasary + if (layer.colorize) { + ctx.set_operator(Cairo.Operator.ATOP); + ctx.set_source_rgb(color.r, color.g, color.b); + ctx.paint(); + + ctx.set_operator(Cairo.Operator.OVER); + ctx.pop_group_to_source(); + ctx.paint(); + } } } - - // store the surface in cache - current_cache.set(icon_name, this.surface); } ///////////////////////////////////////////////////////////////////// diff --git a/src/pies/load.vala b/src/pies/load.vala index b606cf5..4a9274d 100644 --- a/src/pies/load.vala +++ b/src/pies/load.vala @@ -36,6 +36,8 @@ namespace Pies { Pies.create_default_config(); return; } + + message("Loading Pies from \"" + Paths.pie_config + "\"."); // load the settings file Xml.Parser.init(); diff --git a/src/pies/pieManager.vala b/src/pies/pieManager.vala index 162a61f..85d8a14 100644 --- a/src/pies/pieManager.vala +++ b/src/pies/pieManager.vala @@ -51,6 +51,14 @@ public class PieManager : GLib.Object { private static bool a_pie_is_active = false; + ///////////////////////////////////////////////////////////////////// + /// Storing the position of the last Pie. Used for subpies, which are + /// opened at their parents location. + ///////////////////////////////////////////////////////////////////// + + private static int last_x = 0; + private static int last_y = 0; + ///////////////////////////////////////////////////////////////////// /// Initializes all Pies. They are loaded from the pies.conf file. ///////////////////////////////////////////////////////////////////// @@ -73,28 +81,35 @@ public class PieManager : GLib.Object { /// Opens the Pie with the given ID, if it exists. ///////////////////////////////////////////////////////////////////// - public static void open_pie(string id) { + public static void open_pie(string id, bool at_last_position = false) { if (!a_pie_is_active) { Pie? pie = all_pies[id]; if (pie != null) { + Logger.stats("OPEN " + id); + a_pie_is_active = true; var window = new PieWindow(); window.load_pie(pie); - window.open(); + + if (at_last_position) { + window.open_at(last_x, last_y); + } else { + window.open(); + } opened_windows.add(window); window.on_closed.connect(() => { opened_windows.remove(window); if (opened_windows.size == 0) { - ThemedIcon.clear_cache(); Icon.clear_cache(); } }); window.on_closing.connect(() => { + window.get_center_pos(out last_x, out last_y); a_pie_is_active = false; }); diff --git a/src/pies/save.vala b/src/pies/save.vala index c940e5a..aadc7c8 100644 --- a/src/pies/save.vala +++ b/src/pies/save.vala @@ -30,6 +30,11 @@ namespace Pies { ///////////////////////////////////////////////////////////////////// public void save() { + message("Saving Pies to \"" + Paths.pie_config + "\"."); + + // log pie statistics + string pie_line = "PIES"; + // initializes the XML-Writer var writer = new Xml.TextWriter.filename(Paths.pie_config); writer.set_indent(true); @@ -42,6 +47,8 @@ namespace Pies { // if it's no dynamically created Pie if (pie.id.length == 3) { + int slice_count = 0; + // write all attributes of the Pie writer.start_element("pie"); writer.write_attribute("name", pie.name); @@ -63,18 +70,26 @@ namespace Pies { writer.write_attribute("command", action.real_command); writer.write_attribute("quickAction", action.is_quickaction ? "true" : "false"); writer.end_element(); + + ++ slice_count; } } else { writer.start_element("group"); writer.write_attribute("type", GroupRegistry.descriptions[group.get_type().name()].id); writer.end_element(); + + slice_count += group.actions.size; } } writer.end_element(); + + pie_line += " " + pie.id + "(%d)".printf(slice_count); } } writer.end_element(); writer.end_document(); + + Logger.stats(pie_line); } } diff --git a/src/renderers/pieRenderer.vala b/src/renderers/pieRenderer.vala index 67a6b56..09c5f7a 100644 --- a/src/renderers/pieRenderer.vala +++ b/src/renderers/pieRenderer.vala @@ -58,23 +58,23 @@ public class PieRenderer : GLib.Object { public bool turbo_mode { get; private set; default=false; } ///////////////////////////////////////////////////////////////////// - /// All SliceRenderers used to draw this Pie. + /// True if the pie is currently navigated with the keyboard. This is + /// set to false as soon as the mouse moves. ///////////////////////////////////////////////////////////////////// - private Gee.ArrayList slices; + public bool key_board_control { get; set; default=false; } ///////////////////////////////////////////////////////////////////// - /// The renderer for the center of this pie. + /// All SliceRenderers used to draw this Pie. ///////////////////////////////////////////////////////////////////// - private CenterRenderer center; + private Gee.ArrayList slices; ///////////////////////////////////////////////////////////////////// - /// True if the pie is currently navigated with the keyboard. This is - /// set to false as soon as the mouse moves. + /// The renderer for the center of this pie. ///////////////////////////////////////////////////////////////////// - private bool key_board_control = false; + private CenterRenderer center; ///////////////////////////////////////////////////////////////////// /// C'tor, initializes members. @@ -130,9 +130,21 @@ public class PieRenderer : GLib.Object { ///////////////////////////////////////////////////////////////////// public void activate() { - if (this.active_slice >= 0 && this.active_slice < this.slices.size) + if (this.active_slice >= 0 && this.active_slice < this.slices.size) { slices[active_slice].activate(); - this.cancel(); + + if (this.active_slice == this.quickaction) + Logger.stats("ACTIVATE QUICKACTION %d".printf(this.active_slice)); + else + Logger.stats("ACTIVATE %d".printf(this.active_slice)); + } else { + Logger.stats("CANCEL"); + } + + foreach (var slice in this.slices) + slice.fade_out(); + + center.fade_out(); } ///////////////////////////////////////////////////////////////////// @@ -144,6 +156,8 @@ public class PieRenderer : GLib.Object { slice.fade_out(); center.fade_out(); + + Logger.stats("CANCEL"); } ///////////////////////////////////////////////////////////////////// @@ -161,6 +175,8 @@ public class PieRenderer : GLib.Object { this.set_highlighted_slice(this.active_slice+1); else if (this.active_slice != top) this.set_highlighted_slice((this.active_slice-1+this.slice_count())%this.slice_count()); + + this.key_board_control = true; } ///////////////////////////////////////////////////////////////////// @@ -178,6 +194,8 @@ public class PieRenderer : GLib.Object { this.set_highlighted_slice(this.active_slice-1); else if (this.active_slice != bottom) this.set_highlighted_slice((this.active_slice+1)%this.slice_count()); + + this.key_board_control = true; } ///////////////////////////////////////////////////////////////////// @@ -195,6 +213,8 @@ public class PieRenderer : GLib.Object { this.set_highlighted_slice(this.active_slice-1); else if (this.active_slice < left) this.set_highlighted_slice(this.active_slice+1); + + this.key_board_control = true; } ///////////////////////////////////////////////////////////////////// @@ -212,6 +232,8 @@ public class PieRenderer : GLib.Object { this.set_highlighted_slice((this.active_slice+1)%this.slice_count()); else if (this.active_slice < left && this.active_slice != right) this.set_highlighted_slice((this.active_slice-1+this.slice_count())%this.slice_count()); + + this.key_board_control = true; } ///////////////////////////////////////////////////////////////////// @@ -292,8 +314,6 @@ public class PieRenderer : GLib.Object { foreach (var slice in this.slices) slice.set_active_slice(active); - - this.key_board_control = true; } } } diff --git a/src/renderers/pieWindow.vala b/src/renderers/pieWindow.vala index 54dd691..852a739 100644 --- a/src/renderers/pieWindow.vala +++ b/src/renderers/pieWindow.vala @@ -192,6 +192,28 @@ public class PieWindow : Gtk.Window { }); } + ///////////////////////////////////////////////////////////////////// + /// Opens the window at a given location. + ///////////////////////////////////////////////////////////////////// + + public void open_at(int at_x, int at_y) { + this.open(); + this.move(at_x-this.width_request/2, at_y-this.height_request/2); + } + + ///////////////////////////////////////////////////////////////////// + /// Gets the center position of the window. + ///////////////////////////////////////////////////////////////////// + + public void get_center_pos(out int out_x, out int out_y) { + int x=0, y=0, width=0, height=0; + this.get_position(out x, out y); + this.get_size(out width, out height); + + out_x = x + width/2; + out_y = y + height/2; + } + ///////////////////////////////////////////////////////////////////// /// Draw the Pie. ///////////////////////////////////////////////////////////////////// @@ -303,6 +325,7 @@ public class PieWindow : Gtk.Window { else if (key >= 65 && key <= 90) index = (int)key - 55; if (index >= 0 && index < this.renderer.slice_count()) { + this.renderer.key_board_control = true; this.renderer.set_highlighted_slice(index); if (this.renderer.active_slice == index) { diff --git a/src/renderers/sliceRenderer.vala b/src/renderers/sliceRenderer.vala index 4803070..743f13e 100644 --- a/src/renderers/sliceRenderer.vala +++ b/src/renderers/sliceRenderer.vala @@ -86,6 +86,7 @@ public class SliceRenderer : GLib.Object { private AnimatedValue alpha; // for fading in/out private AnimatedValue fade_rotation; // for fading in/out private AnimatedValue fade_scale; // for fading in/out + private AnimatedValue wobble; // for organic wobbling ///////////////////////////////////////////////////////////////////// /// C'tor, initializes all AnimatedValues. @@ -94,9 +95,10 @@ public class SliceRenderer : GLib.Object { public SliceRenderer(PieRenderer parent) { this.parent = parent; - this.fade = new AnimatedValue.linear(0.0, 0.0, Config.global.theme.transition_time); - this.alpha = new AnimatedValue.linear(0.0, 1.0, Config.global.theme.fade_in_time); - this.scale = new AnimatedValue.cubic(AnimatedValue.Direction.OUT, + this.fade = new AnimatedValue.linear(0.0, 0.0, Config.global.theme.transition_time); + this.wobble = new AnimatedValue.linear(0.0, 0.0, Config.global.theme.transition_time); + this.alpha = new AnimatedValue.linear(0.0, 1.0, Config.global.theme.fade_in_time); + this.scale = new AnimatedValue.cubic(AnimatedValue.Direction.OUT, 1.0/Config.global.theme.max_zoom, 1.0/Config.global.theme.max_zoom, Config.global.theme.transition_time, @@ -127,8 +129,8 @@ public class SliceRenderer : GLib.Object { Config.global.theme.caption_color, Config.global.global_scale); - this.active_icon = new ThemedIcon(action.icon, true); - this.inactive_icon = new ThemedIcon(action.icon, false); + this.active_icon = new ThemedIcon(action.name, action.icon, true); + this.inactive_icon = new ThemedIcon(action.name, action.icon, false); this.color = new Color.from_icon(this.active_icon); @@ -195,20 +197,36 @@ public class SliceRenderer : GLib.Object { this.fade.update(frame_time); this.fade_scale.update(frame_time); this.fade_rotation.update(frame_time); + this.wobble.update(frame_time); double direction = 2.0 * PI * position/parent.slice_count() + this.fade_rotation.val; double max_scale = 1.0/Config.global.theme.max_zoom; double diff = fabs(angle-direction); - + if (diff > PI) diff = 2 * PI - diff; + + active = ((parent.active_slice >= 0) && (diff < PI/parent.slice_count())); + + if (parent.active_slice >= 0) { + double wobble = Config.global.theme.wobble*diff/PI*(1-diff/PI); + if ((direction < angle && direction > angle - PI) || direction > PI+angle) { + this.wobble.reset_target(-wobble, Config.global.theme.transition_time*0.5); + } else { + this.wobble.reset_target(wobble, Config.global.theme.transition_time*0.5); + } + } else { + this.wobble.reset_target(0, Config.global.theme.transition_time*0.5); + } + + direction += this.wobble.val; if (diff < 2 * PI * Config.global.theme.zoom_range) max_scale = (Config.global.theme.max_zoom/(diff * (Config.global.theme.max_zoom - 1) /(2 * PI * Config.global.theme.zoom_range) + 1)) /Config.global.theme.max_zoom; - active = ((parent.active_slice >= 0) && (diff < PI/parent.slice_count())); + max_scale = (parent.active_slice >= 0 ? max_scale : 1.0/Config.global.theme.max_zoom); diff --git a/src/themes/sliceLayer.vala b/src/themes/sliceLayer.vala index 2620912..3c650c0 100644 --- a/src/themes/sliceLayer.vala +++ b/src/themes/sliceLayer.vala @@ -23,31 +23,63 @@ namespace GnomePie { ///////////////////////////////////////////////////////////////////////// public class SliceLayer : GLib.Object { + + public enum Type { FILE, ICON, CAPTION } + public enum Visibility { ANY, WITH_CAPTION, WITHOUT_CAPTION } + + public Type layer_type { get; private set; } + public Visibility visibility { get; private set; } ///////////////////////////////////////////////////////////////////// /// Information on the contained image. ///////////////////////////////////////////////////////////////////// public Image image {get; set;} - public string icon_file {get; private set;} + ///////////////////////////////////////////////////////////////////// /// Properties of this layer. ///////////////////////////////////////////////////////////////////// - public bool colorize {get; private set; } - public bool is_icon {get; private set;} - public int icon_size {get; private set;} + public string icon_file {get; private set; default="";} + public bool colorize {get; private set; default=false;} + public int icon_size {get; private set; default=1;} + + public string font {get; private set; default="";} + public int width {get; private set; default=0;} + public int height {get; private set; default=0;} + public int position {get; private set; default=0;} + public Color color {get; private set; default=new Color();} ///////////////////////////////////////////////////////////////////// /// C'tor, initializes all members of the layer. ///////////////////////////////////////////////////////////////////// - public SliceLayer(string icon_file, int icon_size, bool colorize, bool is_icon) { + public SliceLayer.file(string icon_file, int icon_size, bool colorize, Visibility visibility) { + this.layer_type = Type.FILE; this.icon_file = icon_file; this.colorize = colorize; - this.is_icon = is_icon; this.icon_size = icon_size; + this.visibility = visibility; + } + + public SliceLayer.icon(string icon_file, int icon_size, bool colorize, Visibility visibility) { + this.layer_type = Type.ICON; + this.icon_file = icon_file; + this.colorize = colorize; + this.icon_size = icon_size; + this.visibility = visibility; + } + + public SliceLayer.caption(string font, int width, int height, int position, Color color, bool colorize, Visibility visibility) { + this.layer_type = Type.CAPTION; + this.font = font; + this.width = width; + this.height = height; + this.position = position; + this.color = color; + this.visibility = visibility; + this.colorize = colorize; } ///////////////////////////////////////////////////////////////////// @@ -55,9 +87,11 @@ public class SliceLayer : GLib.Object { ///////////////////////////////////////////////////////////////////// public void load_image() { - if (this.icon_file == "" && this.is_icon == true) + this.image = null; + + if (this.icon_file == "" && this.layer_type == Type.ICON) this.image = new Image.empty(this.icon_size, this.icon_size, new Color.from_rgb(1, 1, 1)); - else + else if (this.icon_file != "") this.image = new Image.from_file_at_size(this.icon_file, this.icon_size, this.icon_size); } } diff --git a/src/themes/theme.vala b/src/themes/theme.vala index 269a574..1956046 100644 --- a/src/themes/theme.vala +++ b/src/themes/theme.vala @@ -38,6 +38,7 @@ public class Theme : GLib.Object { public double max_zoom {get; private set; default=1.2;} public double zoom_range {get; private set; default=0.2;} public double transition_time {get; private set; default=0.5;} + public double wobble {get; private set; default=0.0;} public double fade_in_time {get; private set; default=0.2;} public double fade_out_time {get; private set; default=0.1;} public double fade_in_zoom {get; private set; default=1.0;} @@ -49,6 +50,7 @@ public class Theme : GLib.Object { public double active_radius {get; private set; default=45.0;} public double slice_radius {get; private set; default=32.0;} public double slice_gap {get; private set; default=14.0;} + public bool has_slice_captions {get; private set; default=false;} public bool caption {get; private set; default=false;} public string caption_font {get; private set; default="sans 12";} public int caption_width {get; private set; default=100;} @@ -182,6 +184,9 @@ public class Theme : GLib.Object { case "transitiontime": transition_time = double.parse(attr_content); break; + case "wobble": + wobble = double.parse(attr_content); + break; case "fadeintime": fade_in_time = double.parse(attr_content); break; @@ -403,8 +408,15 @@ public class Theme : GLib.Object { if (element_name == "slice_layer") { string file = ""; double scale = 1.0; - bool is_icon = false; + SliceLayer.Type type = SliceLayer.Type.FILE; + SliceLayer.Visibility visibility = SliceLayer.Visibility.ANY; bool colorize = false; + string slice_caption_font = "sans 8"; + int slice_caption_width = 50; + int slice_caption_height = 20; + int pos_x = 0; + int pos_y = 0; + Color slice_caption_color = new Color.from_rgb(1.0f, 1.0f, 1.0f); for (Xml.Attr* attribute = layer->properties; attribute != null; attribute = attribute->next) { string attr_name = attribute->name.down(); @@ -419,13 +431,46 @@ public class Theme : GLib.Object { break; case "type": if (attr_content == "icon") - is_icon = true; + type = SliceLayer.Type.ICON; + else if (attr_content == "caption") + type = SliceLayer.Type.CAPTION; else if (attr_content != "file") warning("Invalid attribute content " + attr_content + " for attribute " + attr_name + " in element!"); break; case "colorize": colorize = bool.parse(attr_content); break; + case "font": + slice_caption_font = attr_content; + break; + case "width": + slice_caption_width = (int)(int.parse(attr_content) * Config.global.global_scale); + if (slice_caption_width % 2 == 1) + --slice_caption_width; + break; + case "height": + slice_caption_height = (int)(int.parse(attr_content) * Config.global.global_scale); + if (slice_caption_height % 2 == 1) + --slice_caption_height; + break; + case "x": + pos_x = (int)(double.parse(attr_content) * Config.global.global_scale); + break; + case "y": + pos_y = (int)(double.parse(attr_content) * Config.global.global_scale); + break; + case "color": + slice_caption_color = new Color.from_string(attr_content); + break; + case "visibility": + if (attr_content == "without_caption") + visibility = SliceLayer.Visibility.WITHOUT_CAPTION; + else if (attr_content == "with_caption") { + this.has_slice_captions = true; + visibility = SliceLayer.Visibility.WITH_CAPTION; + } else if (attr_content != "any") + warning("Invalid attribute content " + attr_content + " for attribute " + attr_name + " in element!"); + break; default: warning("Invalid attribute \"" + attr_name + "\" in element!"); break; @@ -438,9 +483,17 @@ public class Theme : GLib.Object { int size = 2*(int)(slice_radius*scale*max_zoom); if (slice->name.down() == "activeslice") { - active_slice_layers.add(new SliceLayer(file, size, colorize, is_icon)); + if (type == SliceLayer.Type.ICON) active_slice_layers.add(new SliceLayer.icon(file, size, colorize, visibility)); + else if (type == SliceLayer.Type.CAPTION) active_slice_layers.add(new SliceLayer.caption(slice_caption_font, + slice_caption_width, slice_caption_height, + pos_y, slice_caption_color, colorize, visibility)); + else active_slice_layers.add(new SliceLayer.file(file, size, colorize, visibility)); } else { - inactive_slice_layers.add(new SliceLayer(file, size, colorize, is_icon)); + if (type == SliceLayer.Type.ICON) inactive_slice_layers.add(new SliceLayer.icon(file, size, colorize, visibility)); + else if (type == SliceLayer.Type.CAPTION) inactive_slice_layers.add(new SliceLayer.caption(slice_caption_font, + slice_caption_width, slice_caption_height, + pos_y, slice_caption_color, colorize, visibility)); + else inactive_slice_layers.add(new SliceLayer.file(file, size, colorize, visibility)); } } else { diff --git a/src/utilities/config.vala b/src/utilities/config.vala index 5790eef..cc776d5 100644 --- a/src/utilities/config.vala +++ b/src/utilities/config.vala @@ -55,6 +55,7 @@ public class Config : GLib.Object { public double refresh_rate { get; set; default = 60.0; } public double global_scale { get; set; default = 1.0; } public bool show_indicator { get; set; default = true; } + public bool show_captions { get; set; default = true; } public bool auto_start { get; set; default = false; } public Gee.ArrayList themes { get; private set; } @@ -70,6 +71,7 @@ public class Config : GLib.Object { writer.write_attribute("refresh_rate", refresh_rate.to_string()); writer.write_attribute("global_scale", global_scale.to_string()); writer.write_attribute("show_indicator", show_indicator ? "true" : "false"); + writer.write_attribute("show_captions", show_captions ? "true" : "false"); writer.end_element(); writer.end_document(); } @@ -112,6 +114,9 @@ public class Config : GLib.Object { case "show_indicator": show_indicator = bool.parse(attr_content); break; + case "show_captions": + show_captions = bool.parse(attr_content); + break; default: warning("Invalid setting \"" + attr_name + "\" in gnome-pie.conf!"); break; diff --git a/src/utilities/logger.vala b/src/utilities/logger.vala index 3108ba3..5334920 100644 --- a/src/utilities/logger.vala +++ b/src/utilities/logger.vala @@ -17,7 +17,7 @@ this program. If not, see . namespace GnomePie { -///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// /// A static class which beautifies the messages of the default logger. /// Some of this code is inspired by plank's written by Robert Dyer. /// Thanks a lot for this project! @@ -29,22 +29,33 @@ public class Logger { /// If these are set to false, the according messages are not shown ///////////////////////////////////////////////////////////////////// - public static bool display_info { get; set; default = true; } - public static bool display_debug { get; set; default = true; } - public static bool display_warning { get; set; default = true; } - public static bool display_error { get; set; default = true; } + private static const bool display_debug = true; + private static const bool display_warning = true; + private static const bool display_error = true; + private static const bool display_message = true; + + ///////////////////////////////////////////////////////////////////// + /// If these are set to false, the according messages are not logged + ///////////////////////////////////////////////////////////////////// + + private static const bool log_debug = false; + private static const bool log_warning = true; + private static const bool log_error = true; + private static const bool log_message = true; ///////////////////////////////////////////////////////////////////// /// If true, a time stamp is shown in each message. ///////////////////////////////////////////////////////////////////// - public static bool display_time { get; set; default = true; } + private static const bool display_time = false; + private static const bool log_time = true; ///////////////////////////////////////////////////////////////////// /// If true, the origin of the message is shown. In form file:line ///////////////////////////////////////////////////////////////////// - public static bool display_file { get; set; default = false; } + private static const bool display_file = false; + private static const bool log_file = false; ///////////////////////////////////////////////////////////////////// /// A regex, used to format the standard message. @@ -52,6 +63,16 @@ public class Logger { private static Regex regex = null; + ///////////////////////////////////////////////////////////////////// + /// Limit log and statistics size to roughly 1 MB. + ///////////////////////////////////////////////////////////////////// + + private static const int max_log_length = 1000000; + private static const int max_stats_length = 1000000; + + private static int log_length; + private static int stats_length; + ///////////////////////////////////////////////////////////////////// /// Possible terminal colors. ///////////////////////////////////////////////////////////////////// @@ -72,20 +93,84 @@ public class Logger { ///////////////////////////////////////////////////////////////////// public static void init() { + log_length = -1; + stats_length = -1; + try { regex = new Regex("""(.*)\.vala(:\d+): (.*)"""); } catch {} - GLib.Log.set_default_handler(log_func); + GLib.Log.set_handler(null, GLib.LogLevelFlags.LEVEL_MASK, log_func); + } + + ///////////////////////////////////////////////////////////////////// + /// Appends a line to the statistics file + ///////////////////////////////////////////////////////////////////// + + public static void stats(string line) { + var stats = GLib.FileStream.open(Paths.stats, "a"); + + if (stats != null) { + if (stats_length == -1) + stats_length = (int)stats.tell(); + + string final_line = "[" + get_time() + "] " + line + "\n"; + stats.puts(final_line); + stats_length += final_line.length; + } + + if (stats_length > max_stats_length) { + string content = ""; + + try { + GLib.FileUtils.get_contents(Paths.stats, out content); + int split_index = content.index_of_char('\n', stats_length - (int)(max_stats_length*0.9)); + GLib.FileUtils.set_contents(Paths.stats, content.substring(split_index+1)); + + stats_length -= (split_index+1); + } catch (GLib.FileError e) {} + } + } + + ///////////////////////////////////////////////////////////////////// + /// Appends a line to the log file + ///////////////////////////////////////////////////////////////////// + + private static void write_log_line(string line) { + var log = GLib.FileStream.open(Paths.log, "a"); + + if (log != null) { + if (log_length == -1) + log_length = (int)log.tell(); + + log.puts(line); + log_length += line.length; + } + + if (log_length > max_log_length) { + string content = ""; + + try { + GLib.FileUtils.get_contents(Paths.log, out content); + int split_index = content.index_of_char('\n', log_length - (int)(max_log_length*0.9)); + GLib.FileUtils.set_contents(Paths.log, content.substring(split_index+1)); + + log_length -= (split_index+1); + } catch (GLib.FileError e) {} + } } ///////////////////////////////////////////////////////////////////// - /// Displays an Info message. + /// Displays a message. ///////////////////////////////////////////////////////////////////// - private static void info(string message) { - if (display_info) { - stdout.printf(set_color(Color.GREEN, false) + "[" + get_time() + "MESSAGE]" + message); + private static void message(string message, string message_log) { + if (display_message) { + stdout.printf(set_color(Color.GREEN, false) + "[" + (display_time ? get_time() + " " : "") + "MESSAGE]" + message); + } + + if (log_message) { + write_log_line("[" + (log_time ? get_time() + " " : "") + "MESSAGE]" + message_log); } } @@ -93,9 +178,13 @@ public class Logger { /// Displays a Debug message. ///////////////////////////////////////////////////////////////////// - private static void debug(string message) { + private static void debug(string message, string message_log) { if (display_debug) { - stdout.printf(set_color(Color.BLUE, false) + "[" + get_time() + " DEBUG ]" + message); + stdout.printf(set_color(Color.BLUE, false) + "[" + (display_time ? get_time() + " " : "") + " DEBUG ]" + message); + } + + if (log_debug) { + write_log_line("[" + (log_time ? get_time() + " " : "") + " DEBUG ]" + message_log); } } @@ -103,9 +192,13 @@ public class Logger { /// Displays a Warning message. ///////////////////////////////////////////////////////////////////// - private static void warning(string message) { + private static void warning(string message, string message_log) { if (display_warning) { - stdout.printf(set_color(Color.YELLOW, false) + "[" + get_time() + "WARNING]" + message); + stdout.printf(set_color(Color.YELLOW, false) + "[" + (display_time ? get_time() + " " : "") + "WARNING]" + message); + } + + if (log_warning) { + write_log_line("[" + (log_time ? get_time() + " " : "") + "WARNING]" + message_log); } } @@ -113,9 +206,13 @@ public class Logger { /// Displays a Error message. ///////////////////////////////////////////////////////////////////// - private static void error(string message) { + private static void error(string message, string message_log) { if (display_error) { - stdout.printf(set_color(Color.RED, false) + "[" + get_time() + " ERROR ]" + message); + stdout.printf(set_color(Color.RED, false) + "[" + (display_time ? get_time() + " " : "") + " ERROR ]" + message); + } + + if (log_error) { + write_log_line("[" + (log_time ? get_time() + " " : "") + " ERROR ]" + message_log); } } @@ -141,12 +238,8 @@ public class Logger { ///////////////////////////////////////////////////////////////////// private static string get_time() { - if (display_time) { - var now = new DateTime.now_local (); - return "%.2d:%.2d:%.2d:%.6d ".printf (now.get_hour (), now.get_minute (), now.get_second (), now.get_microsecond ()); - } else { - return ""; - } + var now = new DateTime.now_local(); + return "%.4d:%.2d:%.2d:%.2d:%.2d:%.2d:%.6d".printf(now.get_year(), now.get_month(), now.get_day_of_month(), now.get_hour(), now.get_minute(), now.get_second(), now.get_microsecond()); } ///////////////////////////////////////////////////////////////////// @@ -165,27 +258,42 @@ public class Logger { } } + ///////////////////////////////////////////////////////////////////// + /// Helper method to format the message for logging. + ///////////////////////////////////////////////////////////////////// + + private static string create_log_message(string message) { + if (log_file && regex != null && regex.match(message)) { + var parts = regex.split(message); + return " [%s%s] %s\n".printf(parts[1], parts[2], parts[3]); + } else if (regex != null && regex.match(message)) { + var parts = regex.split(message); + return " %s\n".printf(parts[3]); + } else { + return " " + message + "\n"; + } + } + ///////////////////////////////////////////////////////////////////// /// The handler function. ///////////////////////////////////////////////////////////////////// - private static void log_func(string? d, LogLevelFlags flags, string message) { - + private static void log_func(string? d, LogLevelFlags flags, string text) { switch (flags) { case LogLevelFlags.LEVEL_ERROR: case LogLevelFlags.LEVEL_CRITICAL: - error(create_message(message)); + error(create_message(text), create_log_message(text)); break; case LogLevelFlags.LEVEL_INFO: case LogLevelFlags.LEVEL_MESSAGE: - info(create_message(message)); + message(create_message(text), create_log_message(text)); break; case LogLevelFlags.LEVEL_DEBUG: - debug(create_message(message)); + debug(create_message(text), create_log_message(text)); break; case LogLevelFlags.LEVEL_WARNING: default: - warning(create_message(message)); + warning(create_message(text), create_log_message(text)); break; } } diff --git a/src/utilities/paths.vala b/src/utilities/paths.vala index 589cc36..bc3e9b1 100644 --- a/src/utilities/paths.vala +++ b/src/utilities/paths.vala @@ -23,16 +23,30 @@ namespace GnomePie { ///////////////////////////////////////////////////////////////////////// public class Paths : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// The log file, + /// usually ~/.config/gnome-pie/gnome-pie.log. + ///////////////////////////////////////////////////////////////////// + + public static string log { get; private set; default=""; } + + ///////////////////////////////////////////////////////////////////// + /// The statistics file, + /// usually ~/.config/gnome-pie/gnome-pie.stats. + ///////////////////////////////////////////////////////////////////// + + public static string stats { get; private set; default=""; } ///////////////////////////////////////////////////////////////////// - /// The file settings file, + /// The settings file, /// usually ~/.config/gnome-pie/gnome-pie.conf. ///////////////////////////////////////////////////////////////////// public static string settings { get; private set; default=""; } ///////////////////////////////////////////////////////////////////// - /// The file pie configuration file + /// The pie configuration file /// usually ~/.config/gnome-pie/pies.conf. ///////////////////////////////////////////////////////////////////// @@ -186,6 +200,24 @@ public class Paths : GLib.Object { pie_config = config_file.get_path(); settings = config_dir.get_path() + "/gnome-pie.conf"; + log = config_dir.get_path() + "/gnome-pie.log"; + stats = config_dir.get_path() + "/gnome-pie.stats"; + + if (!GLib.File.new_for_path(log).query_exists()) { + try { + FileUtils.set_contents(log, ""); + } catch (GLib.FileError e) { + error(e.message); + } + } + + if (!GLib.File.new_for_path(stats).query_exists()) { + try { + FileUtils.set_contents(stats, ""); + } catch (GLib.FileError e) { + error(e.message); + } + } // autostart file name autostart = GLib.Path.build_filename(GLib.Environment.get_user_config_dir(), @@ -196,7 +228,13 @@ public class Paths : GLib.Object { warning("Failed to find pie configuration file \"pies.conf\"! (This should only happen when Gnome-Pie is started for the first time...)"); if (!GLib.File.new_for_path(settings).query_exists()) - warning("Failed to find settings file \"gnome-pie.conf\"!"); + warning("Failed to find settings file \"gnome-pie.conf\"! (This should only happen when Gnome-Pie is started for the first time...)"); + + if (!GLib.File.new_for_path(log).query_exists()) + warning("Failed to find log file \"gnome-pie.log\"!"); + + if (!GLib.File.new_for_path(stats).query_exists()) + warning("Failed to find statistics file \"gnome-pie.stats\"!"); if (!GLib.File.new_for_path(local_themes).query_exists()) warning("Failed to find local themes directory!"); -- cgit v1.2.3