Commit d2eae9c
Create a backup every time a font is saved
Changed files (16)
modifiedbirdfont/GtkWindow.valaaddedlibbirdfont/BackupDir.valaaddedlibbirdfont/BackupTab.valamodifiedlibbirdfont/BirdFont.valamodifiedlibbirdfont/Font.valamodifiedlibbirdfont/ImportUtils.valamodifiedlibbirdfont/LoadCallback.valamodifiedlibbirdfont/MenuTab.valamodifiedlibbirdfont/OtfFeatureTable.valamodifiedlibbirdfont/Preferences.valamodifiedlibbirdfont/RecentFiles.valamodifiedlibbirdfont/SaveCallback.valamodifiedlibbirdfont/SettingsTab.valamodifiedlibbirdfont/SpinButton.valamodifiedlibbirdfont/String.valamodifiedlibbirdfont/Task.vala
Diff
@@ -531,11 +531,6 @@ public class GtkWindow : Gtk.Window, NativeWindow { } public void set_cursor (int visible) {- if (visible != NativeWindow.VISIBLE) {- get_window ().set_cursor (new Cursor (CursorType.BLANK_CURSOR));- } else {- get_window ().set_cursor (new Cursor (CursorType.ARROW));- } } public double get_screen_scale () {@@ -583,7 +578,7 @@ class TabbarCanvas : DrawingArea { Gtk.Allocation alloc; Context cr; - cr = cairo_create (get_window ());+ cr = cairo_create ((!) get_window ()); get_allocation (out alloc); tabbar.draw (cr, alloc.width, alloc.height);@@ -647,7 +642,7 @@ class ToolboxCanvas : DrawingArea { Gtk.Allocation allocation; get_allocation (out allocation); - Context cw = cairo_create(get_window());+ Context cw = cairo_create((!) get_window()); Toolbox.allocation_width = allocation.width; Toolbox.allocation_height = allocation.height; tb.draw (allocation.width, allocation.height, cw);@@ -712,7 +707,7 @@ public class GlyphCanvasArea : DrawingArea { alloc.x = allocation.x; alloc.y = allocation.y; - Context cw = cairo_create (get_window());+ Context cw = cairo_create ((!) get_window()); Surface s = new Surface.similar (cw.get_target (), Cairo.Content.COLOR_ALPHA, alloc.width, alloc.height); Context c = new Context (s); new file mode 100644@@ -0,0 +1,30 @@+/*+ Copyright (C) 2019 Johan Mattsson+ + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version.++ This library 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 + Lesser General Public License for more details.+*/++using Cairo;+using Math;++namespace BirdFont {++public class BackupDir : GLib.Object {+ public string folder_name;+ public string modification_time;+ + public BackupDir (string folder_name, string modification_time) {+ this.folder_name = folder_name;+ this.modification_time = modification_time;+ }+}++}new file mode 100644@@ -0,0 +1,186 @@+/*+ Copyright (C) 2019 Johan Mattsson++ This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version.++ This library 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 + Lesser General Public License for more details.+*/++using Cairo;+using Math;++namespace BirdFont {++public class BackupTab : Table {+ Gee.ArrayList<Row> rows = new Gee.ArrayList<Row> ();+ + const int FONT_FOLDER = -2;+ const int FONT_FILE = -1;+ + private BackupDir? backup_folder = null;+ + public BackupTab () {+ }++ public override Gee.ArrayList<Row> get_rows () {+ return rows;+ }++ public override void selected_row (Row row, int column, bool delete_button) { + if (row.get_index () == FONT_FOLDER) {+ return_if_fail (row.get_row_data () is BackupDir);+ backup_folder = (BackupDir) row.get_row_data ();+ MainWindow.scrollbar.set_size (0);+ update_rows ();+ } else if (row.get_index () == FONT_FILE) {+ return_if_fail (row.get_row_data () is String);+ String backup_file = (String) row.get_row_data ();+ RecentFiles.load_font (backup_file.c_str);+ MainWindow.scrollbar.set_size (0);+ }++ GlyphCanvas.redraw ();+ }++ public override void update_rows () {+ Row row;+ + rows.clear ();++ if (backup_folder != null) {+ BackupDir folder = (!) backup_folder;+ Gee.ArrayList<string> files = Font.get_sorted_backups (folder.folder_name);++ if (files.size > 0) {+ row = new Row.headline (t_("Backups"));+ rows.add (row); + }+ + if (files.size == 0) {+ row = new Row.headline (t_("No backups for this font."));+ rows.add (row);+ }+ + foreach (string path in files) {+ string name = Font.get_file_from_full_path (path);+ row = new Row.columns_1 (name, FONT_FILE, false);+ String file_name = new String (path); + row.set_row_data (file_name);+ rows.add (row);+ }+ } else { + Gee.ArrayList<BackupDir> backup_folders = get_backup_folders ();+ + if (backup_folders.size == 0) {+ row = new Row.headline (t_("No backups found."));+ rows.add (row);+ }++ if (backup_folders.size > 0) {+ row = new Row.headline (t_("Backups"));+ rows.add (row); + }+ + foreach (BackupDir backup_font in backup_folders) {+ row = new Row.columns_2 (backup_font.folder_name, backup_font.modification_time, FONT_FOLDER, false);+ row.set_row_data (backup_font);+ rows.add (row);+ }+ }+ + GlyphCanvas.redraw ();+ }++ public override string get_label () {+ return t_("Backups");+ }++ public override string get_name () {+ return "Backups";+ }+ + public string get_time_stamp_from_file_name (string file_name) {+ int dash = file_name.last_index_of ("-");+ + if (file_name.has_suffix (".bf_backup") && dash > -1) {+ string time_stamp = file_name.substring (dash + "-".length, file_name.length - dash - ".bf_backup".length);+ time_stamp = time_stamp.replace ("_", " ");+ return time_stamp;+ }+ + warning("Can't obtain timestamp from " + file_name);+ + return "Unknown time.";+ }+ + public Gee.ArrayList<BackupDir> get_backup_folders () {+ FileEnumerator enumerator;+ string folder_name;+ FileInfo? file_info;+ Gee.ArrayList<BackupDir> backup_folders = new Gee.ArrayList<BackupDir> ();+ File dir = Preferences.get_backup_directory ();+ + try {+ printd ("Backup dir: ");+ printd ((!) dir.get_path ());+ printd ("\n");+ + enumerator = dir.enumerate_children (FileAttribute.STANDARD_NAME, 0);+ while ((file_info = enumerator.next_file ()) != null) {+ FileInfo info = (!) file_info;+ folder_name = info.get_name ();+ string full_path = (!) get_child (dir, folder_name).get_path ();+ + printd ("In backup dir: ");+ printd (full_path);+ printd ("\n");+ + if (!FileUtils.test (full_path, FileTest.IS_DIR)) {+ warning (folder_name + " is not a backup directory.");+ continue;+ }+ + if (!folder_name.has_suffix (".backup")) {+ warning (folder_name + " is not a backup directory, expecting the suffix .backup");+ continue;+ }+ + folder_name = folder_name.substring (0, folder_name.length - ".backup".length);+ Gee.ArrayList<string> files = Font.get_sorted_backups (folder_name);+ + if (files.size > 0) {+ string last_file = files.get (files.size - 1);+ string modification_time = get_time_stamp_from_file_name (last_file);+ BackupDir backup = new BackupDir (folder_name, modification_time);+ backup_folders.add (backup);+ }+ }+ } catch (Error e) {+ warning (e.message);+ }+ + backup_folders.sort ((a, b) => {+ BackupDir first, next;++ first = (BackupDir) a;+ next = (BackupDir) b;+ + return Posix.strcmp (b.modification_time, a.modification_time); // descending+ });+ + return backup_folders; + }++ public override void draw (WidgetAllocation allocation, Context cr) {+ MainWindow.get_overview ().allocation = allocation;+ base.draw (allocation, cr);+ }+}++}@@ -406,17 +406,6 @@ public class BirdFont { return settings; } - internal static File get_backup_directory () {- File settings = get_settings_directory ();- File backup = get_child (settings, "backup");-- if (!backup.query_exists ()) {- DirUtils.create ((!) backup.get_path (), 0755);- }-- return backup;- }- public static bool has_argument (string param) { if (is_null (args)) { return false;@@ -356,8 +356,8 @@ public class Font : GLib.Object { return sb.str; } - public string get_file_name () {- string p = get_path ();+ public static string get_file_from_full_path (string path) {+ string p = path; int i = p.last_index_of ("/"); if (i == -1) {@@ -365,10 +365,13 @@ public class Font : GLib.Object { } p = p.substring (i + 1);- return p; } + public string get_file_name () {+ return get_file_from_full_path (get_path ());+ }+ /** @return an absolute path to the font folder. */ public File get_folder () { string p = get_folder_path ();@@ -723,47 +726,6 @@ public class Font : GLib.Object { background_images.add (image); } - /** Delete temporary rescue files. */- public void delete_backup () {- File dir = BirdFont.get_backup_directory ();- File? new_file = null;- File file;- string backup_file;- - new_file = get_child (dir, @"$(name).birdfont");- backup_file = (!) ((!) new_file).get_path ();- - try {- file = File.new_for_path (backup_file);- if (file.query_exists ()) {- file.delete (); - }- } catch (GLib.Error e) {- stderr.printf (@"Failed to delete backup\n");- warning (@"$(e.message) \n");- }- }- - /** Returns path to backup file. */- public string save_backup () {- File dir = BirdFont.get_backup_directory ();- File? temp_file = null;- string backup_file;- BirdFontFile birdfont_file = new BirdFontFile (this);-- temp_file = get_child (dir, @"$(name).birdfont");- backup_file = (!) ((!) temp_file).get_path ();- backup_file = backup_file.replace (" ", "_");- - if (get_path () == backup_file) {- warning ("Refusing to write backup of a backup.");- return backup_file;- }- - birdfont_file.write_font_file (backup_file, true);- return backup_file;- }- public void init_bfp (string directory) { try { bfp_file = new BirdFontPart (this);@@ -794,12 +756,124 @@ public class Font : GLib.Object { settings.save (get_file_name ()); } - public bool save_bfp () {+ private void save_backups () throws GLib.Error {+ string num_backups = Preferences.get ("num_backups");+ + if (num_backups == "") {+ num_backups = "20";+ }+ + int backups = int.parse (num_backups);+ + if (backups == 0) {+ printd ("No backups according to settings. Skipping it.");+ delete_old_backups (backups);+ return;+ }+ + if (backups > 0) {+ string path = (!) font_file;+ string bf_data = "";++ if (FileUtils.get_contents (path, out bf_data)) {+ DateTime now = new DateTime.now_local ();+ string time_stamp = now.to_string ();+ + time_stamp = time_stamp.replace (":", "_");+ time_stamp = time_stamp.replace ("-", "_");+ + string fn = get_file_name ();+ File backup_directory_for_font = Preferences.get_backup_directory_for_font (fn);+ + if (!backup_directory_for_font.query_exists ()) {+ int error = DirUtils.create ((!) backup_directory_for_font.get_path (), 0766);+ + if (error == -1) {+ stderr.printf (@"Failed to create backup directory: $((!) backup_directory_for_font.get_path ())\n");+ }+ }+ + string file_name = get_file_name ();+ + if (file_name.has_suffix (".bf")) {+ file_name = file_name.substring (0, file_name.length - ".bf".length);+ }+ + if (file_name.has_suffix (".birdfont")) {+ file_name = file_name.substring (0, file_name.length - ".birdfont".length);+ }+ + string backup_file_name = file_name + @"-$(time_stamp).bf_backup";+ File backup_file = get_child (backup_directory_for_font, backup_file_name);+ printd (@"Saving backup to: $((!) backup_file.get_path ())\n");+ + FileUtils.set_contents ((!) backup_file.get_path (), bf_data);+ } + }+ + delete_old_backups (backups);+ }+ + public static Gee.ArrayList<string> get_sorted_backups (string font_file_name) {+ Gee.ArrayList<string> backups = new Gee.ArrayList<string> ();++ try {+ File backup_directory_for_font = Preferences.get_backup_directory_for_font (font_file_name);+ Dir dir = Dir.open ((!) backup_directory_for_font.get_path (), 0);+ + string? name = null;+ while ((name = dir.read_name ()) != null) {+ string file_name = (!) name;+ + printd (@"backup_directory_for_font: $((!) backup_directory_for_font.get_path ())\n");+ printd (@"file_name $file_name\n");++ File backup_file = get_child (backup_directory_for_font, file_name);+ + if (FileUtils.test ((!) backup_file.get_path (), FileTest.IS_REGULAR)+ && file_name.has_suffix (".bf_backup")) {+ backups.add ((!) backup_file.get_path ());+ } else {+ warning (@"$file_name does not seem to be a backup file.");+ }+ }+ } catch (GLib.Error error) {+ warning (error.message);+ warning("Can't fetch backup files.");+ }+ + backups.sort ();+ + return backups;+ }+ + public void delete_old_backups (int keep) {+ try {+ string file_name = get_file_name ();+ Gee.ArrayList<string> backups = get_sorted_backups (file_name);+ Gee.ArrayList<string> old_backups = new Gee.ArrayList<string> ();+ + for (int i = 0; i < backups.size - keep; i++) {+ string b = backups.get (i);+ old_backups.add (b);+ }+ + foreach (string path in old_backups) {+ printd (@"Deleting backup: $(path)\n");+ File file = File.new_for_path (path);+ file.delete ();+ }+ } catch (GLib.Error error) {+ warning (error.message);+ warning("Can't delet backup.");+ } + }+ + private bool save_bfp () { return bfp_file.save (); } - public void save_bf () {- Font font;+ private void save_bf () { BirdFontFile birdfont_file = new BirdFontFile (this); string path; bool file_written;@@ -822,10 +896,11 @@ public class Font : GLib.Object { return; } - if (file_written) {- // delete the backup when the font is saved- font = BirdFont.get_current_font ();- font.delete_backup ();+ try {+ save_backups ();+ } catch (GLib.Error e) {+ warning (e.message);+ warning ("Can't save backup."); } modified = false;@@ -889,10 +964,15 @@ public class Font : GLib.Object { if (path.has_suffix (".bf") || path.has_suffix (".BF") || path.has_suffix (".BIRDFONT")- || path.has_suffix (".birdfont")) {+ || path.has_suffix (".birdfont")+ || path.has_suffix (".bf_backup")) { loaded = parse_bf_file (path); format = FontFormat.BIRDFONT;+ + if (path.has_suffix (".bf_backup")) {+ font_file = null;+ } } if (path.has_suffix (".bfp") || path.has_suffix (".BFP")) {@@ -75,8 +75,6 @@ public static int run_import (string[] arg) { } } - font.save_backup ();- foreach (string f in svg_files) { svg = File.new_for_path (f); imported = import_svg_file (font, svg);@@ -88,7 +86,7 @@ public static int run_import (string[] arg) { } } - font.save_bf ();+ font.save (); return 0; }@@ -87,8 +87,6 @@ public class LoadCallback : GLib.Object { Font f = BirdFont.get_current_font (); if (fn != null) {- f.delete_backup ();- f = BirdFont.new_font (); f.set_file ((!) fn);@@ -217,6 +217,10 @@ public class MenuTab : FontDisplay { } } + public static void clear_font_settings () {+ Toolbox.background_tools = new BackgroundTools (); // clear toolbox selection of images+ }+ public static void signal_file_exported () { IdleSource idle = new IdleSource (); idle.set_callback (() => {@@ -230,7 +234,7 @@ public class MenuTab : FontDisplay { }); idle.attach (null); }- + public static void signal_file_saved () { IdleSource idle = new IdleSource (); idle.set_callback (() => {@@ -94,7 +94,7 @@ public class OtfFeatureTable : Table { o = (!) row.get_row_data (); return_if_fail (o is String); s = (String) o;- add_new_alternate (s.data);+ add_new_alternate (s.c_str); } else if (row_index == ALTERNATE_ENTRY) { if (delete_button) { return_if_fail (row.has_row_data ());@@ -60,6 +60,56 @@ public class Preferences { return files; }+ + public static File get_backup_directory () {+ File config_directory = BirdFont.get_settings_directory ();+ File backup_directory = get_child (config_directory, "backup");+ + if (!backup_directory.query_exists ()) {+ int error = DirUtils.create ((!) backup_directory.get_path (), 0766);+ + if (error == -1) {+ warning (@"Failed to create backup directory: $((!) backup_directory.get_path ())\n");+ }+ }+ + return backup_directory;+ }+ + public static File get_backup_directory_for_font (string bf_file_name) {+ if (bf_file_name == "") {+ warning ("no filename.");+ }+ + if (bf_file_name.index_of ("/") > -1) {+ warning ("Expecting a file and not a folder got: " + bf_file_name);+ }+ + File backup_directory = get_backup_directory ();+ string subdir_name = bf_file_name;+ + if (subdir_name.has_suffix (".bf")) {+ subdir_name = subdir_name.substring (0, subdir_name.length - ".bf".length);+ }+ + if (subdir_name.has_suffix (".birdfont")) {+ subdir_name = subdir_name.substring (0, subdir_name.length - ".birdfont".length);+ }+ + subdir_name += ".backup";+ + File backup_subdir = get_child (backup_directory, subdir_name);+ + if (!backup_subdir.query_exists ()) {+ int error = DirUtils.create ((!) backup_subdir.get_path (), 0766);+ + if (error == -1) {+ warning (@"Failed to create backup directory: $((!) backup_subdir.get_path ())\n");+ }+ }++ return backup_subdir;+ } public static void add_recent_files (string file) { string escaped_string = file.replace ("\t", "\\t");@@ -1,5 +1,5 @@ /*- Copyright (C) 2015 Johan Mattsson+ Copyright (C) 2015 2019 Johan Mattsson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -24,8 +24,7 @@ public class RecentFiles : Table { const int NEW_FONT = -5; const int CURRENT_FONT = -4; const int RECENT_FONT = -3;- const int BACKUP = -2;- + public RecentFiles () { } @@ -34,21 +33,15 @@ public class RecentFiles : Table { } public override void selected_row (Row row, int column, bool delete_button) { - Font f;- if (row.get_index () == NEW_FONT) { MenuTab.new_file (); MenuTab.select_overview (); } else if (row.get_index () == RECENT_FONT) { return_if_fail (row.get_row_data () is Font);- f = (Font) row.get_row_data ();+ Font f = (Font) row.get_row_data (); MainWindow.scrollbar.set_size (0); GlyphCanvas.redraw (); load_font (f.get_path ());- } else if (row.get_index () == BACKUP) {- return_if_fail (row.get_row_data () is Font);- f = (Font) row.get_row_data ();- delete_backup (f.get_file_name ()); } GlyphCanvas.redraw ();@@ -57,7 +50,6 @@ public class RecentFiles : Table { public override void update_rows () { Row row; Gee.ArrayList<Font> recent_fonts = get_recent_font_files ();- Gee.ArrayList<Font> backups = get_backups (); Font current_font = BirdFont.get_current_font (); rows.clear ();@@ -65,7 +57,7 @@ public class RecentFiles : Table { if (recent_fonts.size == 0) { row = new Row.headline (t_("No fonts created yet")); rows.add (row);-+ row = new Row.columns_1 (t_("Create a New Font"), NEW_FONT, false); rows.add (row); }@@ -91,17 +83,6 @@ public class RecentFiles : Table { row.set_row_data (font); rows.add (row); }-- if (backups.size > 0) { - row = new Row.headline (t_("Backups"));- rows.add (row); - }- - foreach (Font font in backups) {- row = new Row.columns_1 (font.get_file_name (), BACKUP, true);- row.set_row_data (font);- rows.add (row);- } GlyphCanvas.redraw (); }@@ -144,52 +125,6 @@ public class RecentFiles : Table { return fonts; }-- public Gee.ArrayList<Font> get_backups () {- FileEnumerator enumerator;- string file_name;- FileInfo? file_info;- Gee.ArrayList<Font> backups = new Gee.ArrayList<Font> ();- File dir = BirdFont.get_backup_directory ();- Font font = BirdFont.get_current_font ();- Font backup_font;-- try {- enumerator = dir.enumerate_children (FileAttribute.STANDARD_NAME, 0);- while ((file_info = enumerator.next_file ()) != null) {- file_name = ((!) file_info).get_name ();- - // ignore old backup files- if (file_name.has_prefix ("current_font_")) {- continue;- }- - backup_font = new Font ();- backup_font.set_font_file ((!) get_child (dir, file_name).get_path ());- backups.insert (0, backup_font);- }- } catch (Error e) {- warning (e.message);- }- - return backups; - }-- public void delete_backup (string file_name) {- File backup_file;- - try {- backup_file = BirdFont.get_backup_directory ();- backup_file = get_child (backup_file, file_name);- if (backup_file.query_exists ()) {- backup_file.delete (); - }- } catch (GLib.Error e) {- warning (e.message);- }- - selected_canvas ();- } public override void draw (WidgetAllocation allocation, Context cr) { MainWindow.get_overview ().allocation = allocation;@@ -236,13 +171,17 @@ public class RecentFiles : Table { if (MenuTab.has_suppress_event ()) { return; }- + f = BirdFont.new_font ();- + MainWindow.close_all_tabs ();- + MenuTab.clear_font_settings ();+ f.set_file (fn);- Preferences.add_recent_files (fn);++ if (!fn.has_suffix (".bf_backup")) { + Preferences.add_recent_files (fn);+ } MainWindow.native_window.load (); // background thread });@@ -92,7 +92,6 @@ public class SaveCallback : GLib.Object { if (f.is_bfp ()) { MainWindow.native_window.save (); } else {- f.delete_backup (); fn = f.get_path (); if (f.font_file != null@@ -169,6 +169,32 @@ public class SettingsTab : SettingsDisplay { }); tools.add (new SettingsItem (themes, t_("Color theme"))); + SpinButton num_backups = new SpinButton ("num_backups");+ tools.add (new SettingsItem (num_backups, t_("Number of backups per font")));+ + num_backups.set_integers (true);+ + num_backups.set_max (100);+ num_backups.set_min (0);+ num_backups.set_value ("20");++ if (Preferences.get ("num_backups") != "") {+ Preferences.set ("num_backups", num_backups.get_short_display_value ());+ }++ num_backups.new_value_action.connect ((self) => {+ Preferences.set ("num_backups", num_backups.get_short_display_value ());+ });+ + Tool load_backups = new Tool ("load_backups");+ load_backups.select_action.connect((self) => {+ BackupTab backups = new BackupTab ();+ MainWindow.tabs.add_unique_tab (backups);+ MainWindow.tabs.select_tab_name ("Backups");+ load_backups.selected = false;+ });+ tools.add (new SettingsItem (load_backups, t_("Load a backup font")));+ tools.add (new SettingsItem.head_line (t_("Key Bindings"))); foreach (MenuItem menu_item in MainWindow.get_menu ().sorted_menu_items) {@@ -37,6 +37,7 @@ public class SpinButton : Tool { int step = 1; bool big_number = false;+ bool integers = false; double last_active_time = 0; bool waiting_for_icon_switch = false;@@ -192,6 +193,11 @@ public class SpinButton : Tool { big_number = b; } + public void set_integers (bool i) {+ integers = i;+ big_number = i;+ }+ public static string convert_to_string (double val) { SpinButton sb = new SpinButton (); sb.set_value_round (val);@@ -357,6 +363,11 @@ public class SpinButton : Tool { separator = v.substring (v.index_of_nth_char (3), 1); n3 = (int8) int.parse (v.substring (v.index_of_nth_char (4), 1)); n4 = (int8) int.parse (v.substring (v.index_of_nth_char (5), 1));+ + if (integers) {+ n3 = 0;+ n4 = 0;+ } } if (separator != ".") {@@ -406,6 +417,18 @@ public class SpinButton : Tool { } public string get_short_display_value () { + if (integers) {+ if (n0 == 0 && n1 == 0) {+ return @"$n2";+ }+ + if (n0 == 0) {+ return @"$n1$n2";+ }+ + return @"$n0$n1$n2";+ }+ if (!big_number) { return @"$n0.$n1$n2$n3"; }@@ -436,6 +459,10 @@ public class SpinButton : Tool { public string get_display_value () { string v; + if (integers) {+ return get_short_display_value ();+ }+ if (!big_number) { return @"$n0.$n1$n2$n3$n4"; }@@ -16,10 +16,10 @@ namespace BirdFont { /** Boxed string class. */ public class String : GLib.Object {- public string data;+ public string c_str; public String (string data) {- this.data = data;+ this.c_str = data; } } @@ -1,5 +1,5 @@ /*- Copyright (C) 2014 2015 Johan Mattsson+ Copyright (C) 2014 2015 2019 Johan Mattsson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -17,10 +17,11 @@ namespace BirdFont { public class Task : GLib.Object { public delegate void Runnable ();+ public signal void done (); Runnable task; bool cancelled = false; bool cancelable = false;-+ public Task.empty () { } @@ -63,14 +64,14 @@ public class Task : GLib.Object { } public virtual void run () {- if (task == null) {- warning ("No task set.");- return;- }- task (); - warning ("Task is done.");+ IdleSource idle = new IdleSource ();+ idle.set_callback (() => {+ done ();+ return false;+ });+ idle.attach (null); } public void* perform_task() {