diff options
| author | Alessandro Ghedini <al3xbio@gmail.com> | 2012-03-05 12:19:59 +0100 | 
|---|---|---|
| committer | Alessandro Ghedini <al3xbio@gmail.com> | 2012-03-05 12:19:59 +0100 | 
| commit | 98f3ef2689de06e8ab8b46a91acfa7dd2056a3a6 (patch) | |
| tree | b98e438ac1082925e12af6dfec6d9ebeb4e3035e /src | |
| parent | a824c3e5bdab686901b02667609282e7d596a6af (diff) | |
Imported Upstream version 0.5.1
Diffstat (limited to 'src')
| -rw-r--r-- | src/actionGroups/devicesGroup.vala | 12 | ||||
| -rw-r--r-- | src/actionGroups/menuGroup.vala | 15 | ||||
| -rw-r--r-- | src/actions/actionRegistry.vala | 27 | ||||
| -rw-r--r-- | src/actions/pieAction.vala | 10 | ||||
| -rw-r--r-- | src/deamon.vala | 21 | ||||
| -rw-r--r-- | src/gui/aboutWindow.vala | 5 | ||||
| -rw-r--r-- | src/gui/newSliceWindow.vala | 1 | ||||
| -rw-r--r-- | src/gui/piePreview.vala | 3 | ||||
| -rw-r--r-- | src/gui/settingsWindow.vala | 38 | ||||
| -rw-r--r-- | src/gui/themeList.vala | 12 | ||||
| -rw-r--r-- | src/gui/triggerSelectButton.vala | 4 | ||||
| -rw-r--r-- | src/images/icon.vala | 18 | ||||
| -rw-r--r-- | src/images/renderedText.vala | 81 | ||||
| -rw-r--r-- | src/images/themedIcon.vala | 129 | ||||
| -rw-r--r-- | src/pies/load.vala | 2 | ||||
| -rw-r--r-- | src/pies/pieManager.vala | 21 | ||||
| -rw-r--r-- | src/pies/save.vala | 15 | ||||
| -rw-r--r-- | src/renderers/pieRenderer.vala | 42 | ||||
| -rw-r--r-- | src/renderers/pieWindow.vala | 23 | ||||
| -rw-r--r-- | src/renderers/sliceRenderer.vala | 32 | ||||
| -rw-r--r-- | src/themes/sliceLayer.vala | 50 | ||||
| -rw-r--r-- | src/themes/theme.vala | 61 | ||||
| -rw-r--r-- | src/utilities/config.vala | 5 | ||||
| -rw-r--r-- | src/utilities/logger.vala | 168 | ||||
| -rw-r--r-- | src/utilities/paths.vala | 44 | 
25 files changed, 609 insertions, 230 deletions
| 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 <magnun@codecommunity.org> (PT-BR)",      		"Kim Boram <Boramism@gmail.com> (KO)",              "Eduardo Anabalon <lalo1412@gmail.com> (ES)", -            "Gregoire Bellon-Gervais <greggbg@gmail.com> (FR)", +            "Grégoire Bellon-Gervais <greggbg@gmail.com> (FR)", +            "Alex Maxime <cad.maxime@gmail.com> (FR)",              "Eugene Roskin <pams@imail.ru> (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 @@ -24,6 +24,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 @@ -75,6 +75,24 @@ public class Icon : Image {      }      ///////////////////////////////////////////////////////////////////// +    /// 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<string, Cairo.ImageSurface?> active_cache { private get; private set; } -    private static Gee.HashMap<string, Cairo.ImageSurface?> 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<string, Cairo.ImageSurface?>(); -        inactive_cache = new Gee.HashMap<string, Cairo.ImageSurface?>(); -    }      /////////////////////////////////////////////////////////////////////      /// 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 @@ -52,6 +52,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<SliceRenderer?> 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<SliceRenderer?> 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 @@ -193,6 +193,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 <slice_layer> 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 <slice_layer> element!"); +                                break;                              default:                                  warning("Invalid attribute \"" + attr_name + "\" in <slice_layer> 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<Theme?> 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 <http://www.gnu.org/licenses/>.  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. @@ -53,6 +64,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());  	}  	///////////////////////////////////////////////////////////////////// @@ -166,26 +259,41 @@ 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!"); | 
