Clone in a terminal:
Commit 840ae54
Johan Mattsson - 2014-07-06T20:37:09+00:00
840ae549e0d5da49bb5c496a8401e3028b7ce361johan.mattsson.m@gmail.com

Save, export and load fonts in background threads

Changed files (31)

Diff

diff --git a/birdfont/GtkWindow.vala b/birdfont/GtkWindow.valaindex ebe2faf..6281c28 100644--- a/birdfont/GtkWindow.vala+++ b/birdfont/GtkWindow.vala@@ -119,9 +119,11 @@ public class GtkWindow : Gtk.Window, NativeWindow { 					warning ("Failed to load html into canvas."); 				} 				+				// show the webview when loading has finished 				html_box.set_visible (true); 				glyph_canvas_area.set_visible (false); 				description.canvas.set_visible (false);+				 			} else { 				html_box.set_visible (false); 				glyph_canvas_area.set_visible (true);@@ -188,14 +190,7 @@ public class GtkWindow : Gtk.Window, NativeWindow {  		key_press_event.connect ((t, event) => { 			if (!GtkWindow.text_input_is_active) {-				FontDisplay fd = MainWindow.glyph_canvas.current_display;-				-				if (fd is Glyph) {-					MainWindow.tools.key_press (event.keyval);-				}-				-				MainWindow.glyph_canvas.key_press (event.keyval);-				KeyBindings.add_modifier_from_keyval (event.keyval);+				TabContent.key_press (event.keyval); 			} 			 			return false;@@ -203,13 +198,7 @@ public class GtkWindow : Gtk.Window, NativeWindow { 		 		key_release_event.connect ((t, event) => { 			if (!GtkWindow.text_input_is_active) {-				FontDisplay fd = MainWindow.glyph_canvas.current_display;-				-				if (fd is Glyph) {-					MainWindow.glyph_canvas.key_release (event.keyval);-				}-				-				KeyBindings.remove_modifier_from_keyval (event.keyval);+				TabContent.key_release (event.keyval); 			} 			 			return false;@@ -446,7 +435,7 @@ public class GtkWindow : Gtk.Window, NativeWindow { 				 		Gtk.MenuItem export_item = new Gtk.MenuItem.with_mnemonic (t_("_Export")); 		file_menu.append (export_item);-		export_item.activate.connect (() => { MenuTab.export_font (); });+		export_item.activate.connect (() => { MenuTab.export_fonts_in_background (); }); 		export_item.add_accelerator ("activate", accel_group, 'E', Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE);  		Gtk.MenuItem preview_item = new Gtk.MenuItem.with_mnemonic(t_("_Preview"));@@ -869,6 +858,48 @@ public class GtkWindow : Gtk.Window, NativeWindow { 	public void hide_tooltip () { 		tooltip_window.hide (); 	}+	+	/** Run export in a background thread. */+	public void export () {+		unowned Thread<void*> export_thread;+		MenuTab.start_background_thread ();+		export_thread = Thread.create<void*> (this.export_thread, true);+	}+	+	public void* export_thread () {+		ExportCallback.export_fonts ();+		MenuTab.stop_background_thread ();+		MenuTab.signal_file_exported ();+		return null;+	}+	+	/** Load font in a background thread. */+	public void load () {+		unowned Thread<void*> thread;+		MenuTab.start_background_thread ();+		thread = Thread.create<void*> (this.loading_thread, true);+	}+	+	public void* loading_thread () {+		BirdFont.get_current_font ().load ();+		MenuTab.stop_background_thread ();+		MenuTab.signal_file_loaded ();+		return null;+	}++	/** Save font in a background thread. */+	public void save () {+		unowned Thread<void*> thread;+		MenuTab.start_background_thread ();+		thread = Thread.create<void*> (this.saving_thread, true);+	}+	+	public void* saving_thread () {+		BirdFont.get_current_font ().save ();+		MenuTab.stop_background_thread ();+		MenuTab.signal_file_saved ();+		return null;+	} }  class TabbarCanvas : DrawingArea {@@ -1028,7 +1059,7 @@ public class GlyphCanvasArea : DrawingArea  { 			Surface s = new Surface.similar (cw.get_target (), Cairo.Content.COLOR_ALPHA, alloc.width, alloc.height); 			Context c = new Context (s);  -			glyph_canvas.current_display.draw (alloc, c);+			TabContent.draw (alloc, c);  			cw.save (); 			cw.set_source_surface (c.get_target (), 0, 0);@@ -1042,9 +1073,9 @@ public class GlyphCanvasArea : DrawingArea  { 			set_modifier ((int) e.state); 			 			if (e.type == EventType.BUTTON_PRESS) {-				glyph_canvas.current_display.button_press (e.button, e.x, e.y);	+				TabContent.button_press (e.button, e.x, e.y);	 			} else if (e.type == EventType.2BUTTON_PRESS) {-				glyph_canvas.current_display.double_click (e.button, e.x, e.y);+				TabContent.double_click (e.button, e.x, e.y); 			} 				 			return true;@@ -1052,12 +1083,12 @@ public class GlyphCanvasArea : DrawingArea  { 		 		button_release_event.connect ((t, e)=> { 			set_modifier ((int) e.state);-			glyph_canvas.current_display.button_release ((int) e.button, e.x, e.y);+			TabContent.button_release ((int) e.button, e.x, e.y); 			return true; 		}); 		 		motion_notify_event.connect ((t, e)=> {-			glyph_canvas.current_display.motion_notify (e.x, e.y);		+			TabContent.motion_notify (e.x, e.y);		 			return true; 		}); 		@@ -1065,12 +1096,12 @@ public class GlyphCanvasArea : DrawingArea  { 			set_modifier ((int) e.state); 			 			if (e.direction == Gdk.ScrollDirection.UP) {-				glyph_canvas.current_display.scroll_wheel_up (e.x, e.y);+				TabContent.scroll_wheel_up (e.x, e.y); 			} else if (e.direction == Gdk.ScrollDirection.DOWN) {-				glyph_canvas.current_display.scroll_wheel_down (e.x, e.y)		;+				TabContent.scroll_wheel_down (e.x, e.y)		; 			} 			-			glyph_canvas.current_display.button_release (2, e.x, e.y);+			TabContent.button_release (2, e.x, e.y); 			return true; 		}); 		diff --git a/fonts/Decibel.bf b/fonts/Decibel.bfindex 7b90fb8..bf9de76 100644--- a/fonts/Decibel.bf+++ b/fonts/Decibel.bf@@ -154,13 +154,19 @@ 	</glyph> </collection> <collection unicode="U+41">-	<selected id="1"/>+	<selected id="2"/> 	<glyph id="1" left="-24" right="62"> 		<path stroke="0" data="S 4.0055442724,71.9352515311 L 18.0463917526,72.0412371134 L 9.6455835478,45.5115295875 L -8.0360824742,-0.0412371134 L -24.0279708939,-0.0233893099 L 4.0055442724,71.9352515311" /> 		<path stroke="0" data="S 51.8969072165,0.0000000000 L 31.9793814433,0.0000000000 L 14.3158133394,45.5061415559 L 6.0326460481,72.0412371134 D 10.5378006873,72.0412371134 15.9914089347,72.0412371134 24.0532646048,72.0412371134 L 51.8969072165,0.0000000000" /> 		<path stroke="0" data="S -7.9931271478,16.0014213972 L -8.0714066578,27.0000000000 L 31.9217204899,27.0000000000 L 32.0000000000,16.0014213972 L -7.9931271478,16.0014213972" /> 		<path stroke="0" data="S -23.9831081081,82.0000000000 L -23.9831081081,82.0000000000 O" /> 	</glyph>+	<glyph id="2" left="-24" right="62">+		<path stroke="0" data="S 4.0055442724,71.9352515311 L 16.1931543425,72.0412371134 L 7.7923461377,45.5115295875 L -9.8893198843,-0.0412371134 L -24.0279708939,-0.0233893099 L 4.0055442724,71.9352515311" />+		<path stroke="0" data="S 51.8969072165,0.0000000000 L 31.9793814433,0.0000000000 L 14.3158133394,45.5061415559 L 6.0326460481,72.0412371134 D 10.5378006873,72.0412371134 15.9914089347,72.0412371134 24.0532646048,72.0412371134 L 51.8969072165,0.0000000000" />+		<path stroke="0" data="S -7.9931271478,16.0014213972 L -8.0714066578,27.0000000000 L 31.9217204899,27.0000000000 L 32.0000000000,16.0014213972 L -7.9931271478,16.0014213972" />+		<path stroke="0" data="S -23.9831081081,82.0000000000 L -23.9831081081,82.0000000000 O" />+	</glyph> </collection> <collection unicode="U+42"> 	<selected id="1"/>@@ -594,7 +600,7 @@ 		<path stroke="0" data="S -19.6216336698,29.0115051400 Q -24.6642999998,34.0827683025 -24.7943474080,39.3941248032 Q -23.4181212441,57.2974975135 -3.5611624153,55.7935764075 Q 2.5434328041,55.3116443254 6.3828545964,52.9578825017 L 3.4468747669,41.6000127886 Q 0.1138148249,43.4801399907 -1.7445173835,42.9093020106 Q -4.5648263329,42.4259237995 -4.6986422096,39.7974020980 Q -4.7962978415,37.8791697174 -3.0230534494,35.6510299118 Q -1.3657386278,33.1666149714 4.1805167941,27.0870576542 Q 9.2414493007,22.1003106144 9.3663220078,16.6416077220 Q 7.9352288741,-1.2574627930 -11.8668629849,0.2421561176 Q -19.8547035521,0.8383097625 -25.5044515042,5.3427619029 L -22.5565512787,17.1457227289 Q -18.8941733398,12.8792420661 -14.8999626389,12.5222337432 Q -10.9078406894,12.2421557008 -10.7041540850,16.2259130571 Q -10.7614257889,18.1274994331 -12.4049719508,20.3847026134 Q -14.7448029856,23.5981651711 -19.6216336698,29.0115051400" /> 	</glyph> 	<glyph id="4" left="-26" right="31">-		<path stroke="0" data="S -24.6506973900,39.3042035314 Q -20.8846140121,55.2317158339 -0.0304797517,55.7853855507 Q 13.9812680115,56.0561959654 22.0000000000,52.0000000000 L 16.0000000000,40.0000000000 Q 9.9740634006,44.0345821326 2.0000000000,44.0000000000 Q -1.6214924920,44.0309419081 -3.8693599553,40.7040203038 Q -4.1738495827,39.9653262146 -4.1183761347,39.4377133603 Q -4.0317213369,38.6135319404 -3.5898305978,38.2600191479 Q -1.0038080600,35.3538666192 9.9268433552,32.9042111360 Q 22.8629176372,29.9411203928 22.5213230531,16.5517274890 Q 21.9956772334,-4.0518731988 -11.4699782750,0.1402674997 Q -19.4710094189,0.5203947531 -25.2403925531,4.8705624808 L -22.6124508970,16.7488587665 Q -14.8109879409,13.6008263064 -10.6377551222,12.6651790320 Q 0.3331107811,10.4194878842 0.3298537462,15.1142600408 Q 0.3273158350,18.7570408674 -6.9279797684,20.3664905602 Q -26.8649974518,24.7636313260 -24.6506973900,39.3042035314" />+		<path stroke="0" data="S 9.9268433552,32.9042111360 Q 22.8629176372,29.9411203928 22.5213230531,16.5517274890 Q 21.9956772334,-4.0518731988 -11.4699782750,0.1402674997 Q -19.4710094189,0.5203947531 -25.2403925531,4.8705624808 L -22.6124508970,16.7488587665 Q -14.8109879409,13.6008263064 -10.6377551222,12.6651790320 Q 0.3331107811,10.4194878842 0.3298537462,15.1142600408 Q 0.3273158350,18.7570408674 -6.9279797684,20.3664905602 Q -26.8649974518,24.7636313260 -24.6506973900,39.3042035314 Q -20.8846140121,55.2317158339 -0.0304797517,55.7853855507 Q 13.9812680115,56.0561959654 22.0000000000,52.0000000000 L 16.0000000000,40.0000000000 Q 9.9730905353,43.8707314526 2.0000000000,44.0000000000 Q -1.8456291911,44.0712733683 -3.4501269963,42.5157277724 Q -5.5860726921,40.4435347740 -3.6513689768,38.3236737229 Q -1.1523666620,35.5855088907 9.9268433552,32.9042111360" /> 	</glyph> </collection> <collection unicode="U+74">@@ -944,7 +950,7 @@ <kerning left="o" right="w" hadjustment="-7.0000000000" /> <kerning left="e" right="e" hadjustment="-3.0000000000" /> <kerning left="j" right="o" hadjustment="-1.0000000000" />-<kerning left="o" right="x" hadjustment="-12.6035701094" />+<kerning left="o" right="x" hadjustment="-9.6035701094" /> <kerning left="e" right="f" hadjustment="-4.0000000000" /> <kerning left="v" right="e" hadjustment="-1.0000000000" /> <kerning left="e" right="g" hadjustment="-3.0000000000" />@@ -952,6 +958,7 @@ <kerning left="V" right="O" hadjustment="-4.5454545455" /> <kerning left="v" right="i" hadjustment="3.0000000000" /> <kerning left="C" right="o" hadjustment="-4.0000000000" />+<kerning left="T" right="n" hadjustment="-12.0000000000" /> <kerning left="e" right="l" hadjustment="-1.0000000000" /> <kerning left="v" right="k" hadjustment="-5.0000000000" /> <kerning left="quote" right="i" hadjustment="1.1990407674" />@@ -1027,6 +1034,7 @@ <kerning left="x" right="e" hadjustment="-3.0000000000" /> <kerning left="E" right="l" hadjustment="2.0000000000" /> <kerning left="g" right="h" hadjustment="1.0000000000" />+<kerning left="J" right="u" hadjustment="2.0000000000" /> <kerning left="L" right="Y" hadjustment="-15.0000000000" /> <kerning left="V" right="Ä" hadjustment="-11.0000000000" /> <kerning left="?" right="!" hadjustment="-6.0000000000" />@@ -1296,6 +1304,7 @@ <kerning left="ä" right="t" hadjustment="-3.0000000000" /> <kerning left="T" right="A" hadjustment="-12.0000000000" /> <kerning left="a" right="y" hadjustment="-2.0000000000" />+<kerning left="K" right="r" hadjustment="-3.0000000000" /> <kerning left="W" right="h" hadjustment="1.0000000000" /> <kerning left="W" right="i" hadjustment="3.5971223022" /> <kerning left="A" right="b" hadjustment="-2.0000000000" />diff --git a/libbirdfont/BackgroundSelection.vala b/libbirdfont/BackgroundSelection.valaindex 3776692..b0c37ca 100644--- a/libbirdfont/BackgroundSelection.vala+++ b/libbirdfont/BackgroundSelection.vala@@ -21,7 +21,7 @@ class BackgroundSelection : FontDisplay {  	int active_box = -1; 	ImageSurface add_icon;-	List <string> background_images = new List <string> ();+	Gee.ArrayList <string> background_images = new Gee.ArrayList<string> (); 	WidgetAllocation allocation; 	Glyph glyph; 	@@ -195,11 +195,11 @@ class BackgroundSelection : FontDisplay {  		font = BirdFont.get_current_font (); 				-		if (!(0 <= active_box - 1 < background_images.length ())) {+		if (!(0 <= active_box - 1 < background_images.size)) { 			return; 		} 		-		file = background_images.nth (active_box - 1).data;+		file = background_images.get (active_box - 1); 		bg = new GlyphBackgroundImage (file); 		tb = MainWindow.get_tab_bar (); 		@@ -223,7 +223,7 @@ class BackgroundSelection : FontDisplay { 			} 		} 		-		background_images.prepend (file);+		background_images.insert (0, file); 	}  	public override void selected_canvas () {@@ -251,9 +251,7 @@ class BackgroundSelection : FontDisplay { 		FileInfo fi; 		File img_file; -		while (background_images.length () > 0) {-			background_images.delete_link (background_images.first ());-		}+		background_images.clear (); 		 		foreach (string file in font.background_images) { 			add_unique_background (file);diff --git a/libbirdfont/BirdFont.vala b/libbirdfont/BirdFont.valaindex 86a8668..9b7746a 100644--- a/libbirdfont/BirdFont.vala+++ b/libbirdfont/BirdFont.vala@@ -34,6 +34,7 @@ public static int run_export (string[] arg) { 	bool write_ttf = false; 	bool write_svg = false;	 	File directory;+	Font font; 	 	stdout.printf ("birdfont-export version %s\n", VERSION); 	stdout.printf ("built on %s\n", BUILD_TIMESTAMP);@@ -104,7 +105,9 @@ public static int run_export (string[] arg) { 	BirdFont.current_font = new Font (); 	BirdFont.current_glyph = new Glyph (""); 	-	if (!BirdFont.get_current_font ().load (file_name, false)) {+	font = BirdFont.get_current_font ();+	font.set_file (file_name);+	if (!font.load ()) { 		warning (@"Failed to load font $file_name.\n"); 		 		if (!file_name.has_suffix (".bf")) {diff --git a/libbirdfont/BirdFontFile.vala b/libbirdfont/BirdFontFile.valaindex d973d92..c85dd5a 100644--- a/libbirdfont/BirdFontFile.vala+++ b/libbirdfont/BirdFontFile.vala@@ -36,9 +36,7 @@ class BirdFontFile : GLib.Object { 		 		Parser.init (); 		-		while (font.background_images.length () > 0) {-			font.background_images.remove_link (font.background_images.first ());-		}+		font.background_images.clear (); 		 		font.font_file = path; 		tr = new TextReader.filename (path);@@ -98,8 +96,6 @@ class BirdFontFile : GLib.Object { 	}  	public bool write_font_file (string path, bool backup = false) {-		TabBar.start_wheel ();- 		try { 			DataOutputStream os; 			File file;@@ -137,7 +133,7 @@ class BirdFontFile : GLib.Object { 			os.put_string ("\n"); 			 			// FIXME: add this to a font specific settings file-			if (font.background_images.length () > 0) {+			if (font.background_images.size > 0) { 				os.put_string (@"<images>\n"); 				 				foreach (string f in font.background_images) {@@ -202,8 +198,7 @@ class BirdFontFile : GLib.Object { 			warning (@"$(e.message) \n"); 			return false; 		}-		-		TabBar.stop_wheel ();		+	 		return true; 	} 	@@ -240,8 +235,6 @@ class BirdFontFile : GLib.Object { 				os.put_string ("hadjustment=\""); 				os.put_string (round (KerningClasses.get_instance ().classes_kerning.get (i).val)); 				os.put_string ("\" />\n");--				Tool.yield (); 			} 			 			KerningClasses.get_instance ().get_single_position_pairs ((l, r, k) => {@@ -664,7 +657,6 @@ class BirdFontFile : GLib.Object { 			} 						 			TooltipArea.show_text (t_("Loading XML data."));-			Tool.yield (); 		}  		TooltipArea.show_text ("");@@ -727,9 +719,7 @@ class BirdFontFile : GLib.Object {  				if (attr_name == "hadjustment") { 					hadjustment = double.parse (attr_content);-				}-				-				Tool.yield ();+				}				 			} 			 			if (range_left.get_length () > 1) {@@ -887,7 +877,7 @@ class BirdFontFile : GLib.Object { 					attr_content = prop->children->content; 					 					if (attr_name == "src") {-						font.background_images.append (attr_content);+						font.background_images.add (attr_content); 					} 				} 			}@@ -900,7 +890,7 @@ class BirdFontFile : GLib.Object { 			string attr_content = prop->children->content; 			 			if (attr_name == "width") {-				font.grid_width.append (attr_content);+				font.grid_width.add (attr_content); 			} 		}		 	}diff --git a/libbirdfont/BirdFontPart.vala b/libbirdfont/BirdFontPart.valaindex 3dc7889..daba4a5 100644--- a/libbirdfont/BirdFontPart.vala+++ b/libbirdfont/BirdFontPart.vala@@ -43,10 +43,8 @@ class BirdFontPart : GLib.Object{ 			find_all_parts (bfp_file); 			font.set_bfp (true); 			-			while (font.background_images.length () > 0) {-				font.background_images.remove_link (font.background_images.first ());-			}-			+			font.background_images.clear ();+ 			bfp_dir = File.new_for_path (root_directory); 			image_dir = bfp_dir.get_child ("images"); 			copy_backgrounds ((!) image_dir.get_path ());diff --git a/libbirdfont/CharDatabase.vala b/libbirdfont/CharDatabase.valaindex a1c29f3..bf18d12 100644--- a/libbirdfont/CharDatabase.vala+++ b/libbirdfont/CharDatabase.vala@@ -131,7 +131,7 @@ public class CharDatabase { 	} 	 	public static void show_loading_message () {-		MainWindow.set_status (t_("Loading the unicode character database") + " ...");+		TooltipArea.show_text (t_("Loading the unicode character database") + " ..."); 	} 	 	public static void get_full_unicode (GlyphRange glyph_range) {diff --git a/libbirdfont/DrawingTools.vala b/libbirdfont/DrawingTools.valaindex 2783a2c..1b08a8c 100644--- a/libbirdfont/DrawingTools.vala+++ b/libbirdfont/DrawingTools.vala@@ -554,8 +554,6 @@ public class DrawingTools : ToolCollection  { 			Glyph? g = null; 			FontDisplay fd = MainWindow.get_current_display (); 			TooltipArea.show_text (t_("Creating thumbnails"));-			-			Tool.yield (); 		 			if (fd is Glyph) { 				g = (Glyph) fd;diff --git a/libbirdfont/ExportCallback.vala b/libbirdfont/ExportCallback.valanew file mode 100644index 0000000..82b4633--- /dev/null+++ b/libbirdfont/ExportCallback.vala@@ -0,0 +1,45 @@+/*+    Copyright (C) 2014 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.+*/++namespace BirdFont {++public class ExportCallback : GLib.Object {+	+	public signal void file_exported ();+	+	public ExportCallback () {+	}++	public void export_fonts_in_background () {+		Font font = BirdFont.get_current_font ();		+		if (font.font_file == null) {+			MenuTab.save_callback = new SaveCallback ();+			MenuTab.save_callback.file_saved.connect (() => {+				MainWindow.native_window.export ();+			});+			MenuTab.save_callback.save ();+		} else {+			MainWindow.native_window.export ();+		}+	}+	+	/** Export TTF, EOT and SVG fonts. */+	public static void export_fonts () {+		ExportTool.export_ttf_font_sync ();+		ExportTool.export_svg_font ();+		TooltipArea.show_text (t_("Three font files have been created."));	+	}+}++}diff --git a/libbirdfont/ExportTool.vala b/libbirdfont/ExportTool.valaindex 548e2a9..f372117 100644--- a/libbirdfont/ExportTool.vala+++ b/libbirdfont/ExportTool.vala@@ -154,7 +154,9 @@ public class ExportTool : GLib.Object { 		} 	} -	/** Font must be saves before export. */+	/* Font must be saved before export in order to know where the+	 * generated files should be stored.+	 */ 	internal static void export_all () { 		Font font = BirdFont.get_current_font (); 		@@ -519,7 +521,7 @@ os.put_string ( 		string[] spawn_args = get_birdfont_export (folder, temp_file); 		string c = ""; -		MainWindow.set_status (t_("Writing TTF and EOT files."));+		TooltipArea.show_text (t_("Writing TTF and EOT files."));  		foreach (string s in spawn_args) { 			c += s + " ";@@ -533,7 +535,7 @@ os.put_string ( 	 	public static bool export_svg_font () { 		Font font = BirdFont.get_current_font ();-		MainWindow.set_status (t_("Writing SVG file."));+		TooltipArea.show_text (t_("Writing SVG file.")); 		return export_svg_font_path (font.get_folder ()); 	} 		@@ -601,7 +603,8 @@ os.put_string ( 				if (async) { 					printd ("Loading the intermediate file.\n"); 					f = new Font ();-					if (!f.load (ffi, false)) {+					f.set_file (ffi);+					if (!f.load ()) { 						warning (@"Can't read $ffi"); 					} 				} else {diff --git a/libbirdfont/FileTab.vala b/libbirdfont/FileTab.valaindex 482d1aa..267f017 100644--- a/libbirdfont/FileTab.vala+++ b/libbirdfont/FileTab.vala@@ -55,7 +55,8 @@ public class FileTab : FontDisplay { 			MainWindow.clear_glyph_cache (); 			MainWindow.close_all_tabs (); 			-			loaded = f.load (fn);+			f.set_file (fn);+			loaded = f.load (); // FIXME: background thread 			 			if (!unlikely (loaded)) { 				warning (@"Failed to load font $fn");diff --git a/libbirdfont/Font.vala b/libbirdfont/Font.valaindex 51b759f..9ec1de5 100644--- a/libbirdfont/Font.vala+++ b/libbirdfont/Font.vala@@ -35,7 +35,7 @@ public class Font : GLib.Object { 	/** Table with ligatures. */ 	public GlyphTable ligature; 	-	public List <string> background_images = new List <string> ();+	public Gee.ArrayList<string> background_images = new Gee.ArrayList<string> (); 	public string background_scale = "1"; 		 	/** Top margin */@@ -79,7 +79,7 @@ public class Font : GLib.Object { 	OpenFontFormatReader otf; 	bool otf_font = false; 	-	public List<string> grid_width;+	public Gee.ArrayList<string> grid_width; 	 	/** File format. */ 	public FontFormat format = FontFormat.BIRDFONT;@@ -106,7 +106,7 @@ public class Font : GLib.Object { 		glyph_name = new GlyphTable (); 		ligature = new GlyphTable (); 	-		grid_width = new List<string> ();+		grid_width = new Gee.ArrayList<string> (); 	 		kerning_classes = new KerningClasses (); 		@@ -464,7 +464,7 @@ public class Font : GLib.Object { 	} 	 	public void add_background_image (string file) {-		background_images.append (file);+		background_images.add (file); 	} 	 	/** Delete temporary rescue files. */@@ -529,38 +529,51 @@ public class Font : GLib.Object { 		return bfp; 	} 	+	public void save () {+		if (is_bfp ()) {+			save_bfp ();+		} else {+			save_bf ();+		}+	}+	 	public bool save_bfp () { 		return bfp_file.save (); 	} 	-	public bool save (string path) {+	public void save_bf () { 		Font font; 		BirdFontFile birdfont_file = new BirdFontFile (this);-		bool file_written = birdfont_file.write_font_file (path);+		string path;+		bool file_written;+		+		if (font_file == null) {+			warning ("File name not set.");+			return;+		}+		+		path = (!) font_file;+		file_written = birdfont_file.write_font_file (path);  		if (read_only) { 			warning (@"$path is write protected.");-			return false;			+			TooltipArea.show_text (t_("The file is write protected."));+			return;			 		} 				 		if (!path.has_suffix (".bf")) { 			warning ("Expecting .bf format.");-			return false;+			return; 		} 		 		if (file_written) {-			font_file = path;-			-			// delete backup when font is saved+			// delete the backup when the font is saved 			font = BirdFont.get_current_font (); 			font.delete_backup (); 		} 		 		modified = false;- 		Preferences.add_recent_files (get_path ());-		-		return file_written; 	}  	public void set_font_file (string path) {@@ -576,14 +589,25 @@ public class Font : GLib.Object { 		return (glyph_name.length () == 0); 	} -	public bool load (string path, bool recent = true) {+	public void set_file (string path, bool recent = true) {+		font_file = path;+	}++	public bool load () {+		string path; 		bool loaded = false;+		 		initialised = true; 		otf_font = false; -		while (grid_width.length () > 0) {-			grid_width.remove_link (grid_width.first ());+		if (font_file == null) {+			warning ("No file name.");+			return false; 		}++		path = (!) font_file;++		grid_width.clear (); 	 		// empty cache and fill it with new glyphs from disk 		glyph_cache.remove_all ();@@ -592,7 +616,6 @@ public class Font : GLib.Object { 		 		if (path.has_suffix (".svg")) { 			Toolbox.select_tool_by_name ("cubic_points");-			font_file = path; 			loaded = parse_svg_file (path); 					 			if (!loaded) {@@ -603,25 +626,21 @@ public class Font : GLib.Object { 		} 		 		if (path.has_suffix (".ffi")) {-			font_file = path; 			loaded = parse_bf_file (path); 			format = FontFormat.FFI; 		}  		if (path.has_suffix (".bf")) {-			font_file = path; 			loaded = parse_bf_file (path); 			format = FontFormat.BIRDFONT; 		}  		if (path.has_suffix (".bfp")) {-			font_file = path; 			loaded = parse_bfp_file (path); 			format = FontFormat.BIRDFONT_PART; 		}		 		 		if (path.has_suffix (".ttf")) {-			font_file = path; 			loaded = parse_freetype_file (path); 			 			if (!loaded) {@@ -639,10 +658,11 @@ public class Font : GLib.Object { 					warning (e.message); 				} 			}+			+			font_file = null; // make sure BirdFont asks where to save the file 		}			  		if (path.has_suffix (".otf")) {-			font_file = path; 			loaded = parse_freetype_file (path); 						 			if (!loaded) {@@ -650,12 +670,12 @@ public class Font : GLib.Object { 			} 			 			format = FontFormat.FREETYPE;+			+			font_file = null; 		}	 -		if (recent) {-			Preferences.add_recent_files (get_path ());-		}-					+		Preferences.add_recent_files (get_path ());+		 		return loaded; 	} 	diff --git a/libbirdfont/FontDisplay.vala b/libbirdfont/FontDisplay.valaindex dd1f743..3ab08e3 100644--- a/libbirdfont/FontDisplay.vala+++ b/libbirdfont/FontDisplay.vala@@ -40,32 +40,6 @@ public abstract class FontDisplay : GLib.Object { 	 	public virtual void scroll_to (double percent) { 	}--	public static string path_to_uri (string path) {-		string uri = path;-		string wp;-		-		// wine uri hack-		if (BirdFont.win32) {-			wp = wine_to_unix_path (uri);-			-			if (find_file (wp, "").query_exists ()) {-				uri = wp;-			}--			if (uri.index_of ("\\") > -1) {-				uri = uri.replace ("\\", "/");-			}-		}--		if (uri.index_of ("/") == 0) {-			uri = @"file://$uri";-		} else {-			uri = @"file:///$uri";-		}-		-		return uri;-	} 	 	public virtual void draw (WidgetAllocation allocation, Context cr) { 	}diff --git a/libbirdfont/GlyphCanvas.vala b/libbirdfont/GlyphCanvas.valaindex 0324d15..83b2eba 100644--- a/libbirdfont/GlyphCanvas.vala+++ b/libbirdfont/GlyphCanvas.vala@@ -18,7 +18,9 @@ namespace BirdFont { 
 public class GlyphCanvas : GLib.Object {
 
-	public FontDisplay current_display;
+	/** Tab content. */
+	internal static FontDisplay current_display;
+	
 	public signal void signal_redraw_area (int x, int y, int w, int h);
 	public static WidgetAllocation allocation;
 	
diff --git a/libbirdfont/KerningList.vala b/libbirdfont/KerningList.valaindex 5fedb22..a303deb 100644--- a/libbirdfont/KerningList.vala+++ b/libbirdfont/KerningList.vala@@ -127,7 +127,6 @@ public class KerningList : FontDisplay { 		int y = 0; 		string l, r; 		string[] p;-		double k; 		 		l = ""; 		r = "";diff --git a/libbirdfont/KeyBindings.vala b/libbirdfont/KeyBindings.valaindex f928c4b..d35a834 100644--- a/libbirdfont/KeyBindings.vala+++ b/libbirdfont/KeyBindings.vala@@ -110,7 +110,9 @@ public class KeyBindings { 	}  	public static void remove_modifier_from_keyval (uint keyval) {-		uint mod = get_mod_from_key (keyval);+		uint mod;+				+		mod = get_mod_from_key (keyval); 		set_modifier (modifier ^ mod);		 	} diff --git a/libbirdfont/LoadCallback.vala b/libbirdfont/LoadCallback.valanew file mode 100644index 0000000..9483ba5--- /dev/null+++ b/libbirdfont/LoadCallback.vala@@ -0,0 +1,84 @@+/*+    Copyright (C) 2014 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.+*/++namespace BirdFont {+	+public class LoadCallback : GLib.Object {++	public signal void file_loaded ();+	+	public LoadCallback () {	+	}++	public void load () {+		SaveDialogListener dialog;+		Font font;+		+		if (MenuTab.suppress_event) {+			warn_if_test ("Event suppressed");+			return;+		}++		dialog = new SaveDialogListener ();+		font = BirdFont.get_current_font ();+				+		MainWindow.close_all_tabs ();+		+		dialog.signal_discard.connect (() => {+			load_new_font ();+		});++		dialog.signal_save.connect (() => {+			MenuTab.save ();+			load_new_font ();+		});+		+		if (!font.is_modified ()) {+			dialog.signal_discard ();+		} else {+			MainWindow.native_window.set_save_dialog (dialog);+		}+	}++	private void load_new_font () {+		string? fn;+		Font f;++		if (MenuTab.suppress_event) {+			warn_if_test ("Event suppressed");+			return;+		}+		+		f = BirdFont.get_current_font ();+		fn = MainWindow.file_chooser_open (t_("Open"));+		+		if (fn != null) {+			f.delete_backup ();+			+			f = BirdFont.new_font ();+			+			MainWindow.clear_glyph_cache ();+			+			f.set_file ((!) fn);+			MainWindow.native_window.load ();+			+			file_loaded.connect (() => {+				KerningTools.update_kerning_classes ();+				MenuTab.select_overview ();+			});+		}+	}+}+	+}diff --git a/libbirdfont/MainWindow.vala b/libbirdfont/MainWindow.valaindex 7b444d8..f90d3de 100644--- a/libbirdfont/MainWindow.vala+++ b/libbirdfont/MainWindow.vala@@ -14,7 +14,7 @@ 
 namespace BirdFont {
 
-public class MainWindow {
+public class MainWindow : GLib.Object {
 	
 	public static Toolbox tools;
 	public static GlyphCanvas glyph_canvas;
@@ -190,13 +190,6 @@ public class MainWindow { 		return t_(s);
 	}
 	
-	public static void set_status (string s) {
-		if (!is_null (tooltip)) {
-			TooltipArea.show_text (s);
-			Tool.yield ();
-		}  
-	}
-	
 	public static KerningDisplay get_kerning_display () {
 		return kerning_display;
 	}
diff --git a/libbirdfont/MenuTab.vala b/libbirdfont/MenuTab.valaindex da0d7e7..79914b8 100644--- a/libbirdfont/MenuTab.vala+++ b/libbirdfont/MenuTab.vala@@ -16,40 +16,52 @@ namespace BirdFont {  public class MenuTab : FontDisplay { 	-	/** Ignore new actions when export is in progress.-	 * -	 * BirdFont runs in a single thread but the glib main loop will still-	 * execute events with the idle priority in order to update the -	 * progress bar while export, save and possibly other actions are -	 * in progress. +	/** Ignore input events when the background thread is running. 	 *  	 * Do always check the return value of set_suppress_event when this 	 * variable is updated. 	 */-	public static bool suppress_event = false;+	public static bool suppress_event;++	/** A notification sent when the file has been saved. */+	public static SaveCallback save_callback;++	/** A notification sent when the file has been loaded. */+	public static LoadCallback load_callback;++	/** A notification sent when the file has been loaded. */+	public static ExportCallback export_callback;  	public MenuTab () {+		save_callback = new SaveCallback ();+		load_callback = new LoadCallback ();+		export_callback = new ExportCallback ();+		+		suppress_event = false; 	}-	-	public static void export_font ()  {-		Font font = BirdFont.get_current_font ();		-		if (font.font_file == null) {-			if (MenuTab.save ()) {-				export_all ();-			}-		} else {-			export_all ();-		}-	}-	-	public static void export_all () {++	public static void start_background_thread () { 		if (!set_suppress_event (true)) { 			warning ("suppressed event"); 			return; 		}-				-		ExportTool.export_all ();-		set_suppress_event (false);	+		+		TabBar.start_wheel ();+	}++	public static void stop_background_thread () {+		IdleSource idle = new IdleSource ();+		idle.set_callback (() => {+			set_suppress_event (false);+			TabBar.stop_wheel ();+			return false;+		});+		idle.attach (null);+	}+	+	public static void export_fonts_in_background () {+		MenuTab.export_callback = new ExportCallback ();+		MenuTab.export_callback.export_fonts_in_background (); 	} 	 	public static bool set_suppress_event (bool e) {@@ -81,92 +93,26 @@ public class MenuTab : FontDisplay { 			Toolbox.select_tool_by_name ("available_characters");	 		} 	}--	public static bool save_as ()  {-		string? fn = null;-		string f;-		string file_name;-		File file;-		bool saved = false;-		Font font = BirdFont.get_current_font ();-		int i;-		-		if (suppress_event) {-			warn_if_test ("Event suppressed");-			return false;-		}-		-		fn = MainWindow.file_chooser_save (t_("Save"));-		-		if (fn != null) {-			f = (!) fn;-			-			if (f.has_suffix (".bf")) {-				f = f.replace (".bf", "");-			}-			-			file_name = @"$(f).bf";-			file = File.new_for_path (file_name);-			i = 2;-			while (file.query_exists ()) {-				file_name = @"$(f)_$i.bf";-				file = File.new_for_path (file_name);-				i++;-			}-			-			font.font_file = file_name;-			save ();-			saved = true;-		}-		-		return saved;+	+	public static void signal_file_exported () {+		export_callback.file_exported ();+	}+	+	public static void signal_file_saved () {+		save_callback.file_saved (); 	} -	public static bool save () {-		Font f;-		string fn;-		bool saved = false;--		if (suppress_event) {-			warn_if_test ("Event suppressed");-			return false;-		}-		-		if (!set_suppress_event (true)) {-			return false;-		}--		f = BirdFont.get_current_font ();--		if (f.is_bfp ()) {-			saved = f.save_bfp ();-			set_suppress_event (false);-		} else {-			f.delete_backup ();-			fn = f.get_path ();-			-			if (f.font_file != null && fn.has_suffix (".bf")) {-				set_font_setting_from_tools (f); -				saved = f.save (fn);-				set_suppress_event (false);-			} else {-				set_suppress_event (false);-				saved = save_as ();-			}-		}-		-		return saved;+	public static void signal_file_loaded () {+		load_callback.file_loaded (); 	}-	+		 	public static void set_font_setting_from_tools (Font f) {	 		f.background_scale = MainWindow.get_drawing_tools ().background_scale.get_display_value (); 		-		while (f.grid_width.length () > 0) {-			f.grid_width.remove_link (f.grid_width.first ());-		}+		f.grid_width.clear (); 		 		foreach (SpinButton s in GridTool.sizes) {-			f.grid_width.append (s.get_display_value ());+			f.grid_width.add (s.get_display_value ()); 		} 	} 	@@ -237,59 +183,6 @@ public class MenuTab : FontDisplay { 		 		return; 	}-	-	public static void load () {-		SaveDialogListener dialog = new SaveDialogListener ();-		Font font = BirdFont.get_current_font ();-		-		if (suppress_event) {-			warn_if_test ("Event suppressed");-			return;-		}-		-		MainWindow.close_all_tabs ();-		-		dialog.signal_discard.connect (() => {-			load_new_font ();-		});--		dialog.signal_save.connect (() => {-			MenuTab.save ();-			load_new_font ();-		});-		-		if (!font.is_modified ()) {-			dialog.signal_discard ();-		} else {-			MainWindow.native_window.set_save_dialog (dialog);-		}-	}--	private static void load_new_font () {-		string? fn;-		Font f;--		if (suppress_event) {-			warn_if_test ("Event suppressed");-			return;-		}-		-		f = BirdFont.get_current_font ();-		fn = MainWindow.file_chooser_open (t_("Open"));-		-		if (fn != null) {-			f.delete_backup ();-			-			f = BirdFont.new_font ();-			-			MainWindow.clear_glyph_cache ();-			f.load ((!)fn);-			-			KerningTools.update_kerning_classes ();-			-			select_overview ();		-		}-	}  	public static void quit () { 		SaveDialogListener dialog = new SaveDialogListener ();@@ -353,9 +246,11 @@ public class MenuTab : FontDisplay { 		} 		 		if (font.font_file == null) {-			if (MenuTab.save ()) {+			save_callback = new SaveCallback ();+			save_callback.file_saved.connect (() => { 				show_preview_tab ();-			}+			});+			save_callback.save (); 		} else { 			show_preview_tab (); 		}@@ -446,5 +341,22 @@ public class MenuTab : FontDisplay { 		} 		context.release (); 	}+	+	public static void save_as ()  {+		MenuTab.save_callback = new SaveCallback ();+		MenuTab.save_callback.save_as();+	}++	public static void save ()  {+		MenuTab.save_callback = new SaveCallback ();+		MenuTab.save_callback.save ();+	}+	+	public static void load () {+		load_callback = new LoadCallback ();+		load_callback.load ();+	}+	 }+ }diff --git a/libbirdfont/NativeWindow.vala b/libbirdfont/NativeWindow.valaindex 2922873..7fc1974 100644--- a/libbirdfont/NativeWindow.vala+++ b/libbirdfont/NativeWindow.vala@@ -57,6 +57,16 @@ public interface NativeWindow : GLib.Object { 	 	/** Hide help text. */ 	public abstract void hide_tooltip ();+	+	/** Export fonts in a background thread. */+	public abstract void export ();++	/** Load font in a background thread. */+	public abstract void load ();+	+	/** Save font in a background thread. */+	public abstract void save ();+	 }  }diff --git a/libbirdfont/OpenFontFormat/CodePageBits.vala b/libbirdfont/OpenFontFormat/CodePageBits.valaindex 249696d..c012534 100644--- a/libbirdfont/OpenFontFormat/CodePageBits.vala+++ b/libbirdfont/OpenFontFormat/CodePageBits.vala@@ -42,8 +42,6 @@ public class CodePageBits : GLib.Object { 			} else { 				set_bits_for_glyph (g, ref p0, ref p1); 			}-			-			Tool.yield (); 		} 	} diff --git a/libbirdfont/OpenFontFormat/DirectoryTable.vala b/libbirdfont/OpenFontFormat/DirectoryTable.valaindex 1bdc73c..546d991 100644--- a/libbirdfont/OpenFontFormat/DirectoryTable.vala+++ b/libbirdfont/OpenFontFormat/DirectoryTable.vala@@ -66,7 +66,7 @@ public class DirectoryTable : Table { 		glyf_table.process (); 		gasp_table.process (); 		gdef_table.process ();-		gsub_table.process ();+		// FIXME: implement gsub_table.process (); 		cmap_table.process (glyf_table); 		cvt_table.process (); 		hmtx_table.process ();diff --git a/libbirdfont/OpenFontFormat/FontData.vala b/libbirdfont/OpenFontFormat/FontData.valaindex 9358634..98aae72 100644--- a/libbirdfont/OpenFontFormat/FontData.vala+++ b/libbirdfont/OpenFontFormat/FontData.vala@@ -55,7 +55,6 @@ public class FontData : Object { 	 	public void write_table (OtfInputStream dis, uint32 offset, uint32 length) throws Error { 		uint32 l = length + (length % 4);  // padding after end of table-		uint32 added_bytes = 0; 		uint8 b; 		 		if (length >= l) {@@ -74,11 +73,6 @@ public class FontData : Object { 		while (wp < l) { 			b = dis.read_byte (); 			add (b);-			added_bytes++;-			-			if (added_bytes % 1024 == 0) {-				Tool.yield ();-			} 		} 		 		rp = 0;diff --git a/libbirdfont/OpenFontFormat/OpenFontFormatReader.vala b/libbirdfont/OpenFontFormat/OpenFontFormatReader.valaindex 035575f..ca3b854 100644--- a/libbirdfont/OpenFontFormat/OpenFontFormatReader.vala+++ b/libbirdfont/OpenFontFormat/OpenFontFormatReader.vala@@ -189,8 +189,6 @@ public class OpenFontFormatReader : Object { 					bf_kerning.append (@"$kerning".replace (",", ".")); 					bf_kerning.append ("\" />\n"); 				}-			-				Tool.yield (); 			} 		} catch (GLib.Error e) { 			warning (@"Failed to parse font. $(e.message)");diff --git a/libbirdfont/OpenFontFormat/OpenFontFormatWriter.vala b/libbirdfont/OpenFontFormat/OpenFontFormatWriter.valaindex 611511a..a9d0624 100644--- a/libbirdfont/OpenFontFormat/OpenFontFormatWriter.vala+++ b/libbirdfont/OpenFontFormat/OpenFontFormatWriter.vala@@ -46,8 +46,6 @@ public class OpenFontFormatWriter : Object  { 		unowned List<Table> tables; 		FontData fd; 		uint l;--		TabBar.start_wheel (); 		 		font = nfont; 				@@ -70,8 +68,6 @@ public class OpenFontFormatWriter : Object  { 				os.put_byte (data[j]); 			} 		}-		-		TabBar.stop_wheel (); 	} 	 	public void close () throws Error {diff --git a/libbirdfont/Preview.vala b/libbirdfont/Preview.valaindex 16ff511..cb4098a 100644--- a/libbirdfont/Preview.vala+++ b/libbirdfont/Preview.vala@@ -85,7 +85,7 @@ public class Preview : FontDisplay { 	}  	public static string get_uri () {-		return path_to_uri ((!) get_html_file ().get_path ());+		return TabContent.path_to_uri ((!) get_html_file ().get_path ()); 	} 	 	public static string get_windows_uri () {@@ -149,9 +149,9 @@ public class Preview : FontDisplay { 				warning ("Failed to copy svg file."); 			} 			while ((line = dis.read_line (null)) != null) {-				line = ((!) line).replace (@"$(font.get_full_name ()).ttf", @"$(FontDisplay.path_to_uri ((!) f_ttf.get_path ()))?$rid");-				line = ((!) line).replace (@"$(font.get_full_name ()).eot", @"$(FontDisplay.path_to_uri ((!) f_eot.get_path ()))?$rid");-				line = ((!) line).replace (@"$(font.get_full_name ()).svg", @"$(FontDisplay.path_to_uri ((!) f_svg.get_path ()))?$rid");+				line = ((!) line).replace (@"$(font.get_full_name ()).ttf", @"$(TabContent.path_to_uri ((!) f_ttf.get_path ()))?$rid");+				line = ((!) line).replace (@"$(font.get_full_name ()).eot", @"$(TabContent.path_to_uri ((!) f_eot.get_path ()))?$rid");+				line = ((!) line).replace (@"$(font.get_full_name ()).svg", @"$(TabContent.path_to_uri ((!) f_svg.get_path ()))?$rid"); 				sb.append ((!) line); 			} 		} catch (Error e) {diff --git a/libbirdfont/PreviewTools.vala b/libbirdfont/PreviewTools.valaindex 7592abb..4ee4f1e 100644--- a/libbirdfont/PreviewTools.vala+++ b/libbirdfont/PreviewTools.vala@@ -18,8 +18,6 @@ public class PreviewTools : ToolCollection  { 	public List<Expander> expanders; 	public Expander classes; 	-	private static bool suppress_event = false;-	 	public PreviewTools () { 		Expander webview_tools = new Expander (); 		@@ -31,7 +29,7 @@ public class PreviewTools : ToolCollection  { 		 		Tool export_fonts_button = new Tool ("export_fonts", t_("Export fonts")); 		export_fonts_button.select_action.connect ((self) => {-			export_fonts ();+			MenuTab.export_fonts_in_background (); 		}); 		webview_tools.add_tool (export_fonts_button); @@ -46,29 +44,26 @@ public class PreviewTools : ToolCollection  { 		expanders.append (webview_tools); 	} -	 	/** Export fonts and update html canvas. */ 	public static void update_preview () {-		export_fonts ();--		if (!Preview.has_html_document ()) {-			Preview.generate_html_document ();-		}-		-		MainWindow.tabs.select_tab_name ("Preview");+		MenuTab.export_callback = new ExportCallback ();+		MenuTab.export_callback.file_exported.connect (signal_preview_updated);+		MenuTab.export_callback.export_fonts_in_background (); 	}++	private static void signal_preview_updated () {+		IdleSource idle = new IdleSource ();++		idle.set_callback (() => {+			if (!Preview.has_html_document ()) {+				Preview.generate_html_document ();+			}+			+			MainWindow.tabs.select_tab_name ("Preview");+			return false;+		}); 		-	/** Export TTF, EOT and SVG fonts. */-	public static void export_fonts () {-		if (!suppress_event) {-			suppress_event = true;-			ExportTool.export_ttf_font_sync ();-			ExportTool.export_svg_font ();-			TooltipArea.show_text (t_("Three font files have been created."));	-			suppress_event = false;-		} else {-			warn_if_test ("Export event suppressed");-		}+		idle.attach (null);	 	}  	/** Generate the preview document. */diff --git a/libbirdfont/SaveCallback.vala b/libbirdfont/SaveCallback.valanew file mode 100644index 0000000..573df49--- /dev/null+++ b/libbirdfont/SaveCallback.vala@@ -0,0 +1,92 @@+/*+    Copyright (C) 2014 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.+*/++namespace BirdFont {++public class SaveCallback : GLib.Object {+	+	public signal void file_saved ();+	+	public SaveCallback () {	+	}+	+	public bool save_as ()  {+		string? fn = null;+		string f;+		string file_name;+		File file;+		bool saved = false;+		Font font = BirdFont.get_current_font ();+		int i;+		+		if (MenuTab.suppress_event) {+			warn_if_test ("Event suppressed");+			return false;+		}+		+		fn = MainWindow.file_chooser_save (t_("Save"));+		+		if (fn != null) {+			f = (!) fn;+			+			if (f.has_suffix (".bf")) {+				f = f.replace (".bf", "");+			}+			+			file_name = @"$(f).bf";+			file = File.new_for_path (file_name);+			i = 2;+			while (file.query_exists ()) {+				file_name = @"$(f)_$i.bf";+				file = File.new_for_path (file_name);+				i++;+			}+			+			font.font_file = file_name;+			save ();+			saved = true;+		}+		+		return saved;+	}++	public void save () {+		Font f;+		string fn;+		+		if (MenuTab.suppress_event) {+			warn_if_test ("Event suppressed");+			return;+		}+		+		f = BirdFont.get_current_font ();++		if (f.is_bfp ()) {+			MainWindow.native_window.save ();+		} else {+			f.delete_backup ();+			fn = f.get_path ();+			+			if (f.font_file != null && fn.has_suffix (".bf")) {+				MenuTab.set_font_setting_from_tools (f);+				f.set_font_file (fn);+				MainWindow.native_window.save ();+			} else {+				save_as ();+			}+		}+	}+}+	+}diff --git a/libbirdfont/TabContent.vala b/libbirdfont/TabContent.valanew file mode 100644index 0000000..d86ec2e--- /dev/null+++ b/libbirdfont/TabContent.vala@@ -0,0 +1,152 @@+/*+    Copyright (C) 2014 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;++namespace BirdFont {++/** Interface for events from native window to the current tab. */+public class TabContent : GLib.Object {+	+	public static bool has_scrollbar () {+		if (MenuTab.suppress_event) {+			return false;+		}+		+		return GlyphCanvas.current_display.has_scrollbar ();+	}+	+	public static void scroll_to (double percent) {+		if (MenuTab.suppress_event) {+			return;+		}+		+		GlyphCanvas.current_display.scroll_to (percent);+	}+	+	public static void draw (WidgetAllocation allocation, Context cr) {+		if (MenuTab.suppress_event) {+			cr.save ();+			cr.set_source_rgba (1, 1, 1, 1);+			cr.rectangle (0, 0, allocation.width, allocation.height);+			cr.fill ();+			cr.restore ();+		} else {+			GlyphCanvas.current_display.draw (allocation, cr);+		}+	}+	+	public static void key_press (uint keyval) {+		if (MenuTab.suppress_event) {+			return;+		}++		if (GlyphCanvas.current_display is Glyph) {+			MainWindow.tools.key_press (keyval);+		}+		+		KeyBindings.add_modifier_from_keyval (keyval);+		+		GlyphCanvas.current_display.key_press (keyval);+	}+	+	public static void key_release (uint keyval) {+		if (MenuTab.suppress_event) {+			return;+		}+		+		if (GlyphCanvas.current_display is Glyph) {+			GlyphCanvas.current_display.key_release (keyval);+		}+		+		KeyBindings.remove_modifier_from_keyval (keyval);+	}+	+	public static void motion_notify (double x, double y) {+		if (MenuTab.suppress_event) {+			return;+		}+		+		GlyphCanvas.current_display.motion_notify (x, y);+	}+	+	public static void button_release (int button, double x, double y) {+		if (MenuTab.suppress_event) {+			return;+		}+		+		GlyphCanvas.current_display.button_release (button, x, y);+	}+	+	public static void button_press (uint button, double x, double y) {+		if (MenuTab.suppress_event) {+			return;+		}+		+		GlyphCanvas.current_display.button_press (button, x, y);+	}++	public static void double_click (uint button, double ex, double ey) {+		if (MenuTab.suppress_event) {+			return;+		}+		+		GlyphCanvas.current_display.double_click (button, ex, ey);+	}+	+	public static void scroll_wheel_up (double x, double y) {+		if (MenuTab.suppress_event) {+			return;+		}+		+		GlyphCanvas.current_display.scroll_wheel_up (x, y);+	}+	+	public static void scroll_wheel_down (double x, double y) {+		if (MenuTab.suppress_event) {+			return;+		}+		+		GlyphCanvas.current_display.scroll_wheel_down (x, y);+	}++	public static string path_to_uri (string path) {+		string uri = path;+		string wp;+		+		// wine uri hack+		if (BirdFont.win32) {+			wp = wine_to_unix_path (uri);+			+			if (SearchPaths.find_file (wp, "").query_exists ()) {+				uri = wp;+			}++			if (uri.index_of ("\\") > -1) {+				uri = uri.replace ("\\", "/");+			}+		}++		if (uri.index_of ("/") == 0) {+			uri = @"file://$uri";+		} else {+			uri = @"file:///$uri";+		}+		+		return uri;+	}+}++}+diff --git a/libbirdfont/TestCases.vala b/libbirdfont/TestCases.valaindex 623a75b..831bc02 100644--- a/libbirdfont/TestCases.vala+++ b/libbirdfont/TestCases.vala@@ -104,7 +104,8 @@ class TestCases { 		 		f.set_read_only (true); 		-		if (!f.load (fn)) {+		f.set_file (fn);+		if (!f.load ()) { 			warning (@"Failed to load fond $fn"); 			return; 		}@@ -222,8 +223,7 @@ class TestCases { 		} 		 		Tool.yield ();-		-		font.load ((!) f.get_path ());+		font.load (); 	}  	public static void test_parse_quadratic_paths () {diff --git a/libbirdfont/TooltipArea.vala b/libbirdfont/TooltipArea.valaindex 25db226..12190c1 100644--- a/libbirdfont/TooltipArea.vala+++ b/libbirdfont/TooltipArea.vala@@ -32,12 +32,13 @@ public class TooltipArea : GLib.Object { 	} 	 	public static void show_text (string text) {-		if (is_null (MainWindow.get_tooltip ())) {-			return;-		}-		-		MainWindow.get_tooltip ().tooltip = text;-		MainWindow.get_tooltip ().redraw ();+		IdleSource idle = new IdleSource ();+		idle.set_callback (() => {+			MainWindow.get_tooltip ().tooltip = text;+			MainWindow.get_tooltip ().redraw ();+			return false;+		});+		idle.attach (null); 	} 	 	public void set_text_from_tool () {

Contact

Email: johan.mattsson.m@gmail.com
Mastodon: typo.social/@birdfont
GitHub: johanmattssonm
LinkedIn: johan-mattsson-2ab324112