Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Cris Dywan | ||||
Approved revision: | 6334 | ||||
Merged at revision: | 6384 | ||||
Proposed branch: | lp:~midori/midori/tabby | ||||
Merge into: | lp:midori | ||||
Diff against target: |
794 lines (+452/-219) 9 files modified
data/tabby/Create.sql (+33/-0) extensions/delayed-load.vala (+1/-35) extensions/tabby.vala (+402/-0) katze/midori-paths.vala (+1/-1) midori/midori-extension.c (+5/-1) midori/midori-frontend.c (+2/-1) midori/midori-session.c (+5/-178) midori/midori-session.h (+0/-3) midori/midori.vapi (+3/-0) |
||||
To merge this branch: | bzr merge lp:~midori/midori/tabby | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Paweł Forysiuk | Approve | ||
Cris Dywan | Approve | ||
Review via email: mp+178448@code.launchpad.net |
Commit message
Introduce tabby, the new session manager
Future work items:
https:/
Description of the change
To post a comment you must log in.
Revision history for this message
André Stösel (ivaldi) wrote : | # |
Revision history for this message
Cris Dywan (kalikiana) wrote : | # |
I made some improvements to error handling at startup and fixed it to work out of the build folder with cmake. I also resolved the "error" after first startup due to re-creating the tables.
Personally I learn towards merging now. I would look into re-factoring the database creation/ update/ import in a separate branch - I think we don't want to rush it, and it doesn't block tabby.
But I'd like a decision from Paweł before top-approving this. He expressed a strong wish to have the about: page on startup to restore other sessions asap.
review:
Approve
Revision history for this message
Paweł Forysiuk (tuxator) wrote : | # |
Ok lets get this in, should be no worse in any way than we have now even if some stuff is hidden.
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory 'data/tabby' |
2 | === added file 'data/tabby/Create.sql' |
3 | --- data/tabby/Create.sql 1970-01-01 00:00:00 +0000 |
4 | +++ data/tabby/Create.sql 2013-09-07 14:18:40 +0000 |
5 | @@ -0,0 +1,33 @@ |
6 | +CREATE TABLE IF NOT EXISTS sessions |
7 | +( |
8 | + id INTEGER PRIMARY KEY, |
9 | + parent_id INTEGER DEFAULT 0, |
10 | + crdate INTEGER DEFAULT 0, |
11 | + tstamp INTEGER DEFAULT 0, |
12 | + closed INTEGER DEFAULT 0, |
13 | + title TEXT DEFAULT NULL, |
14 | + FOREIGN KEY(parent_id) REFERENCES sessions(id) |
15 | +); |
16 | + |
17 | +CREATE TABLE IF NOT EXISTS tabs |
18 | +( |
19 | + id INTEGER PRIMARY KEY, |
20 | + session_id INTEGER NOT NULL, |
21 | + uri TEXT DEFAULT NULL, |
22 | + icon TEXT DEFAULT NULL, |
23 | + title TEXT DEFAULT NULL, |
24 | + crdate INTEGER DEFAULT 0, |
25 | + tstamp INTEGER DEFAULT 0, |
26 | + closed INTEGER DEFAULT 0, |
27 | + FOREIGN KEY(session_id) REFERENCES sessions(id) |
28 | +); |
29 | + |
30 | +CREATE TABLE IF NOT EXISTS tab_history |
31 | +( |
32 | + id INTEGER PRIMARY KEY, |
33 | + tab_id INTEGER, |
34 | + url TEXT, |
35 | + icon TEXT, |
36 | + title TEXT, |
37 | + FOREIGN KEY(tab_id) REFERENCES tabs(id) |
38 | +); |
39 | |
40 | === modified file 'extensions/delayed-load.vala' |
41 | --- extensions/delayed-load.vala 2013-04-25 22:09:04 +0000 |
42 | +++ extensions/delayed-load.vala 2013-09-07 14:18:40 +0000 |
43 | @@ -106,7 +106,6 @@ |
44 | |
45 | private class Manager : Midori.Extension { |
46 | private int timeout = 0; |
47 | - private bool initialized = false; |
48 | private HashTable<Midori.Browser, TabShaker> tasks; |
49 | |
50 | public signal void preferences_changed (); |
51 | @@ -141,39 +140,12 @@ |
52 | item.ref(); |
53 | |
54 | int64 delay = item.get_meta_integer ("delay"); |
55 | - if (delay == Midori.Delay.PENDING_UNDELAY && new_view.progress < 1.0 && this.initialized) { |
56 | + if (delay == Midori.Delay.PENDING_UNDELAY && new_view.progress < 1.0) { |
57 | this.schedule_reload (browser, new_view); |
58 | } |
59 | } |
60 | } |
61 | |
62 | - private bool reload_first_tab () { |
63 | - Midori.App app = get_app (); |
64 | - Midori.Browser? browser = app.browser; |
65 | - Midori.View? view = browser.tab as Midori.View; |
66 | - |
67 | - if (view != null) { |
68 | - this.initialized = true; |
69 | - Katze.Item item = view.get_proxy_item (); |
70 | - item.ref(); |
71 | - |
72 | - int64 delay = item.get_meta_integer ("delay"); |
73 | - if (delay != Midori.Delay.DELAYED) { |
74 | - if (view.load_status == Midori.LoadStatus.FINISHED) { |
75 | - if (this.timeout != 0) |
76 | - this.tasks.set (browser, new TabShaker (browser)); |
77 | - |
78 | - if (view.progress < 1.0) |
79 | - this.schedule_reload (browser, view); |
80 | - |
81 | - return false; |
82 | - } |
83 | - } |
84 | - } |
85 | - |
86 | - return true; |
87 | - } |
88 | - |
89 | private void browser_added (Midori.Browser browser) { |
90 | browser.switch_tab.connect_after (this.tab_changed); |
91 | } |
92 | @@ -188,12 +160,6 @@ |
93 | |
94 | this.preferences_changed (); |
95 | |
96 | - Midori.Browser? focused_browser = app.browser; |
97 | - if (focused_browser == null) |
98 | - Midori.Timeout.add (50, this.reload_first_tab); |
99 | - else |
100 | - this.initialized = true; |
101 | - |
102 | foreach (Midori.Browser browser in app.get_browsers ()) { |
103 | browser_added (browser); |
104 | } |
105 | |
106 | === added file 'extensions/tabby.vala' |
107 | --- extensions/tabby.vala 1970-01-01 00:00:00 +0000 |
108 | +++ extensions/tabby.vala 2013-09-07 14:18:40 +0000 |
109 | @@ -0,0 +1,402 @@ |
110 | +/* |
111 | + Copyright (C) 2013 André Stösel <andre@stoesel.de> |
112 | + |
113 | + This library is free software; you can redistribute it and/or |
114 | + modify it under the terms of the GNU Lesser General Public |
115 | + License as published by the Free Software Foundation; either |
116 | + version 2.1 of the License, or (at your option) any later version. |
117 | + |
118 | + See the file COPYING for the full license text. |
119 | +*/ |
120 | + |
121 | +namespace Tabby { |
122 | + /* function called from Manager object */ |
123 | + public interface IStorage : GLib.Object { |
124 | + public abstract Katze.Array get_sessions (); |
125 | + public abstract Base.Session get_new_session (); |
126 | + public abstract void restore_last_sessions (); |
127 | + public abstract void import_session (Katze.Array tabs); |
128 | + } |
129 | + |
130 | + public interface ISession : GLib.Object { |
131 | + public abstract Katze.Array get_tabs (); |
132 | + public abstract void add_item (Katze.Item item); |
133 | + public abstract void attach (Midori.Browser browser); |
134 | + public abstract void restore (Midori.Browser browser); |
135 | + public abstract void close (); |
136 | + } |
137 | + |
138 | + namespace Base { |
139 | + /* each base class should connect to all necessary signals and provide an abstract function to handle them */ |
140 | + |
141 | + public abstract class Storage : GLib.Object, IStorage { |
142 | + public Midori.App app { get; construct; } |
143 | + |
144 | + public abstract Katze.Array get_sessions (); |
145 | + public abstract Base.Session get_new_session (); |
146 | + public void restore_last_sessions () { |
147 | + Katze.Array sessions = this.get_sessions (); |
148 | + if (sessions.is_empty ()) { |
149 | + sessions.add_item (this.get_new_session ()); |
150 | + } |
151 | + |
152 | + GLib.List<unowned Katze.Item> items = sessions.get_items (); |
153 | + foreach (Katze.Item item in items) { |
154 | + Session session = item as Session; |
155 | + Midori.Browser browser = this.app.create_browser (); |
156 | + |
157 | + /* FixMe: tabby-session should be set in .restore and .attch */ |
158 | + browser.set_data<Base.Session> ("tabby-session", session as Base.Session); |
159 | + |
160 | + app.add_browser (browser); |
161 | + browser.show (); |
162 | + |
163 | + session.restore (browser); |
164 | + } |
165 | + } |
166 | + |
167 | + public void import_session (Katze.Array tabs) { |
168 | + Session session = this.get_new_session (); |
169 | + GLib.List<unowned Katze.Item> items = tabs.get_items (); |
170 | + foreach (Katze.Item item in items) { |
171 | + session.add_item (item); |
172 | + } |
173 | + } |
174 | + } |
175 | + |
176 | + public abstract class Session : GLib.Object, ISession { |
177 | + public abstract void add_item (Katze.Item item); |
178 | + public abstract void uri_changed (Midori.View view, string uri); |
179 | + public abstract void tab_added (Midori.Browser browser, Midori.View view); |
180 | + public abstract void tab_removed (Midori.Browser browser, Midori.View view); |
181 | + public abstract void close (); |
182 | + public abstract Katze.Array get_tabs (); |
183 | + |
184 | + public void attach (Midori.Browser browser) { |
185 | + browser.add_tab.connect (this.tab_added); |
186 | + browser.add_tab.connect (this.helper_uri_changed); |
187 | + browser.remove_tab.connect (this.tab_removed); |
188 | + |
189 | + foreach (Midori.View view in browser.get_tabs ()) { |
190 | + this.tab_added (browser, view); |
191 | + this.helper_uri_changed (browser, view); |
192 | + } |
193 | + } |
194 | + |
195 | + public void restore (Midori.Browser browser) { |
196 | + Katze.Array tabs = this.get_tabs (); |
197 | + |
198 | + if(tabs.is_empty ()) { |
199 | + Katze.Item item = new Katze.Item (); |
200 | + item.uri = "about:home"; |
201 | + tabs.add_item (item); |
202 | + } |
203 | + |
204 | + browser.add_tab.connect (this.tab_added); |
205 | + browser.add_tab.connect (this.helper_uri_changed); |
206 | + browser.remove_tab.connect (this.tab_removed); |
207 | + |
208 | + GLib.List<unowned Katze.Item> items = tabs.get_items (); |
209 | + unowned GLib.List<unowned Katze.Item> u_items = items; |
210 | + |
211 | + bool delay = false; |
212 | + |
213 | + GLib.Idle.add (() => { |
214 | + /* Note: we need to use `items` for something to maintain a valid reference */ |
215 | + if (items.length () > 0) { |
216 | + for (int i = 0; i < 3; i++) { |
217 | + if (u_items == null) |
218 | + return false; |
219 | + |
220 | + Katze.Item t_item = u_items.data<Katze.Item>; |
221 | + |
222 | + if (delay) |
223 | + t_item.set_meta_integer ("delay", Midori.Delay.DELAYED); |
224 | + else |
225 | + delay = true; |
226 | + |
227 | + browser.add_item (t_item); |
228 | + |
229 | + u_items = u_items.next; |
230 | + } |
231 | + } |
232 | + return u_items != null; |
233 | + }); |
234 | + } |
235 | + |
236 | + private void helper_uri_changed (Midori.Browser browser, Midori.View view) { |
237 | + /* FixMe: skip first event while restoring the session */ |
238 | + view.web_view.notify["uri"].connect ( () => { |
239 | + this.uri_changed (view, view.web_view.uri); |
240 | + }); |
241 | + } |
242 | + } |
243 | + } |
244 | + |
245 | + namespace Local { |
246 | + private class Session : Base.Session { |
247 | + public static int open_sessions = 0; |
248 | + public int64 id { get; private set; } |
249 | + private unowned Sqlite.Database db; |
250 | + |
251 | + public override void add_item (Katze.Item item) { |
252 | + GLib.DateTime time = new DateTime.now_local (); |
253 | + string sqlcmd = "INSERT INTO `tabs` (`crdate`, `tstamp`, `session_id`, `uri`) VALUES (:tstamp, :tstamp, :session_id, :uri);"; |
254 | + Sqlite.Statement stmt; |
255 | + if (this.db.prepare_v2 (sqlcmd, -1, out stmt, null) != Sqlite.OK) |
256 | + critical (_("Failed to update database: %s"), db.errmsg); |
257 | + stmt.bind_int64 (stmt.bind_parameter_index (":tstamp"), time.to_unix ()); |
258 | + stmt.bind_int64 (stmt.bind_parameter_index (":session_id"), this.id); |
259 | + stmt.bind_text (stmt.bind_parameter_index (":uri"), item.uri); |
260 | + if (stmt.step () != Sqlite.DONE) |
261 | + critical (_("Failed to update database: %s"), db.errmsg); |
262 | + else { |
263 | + int64 tab_id = this.db.last_insert_rowid (); |
264 | + item.set_meta_integer ("tabby-id", tab_id); |
265 | + } |
266 | + } |
267 | + |
268 | + protected override void uri_changed (Midori.View view, string uri) { |
269 | + unowned Katze.Item item = view.get_proxy_item (); |
270 | + int64 tab_id = item.get_meta_integer ("tabby-id"); |
271 | + string sqlcmd = "UPDATE `tabs` SET uri = :uri, title = :title WHERE session_id = :session_id AND id = :tab_id;"; |
272 | + Sqlite.Statement stmt; |
273 | + if (this.db.prepare_v2 (sqlcmd, -1, out stmt, null) != Sqlite.OK) |
274 | + critical (_("Failed to update database: %s"), db.errmsg ()); |
275 | + stmt.bind_text (stmt.bind_parameter_index (":uri"), uri); |
276 | + stmt.bind_text (stmt.bind_parameter_index (":title"), view.get_display_title ()); |
277 | + stmt.bind_int64 (stmt.bind_parameter_index (":session_id"), this.id); |
278 | + stmt.bind_int64 (stmt.bind_parameter_index (":tab_id"), tab_id); |
279 | + if (stmt.step () != Sqlite.DONE) |
280 | + critical (_("Failed to update database: %s"), db.errmsg ()); |
281 | + } |
282 | + |
283 | + protected override void tab_added (Midori.Browser browser, Midori.View view) { |
284 | + unowned Katze.Item item = view.get_proxy_item (); |
285 | + int64 tab_id = item.get_meta_integer ("tabby-id"); |
286 | + if (tab_id < 1) { |
287 | + this.add_item (item); |
288 | + } |
289 | + } |
290 | + |
291 | + protected override void tab_removed (Midori.Browser browser, Midori.View view) { |
292 | + unowned Katze.Item item = view.get_proxy_item (); |
293 | + int64 tab_id = item.get_meta_integer ("tabby-id"); |
294 | + /* FixMe: mark as deleted */ |
295 | + string sqlcmd = "DELETE FROM `tabs` WHERE session_id = :session_id AND id = :tab_id;"; |
296 | + Sqlite.Statement stmt; |
297 | + if (this.db.prepare_v2 (sqlcmd, -1, out stmt, null) != Sqlite.OK) |
298 | + critical (_("Failed to update database: %s"), db.errmsg ()); |
299 | + stmt.bind_int64 (stmt.bind_parameter_index (":session_id"), this.id); |
300 | + stmt.bind_int64 (stmt.bind_parameter_index (":tab_id"), tab_id); |
301 | + if (stmt.step () != Sqlite.DONE) |
302 | + critical (_("Failed to update database: %s"), db.errmsg ()); |
303 | + } |
304 | + |
305 | + public override void close() { |
306 | + if (Session.open_sessions == 1) |
307 | + return; |
308 | + |
309 | + GLib.DateTime time = new DateTime.now_local (); |
310 | + string sqlcmd = "UPDATE `sessions` SET closed = 1, tstamp = :tstamp WHERE id = :session_id;"; |
311 | + Sqlite.Statement stmt; |
312 | + if (this.db.prepare_v2 (sqlcmd, -1, out stmt, null) != Sqlite.OK) |
313 | + critical (_("Failed to update database: %s"), db.errmsg ()); |
314 | + |
315 | + stmt.bind_int64 (stmt.bind_parameter_index (":session_id"), this.id); |
316 | + stmt.bind_int64 (stmt.bind_parameter_index (":tstamp"), time.to_unix ()); |
317 | + if (stmt.step () != Sqlite.DONE) |
318 | + critical (_("Failed to update database: %s"), db.errmsg ()); |
319 | + } |
320 | + |
321 | + public override Katze.Array get_tabs() { |
322 | + Katze.Array tabs = new Katze.Array (typeof (Katze.Item)); |
323 | + |
324 | + string sqlcmd = "SELECT id, uri, title FROM tabs WHERE session_id = :session_id"; |
325 | + Sqlite.Statement stmt; |
326 | + if (this.db.prepare_v2 (sqlcmd, -1, out stmt, null) != Sqlite.OK) |
327 | + critical (_("Failed to select from database: %s"), db.errmsg ()); |
328 | + stmt.bind_int64 (stmt.bind_parameter_index (":session_id"), this.id); |
329 | + int result = stmt.step (); |
330 | + if (!(result == Sqlite.DONE || result == Sqlite.ROW)) { |
331 | + critical (_("Failed to select from database: %s"), db.errmsg ()); |
332 | + return tabs; |
333 | + } |
334 | + |
335 | + while (result == Sqlite.ROW) { |
336 | + Katze.Item item = new Katze.Item (); |
337 | + int64 id = stmt.column_int64 (0); |
338 | + string uri = stmt.column_text (1); |
339 | + string title = stmt.column_text (2); |
340 | + item.uri = uri; |
341 | + item.name = title; |
342 | + item.set_meta_integer ("tabby-id", id); |
343 | + tabs.add_item (item); |
344 | + result = stmt.step (); |
345 | + } |
346 | + |
347 | + return tabs; |
348 | + } |
349 | + |
350 | + internal Session (Sqlite.Database db) { |
351 | + this.db = db; |
352 | + |
353 | + GLib.DateTime time = new DateTime.now_local (); |
354 | + |
355 | + string sqlcmd = "INSERT INTO `sessions` (`tstamp`) VALUES (:tstamp);"; |
356 | + Sqlite.Statement stmt; |
357 | + if (this.db.prepare_v2 (sqlcmd, -1, out stmt, null) != Sqlite.OK) |
358 | + critical (_("Failed to update database: %s"), db.errmsg); |
359 | + stmt.bind_int64 (stmt.bind_parameter_index (":tstamp"), time.to_unix ()); |
360 | + if (stmt.step () != Sqlite.DONE) |
361 | + critical (_("Failed to update database: %s"), db.errmsg); |
362 | + else |
363 | + this.id = this.db.last_insert_rowid (); |
364 | + } |
365 | + |
366 | + internal Session.with_id (Sqlite.Database db, int64 id) { |
367 | + this.db = db; |
368 | + this.id = id; |
369 | + |
370 | + GLib.DateTime time = new DateTime.now_local (); |
371 | + string sqlcmd = "UPDATE `sessions` SET closed = 0, tstamp = :tstamp WHERE id = :session_id;"; |
372 | + Sqlite.Statement stmt; |
373 | + if (this.db.prepare_v2 (sqlcmd, -1, out stmt, null) != Sqlite.OK) |
374 | + critical (_("Failed to update database: %s"), db.errmsg); |
375 | + |
376 | + stmt.bind_int64 (stmt.bind_parameter_index (":session_id"), this.id); |
377 | + stmt.bind_int64 (stmt.bind_parameter_index (":tstamp"), time.to_unix ()); |
378 | + if (stmt.step () != Sqlite.DONE) |
379 | + critical (_("Failed to update database: %s"), db.errmsg); |
380 | + } |
381 | + |
382 | + construct { |
383 | + Session.open_sessions++; |
384 | + } |
385 | + |
386 | + ~Session () { |
387 | + Session.open_sessions--; |
388 | + } |
389 | + |
390 | + } |
391 | + |
392 | + private class Storage : Base.Storage { |
393 | + protected Sqlite.Database db; |
394 | + |
395 | + public override Katze.Array get_sessions () { |
396 | + Katze.Array sessions = new Katze.Array (typeof (Session)); |
397 | + |
398 | + string sqlcmd = "SELECT id FROM sessions WHERE closed = 0;"; |
399 | + Sqlite.Statement stmt; |
400 | + if (this.db.prepare_v2 (sqlcmd, -1, out stmt, null) != Sqlite.OK) |
401 | + critical (_("Failed to select from database: %s"), db.errmsg); |
402 | + int result = stmt.step (); |
403 | + if (!(result == Sqlite.DONE || result == Sqlite.ROW)) { |
404 | + critical (_("Failed to select from database: %s"), db.errmsg); |
405 | + return sessions; |
406 | + } |
407 | + |
408 | + while (result == Sqlite.ROW) { |
409 | + int64 id = stmt.column_int64 (0); |
410 | + sessions.add_item (new Session.with_id (this.db, id)); |
411 | + result = stmt.step (); |
412 | + } |
413 | + |
414 | + if (sessions.is_empty ()) { |
415 | + sessions.add_item (new Session (this.db)); |
416 | + } |
417 | + |
418 | + return sessions; |
419 | + } |
420 | + |
421 | + public override Base.Session get_new_session () { |
422 | + return new Session (this.db) as Base.Session; |
423 | + } |
424 | + |
425 | + internal Storage (Midori.App app) { |
426 | + GLib.Object (app: app); |
427 | + |
428 | + string db_path = Midori.Paths.get_config_filename_for_writing ("tabby.db"); |
429 | + |
430 | + /* FixMe: why does GLib.FileUtils.test(db_path, GLib.FileTest.EXISTS); randomly work or not? */ |
431 | + |
432 | + if (Sqlite.Database.open_v2 (db_path, out this.db) != Sqlite.OK) |
433 | + critical (_("Failed to open stored session: %s"), db.errmsg); |
434 | + |
435 | + string filename = Midori.Paths.get_res_filename ("tabby/Create.sql"); |
436 | + string schema; |
437 | + try { |
438 | + bool success = FileUtils.get_contents (filename, out schema, null); |
439 | + if (!success || schema == null) |
440 | + critical (_("Failed to open database schema file: %s"), filename); |
441 | + if (success && schema != null) |
442 | + if (this.db.exec (schema) != Sqlite.OK) |
443 | + critical (_("Failed to execute database schema: %s"), filename); |
444 | + else { |
445 | + string config_file = Midori.Paths.get_config_filename_for_reading ("session.xbel"); |
446 | + try { |
447 | + Katze.Array old_session = new Katze.Array (typeof (Katze.Item)); |
448 | + Midori.array_from_file (old_session, config_file, "xbel-tiny"); |
449 | + this.import_session (old_session); |
450 | + } catch (GLib.FileError file_error) { |
451 | + /* no old session.xbel -> could be a new profile -> ignore it */ |
452 | + } catch (GLib.Error error) { |
453 | + critical (_("Failed to import legacy session: %s"), error.message); |
454 | + } |
455 | + } |
456 | + } catch (GLib.FileError schema_error) { |
457 | + critical (_("Failed to open database schema file: %s"), schema_error.message); |
458 | + } |
459 | + } |
460 | + } |
461 | + } |
462 | + |
463 | + private class Manager : Midori.Extension { |
464 | + private Base.Storage storage; |
465 | + private bool load_session () { |
466 | + this.storage.restore_last_sessions (); |
467 | + return false; |
468 | + } |
469 | + |
470 | + private void browser_added (Midori.Browser browser) { |
471 | + Base.Session session = browser.get_data<Base.Session> ("tabby-session"); |
472 | + if (session == null) { |
473 | + session = this.storage.get_new_session () as Base.Session; |
474 | + browser.set_data<Base.Session> ("tabby-session", session); |
475 | + session.attach (browser); |
476 | + } |
477 | + } |
478 | + |
479 | + private void browser_removed (Midori.Browser browser) { |
480 | + Base.Session session = browser.get_data<Base.Session> ("tabby-session"); |
481 | + if (session == null) { |
482 | + GLib.warning ("missing session"); |
483 | + } else { |
484 | + session.close (); |
485 | + } |
486 | + } |
487 | + |
488 | + private void activated (Midori.App app) { |
489 | + /* FixMe: provide an option to replace Local.Storage with IStorage based Objects */ |
490 | + this.storage = new Local.Storage (this.get_app ()) as Base.Storage; |
491 | + |
492 | + app.add_browser.connect (browser_added); |
493 | + app.remove_browser.connect (browser_removed); |
494 | + |
495 | + GLib.Idle.add (this.load_session); |
496 | + } |
497 | + |
498 | + internal Manager () { |
499 | + GLib.Object (name: _("Tabby"), |
500 | + description: _("Tab and session management."), |
501 | + version: "0.1", |
502 | + authors: "André Stösel <andre@stoesel.de>"); |
503 | + |
504 | + activate.connect (this.activated); |
505 | + } |
506 | + } |
507 | +} |
508 | + |
509 | +public Midori.Extension extension_init () { |
510 | + return new Tabby.Manager (); |
511 | +} |
512 | |
513 | === modified file 'katze/midori-paths.vala' |
514 | --- katze/midori-paths.vala 2013-08-02 18:35:37 +0000 |
515 | +++ katze/midori-paths.vala 2013-09-07 14:18:40 +0000 |
516 | @@ -354,7 +354,7 @@ |
517 | |
518 | /* Fallback to build folder */ |
519 | path = Path.build_filename ((File.new_for_path (exec_path) |
520 | - .get_parent ().get_parent ().get_path ()), "data", filename); |
521 | + .get_parent ().get_path ()), "data", filename); |
522 | if (Posix.access (path, Posix.F_OK) == 0) |
523 | return path; |
524 | |
525 | |
526 | === modified file 'midori/midori-extension.c' |
527 | --- midori/midori-extension.c 2013-07-07 11:29:11 +0000 |
528 | +++ midori/midori-extension.c 2013-09-07 14:18:40 +0000 |
529 | @@ -561,6 +561,8 @@ |
530 | /* FIXME need proper stock extension mechanism */ |
531 | g_assert (midori_extension_activate_gracefully (app, extension_path, "libtransfers." G_MODULE_SUFFIX, activate)); |
532 | g_assert (midori_extension_activate_gracefully (app, extension_path, "libapps." G_MODULE_SUFFIX, activate)); |
533 | + g_assert (midori_extension_activate_gracefully (app, extension_path, "libdelayed-load." G_MODULE_SUFFIX, activate)); |
534 | + g_assert (midori_extension_activate_gracefully (app, extension_path, "libtabby." G_MODULE_SUFFIX, activate)); |
535 | } |
536 | else |
537 | { |
538 | @@ -673,7 +675,9 @@ |
539 | return; |
540 | /* FIXME need proper stock extension mechanism */ |
541 | if (!strcmp (filename, "libtransfers." G_MODULE_SUFFIX) |
542 | - || !strcmp (filename, "libapps." G_MODULE_SUFFIX)) |
543 | + || !strcmp (filename, "libapps." G_MODULE_SUFFIX) |
544 | + || !strcmp (filename, "libdelayed-load." G_MODULE_SUFFIX) |
545 | + || !strcmp (filename, "libtabby." G_MODULE_SUFFIX)) |
546 | return; |
547 | |
548 | katze_array_add_item (extensions, extension); |
549 | |
550 | === modified file 'midori/midori-frontend.c' |
551 | --- midori/midori-frontend.c 2013-08-29 20:27:55 +0000 |
552 | +++ midori/midori-frontend.c 2013-09-07 14:18:40 +0000 |
553 | @@ -585,9 +585,10 @@ |
554 | g_signal_connect (app, "add-browser", |
555 | G_CALLBACK (midori_app_add_browser_cb), NULL); |
556 | |
557 | + midori_session_persistent_settings (settings, app); |
558 | + |
559 | g_idle_add (midori_load_soup_session_full, settings); |
560 | g_idle_add (midori_load_extensions, app); |
561 | - g_idle_add (midori_load_session, session); |
562 | return app; |
563 | } |
564 | |
565 | |
566 | === modified file 'midori/midori-session.c' |
567 | --- midori/midori-session.c 2013-09-02 20:05:07 +0000 |
568 | +++ midori/midori-session.c 2013-09-07 14:18:40 +0000 |
569 | @@ -395,38 +395,6 @@ |
570 | g_free (config_file); |
571 | } |
572 | |
573 | -void |
574 | -midori_session_persistent_settings (MidoriWebSettings* settings, |
575 | - MidoriApp* app) |
576 | -{ |
577 | - g_signal_connect_after (settings, "notify", G_CALLBACK (settings_notify_cb), app); |
578 | -} |
579 | - |
580 | -static void |
581 | -midori_browser_action_last_session_activate_cb (GtkAction* action, |
582 | - MidoriBrowser* browser) |
583 | -{ |
584 | - KatzeArray* old_session = katze_array_new (KATZE_TYPE_ITEM); |
585 | - gchar* config_file = midori_paths_get_config_filename_for_reading ("session.old.xbel"); |
586 | - GError* error = NULL; |
587 | - if (midori_array_from_file (old_session, config_file, "xbel-tiny", &error)) |
588 | - { |
589 | - KatzeItem* item; |
590 | - KATZE_ARRAY_FOREACH_ITEM (item, old_session) |
591 | - midori_browser_add_item (browser, item); |
592 | - } |
593 | - else |
594 | - { |
595 | - sokoke_message_dialog (GTK_MESSAGE_ERROR, |
596 | - _("The session couldn't be loaded: %s\n"), error->message, FALSE); |
597 | - g_error_free (error); |
598 | - } |
599 | - g_free (config_file); |
600 | - gtk_action_set_sensitive (action, FALSE); |
601 | - g_signal_handlers_disconnect_by_func (action, |
602 | - midori_browser_action_last_session_activate_cb, browser); |
603 | -} |
604 | - |
605 | static void |
606 | midori_session_accel_map_changed_cb (GtkAccelMap* accel_map, |
607 | gchar* accel_path, |
608 | @@ -438,153 +406,12 @@ |
609 | g_free (config_file); |
610 | } |
611 | |
612 | -static guint save_timeout = 0; |
613 | - |
614 | -static gboolean |
615 | -midori_session_save_timeout_cb (KatzeArray* session) |
616 | -{ |
617 | - gchar* config_file = midori_paths_get_config_filename_for_writing ("session.xbel"); |
618 | - GError* error = NULL; |
619 | - if (!midori_array_to_file (session, config_file, "xbel-tiny", &error)) |
620 | - { |
621 | - g_warning (_("The session couldn't be saved. %s"), error->message); |
622 | - g_error_free (error); |
623 | - } |
624 | - g_free (config_file); |
625 | - |
626 | - save_timeout = 0; |
627 | - return FALSE; |
628 | -} |
629 | - |
630 | -static void |
631 | -midori_browser_session_cb (MidoriBrowser* browser, |
632 | - gpointer pspec, |
633 | - KatzeArray* session) |
634 | -{ |
635 | - if (!save_timeout) |
636 | - save_timeout = midori_timeout_add_seconds ( |
637 | - 5, (GSourceFunc)midori_session_save_timeout_cb, session, NULL); |
638 | -} |
639 | - |
640 | -static void |
641 | -midori_app_quit_cb (MidoriBrowser* browser, |
642 | - KatzeArray* session) |
643 | -{ |
644 | - midori_session_save_timeout_cb (session); |
645 | -} |
646 | - |
647 | -static void |
648 | -midori_browser_weak_notify_cb (MidoriBrowser* browser, |
649 | - KatzeArray* session) |
650 | -{ |
651 | - g_object_disconnect (browser, "any-signal", |
652 | - G_CALLBACK (midori_browser_session_cb), session, NULL); |
653 | -} |
654 | - |
655 | -gboolean |
656 | -midori_load_session (gpointer data) |
657 | -{ |
658 | - KatzeArray* saved_session = KATZE_ARRAY (data); |
659 | - MidoriBrowser* browser; |
660 | - MidoriApp* app = katze_item_get_parent (KATZE_ITEM (saved_session)); |
661 | - MidoriWebSettings* settings = katze_object_get_object (app, "settings"); |
662 | - MidoriStartup load_on_startup; |
663 | - gchar* config_file; |
664 | - KatzeArray* session; |
665 | - KatzeItem* item; |
666 | - gint64 current; |
667 | - gchar** open_uris = g_object_get_data (G_OBJECT (app), "open-uris"); |
668 | - gchar** execute_commands = g_object_get_data (G_OBJECT (app), "execute-commands"); |
669 | - gchar* uri; |
670 | - guint i = 0; |
671 | - gboolean startup_timer = midori_debug ("startup"); |
672 | - GTimer* timer = startup_timer ? g_timer_new () : NULL; |
673 | - |
674 | - browser = midori_app_create_browser (app); |
675 | - midori_session_persistent_settings (settings, app); |
676 | - |
677 | - config_file = midori_paths_get_config_filename_for_reading ("session.old.xbel"); |
678 | - if (g_access (config_file, F_OK) == 0) |
679 | - { |
680 | - GtkActionGroup* action_group = midori_browser_get_action_group (browser); |
681 | - GtkAction* action = gtk_action_group_get_action (action_group, "LastSession"); |
682 | - g_signal_connect (action, "activate", |
683 | - G_CALLBACK (midori_browser_action_last_session_activate_cb), browser); |
684 | - gtk_action_set_visible (action, TRUE); |
685 | - } |
686 | - midori_app_add_browser (app, browser); |
687 | - gtk_widget_show (GTK_WIDGET (browser)); |
688 | - |
689 | - katze_assign (config_file, midori_paths_get_config_filename_for_reading ("accels")); |
690 | +void |
691 | +midori_session_persistent_settings (MidoriWebSettings* settings, |
692 | + MidoriApp* app) |
693 | +{ |
694 | + g_signal_connect_after (settings, "notify", G_CALLBACK (settings_notify_cb), app); |
695 | g_signal_connect_after (gtk_accel_map_get (), "changed", |
696 | G_CALLBACK (midori_session_accel_map_changed_cb), NULL); |
697 | |
698 | - load_on_startup = (MidoriStartup)g_object_get_data (G_OBJECT (settings), "load-on-startup"); |
699 | - if (katze_array_is_empty (saved_session)) |
700 | - { |
701 | - item = katze_item_new (); |
702 | - if (open_uris) |
703 | - { |
704 | - uri = sokoke_magic_uri (open_uris[i], TRUE, TRUE); |
705 | - katze_item_set_uri (item, uri); |
706 | - g_free (uri); |
707 | - i++; |
708 | - } else if (load_on_startup == MIDORI_STARTUP_BLANK_PAGE) |
709 | - katze_item_set_uri (item, "about:new"); |
710 | - else |
711 | - katze_item_set_uri (item, "about:home"); |
712 | - katze_array_add_item (saved_session, item); |
713 | - g_object_unref (item); |
714 | - } |
715 | - |
716 | - session = midori_browser_get_proxy_array (browser); |
717 | - KATZE_ARRAY_FOREACH_ITEM (item, saved_session) |
718 | - { |
719 | - katze_item_set_meta_integer (item, "append", 1); |
720 | - katze_item_set_meta_integer (item, "dont-write-history", 1); |
721 | - if (load_on_startup == MIDORI_STARTUP_DELAYED_PAGES |
722 | - || katze_item_get_meta_integer (item, "delay") == MIDORI_DELAY_PENDING_UNDELAY) |
723 | - katze_item_set_meta_integer (item, "delay", MIDORI_DELAY_DELAYED); |
724 | - midori_browser_add_item (browser, item); |
725 | - } |
726 | - |
727 | - current = katze_item_get_meta_integer (KATZE_ITEM (saved_session), "current"); |
728 | - if (!(item = katze_array_get_nth_item (saved_session, current))) |
729 | - { |
730 | - current = 0; |
731 | - item = katze_array_get_nth_item (saved_session, 0); |
732 | - } |
733 | - midori_browser_set_current_page (browser, current); |
734 | - if (midori_uri_is_blank (katze_item_get_uri (item))) |
735 | - midori_browser_activate_action (browser, "Location"); |
736 | - |
737 | - /* `i` also used above; in that case we won't re-add the same URLs here */ |
738 | - for (; open_uris && open_uris[i]; i++) |
739 | - { |
740 | - uri = sokoke_magic_uri (open_uris[i], TRUE, TRUE); |
741 | - midori_browser_add_uri (browser, uri); |
742 | - g_free (uri); |
743 | - } |
744 | - |
745 | - g_object_unref (settings); |
746 | - g_object_unref (saved_session); |
747 | - g_free (config_file); |
748 | - |
749 | - g_signal_connect_after (browser, "add-tab", |
750 | - G_CALLBACK (midori_browser_session_cb), session); |
751 | - g_signal_connect_after (browser, "remove-tab", |
752 | - G_CALLBACK (midori_browser_session_cb), session); |
753 | - g_signal_connect (app, "quit", |
754 | - G_CALLBACK (midori_app_quit_cb), session); |
755 | - g_object_weak_ref (G_OBJECT (session), |
756 | - (GWeakNotify)(midori_browser_weak_notify_cb), browser); |
757 | - |
758 | - if (execute_commands != NULL) |
759 | - midori_app_send_command (app, execute_commands); |
760 | - |
761 | - if (startup_timer) |
762 | - g_debug ("Session setup:\t%f", g_timer_elapsed (timer, NULL)); |
763 | - |
764 | - return FALSE; |
765 | } |
766 | - |
767 | |
768 | === modified file 'midori/midori-session.h' |
769 | --- midori/midori-session.h 2013-05-23 22:15:27 +0000 |
770 | +++ midori/midori-session.h 2013-09-07 14:18:40 +0000 |
771 | @@ -25,9 +25,6 @@ |
772 | gboolean |
773 | midori_load_extensions (gpointer data); |
774 | |
775 | -gboolean |
776 | -midori_load_session (gpointer data); |
777 | - |
778 | void |
779 | midori_session_persistent_settings (MidoriWebSettings* settings, |
780 | MidoriApp* app); |
781 | |
782 | === modified file 'midori/midori.vapi' |
783 | --- midori/midori.vapi 2013-08-20 08:24:46 +0000 |
784 | +++ midori/midori.vapi 2013-09-07 14:18:40 +0000 |
785 | @@ -21,6 +21,9 @@ |
786 | [CCode (array_length = false)] string[]? uris, [CCode (array_length = false)] string[]? commands, int reset, string? block); |
787 | public static void normal_app_on_quit (App app); |
788 | |
789 | + [CCode (cheader_filename = "midori/midori-array.h")] |
790 | + public static bool array_from_file (Katze.Array array, string filename, string format) throws GLib.Error; |
791 | + |
792 | [CCode (cheader_filename = "midori/midori.h")] |
793 | public class App : GLib.Object { |
794 | public App (string? name=null); |
This is an early alpha and there are still some features missing and many bugs included.
Please open new bugs (tag "tabby") instead of adding comments.