summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlessandro Ghedini <al3xbio@gmail.com>2012-03-05 12:19:59 +0100
committerAlessandro Ghedini <al3xbio@gmail.com>2012-03-05 12:19:59 +0100
commit98f3ef2689de06e8ab8b46a91acfa7dd2056a3a6 (patch)
treeb98e438ac1082925e12af6dfec6d9ebeb4e3035e /src
parenta824c3e5bdab686901b02667609282e7d596a6af (diff)
Imported Upstream version 0.5.1
Diffstat (limited to 'src')
-rw-r--r--src/actionGroups/devicesGroup.vala12
-rw-r--r--src/actionGroups/menuGroup.vala15
-rw-r--r--src/actions/actionRegistry.vala27
-rw-r--r--src/actions/pieAction.vala10
-rw-r--r--src/deamon.vala21
-rw-r--r--src/gui/aboutWindow.vala5
-rw-r--r--src/gui/newSliceWindow.vala1
-rw-r--r--src/gui/piePreview.vala3
-rw-r--r--src/gui/settingsWindow.vala38
-rw-r--r--src/gui/themeList.vala12
-rw-r--r--src/gui/triggerSelectButton.vala4
-rw-r--r--src/images/icon.vala18
-rw-r--r--src/images/renderedText.vala81
-rw-r--r--src/images/themedIcon.vala129
-rw-r--r--src/pies/load.vala2
-rw-r--r--src/pies/pieManager.vala21
-rw-r--r--src/pies/save.vala15
-rw-r--r--src/renderers/pieRenderer.vala42
-rw-r--r--src/renderers/pieWindow.vala23
-rw-r--r--src/renderers/sliceRenderer.vala32
-rw-r--r--src/themes/sliceLayer.vala50
-rw-r--r--src/themes/theme.vala61
-rw-r--r--src/utilities/config.vala5
-rw-r--r--src/utilities/logger.vala168
-rw-r--r--src/utilities/paths.vala44
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!");