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