diff options
| author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2015-09-27 15:07:18 +0200 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2015-09-27 15:07:18 +0200 | 
| commit | e5da485f77b3b8cd3bc32c13e4497a64a2ad10c3 (patch) | |
| tree | b7351c6674108ea5746d70fdc2ff6c59bdc84595 /src | |
| parent | bbabe0f4e471dd984a1c01353c44d4eb1f336473 (diff) | |
| parent | 16fe2e5d0525422ba6ca5db9e92a93d17caae302 (diff) | |
Merge new upstream release
Diffstat (limited to 'src')
| -rw-r--r-- | src/deamon.vala | 8 | ||||
| -rw-r--r-- | src/gui/preferencesWindow.vala | 134 | ||||
| -rw-r--r-- | src/gui/themeList.vala | 20 | ||||
| -rw-r--r-- | src/gui/tipViewer.vala | 163 | ||||
| -rwxr-xr-x | src/renderers/pieWindow.vala | 12 | ||||
| -rw-r--r-- | src/themes/theme.vala | 36 | ||||
| -rw-r--r-- | src/themes/themeImporter.vala | 62 | ||||
| -rw-r--r-- | src/utilities/archiveReader.vala | 123 | ||||
| -rw-r--r-- | src/utilities/archiveWriter.vala | 139 | ||||
| -rw-r--r-- | src/utilities/config.vala | 35 | 
10 files changed, 708 insertions, 24 deletions
| diff --git a/src/deamon.vala b/src/deamon.vala index 8c84f3a..f4e1aeb 100644 --- a/src/deamon.vala +++ b/src/deamon.vala @@ -43,7 +43,7 @@ public class Deamon : GLib.Application {      /////////////////////////////////////////////////////////////////////      public static int main(string[] args) { -        version = "0.6.5"; +        version = "0.6.6";          // disable overlay scrollbar --- hacky workaround for black /          // transparent background @@ -192,10 +192,12 @@ public class Deamon : GLib.Application {          }          if (reset) { -            if (GLib.FileUtils.remove(Paths.pie_config) == 0) +            if (GLib.FileUtils.remove(Paths.pie_config) == 0) {                  message("Removed file \"%s\"", Paths.pie_config); -            if (GLib.FileUtils.remove(Paths.settings) == 0) +            } +            if (GLib.FileUtils.remove(Paths.settings) == 0) {                  message("Removed file \"%s\"", Paths.settings); +            }              return true;          } diff --git a/src/gui/preferencesWindow.vala b/src/gui/preferencesWindow.vala index 5d22d6b..d671501 100644 --- a/src/gui/preferencesWindow.vala +++ b/src/gui/preferencesWindow.vala @@ -154,6 +154,17 @@ public class PreferencesWindow : GLib.Object {          scroll_area = builder.get_object("theme-scrolledwindow") as Gtk.ScrolledWindow;          scroll_area.add(this.theme_list); +        (builder.get_object("theme-help-button") as Gtk.Button).clicked.connect(() => { +            try{ +                GLib.AppInfo.launch_default_for_uri("http://simmesimme.github.io/lessons/2015/04/26/themes-for-gnome-pie/", null); +            } catch (Error e) { +                warning(e.message); +            } +        }); + +        (builder.get_object("theme-export-button") as Gtk.Button).clicked.connect(on_export_theme_button_clicked); +        (builder.get_object("theme-import-button") as Gtk.Button).clicked.connect(on_import_theme_button_clicked); +          this.autostart = (builder.get_object("autostart-checkbox") as Gtk.ToggleButton);          this.autostart.toggled.connect(on_autostart_toggled); @@ -209,6 +220,33 @@ public class PreferencesWindow : GLib.Object {                  Config.global.max_visible_slices = (int)range_slices.get_value();              }); +        var info_box = (builder.get_object("info-box") as Gtk.Box); + +        // info label +        var info_label = new TipViewer({ +            _("Pies can be opened with the terminal command \"gnome-pie --open=ID\"."), +            _("Feel free to visit Gnome-Pie's homepage at %s!").printf("<a href='http://simmesimme.github.io/gnome-pie.html'>gnome-pie.simonschneegans.de</a>"), +            _("If you want to give some feedback, please write an e-mail to %s!").printf("<a href='mailto:code@simonschneegans.de'>code@simonschneegans.de</a>"), +            _("You can support the development of Gnome-Pie by donating via %s.").printf("<a href='https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=X65SUVC4ZTQSC'>Paypal</a>"), +            _("Translating Gnome-Pie to your language is easy. Translations are managed at %s.").printf("<a href='https://translate.zanata.org/zanata/iteration/view/gnome-pie/develop'>Zanata</a>"), +            _("It's easy to create new themes for Gnome-Pie. Read the <a href='%s'>Tutorial</a> online.").printf("http://simmesimme.github.io/lessons/2015/04/26/themes-for-gnome-pie/"), +            _("It's usually a good practive to have at most twelve slices per pie."), +            _("You can export themes you created and share them with the community!"), +            _("The source code of Gnome-Pie is available on %s.").printf("<a href='https://github.com/Simmesimme/Gnome-Pie'>Github</a>"), +            _("Bugs can be reported at %s!").printf("<a href='https://github.com/Simmesimme/Gnome-Pie/issues'>Github</a>"), +            _("Suggestions can be posted on %s!").printf("<a href='https://github.com/Simmesimme/Gnome-Pie/issues'>Github</a>"), +            _("An awesome companion of Gnome-Pie is %s. It will make using your computer feel like magic!").printf("<a href='https://github.com/thjaeger/easystroke/wiki'>Easystroke</a>"), +            _("You can drag'n'drop applications from your main menu to the pie above."), +            _("You may drag'n'drop URLs and bookmarks from your internet browser to the pie above."), +            _("You can drag'n'drop files and folders from your file browser to the pie above."), +            _("You can drag'n'drop pies from the list on the left into other pies in order to create sub-pies."), +            _("You can drag'n'drop pies from the list on the left to your desktop or dock to create a launcher for this pie.") +        }); +        this.window.show.connect(info_label.start_slide_show); +        this.window.hide.connect(info_label.stop_slide_show); + +        info_box.pack_end(info_label); +          this.window.hide.connect(() => {              // save settings on close              Config.global.save(); @@ -290,15 +328,105 @@ public class PreferencesWindow : GLib.Object {                  FileUtils.set_contents(Paths.autostart, autostart_entry);                  FileUtils.chmod(Paths.autostart, 0755);              } catch (Error e) { -                var d = new Gtk.MessageDialog (this.window, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, +                var d = new Gtk.MessageDialog(this.window, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE,                                             "%s", e.message); -                d.run (); -                d.destroy (); +                d.run(); +                d.destroy();              }          }      }      ///////////////////////////////////////////////////////////////////// +    /// Saves the current theme to an archive. +    ///////////////////////////////////////////////////////////////////// + +    private void on_export_theme_button_clicked(Gtk.Button button) { +        var dialog = new Gtk.FileChooserDialog("Pick a file", this.window, +                                               Gtk.FileChooserAction.SAVE, +                                               "_Cancel", +                                               Gtk.ResponseType.CANCEL, +                                               "_Save", +                                               Gtk.ResponseType.ACCEPT); + +        dialog.set_do_overwrite_confirmation(true); +        dialog.set_modal(true); +        dialog.filter = new Gtk.FileFilter(); +        dialog.filter.add_pattern ("*.tar.gz"); +        dialog.set_current_name(Config.global.theme.name + ".tar.gz"); + +        dialog.response.connect((d, result) => { +            if (result == Gtk.ResponseType.ACCEPT) { +                var file = dialog.get_filename(); +                if (!file.has_suffix(".tar.gz")) { +                    file = file + ".tar.gz"; +                } +                Config.global.theme.export(file); +            } +            dialog.destroy(); +        }); +        dialog.show(); +    } + +    ///////////////////////////////////////////////////////////////////// +    /// Imports a new theme from an archive. +    ///////////////////////////////////////////////////////////////////// + +    private void on_import_theme_button_clicked(Gtk.Button button) { +        var dialog = new Gtk.FileChooserDialog("Pick a file", this.window, +                                               Gtk.FileChooserAction.OPEN, +                                               "_Cancel", +                                               Gtk.ResponseType.CANCEL, +                                               "_Open", +                                               Gtk.ResponseType.ACCEPT); + +        dialog.set_modal(true); +        dialog.filter = new Gtk.FileFilter(); +        dialog.filter.add_pattern ("*.tar.gz"); + +        var result = Gtk.MessageType.INFO; +        var message = _("Sucessfully imported new theme!"); + +        dialog.response.connect((d, r) => { +            if (r == Gtk.ResponseType.ACCEPT) { +                var file = dialog.get_filename(); + +                var a = new ThemeImporter(); +                if (a.open(file)) { +                    if (a.is_valid_theme) { +                        if (!Config.global.has_theme(a.theme_name)) { +                            if (a.extract_to(Paths.local_themes + "/" + a.theme_name)) { +                                Config.global.load_themes(a.theme_name); +                                this.theme_list.reload(); +                            } else { +                                message = _("An error occured while importing the theme: Failed to extract theme!"); +                                result = Gtk.MessageType.ERROR; +                            } +                        } else { +                            message = _("An error occured while importing the theme: A theme with this name does already exist!"); +                            result = Gtk.MessageType.ERROR; +                        } +                    } else { +                        message = _("An error occured while importing the theme: Theme archive does not contain a valid theme!"); +                        result = Gtk.MessageType.ERROR; +                    } +                } else { +                    message = _("An error occured while importing the theme: Failed to open theme archive!"); +                    result = Gtk.MessageType.ERROR; +                } +                a.close(); + +                var result_dialog = new Gtk.MessageDialog(null, Gtk.DialogFlags.MODAL, +                                                          result, Gtk.ButtonsType.CLOSE, message); +                result_dialog.run(); +                result_dialog.destroy(); +            } +            dialog.destroy(); + +        }); +        dialog.show(); +    } + +    /////////////////////////////////////////////////////////////////////      /// Shows or hides the indicator.      ///////////////////////////////////////////////////////////////////// diff --git a/src/gui/themeList.vala b/src/gui/themeList.vala index 517c6d5..46ae876 100644 --- a/src/gui/themeList.vala +++ b/src/gui/themeList.vala @@ -51,9 +51,6 @@ class ThemeList : Gtk.TreeView {      public ThemeList() {          GLib.Object(); -        var data = new Gtk.ListStore(2, typeof(Gdk.Pixbuf), -                                        typeof(string)); -        this.set_model(data);          this.set_headers_visible(true);          this.set_grid_lines(Gtk.TreeViewGridLines.NONE);          this.set_fixed_height_mode(true); @@ -79,7 +76,7 @@ class ThemeList : Gtk.TreeView {              Gtk.TreeIter active;              if (this.get_selection().get_selected(null, out active)) {                  Timeout.add(10, () => { -                    int index = int.parse(data.get_path(active).to_string()); +                    int index = int.parse(this.model.get_path(active).to_string());                      Config.global.theme = Config.global.themes[index];                      this.on_select_new(); @@ -91,6 +88,15 @@ class ThemeList : Gtk.TreeView {              }          }); +        reload(); +    } + +    public void reload() { + +        var data = new Gtk.ListStore(2, typeof(Gdk.Pixbuf), +                                        typeof(string)); +        this.set_model(data); +          // load all themes into the list          var themes = Config.global.themes;          foreach(var theme in themes) { @@ -99,10 +105,10 @@ class ThemeList : Gtk.TreeView {              data.set(current, DataPos.ICON, theme.preview_icon.to_pixbuf());              data.set(current, DataPos.NAME, GLib.Markup.escape_text(theme.name)+"\n"                                              + "<span font-size='x-small'>" + GLib.Markup.escape_text(theme.description) -                                            + " - <i>"+GLib.Markup.escape_text(_("By")+" "+theme.author) -                                            + "</i></span>"); -            if(theme == Config.global.theme) +                                            + "</span>"); +            if(theme == Config.global.theme) {                  get_selection().select_iter(current); +            }          }      }  } diff --git a/src/gui/tipViewer.vala b/src/gui/tipViewer.vala new file mode 100644 index 0000000..e2158bd --- /dev/null +++ b/src/gui/tipViewer.vala @@ -0,0 +1,163 @@ +///////////////////////////////////////////////////////////////////////// +// Copyright (c) 2011-2015 by Simon Schneegans +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or (at +// your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +///////////////////////////////////////////////////////////////////////// + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A widget showing tips. The tips are beautifully faded in and out. +///////////////////////////////////////////////////////////////////////// + +public class TipViewer : Gtk.Label { + +    ///////////////////////////////////////////////////////////////////// +    /// Some settings tweaking the behavior of the TipViewer. +    ///////////////////////////////////////////////////////////////////// + +    private const double fade_time = 0.5; +    private const double frame_rate = 20.0; +    private const double base_delay = 3.0; + +    ///////////////////////////////////////////////////////////////////// +    /// False, if the playback of tips is stopped. +    ///////////////////////////////////////////////////////////////////// + +    private bool playing = false; + +    ///////////////////////////////////////////////////////////////////// +    /// An array containing all tips. +    ///////////////////////////////////////////////////////////////////// + +    private string[] tips; + +    ///////////////////////////////////////////////////////////////////// +    /// The index of the currently displayed tip. +    ///////////////////////////////////////////////////////////////////// + +    private int index = -1; + +    ///////////////////////////////////////////////////////////////////// +    /// The fading value. +    ///////////////////////////////////////////////////////////////////// + +    private AnimatedValue alpha; + +    ///////////////////////////////////////////////////////////////////// +    /// C'tor, initializes all members and sets the basic layout. +    ///////////////////////////////////////////////////////////////////// + +    public TipViewer(string[] tips) { +        this.tips = tips; + +        this.alpha = new AnimatedValue.linear(0.0, 1.0, fade_time); + +        this.set_alignment (0.0f, 0.5f); +        this.opacity = 0; +        this.wrap = true; +        this.valign = Gtk.Align.END; +        this.set_use_markup(true); + +        this.override_font(Pango.FontDescription.from_string("8")); +    } + +    ///////////////////////////////////////////////////////////////////// +    /// Starts the playback of tips. +    ///////////////////////////////////////////////////////////////////// + +    public void start_slide_show() { +        if (!this.playing && tips.length > 1) { +            this.playing = true; +            show_tip(); +        } +    } + +    ///////////////////////////////////////////////////////////////////// +    /// Stops the playback of tips. +    ///////////////////////////////////////////////////////////////////// + +    public void stop_slide_show() { +        this.playing = false; +    } + +    ///////////////////////////////////////////////////////////////////// +    /// Starts the fading in. +    ///////////////////////////////////////////////////////////////////// + +    private void fade_in() { +        this.alpha = new AnimatedValue.linear(this.alpha.val, 1.0, fade_time); + +        GLib.Timeout.add((uint)(1000.0/frame_rate), () => { +            this.alpha.update(1.0/frame_rate); +            this.opacity = this.alpha.val; + +            return (this.alpha.val != 1.0); +        }); +    } + +    ///////////////////////////////////////////////////////////////////// +    /// Starts the fading out. +    ///////////////////////////////////////////////////////////////////// + +    private void fade_out() { +        this.alpha = new AnimatedValue.linear(this.alpha.val, 0.0, fade_time); + +        GLib.Timeout.add((uint)(1000.0/frame_rate), () => { +            this.alpha.update(1.0/frame_rate); +            this.opacity = this.alpha.val; + +            return (this.alpha.val != 0.0); +        }); +    } + +    private void show_tip() { + +        this.set_random_tip(); + +        this.fade_in(); + +        uint delay = (uint)(base_delay*1000.0) + tips[this.index].length*30; + +        GLib.Timeout.add(delay, () => { +            this.fade_out(); + +            if (this.playing) { +                GLib.Timeout.add((uint)(1000.0*fade_time), () => { +                    this.show_tip(); +                    return false; +                }); +            } + +            return false; +        }); +    } + +    ///////////////////////////////////////////////////////////////////// +    /// Chooses the next random tip. +    ///////////////////////////////////////////////////////////////////// + +    private void set_random_tip() { +        if (tips.length > 1) { +            int next_index = -1; +            do { +                next_index = GLib.Random.int_range(0, tips.length); +            } while (next_index == this.index); +            this.index = next_index; +            this.label = tips[this.index]; +        } +    } +} + +} diff --git a/src/renderers/pieWindow.vala b/src/renderers/pieWindow.vala index a49813a..c1d70b7 100755 --- a/src/renderers/pieWindow.vala +++ b/src/renderers/pieWindow.vala @@ -149,10 +149,12 @@ public class PieWindow : Gtk.Window {          // remember last pressed key in order to disable key repeat          uint last_key = 0; +        uint32 last_time_stamp = 0;          this.key_press_event.connect((e) => {              if (e.keyval != last_key) { -                last_key = e.keyval; -                this.handle_key_press(e.keyval, e.time, e.str); +                this.handle_key_press(e.keyval, e.time, last_time_stamp, e.str); +                last_key        = e.keyval; +                last_time_stamp = e.time;              }              return true;          }); @@ -436,7 +438,11 @@ public class PieWindow : Gtk.Window {      /// Do some useful stuff when keys are pressed.      ///////////////////////////////////////////////////////////////////// -    private void handle_key_press(uint key, uint32 time_stamp, string text) { +    private void handle_key_press(uint key, uint32 time_stamp, uint32 last_time_stamp, string text) { +        if (last_time_stamp + 1000 < time_stamp) { +            this.search_string = ""; +        } +          if      (Gdk.keyval_name(key) == "Escape") this.cancel();          else if (Gdk.keyval_name(key) == "Return") this.activate_slice(time_stamp);          else if (!PieManager.get_is_turbo(this.renderer.id)) { diff --git a/src/themes/theme.vala b/src/themes/theme.vala index a7dd4f8..98e8994 100644 --- a/src/themes/theme.vala +++ b/src/themes/theme.vala @@ -115,6 +115,42 @@ public class Theme : GLib.Object {          return true;      } + +    ///////////////////////////////////////////////////////////////////// +    /// Exports the theme directory to an importable archive. +    ///////////////////////////////////////////////////////////////////// + +    public void export(string file) { + +        var archive = new ArchiveWriter(); +        bool success = true; + +        if (!archive.open(file)) { +            warning("Cannot open file " + file + " for writing!"); +            success = false; +        } else if (!archive.add(this.directory)) { +            warning("Cannot append directory " + this.directory + " to archive!"); +            success = false; +        } + +        archive.close(); + +        if (success) { +            var message = _("Successfully exported the theme \"%s\"!").printf(this.name); +            var dialog = new Gtk.MessageDialog(null, Gtk.DialogFlags.MODAL, +                                               Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE, message); +            dialog.run(); +            dialog.destroy(); + +        } else { +            var message = _("An error occured while exporting the theme \"%s\"! Please check the console output.").printf(this.name); +            var dialog = new Gtk.MessageDialog(null, Gtk.DialogFlags.MODAL, +                                               Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, message); +            dialog.run(); +            dialog.destroy(); +        } +    } +      /////////////////////////////////////////////////////////////////////      /// Loads all images of the theme.      ///////////////////////////////////////////////////////////////////// diff --git a/src/themes/themeImporter.vala b/src/themes/themeImporter.vala new file mode 100644 index 0000000..f110696 --- /dev/null +++ b/src/themes/themeImporter.vala @@ -0,0 +1,62 @@ +///////////////////////////////////////////////////////////////////////// +// Copyright (c) 2011-2015 by Simon Schneegans +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or (at +// your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +///////////////////////////////////////////////////////////////////////// + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// This class provides functions to check whether an archive contains a +/// valid Gnome-Pie theme. +///////////////////////////////////////////////////////////////////////// + +public class ThemeImporter : ArchiveReader { + +    public bool     is_valid_theme; +    public string   theme_name; + +    ///////////////////////////////////////////////////////////////////// +    /// Returns +    ///////////////////////////////////////////////////////////////////// + +    public new bool open(string path) { + +        this.is_valid_theme = false; +        this.theme_name = ""; + +        var tmp_reader = new ArchiveReader(); + +        if (tmp_reader.open(path)) { +            try { +                var tmp_dir = GLib.DirUtils.make_tmp("gnomepieXXXXXX"); +                if (tmp_reader.extract_to(tmp_dir)) { +                    var tmp_theme = new Theme(tmp_dir); +                    if (tmp_theme.load()) { +                        is_valid_theme = true; +                        theme_name = tmp_theme.name; +                    } +                } +            } catch (Error e) { +                warning(e.message); +            } +        } + +        tmp_reader.close(); + +        return base.open(path); +    } +} + +} diff --git a/src/utilities/archiveReader.vala b/src/utilities/archiveReader.vala new file mode 100644 index 0000000..16e4541 --- /dev/null +++ b/src/utilities/archiveReader.vala @@ -0,0 +1,123 @@ +///////////////////////////////////////////////////////////////////////// +// Copyright (c) 2011-2015 by Simon Schneegans +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or (at +// your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +///////////////////////////////////////////////////////////////////////// + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// This class can be used to unpack an archive to a directory. +///////////////////////////////////////////////////////////////////////// + +public class ArchiveReader : GLib.Object { + +    private Archive.Read        archive; +    private Archive.WriteDisk   writer; + +    ///////////////////////////////////////////////////////////////////// +    /// Constructs a new ArchiveReader +    ///////////////////////////////////////////////////////////////////// + +    public ArchiveReader() { +        this.archive = new Archive.Read(); +        this.archive.support_format_all(); +        this.archive.support_filter_all(); + +        this.writer = new Archive.WriteDisk(); +        this.writer.set_options( +            Archive.ExtractFlags.TIME | +            Archive.ExtractFlags.PERM | +            Archive.ExtractFlags.ACL | +            Archive.ExtractFlags.FFLAGS +        ); +        this.writer.set_standard_lookup(); +    } + +    ///////////////////////////////////////////////////////////////////// +    /// Call this once after you created the ArchiveReader. Pass the +    /// path to the target archive location. +    ///////////////////////////////////////////////////////////////////// + +    public bool open(string path) { +        return this.archive.open_filename(path, 10240) == Archive.Result.OK; +    } + +    ///////////////////////////////////////////////////////////////////// +    /// Extracts all files from the previously opened archive. +    ///////////////////////////////////////////////////////////////////// + +    public bool extract_to(string directory) { +        while (true) { +            unowned Archive.Entry entry; +            var r = this.archive.next_header(out entry); + +            if (r == Archive.Result.EOF) { +                break; +            } + +            if (r != Archive.Result.OK) { +                warning(this.archive.error_string()); +                return false; +            } + +            entry.set_pathname(directory + "/" + entry.pathname()); + +            r = this.writer.write_header(entry); + +            if (r != Archive.Result.OK) { +                warning(this.writer.error_string()); +                return false; +            } + +            if (entry.size() > 0) { +                while (true) { +                    size_t offset, size; +                    void *buff; + +                    r = this.archive.read_data_block(out buff, out size, out offset); +                    if (r == Archive.Result.EOF) { +                        break; +                    } + +                    if (r != Archive.Result.OK) { +                        warning(this.archive.error_string()); +                        return false; +                    } + +                    this.writer.write_data_block(buff, size, offset); +                } +            } + +            r = this.writer.finish_entry(); + +            if (r != Archive.Result.OK) { +                warning(this.writer.error_string()); +                return false; +            } +        } +        return true; +    } + +    ///////////////////////////////////////////////////////////////////// +    /// When all files have been added, close the directory again. +    ///////////////////////////////////////////////////////////////////// + +    public void close() { +        this.archive.close(); +        this.writer.close(); +    } +} + +} diff --git a/src/utilities/archiveWriter.vala b/src/utilities/archiveWriter.vala new file mode 100644 index 0000000..92bd31b --- /dev/null +++ b/src/utilities/archiveWriter.vala @@ -0,0 +1,139 @@ +///////////////////////////////////////////////////////////////////////// +// Copyright (c) 2011-2015 by Simon Schneegans +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or (at +// your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +///////////////////////////////////////////////////////////////////////// + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// This class can be used to pack a directory of files recursively into +/// a *.tar.gz archive. +///////////////////////////////////////////////////////////////////////// + +public class ArchiveWriter : GLib.Object { + +    private Archive.Write archive; + +    ///////////////////////////////////////////////////////////////////// +    /// Constructs a new ArchiveWriter +    ///////////////////////////////////////////////////////////////////// + +    public ArchiveWriter() { +        this.archive = new Archive.Write(); +        this.archive.add_filter_gzip(); +        this.archive.set_format_pax_restricted(); + +    } + +    ///////////////////////////////////////////////////////////////////// +    /// Call this once after you created the ArchiveWriter. Pass the +    /// path to the target archive location. +    ///////////////////////////////////////////////////////////////////// + +    public bool open(string path) { +        return this.archive.open_filename(path) == Archive.Result.OK; +    } + +    ///////////////////////////////////////////////////////////////////// +    /// Adds all files of a given directory to the previously opened +    /// archive. +    ///////////////////////////////////////////////////////////////////// + +    public bool add(string directory) { +        return add_directory(directory, directory); +    } + +    ///////////////////////////////////////////////////////////////////// +    /// When all files have been added, close the directory again. +    ///////////////////////////////////////////////////////////////////// + +    public void close() { +        this.archive.close(); +    } + +    ///////////////////////////////////////////////////////////////////// +    /// Private helper function which traveres a directory recursively. +    ///////////////////////////////////////////////////////////////////// + +    private bool add_directory(string directory, string relative_to) { +        try { +            var d = Dir.open(directory); +            string name; +            while ((name = d.read_name()) != null) { +                string path = Path.build_filename(directory, name); +                if (FileUtils.test(path, FileTest.IS_DIR)) { +                    if (!add_directory(path, relative_to)) { +                        return false; +                    } + +                } else if (FileUtils.test(path, FileTest.IS_REGULAR)) { +                    if (!add_file(path, relative_to)) { +                        return false; +                    } + +                } else { +                    warning("Packaging theme: Ignoring irregular file " + name); +                } +            } +        } catch (Error e) { +            warning (e.message); +            return false; +        } + +        return true; + +    } + +    ///////////////////////////////////////////////////////////////////// +    /// Private halper which adds a file to the archive. +    ///////////////////////////////////////////////////////////////////// + +    public bool add_file(string path, string relative_to) { +        var entry = new Archive.Entry(); +        entry.set_pathname(path.replace(relative_to, "")); + +        Posix.Stat st; +        Posix.stat(path, out st); +        entry.copy_stat(st); +        entry.set_size(st.st_size); + +        if (this.archive.write_header(entry) == Archive.Result.OK) { +            try { +                var reader = File.new_for_path(path).read(); +                uint8 buffer[4096]; + +                var len = reader.read(buffer); + +                while(len > 0) { +                    this.archive.write_data(buffer, len); +                    len = reader.read(buffer); +                } + +                this.archive.finish_entry(); +            } catch (Error e) { +                warning (e.message); +                return false; +            } + +        } else { +            warning("Failed to include file " + path + " into archive"); +            return false; +        } + +        return true; +    } +} + +} diff --git a/src/utilities/config.vala b/src/utilities/config.vala index 538602d..5dedddb 100644 --- a/src/utilities/config.vala +++ b/src/utilities/config.vala @@ -161,7 +161,9 @@ public class Config : GLib.Object {          load_themes(theme_name); -        if (error_occrured) save(); +        if (error_occrured) { +            save(); +        }      }      ///////////////////////////////////////////////////////////////////// @@ -177,18 +179,19 @@ public class Config : GLib.Object {              // load global themes              var d = Dir.open(Paths.global_themes);              while ((name = d.read_name()) != null) { -                var theme = new Theme(Paths.global_themes + "/" + name); +                var new_theme = new Theme(Paths.global_themes + "/" + name); -                if (theme.load()) -                    themes.add(theme); +                if (new_theme.load()) { +                    themes.add(new_theme); +                }              }              // load local themes              d = Dir.open(Paths.local_themes);              while ((name = d.read_name()) != null) { -                var theme = new Theme(Paths.local_themes + "/" + name); -                if (theme.load()) -                    themes.add(theme); +                var new_theme = new Theme(Paths.local_themes + "/" + name); +                if (new_theme.load()) +                    themes.add(new_theme);              }          } catch (Error e) { @@ -211,10 +214,26 @@ public class Config : GLib.Object {                  warning("Theme \"" + current + "\" not found! Using fallback...");              }              theme.load_images(); +        } else { +            error("No theme found!");          } -        else error("No theme found!");      } +    ///////////////////////////////////////////////////////////////////// +    /// Returns true if a loaded theme has the given name or is in a +    /// directory with the given name. +    ///////////////////////////////////////////////////////////////////// + +    public bool has_theme(string name) { + +        foreach (var theme in themes) { +            if (theme.name == name || theme.directory.has_suffix(name)) { +                return true; +            } +        } + +        return false; +    }  }  } | 
