Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Paweł Forysiuk | ||||
Approved revision: | 6587 | ||||
Merged at revision: | 6569 | ||||
Proposed branch: | lp:~midori/midori/openWith | ||||
Merge into: | lp:midori | ||||
Diff against target: |
1725 lines (+904/-475) 19 files modified
extensions/addons.c (+5/-4) extensions/open-with.vala (+802/-0) extensions/transfers.vala (+2/-7) katze/katze-utils.c (+1/-211) katze/katze.vapi (+7/-0) katze/midori-uri.vala (+17/-0) midori/midori-app.c (+1/-1) midori/midori-browser.c (+5/-44) midori/midori-dialog.vala (+14/-0) midori/midori-download.vala (+7/-4) midori/midori-extension.c (+2/-0) midori/midori-frontend.c (+2/-1) midori/midori-preferences.c (+0/-12) midori/midori-tab.vala (+2/-0) midori/midori-view.c (+13/-31) midori/midori.vapi (+1/-0) midori/sokoke.c (+22/-143) midori/sokoke.h (+0/-17) po/POTFILES.in (+1/-0) |
||||
To merge this branch: | bzr merge lp:~midori/midori/openWith | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Paweł Forysiuk | Approve | ||
Review via email: mp+207737@code.launchpad.net |
Commit message
Implement Open With extension dealing with file types
Description of the change
To post a comment you must log in.
lp:~midori/midori/openWith
updated
- 6583. By Paweł Forysiuk
-
Don't bother fetching hicon if path to executable is null, update code style a bit
- 6584. By Paweł Forysiuk
-
Merge lp:midori
- 6585. By Paweł Forysiuk
-
Add some sanity checks when feching hIcon
- 6586. By Cris Dywan
-
Implement Customize… menu item in Chooser
- 6587. By Cris Dywan
-
Add tooltip about customization to treeview
Revision history for this message
Paweł Forysiuk (tuxator) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'extensions/addons.c' | |||
2 | --- extensions/addons.c 2013-06-21 23:18:01 +0000 | |||
3 | +++ extensions/addons.c 2014-02-25 19:27:20 +0000 | |||
4 | @@ -485,8 +485,8 @@ | |||
5 | 485 | else | 485 | else |
6 | 486 | { | 486 | { |
7 | 487 | gchar* element_uri = g_filename_to_uri (element->fullpath, NULL, NULL); | 487 | gchar* element_uri = g_filename_to_uri (element->fullpath, NULL, NULL); |
10 | 488 | sokoke_show_uri (NULL, element_uri, | 488 | gboolean handled = FALSE; |
11 | 489 | gtk_get_current_event_time (), NULL); | 489 | g_signal_emit_by_name (midori_browser_get_current_tab (browser), "open-uri", element_uri, &handled); |
12 | 490 | g_free (element_uri); | 490 | g_free (element_uri); |
13 | 491 | } | 491 | } |
14 | 492 | 492 | ||
15 | @@ -522,8 +522,9 @@ | |||
16 | 522 | folder_uri = g_filename_to_uri (folder, NULL, NULL); | 522 | folder_uri = g_filename_to_uri (folder, NULL, NULL); |
17 | 523 | g_free (folder); | 523 | g_free (folder); |
18 | 524 | 524 | ||
21 | 525 | sokoke_show_uri (gtk_widget_get_screen (GTK_WIDGET (addons->treeview)), | 525 | MidoriBrowser* browser = midori_browser_get_for_widget (addons->treeview); |
22 | 526 | folder_uri, gtk_get_current_event_time (), NULL); | 526 | gboolean handled = FALSE; |
23 | 527 | g_signal_emit_by_name (midori_browser_get_current_tab (browser), "open-uri", folder_uri, &handled); | ||
24 | 527 | g_free (folder_uri); | 528 | g_free (folder_uri); |
25 | 528 | } | 529 | } |
26 | 529 | 530 | ||
27 | 530 | 531 | ||
28 | === added file 'extensions/open-with.vala' | |||
29 | --- extensions/open-with.vala 1970-01-01 00:00:00 +0000 | |||
30 | +++ extensions/open-with.vala 2014-02-25 19:27:20 +0000 | |||
31 | @@ -0,0 +1,802 @@ | |||
32 | 1 | /* | ||
33 | 2 | Copyright (C) 2014 Christian Dywan <christian@twotoasts.de> | ||
34 | 3 | |||
35 | 4 | This library is free software; you can redistribute it and/or | ||
36 | 5 | modify it under the terms of the GNU Lesser General Public | ||
37 | 6 | License as published by the Free Software Foundation; either | ||
38 | 7 | version 2.1 of the License, or (at your option) any later version. | ||
39 | 8 | |||
40 | 9 | See the file COPYING for the full license text. | ||
41 | 10 | */ | ||
42 | 11 | |||
43 | 12 | #if HAVE_WIN32 | ||
44 | 13 | namespace Sokoke { | ||
45 | 14 | extern static Gdk.Pixbuf get_gdk_pixbuf_from_win32_executable (string path); | ||
46 | 15 | } | ||
47 | 16 | #endif | ||
48 | 17 | |||
49 | 18 | namespace ExternalApplications { | ||
50 | 19 | bool open_app_info (AppInfo app_info, string uri, string content_type) { | ||
51 | 20 | Midori.URI.recursive_fork_protection (uri, true); | ||
52 | 21 | |||
53 | 22 | try { | ||
54 | 23 | var uris = new List<File> (); | ||
55 | 24 | uris.append (File.new_for_uri (uri)); | ||
56 | 25 | app_info.launch (uris, null); | ||
57 | 26 | new Associations ().remember (content_type, app_info); | ||
58 | 27 | return true; | ||
59 | 28 | } catch (Error error) { | ||
60 | 29 | warning ("Failed to open \"%s\": %s", uri, error.message); | ||
61 | 30 | return false; | ||
62 | 31 | } | ||
63 | 32 | } | ||
64 | 33 | |||
65 | 34 | class Associations : Object { | ||
66 | 35 | #if HAVE_WIN32 | ||
67 | 36 | string config_dir; | ||
68 | 37 | string filename; | ||
69 | 38 | KeyFile keyfile; | ||
70 | 39 | |||
71 | 40 | public Associations () { | ||
72 | 41 | config_dir = Midori.Paths.get_extension_config_dir ("open-with"); | ||
73 | 42 | filename = Path.build_filename (config_dir, "config"); | ||
74 | 43 | keyfile = new KeyFile (); | ||
75 | 44 | |||
76 | 45 | try { | ||
77 | 46 | keyfile.load_from_file (filename, KeyFileFlags.NONE); | ||
78 | 47 | } catch (FileError.NOENT exist_error) { | ||
79 | 48 | /* It's no error if no config file exists */ | ||
80 | 49 | } catch (Error error) { | ||
81 | 50 | warning ("Failed to load associations: %s", error.message); | ||
82 | 51 | } | ||
83 | 52 | } | ||
84 | 53 | |||
85 | 54 | public bool open (string content_type, string uri) { | ||
86 | 55 | Midori.URI.recursive_fork_protection (uri, true); | ||
87 | 56 | try { | ||
88 | 57 | string commandline = keyfile.get_string ("mimes", content_type); | ||
89 | 58 | if ("%u" in commandline) | ||
90 | 59 | commandline = commandline.replace ("%u", Shell.quote (uri)); | ||
91 | 60 | else if ("%F" in commandline) | ||
92 | 61 | commandline = commandline.replace ("%F", Shell.quote (Filename.from_uri (uri))); | ||
93 | 62 | return Process.spawn_command_line_async (commandline); | ||
94 | 63 | } catch (KeyFileError error) { | ||
95 | 64 | /* Not remembered before */ | ||
96 | 65 | return false; | ||
97 | 66 | } catch (Error error) { | ||
98 | 67 | warning ("Failed to open \"%s\": %s", uri, error.message); | ||
99 | 68 | return false; | ||
100 | 69 | } | ||
101 | 70 | } | ||
102 | 71 | |||
103 | 72 | public void remember (string content_type, AppInfo app_info) throws Error { | ||
104 | 73 | keyfile.set_string ("mimes", content_type, get_commandline (app_info)); | ||
105 | 74 | FileUtils.set_contents (filename, keyfile.to_data ()); | ||
106 | 75 | } | ||
107 | 76 | |||
108 | 77 | public void custom (string content_type, string commandline, string name, string uri) { | ||
109 | 78 | keyfile.set_string ("mimes", content_type, commandline); | ||
110 | 79 | try { | ||
111 | 80 | FileUtils.set_contents (filename, keyfile.to_data ()); | ||
112 | 81 | } catch (Error error) { | ||
113 | 82 | warning ("Failed to add remember custom command line for \"%s\": %s", uri, error.message); | ||
114 | 83 | } | ||
115 | 84 | open (content_type, uri); | ||
116 | 85 | } | ||
117 | 86 | } | ||
118 | 87 | #else | ||
119 | 88 | public Associations () { | ||
120 | 89 | } | ||
121 | 90 | |||
122 | 91 | public bool open (string content_type, string uri) { | ||
123 | 92 | var app_info = AppInfo.get_default_for_type (content_type, false); | ||
124 | 93 | if (app_info == null) | ||
125 | 94 | return false; | ||
126 | 95 | return open_app_info (app_info, uri, content_type); | ||
127 | 96 | } | ||
128 | 97 | |||
129 | 98 | public void remember (string content_type, AppInfo app_info) throws Error { | ||
130 | 99 | app_info.set_as_last_used_for_type (content_type); | ||
131 | 100 | app_info.set_as_default_for_type (content_type); | ||
132 | 101 | } | ||
133 | 102 | |||
134 | 103 | public void custom (string content_type, string commandline, string name, string uri) { | ||
135 | 104 | try { | ||
136 | 105 | var app_info = AppInfo.create_from_commandline (commandline, name, | ||
137 | 106 | "%u" in commandline ? AppInfoCreateFlags.SUPPORTS_URIS : AppInfoCreateFlags.NONE); | ||
138 | 107 | open_app_info (app_info, uri, content_type); | ||
139 | 108 | } catch (Error error) { | ||
140 | 109 | warning ("Failed to add custom command line for \"%s\": %s", uri, error.message); | ||
141 | 110 | } | ||
142 | 111 | } | ||
143 | 112 | } | ||
144 | 113 | #endif | ||
145 | 114 | |||
146 | 115 | static string get_commandline (AppInfo app_info) { | ||
147 | 116 | return app_info.get_commandline () ?? app_info.get_executable (); | ||
148 | 117 | } | ||
149 | 118 | |||
150 | 119 | static string describe_app_info (AppInfo app_info) { | ||
151 | 120 | string name = app_info.get_display_name () ?? (Path.get_basename (app_info.get_executable ())); | ||
152 | 121 | string desc = app_info.get_description () ?? get_commandline (app_info); | ||
153 | 122 | return Markup.printf_escaped ("<b>%s</b>\n%s", name, desc); | ||
154 | 123 | } | ||
155 | 124 | |||
156 | 125 | static Icon? app_info_get_icon (AppInfo app_info) { | ||
157 | 126 | #if HAVE_WIN32 | ||
158 | 127 | return Sokoke.get_gdk_pixbuf_from_win32_executable (app_info.get_executable ()); | ||
159 | 128 | #else | ||
160 | 129 | return app_info.get_icon (); | ||
161 | 130 | #endif | ||
162 | 131 | } | ||
163 | 132 | |||
164 | 133 | class CustomizerDialog : Gtk.Dialog { | ||
165 | 134 | public Gtk.Entry name_entry; | ||
166 | 135 | public Gtk.Entry commandline_entry; | ||
167 | 136 | |||
168 | 137 | public CustomizerDialog (AppInfo app_info, Gtk.Widget widget) { | ||
169 | 138 | var browser = Midori.Browser.get_for_widget (widget); | ||
170 | 139 | transient_for = browser; | ||
171 | 140 | |||
172 | 141 | title = _("Custom…"); | ||
173 | 142 | #if !HAVE_GTK3 | ||
174 | 143 | has_separator = false; | ||
175 | 144 | #endif | ||
176 | 145 | destroy_with_parent = true; | ||
177 | 146 | set_icon_name (Gtk.STOCK_OPEN); | ||
178 | 147 | resizable = false; | ||
179 | 148 | add_buttons (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, | ||
180 | 149 | Gtk.STOCK_SAVE, Gtk.ResponseType.ACCEPT); | ||
181 | 150 | |||
182 | 151 | var vbox = new Gtk.VBox (false, 8); | ||
183 | 152 | vbox.border_width = 8; | ||
184 | 153 | (get_content_area () as Gtk.Box).pack_start (vbox, true, true, 8); | ||
185 | 154 | |||
186 | 155 | var sizegroup = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL); | ||
187 | 156 | var label = new Gtk.Label (_("Name:")); | ||
188 | 157 | sizegroup.add_widget (label); | ||
189 | 158 | label.set_alignment (0.0f, 0.5f); | ||
190 | 159 | vbox.pack_start (label, false, false, 0); | ||
191 | 160 | name_entry = new Gtk.Entry (); | ||
192 | 161 | name_entry.activates_default = true; | ||
193 | 162 | sizegroup.add_widget (name_entry); | ||
194 | 163 | vbox.pack_start (name_entry, true, true, 0); | ||
195 | 164 | |||
196 | 165 | label = new Gtk.Label (_("Command Line:")); | ||
197 | 166 | sizegroup.add_widget (label); | ||
198 | 167 | label.set_alignment (0.0f, 0.5f); | ||
199 | 168 | vbox.pack_start (label, false, false, 0); | ||
200 | 169 | commandline_entry = new Gtk.Entry (); | ||
201 | 170 | commandline_entry.activates_default = true; | ||
202 | 171 | sizegroup.add_widget (name_entry); | ||
203 | 172 | sizegroup.add_widget (commandline_entry); | ||
204 | 173 | vbox.pack_start (commandline_entry, true, true, 0); | ||
205 | 174 | get_content_area ().show_all (); | ||
206 | 175 | set_default_response (Gtk.ResponseType.ACCEPT); | ||
207 | 176 | |||
208 | 177 | name_entry.text = app_info.get_name (); | ||
209 | 178 | commandline_entry.text = get_commandline (app_info); | ||
210 | 179 | } | ||
211 | 180 | } | ||
212 | 181 | |||
213 | 182 | private class Chooser : Gtk.VBox { | ||
214 | 183 | Gtk.ListStore store = new Gtk.ListStore (1, typeof (AppInfo)); | ||
215 | 184 | Gtk.TreeView treeview; | ||
216 | 185 | List<AppInfo> available; | ||
217 | 186 | string content_type; | ||
218 | 187 | string uri; | ||
219 | 188 | |||
220 | 189 | public Chooser (string uri, string content_type) { | ||
221 | 190 | this.content_type = content_type; | ||
222 | 191 | this.uri = uri; | ||
223 | 192 | |||
224 | 193 | Gtk.TreeViewColumn column; | ||
225 | 194 | |||
226 | 195 | treeview = new Gtk.TreeView.with_model (store); | ||
227 | 196 | treeview.headers_visible = false; | ||
228 | 197 | |||
229 | 198 | store.set_sort_column_id (0, Gtk.SortType.ASCENDING); | ||
230 | 199 | store.set_sort_func (0, tree_sort_func); | ||
231 | 200 | |||
232 | 201 | column = new Gtk.TreeViewColumn (); | ||
233 | 202 | Gtk.CellRendererPixbuf renderer_icon = new Gtk.CellRendererPixbuf (); | ||
234 | 203 | column.pack_start (renderer_icon, false); | ||
235 | 204 | column.set_cell_data_func (renderer_icon, on_render_icon); | ||
236 | 205 | treeview.append_column (column); | ||
237 | 206 | |||
238 | 207 | column = new Gtk.TreeViewColumn (); | ||
239 | 208 | column.set_sizing (Gtk.TreeViewColumnSizing.AUTOSIZE); | ||
240 | 209 | Gtk.CellRendererText renderer_text = new Gtk.CellRendererText (); | ||
241 | 210 | column.pack_start (renderer_text, true); | ||
242 | 211 | column.set_expand (true); | ||
243 | 212 | column.set_cell_data_func (renderer_text, on_render_text); | ||
244 | 213 | treeview.append_column (column); | ||
245 | 214 | |||
246 | 215 | treeview.row_activated.connect (row_activated); | ||
247 | 216 | treeview.show (); | ||
248 | 217 | var scrolled = new Gtk.ScrolledWindow (null, null); | ||
249 | 218 | scrolled.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); | ||
250 | 219 | scrolled.add (treeview); | ||
251 | 220 | pack_start (scrolled); | ||
252 | 221 | int height; | ||
253 | 222 | treeview.create_pango_layout ("a\nb").get_pixel_size (null, out height); | ||
254 | 223 | scrolled.set_size_request (-1, height * 5); | ||
255 | 224 | treeview.button_release_event.connect (button_released); | ||
256 | 225 | treeview.tooltip_text = _("Right-click a suggestion to customize it"); | ||
257 | 226 | |||
258 | 227 | available = new List<AppInfo> (); | ||
259 | 228 | foreach (var app_info in AppInfo.get_all_for_type (content_type)) | ||
260 | 229 | launcher_added (app_info, uri); | ||
261 | 230 | |||
262 | 231 | if (store.iter_n_children (null) < 1) { | ||
263 | 232 | foreach (var app_info in AppInfo.get_all ()) | ||
264 | 233 | launcher_added (app_info, uri); | ||
265 | 234 | } | ||
266 | 235 | } | ||
267 | 236 | |||
268 | 237 | bool button_released (Gdk.EventButton event) { | ||
269 | 238 | if (event.button == 3) | ||
270 | 239 | return show_popup_menu (event); | ||
271 | 240 | return false; | ||
272 | 241 | } | ||
273 | 242 | |||
274 | 243 | bool show_popup_menu (Gdk.EventButton? event) { | ||
275 | 244 | Gtk.TreeIter iter; | ||
276 | 245 | if (treeview.get_selection ().get_selected (null, out iter)) { | ||
277 | 246 | AppInfo app_info; | ||
278 | 247 | store.get (iter, 0, out app_info); | ||
279 | 248 | |||
280 | 249 | var menu = new Gtk.Menu (); | ||
281 | 250 | var menuitem = new Gtk.ImageMenuItem.with_mnemonic (_("Custom…")); | ||
282 | 251 | menuitem.image = new Gtk.Image.from_stock (Gtk.STOCK_EDIT, Gtk.IconSize.MENU); | ||
283 | 252 | menuitem.activate.connect (() => { | ||
284 | 253 | customize_app_info (app_info, content_type, uri); | ||
285 | 254 | }); | ||
286 | 255 | menu.append (menuitem); | ||
287 | 256 | menu.show_all (); | ||
288 | 257 | Katze.widget_popup (treeview, menu, null, Katze.MenuPos.CURSOR); | ||
289 | 258 | |||
290 | 259 | return true; | ||
291 | 260 | } | ||
292 | 261 | return false; | ||
293 | 262 | } | ||
294 | 263 | |||
295 | 264 | void customize_app_info (AppInfo app_info, string content_type, string uri) { | ||
296 | 265 | var dialog = new CustomizerDialog (app_info, this); | ||
297 | 266 | bool accept = dialog.run () == Gtk.ResponseType.ACCEPT; | ||
298 | 267 | if (accept) { | ||
299 | 268 | string name = dialog.name_entry.text; | ||
300 | 269 | string commandline = dialog.commandline_entry.text; | ||
301 | 270 | new Associations ().custom (content_type, commandline, name, uri); | ||
302 | 271 | customized (app_info, content_type, uri); | ||
303 | 272 | } | ||
304 | 273 | dialog.destroy (); | ||
305 | 274 | } | ||
306 | 275 | |||
307 | 276 | public List<AppInfo> get_available () { | ||
308 | 277 | return available.copy (); | ||
309 | 278 | } | ||
310 | 279 | |||
311 | 280 | public AppInfo get_app_info () { | ||
312 | 281 | Gtk.TreeIter iter; | ||
313 | 282 | if (treeview.get_selection ().get_selected (null, out iter)) { | ||
314 | 283 | AppInfo app_info; | ||
315 | 284 | store.get (iter, 0, out app_info); | ||
316 | 285 | return app_info; | ||
317 | 286 | } | ||
318 | 287 | assert_not_reached (); | ||
319 | 288 | } | ||
320 | 289 | |||
321 | 290 | void on_render_icon (Gtk.CellLayout column, Gtk.CellRenderer renderer, | ||
322 | 291 | Gtk.TreeModel model, Gtk.TreeIter iter) { | ||
323 | 292 | |||
324 | 293 | AppInfo app_info; | ||
325 | 294 | model.get (iter, 0, out app_info); | ||
326 | 295 | |||
327 | 296 | renderer.set ("gicon", app_info_get_icon (app_info), | ||
328 | 297 | "stock-size", Gtk.IconSize.DIALOG, | ||
329 | 298 | "xpad", 4); | ||
330 | 299 | } | ||
331 | 300 | |||
332 | 301 | void on_render_text (Gtk.CellLayout column, Gtk.CellRenderer renderer, | ||
333 | 302 | Gtk.TreeModel model, Gtk.TreeIter iter) { | ||
334 | 303 | |||
335 | 304 | AppInfo app_info; | ||
336 | 305 | model.get (iter, 0, out app_info); | ||
337 | 306 | renderer.set ("markup", describe_app_info (app_info), | ||
338 | 307 | "ellipsize", Pango.EllipsizeMode.END); | ||
339 | 308 | } | ||
340 | 309 | |||
341 | 310 | void launcher_added (AppInfo app_info, string uri) { | ||
342 | 311 | if (!app_info.should_show ()) | ||
343 | 312 | return; | ||
344 | 313 | |||
345 | 314 | Gtk.TreeIter iter; | ||
346 | 315 | store.append (out iter); | ||
347 | 316 | store.set (iter, 0, app_info); | ||
348 | 317 | |||
349 | 318 | available.append (app_info); | ||
350 | 319 | } | ||
351 | 320 | |||
352 | 321 | int tree_sort_func (Gtk.TreeModel model, Gtk.TreeIter a, Gtk.TreeIter b) { | ||
353 | 322 | AppInfo app_info1, app_info2; | ||
354 | 323 | model.get (a, 0, out app_info1); | ||
355 | 324 | model.get (b, 0, out app_info2); | ||
356 | 325 | return strcmp (app_info1.get_display_name (), app_info2.get_display_name ()); | ||
357 | 326 | } | ||
358 | 327 | |||
359 | 328 | void row_activated (Gtk.TreePath path, Gtk.TreeViewColumn column) { | ||
360 | 329 | Gtk.TreeIter iter; | ||
361 | 330 | if (store.get_iter (out iter, path)) { | ||
362 | 331 | AppInfo app_info; | ||
363 | 332 | store.get (iter, 0, out app_info); | ||
364 | 333 | selected (app_info); | ||
365 | 334 | } | ||
366 | 335 | } | ||
367 | 336 | |||
368 | 337 | public signal void selected (AppInfo app_info); | ||
369 | 338 | public signal void customized (AppInfo app_info, string content_type, string uri); | ||
370 | 339 | } | ||
371 | 340 | |||
372 | 341 | class ChooserDialog : Gtk.Dialog { | ||
373 | 342 | public Chooser chooser { get; private set; } | ||
374 | 343 | |||
375 | 344 | public ChooserDialog (string uri, string content_type, Gtk.Widget widget) { | ||
376 | 345 | string filename; | ||
377 | 346 | if (uri.has_prefix ("file://")) | ||
378 | 347 | filename = Midori.Download.get_basename_for_display (uri); | ||
379 | 348 | else | ||
380 | 349 | filename = uri; | ||
381 | 350 | |||
382 | 351 | var browser = Midori.Browser.get_for_widget (widget); | ||
383 | 352 | transient_for = browser; | ||
384 | 353 | |||
385 | 354 | title = _("Choose application"); | ||
386 | 355 | #if !HAVE_GTK3 | ||
387 | 356 | has_separator = false; | ||
388 | 357 | #endif | ||
389 | 358 | destroy_with_parent = true; | ||
390 | 359 | set_icon_name (Gtk.STOCK_OPEN); | ||
391 | 360 | resizable = false; | ||
392 | 361 | add_buttons (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, | ||
393 | 362 | Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT); | ||
394 | 363 | |||
395 | 364 | var vbox = new Gtk.VBox (false, 8); | ||
396 | 365 | vbox.border_width = 8; | ||
397 | 366 | (get_content_area () as Gtk.Box).pack_start (vbox, true, true, 8); | ||
398 | 367 | var label = new Gtk.Label (_("Select an application to open \"%s\"".printf (filename))); | ||
399 | 368 | label.ellipsize = Pango.EllipsizeMode.MIDDLE; | ||
400 | 369 | vbox.pack_start (label, false, false, 0); | ||
401 | 370 | if (uri == "") | ||
402 | 371 | label.no_show_all = true; | ||
403 | 372 | chooser = new Chooser (uri, content_type); | ||
404 | 373 | vbox.pack_start (chooser, true, true, 0); | ||
405 | 374 | |||
406 | 375 | get_content_area ().show_all (); | ||
407 | 376 | set_default_response (Gtk.ResponseType.ACCEPT); | ||
408 | 377 | chooser.selected.connect ((app_info) => { | ||
409 | 378 | response (Gtk.ResponseType.ACCEPT); | ||
410 | 379 | }); | ||
411 | 380 | chooser.customized.connect ((app_info, content_type, uri) => { | ||
412 | 381 | response (Gtk.ResponseType.CANCEL); | ||
413 | 382 | }); | ||
414 | 383 | } | ||
415 | 384 | |||
416 | 385 | public AppInfo? open_with () { | ||
417 | 386 | show (); | ||
418 | 387 | bool accept = run () == Gtk.ResponseType.ACCEPT; | ||
419 | 388 | hide (); | ||
420 | 389 | |||
421 | 390 | if (!accept) | ||
422 | 391 | return null; | ||
423 | 392 | return chooser.get_app_info (); | ||
424 | 393 | } | ||
425 | 394 | } | ||
426 | 395 | |||
427 | 396 | class ChooserButton : Gtk.Button { | ||
428 | 397 | public AppInfo? app_info { get; set; } | ||
429 | 398 | public string? commandline { get; set; } | ||
430 | 399 | ChooserDialog dialog; | ||
431 | 400 | Gtk.Label app_name; | ||
432 | 401 | Gtk.Image icon; | ||
433 | 402 | |||
434 | 403 | public ChooserButton (string mime_type, string? commandline) { | ||
435 | 404 | string content_type = ContentType.from_mime_type (mime_type); | ||
436 | 405 | dialog = new ChooserDialog ("", content_type, this); | ||
437 | 406 | app_info = null; | ||
438 | 407 | foreach (var candidate in dialog.chooser.get_available ()) { | ||
439 | 408 | if (get_commandline (candidate) == commandline) | ||
440 | 409 | app_info = candidate; | ||
441 | 410 | } | ||
442 | 411 | |||
443 | 412 | var hbox = new Gtk.HBox (false, 4); | ||
444 | 413 | icon = new Gtk.Image (); | ||
445 | 414 | hbox.pack_start (icon, false, false, 0); | ||
446 | 415 | app_name = new Gtk.Label (null); | ||
447 | 416 | app_name.use_markup = true; | ||
448 | 417 | app_name.ellipsize = Pango.EllipsizeMode.END; | ||
449 | 418 | hbox.pack_start (app_name, true, true, 0); | ||
450 | 419 | add (hbox); | ||
451 | 420 | show_all (); | ||
452 | 421 | update_label (); | ||
453 | 422 | |||
454 | 423 | clicked.connect (() => { | ||
455 | 424 | app_info = dialog.open_with (); | ||
456 | 425 | string new_commandline = app_info != null ? get_commandline (app_info) : null; | ||
457 | 426 | commandline = new_commandline; | ||
458 | 427 | selected (new_commandline); | ||
459 | 428 | update_label (); | ||
460 | 429 | }); | ||
461 | 430 | } | ||
462 | 431 | |||
463 | 432 | void update_label () { | ||
464 | 433 | app_name.label = app_info != null ? describe_app_info (app_info).replace ("\n", " ") : _("None"); | ||
465 | 434 | icon.set_from_gicon (app_info != null ? app_info_get_icon (app_info) : null, Gtk.IconSize.BUTTON); | ||
466 | 435 | } | ||
467 | 436 | |||
468 | 437 | public signal void selected (string? commandline); | ||
469 | 438 | } | ||
470 | 439 | |||
471 | 440 | class Types : Gtk.VBox { | ||
472 | 441 | public Gtk.ListStore store = new Gtk.ListStore (2, typeof (string), typeof (AppInfo)); | ||
473 | 442 | Gtk.TreeView treeview; | ||
474 | 443 | |||
475 | 444 | public Types () { | ||
476 | 445 | Gtk.TreeViewColumn column; | ||
477 | 446 | |||
478 | 447 | treeview = new Gtk.TreeView.with_model (store); | ||
479 | 448 | treeview.headers_visible = false; | ||
480 | 449 | |||
481 | 450 | store.set_sort_column_id (0, Gtk.SortType.ASCENDING); | ||
482 | 451 | store.set_sort_func (0, tree_sort_func); | ||
483 | 452 | |||
484 | 453 | column = new Gtk.TreeViewColumn (); | ||
485 | 454 | column.set_sizing (Gtk.TreeViewColumnSizing.AUTOSIZE); | ||
486 | 455 | Gtk.CellRendererPixbuf renderer_type_icon = new Gtk.CellRendererPixbuf (); | ||
487 | 456 | column.pack_start (renderer_type_icon, false); | ||
488 | 457 | column.set_cell_data_func (renderer_type_icon, on_render_type_icon); | ||
489 | 458 | treeview.append_column (column); | ||
490 | 459 | |||
491 | 460 | column = new Gtk.TreeViewColumn (); | ||
492 | 461 | column.set_sizing (Gtk.TreeViewColumnSizing.AUTOSIZE); | ||
493 | 462 | Gtk.CellRendererText renderer_type_text = new Gtk.CellRendererText (); | ||
494 | 463 | column.pack_start (renderer_type_text, true); | ||
495 | 464 | column.set_cell_data_func (renderer_type_text, on_render_type_text); | ||
496 | 465 | treeview.append_column (column); | ||
497 | 466 | |||
498 | 467 | column = new Gtk.TreeViewColumn (); | ||
499 | 468 | column.set_sizing (Gtk.TreeViewColumnSizing.AUTOSIZE); | ||
500 | 469 | Gtk.CellRendererPixbuf renderer_icon = new Gtk.CellRendererPixbuf (); | ||
501 | 470 | column.pack_start (renderer_icon, false); | ||
502 | 471 | column.set_cell_data_func (renderer_icon, on_render_icon); | ||
503 | 472 | treeview.append_column (column); | ||
504 | 473 | |||
505 | 474 | column = new Gtk.TreeViewColumn (); | ||
506 | 475 | column.set_sizing (Gtk.TreeViewColumnSizing.AUTOSIZE); | ||
507 | 476 | Gtk.CellRendererText renderer_text = new Gtk.CellRendererText (); | ||
508 | 477 | column.pack_start (renderer_text, true); | ||
509 | 478 | column.set_expand (true); | ||
510 | 479 | column.set_cell_data_func (renderer_text, on_render_text); | ||
511 | 480 | treeview.append_column (column); | ||
512 | 481 | |||
513 | 482 | treeview.row_activated.connect (row_activated); | ||
514 | 483 | treeview.show (); | ||
515 | 484 | var scrolled = new Gtk.ScrolledWindow (null, null); | ||
516 | 485 | scrolled.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); | ||
517 | 486 | scrolled.add (treeview); | ||
518 | 487 | pack_start (scrolled); | ||
519 | 488 | int height; | ||
520 | 489 | treeview.create_pango_layout ("a\nb").get_pixel_size (null, out height); | ||
521 | 490 | scrolled.set_size_request (-1, height * 5); | ||
522 | 491 | |||
523 | 492 | foreach (string content_type in ContentType.list_registered ()) | ||
524 | 493 | launcher_added (content_type); | ||
525 | 494 | foreach (string scheme in Vfs.get_default ().get_supported_uri_schemes ()) | ||
526 | 495 | launcher_added ("x-scheme-handler/" + scheme); | ||
527 | 496 | |||
528 | 497 | treeview.size_allocate.connect_after ((allocation) => { | ||
529 | 498 | treeview.columns_autosize (); | ||
530 | 499 | }); | ||
531 | 500 | } | ||
532 | 501 | |||
533 | 502 | void on_render_type_icon (Gtk.CellLayout column, Gtk.CellRenderer renderer, | ||
534 | 503 | Gtk.TreeModel model, Gtk.TreeIter iter) { | ||
535 | 504 | |||
536 | 505 | string content_type; | ||
537 | 506 | store.get (iter, 0, out content_type); | ||
538 | 507 | |||
539 | 508 | renderer.set ("gicon", ContentType.get_icon (content_type), | ||
540 | 509 | "stock-size", Gtk.IconSize.BUTTON, | ||
541 | 510 | "xpad", 4); | ||
542 | 511 | } | ||
543 | 512 | |||
544 | 513 | void on_render_type_text (Gtk.CellLayout column, Gtk.CellRenderer renderer, | ||
545 | 514 | Gtk.TreeModel model, Gtk.TreeIter iter) { | ||
546 | 515 | |||
547 | 516 | string content_type; | ||
548 | 517 | AppInfo app_info; | ||
549 | 518 | store.get (iter, 0, out content_type, 1, out app_info); | ||
550 | 519 | |||
551 | 520 | string desc, mime_type; | ||
552 | 521 | if (content_type.has_prefix ("x-scheme-handler/")) { | ||
553 | 522 | desc = content_type.split ("/")[1] + "://"; | ||
554 | 523 | mime_type = ""; | ||
555 | 524 | } else { | ||
556 | 525 | desc = ContentType.get_description (content_type); | ||
557 | 526 | mime_type = ContentType.get_mime_type (content_type); | ||
558 | 527 | } | ||
559 | 528 | |||
560 | 529 | renderer.set ("markup", | ||
561 | 530 | Markup.printf_escaped ("<b>%s</b>\n%s", | ||
562 | 531 | desc, mime_type), | ||
563 | 532 | #if HAVE_GTK3 | ||
564 | 533 | "max-width-chars", 30, | ||
565 | 534 | #else | ||
566 | 535 | "width-chars", 30, | ||
567 | 536 | #endif | ||
568 | 537 | "ellipsize", Pango.EllipsizeMode.END); | ||
569 | 538 | } | ||
570 | 539 | |||
571 | 540 | void on_render_icon (Gtk.CellLayout column, Gtk.CellRenderer renderer, | ||
572 | 541 | Gtk.TreeModel model, Gtk.TreeIter iter) { | ||
573 | 542 | |||
574 | 543 | AppInfo app_info; | ||
575 | 544 | model.get (iter, 1, out app_info); | ||
576 | 545 | |||
577 | 546 | renderer.set ("gicon", app_info_get_icon (app_info), | ||
578 | 547 | "stock-size", Gtk.IconSize.MENU, | ||
579 | 548 | "xpad", 4); | ||
580 | 549 | } | ||
581 | 550 | |||
582 | 551 | void on_render_text (Gtk.CellLayout column, Gtk.CellRenderer renderer, | ||
583 | 552 | Gtk.TreeModel model, Gtk.TreeIter iter) { | ||
584 | 553 | |||
585 | 554 | AppInfo app_info; | ||
586 | 555 | model.get (iter, 1, out app_info); | ||
587 | 556 | renderer.set ("markup", describe_app_info (app_info), | ||
588 | 557 | "ellipsize", Pango.EllipsizeMode.END); | ||
589 | 558 | } | ||
590 | 559 | |||
591 | 560 | void launcher_added (string content_type) { | ||
592 | 561 | var app_info = AppInfo.get_default_for_type (content_type, false); | ||
593 | 562 | if (app_info == null) | ||
594 | 563 | return; | ||
595 | 564 | |||
596 | 565 | Gtk.TreeIter iter; | ||
597 | 566 | store.append (out iter); | ||
598 | 567 | store.set (iter, 0, content_type, 1, app_info); | ||
599 | 568 | } | ||
600 | 569 | |||
601 | 570 | int tree_sort_func (Gtk.TreeModel model, Gtk.TreeIter a, Gtk.TreeIter b) { | ||
602 | 571 | string content_type1, content_type2; | ||
603 | 572 | model.get (a, 0, out content_type1); | ||
604 | 573 | model.get (b, 0, out content_type2); | ||
605 | 574 | return strcmp (content_type1, content_type2); | ||
606 | 575 | } | ||
607 | 576 | |||
608 | 577 | void row_activated (Gtk.TreePath path, Gtk.TreeViewColumn column) { | ||
609 | 578 | Gtk.TreeIter iter; | ||
610 | 579 | if (store.get_iter (out iter, path)) { | ||
611 | 580 | string content_type; | ||
612 | 581 | store.get (iter, 0, out content_type); | ||
613 | 582 | selected (content_type, iter); | ||
614 | 583 | } | ||
615 | 584 | } | ||
616 | 585 | |||
617 | 586 | public signal void selected (string content_type, Gtk.TreeIter iter); | ||
618 | 587 | } | ||
619 | 588 | |||
620 | 589 | |||
621 | 590 | private class Manager : Midori.Extension { | ||
622 | 591 | enum NextStep { | ||
623 | 592 | TRY_OPEN, | ||
624 | 593 | OPEN_WITH | ||
625 | 594 | } | ||
626 | 595 | |||
627 | 596 | bool open_uri (Midori.Tab tab, string uri) { | ||
628 | 597 | return open_with_type (uri, get_content_type (uri, null), tab, NextStep.TRY_OPEN); | ||
629 | 598 | } | ||
630 | 599 | |||
631 | 600 | bool navigation_requested (WebKit.WebView web_view, WebKit.WebFrame frame, WebKit.NetworkRequest request, | ||
632 | 601 | WebKit.WebNavigationAction action, WebKit.WebPolicyDecision decision) { | ||
633 | 602 | |||
634 | 603 | string uri = request.uri; | ||
635 | 604 | if (Midori.URI.is_http (uri) || Midori.URI.is_blank (uri)) | ||
636 | 605 | return false; | ||
637 | 606 | |||
638 | 607 | decision.ignore (); | ||
639 | 608 | |||
640 | 609 | string content_type = get_content_type (uri, null); | ||
641 | 610 | open_with_type (uri, content_type, web_view, NextStep.TRY_OPEN); | ||
642 | 611 | return true; | ||
643 | 612 | } | ||
644 | 613 | |||
645 | 614 | string get_content_type (string uri, string? mime_type) { | ||
646 | 615 | if (!uri.has_prefix ("file://") && !Midori.URI.is_http (uri)) { | ||
647 | 616 | string protocol = uri.split(":", 2)[0]; | ||
648 | 617 | return "x-scheme-handler/" + protocol; | ||
649 | 618 | } else if (mime_type == null) { | ||
650 | 619 | string filename; | ||
651 | 620 | bool uncertain; | ||
652 | 621 | try { | ||
653 | 622 | filename = Filename.from_uri (uri); | ||
654 | 623 | } catch (Error error) { | ||
655 | 624 | filename = uri; | ||
656 | 625 | } | ||
657 | 626 | return ContentType.guess (filename, null, out uncertain); | ||
658 | 627 | } | ||
659 | 628 | return ContentType.from_mime_type (mime_type); | ||
660 | 629 | } | ||
661 | 630 | |||
662 | 631 | bool open_with_type (string uri, string content_type, Gtk.Widget widget, NextStep next_step) { | ||
663 | 632 | #if HAVE_WEBKIT2 | ||
664 | 633 | return open_now (uri, content_type, widget, next_step); | ||
665 | 634 | #else | ||
666 | 635 | if (!Midori.URI.is_http (uri)) | ||
667 | 636 | return open_now (uri, content_type, widget, next_step); | ||
668 | 637 | |||
669 | 638 | var download = new WebKit.Download (new WebKit.NetworkRequest (uri)); | ||
670 | 639 | download.destination_uri = Midori.Download.prepare_destination_uri (download, null); | ||
671 | 640 | if (!Midori.Download.has_enough_space (download, download.destination_uri)) | ||
672 | 641 | return false; | ||
673 | 642 | |||
674 | 643 | download.notify["status"].connect ((pspec) => { | ||
675 | 644 | if (download.status == WebKit.DownloadStatus.FINISHED) { | ||
676 | 645 | open_now (download.destination_uri, content_type, widget, next_step); | ||
677 | 646 | } | ||
678 | 647 | else if (download.status == WebKit.DownloadStatus.ERROR) | ||
679 | 648 | Midori.show_message_dialog (Gtk.MessageType.ERROR, | ||
680 | 649 | _("Error downloading the image!"), | ||
681 | 650 | _("Can not download selected image."), false); | ||
682 | 651 | }); | ||
683 | 652 | download.start (); | ||
684 | 653 | return true; | ||
685 | 654 | #endif | ||
686 | 655 | } | ||
687 | 656 | |||
688 | 657 | bool open_now (string uri, string content_type, Gtk.Widget widget, NextStep next_step) { | ||
689 | 658 | if (next_step == NextStep.TRY_OPEN && (new Associations ()).open (content_type, uri)) | ||
690 | 659 | return true; | ||
691 | 660 | if (open_with (uri, content_type, widget) != null) | ||
692 | 661 | return true; | ||
693 | 662 | return false; | ||
694 | 663 | } | ||
695 | 664 | |||
696 | 665 | AppInfo? open_with (string uri, string content_type, Gtk.Widget widget) { | ||
697 | 666 | var dialog = new ChooserDialog (uri, content_type, widget); | ||
698 | 667 | |||
699 | 668 | var app_info = dialog.open_with (); | ||
700 | 669 | dialog.destroy (); | ||
701 | 670 | |||
702 | 671 | if (uri == "") | ||
703 | 672 | return app_info; | ||
704 | 673 | |||
705 | 674 | if (app_info == null) | ||
706 | 675 | return app_info; | ||
707 | 676 | |||
708 | 677 | return open_app_info (app_info, uri, content_type) ? app_info : null; | ||
709 | 678 | } | ||
710 | 679 | |||
711 | 680 | void context_menu (Midori.Tab tab, WebKit.HitTestResult hit_test_result, Midori.ContextAction menu) { | ||
712 | 681 | if ((hit_test_result.context & WebKit.HitTestResultContext.LINK) != 0) { | ||
713 | 682 | string uri = hit_test_result.link_uri; | ||
714 | 683 | var action = new Gtk.Action ("OpenWith", _("Open _with…"), null, null); | ||
715 | 684 | action.activate.connect ((action) => { | ||
716 | 685 | open_with_type (uri, get_content_type (uri, null), tab, NextStep.OPEN_WITH); | ||
717 | 686 | }); | ||
718 | 687 | menu.add (action); | ||
719 | 688 | } | ||
720 | 689 | #if !HAVE_WEBKIT2 | ||
721 | 690 | if ((hit_test_result.context & WebKit.HitTestResultContext.IMAGE) != 0) { | ||
722 | 691 | string uri = hit_test_result.image_uri; | ||
723 | 692 | var action = new Gtk.Action ("OpenImageInViewer", _("Open in Image _Viewer"), null, null); | ||
724 | 693 | action.activate.connect ((action) => { | ||
725 | 694 | open_with_type (uri, get_content_type (uri, null), tab, NextStep.TRY_OPEN); | ||
726 | 695 | }); | ||
727 | 696 | menu.add (action); | ||
728 | 697 | } | ||
729 | 698 | #endif | ||
730 | 699 | } | ||
731 | 700 | |||
732 | 701 | void show_preferences (Katze.Preferences preferences) { | ||
733 | 702 | var settings = get_app ().settings; | ||
734 | 703 | var category = preferences.add_category (_("File Types"), Gtk.STOCK_FILE); | ||
735 | 704 | preferences.add_group (null); | ||
736 | 705 | |||
737 | 706 | var sizegroup = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL); | ||
738 | 707 | var label = new Gtk.Label (_("Text Editor")); | ||
739 | 708 | sizegroup.add_widget (label); | ||
740 | 709 | label.set_alignment (0.0f, 0.5f); | ||
741 | 710 | preferences.add_widget (label, "indented"); | ||
742 | 711 | var entry = new ChooserButton ("text/plain", settings.text_editor); | ||
743 | 712 | sizegroup.add_widget (entry); | ||
744 | 713 | entry.selected.connect ((commandline) => { | ||
745 | 714 | settings.text_editor = commandline; | ||
746 | 715 | }); | ||
747 | 716 | preferences.add_widget (entry, "spanned"); | ||
748 | 717 | |||
749 | 718 | label = new Gtk.Label (_("News Aggregator")); | ||
750 | 719 | sizegroup.add_widget (label); | ||
751 | 720 | label.set_alignment (0.0f, 0.5f); | ||
752 | 721 | preferences.add_widget (label, "indented"); | ||
753 | 722 | entry = new ChooserButton ("application/rss+xml", settings.news_aggregator); | ||
754 | 723 | sizegroup.add_widget (entry); | ||
755 | 724 | entry.selected.connect ((commandline) => { | ||
756 | 725 | settings.news_aggregator = commandline; | ||
757 | 726 | }); | ||
758 | 727 | preferences.add_widget (entry, "spanned"); | ||
759 | 728 | |||
760 | 729 | var types = new Types (); | ||
761 | 730 | types.selected.connect ((content_type, iter) => { | ||
762 | 731 | var app_info = open_with ("", content_type, preferences); | ||
763 | 732 | if (app_info == null) | ||
764 | 733 | return; | ||
765 | 734 | try { | ||
766 | 735 | app_info.set_as_default_for_type (content_type); | ||
767 | 736 | types.store.set (iter, 1, app_info); | ||
768 | 737 | } catch (Error error) { | ||
769 | 738 | warning ("Failed to select default for \"%s\": %s", content_type, error.message); | ||
770 | 739 | } | ||
771 | 740 | }); | ||
772 | 741 | category.pack_start (types, true, true, 0); | ||
773 | 742 | types.show_all (); | ||
774 | 743 | } | ||
775 | 744 | |||
776 | 745 | public void tab_added (Midori.Browser browser, Midori.View view) { | ||
777 | 746 | view.web_view.navigation_policy_decision_requested.connect (navigation_requested); | ||
778 | 747 | view.open_uri.connect (open_uri); | ||
779 | 748 | view.context_menu.connect (context_menu); | ||
780 | 749 | } | ||
781 | 750 | |||
782 | 751 | public void tab_removed (Midori.Browser browser, Midori.View view) { | ||
783 | 752 | view.web_view.navigation_policy_decision_requested.disconnect (navigation_requested); | ||
784 | 753 | view.open_uri.disconnect (open_uri); | ||
785 | 754 | view.context_menu.disconnect (context_menu); | ||
786 | 755 | } | ||
787 | 756 | |||
788 | 757 | void browser_added (Midori.Browser browser) { | ||
789 | 758 | foreach (var tab in browser.get_tabs ()) | ||
790 | 759 | tab_added (browser, tab); | ||
791 | 760 | browser.add_tab.connect (tab_added); | ||
792 | 761 | browser.remove_tab.connect (tab_removed); | ||
793 | 762 | browser.show_preferences.connect (show_preferences); | ||
794 | 763 | } | ||
795 | 764 | |||
796 | 765 | void activated (Midori.App app) { | ||
797 | 766 | foreach (var browser in app.get_browsers ()) | ||
798 | 767 | browser_added (browser); | ||
799 | 768 | app.add_browser.connect (browser_added); | ||
800 | 769 | } | ||
801 | 770 | |||
802 | 771 | void browser_removed (Midori.Browser browser) { | ||
803 | 772 | foreach (var tab in browser.get_tabs ()) | ||
804 | 773 | tab_removed (browser, tab); | ||
805 | 774 | browser.add_tab.disconnect (tab_added); | ||
806 | 775 | browser.remove_tab.disconnect (tab_removed); | ||
807 | 776 | browser.show_preferences.disconnect (show_preferences); | ||
808 | 777 | } | ||
809 | 778 | |||
810 | 779 | void deactivated () { | ||
811 | 780 | var app = get_app (); | ||
812 | 781 | foreach (var browser in app.get_browsers ()) | ||
813 | 782 | browser_removed (browser); | ||
814 | 783 | app.add_browser.disconnect (browser_added); | ||
815 | 784 | |||
816 | 785 | } | ||
817 | 786 | |||
818 | 787 | internal Manager () { | ||
819 | 788 | GLib.Object (name: "External Applications", | ||
820 | 789 | description: "Choose what to open unknown file types with", | ||
821 | 790 | version: "0.1" + Midori.VERSION_SUFFIX, | ||
822 | 791 | authors: "Christian Dywan <christian@twotoasts.de>"); | ||
823 | 792 | |||
824 | 793 | this.activate.connect (activated); | ||
825 | 794 | this.deactivate.connect (deactivated); | ||
826 | 795 | } | ||
827 | 796 | } | ||
828 | 797 | } | ||
829 | 798 | |||
830 | 799 | public Midori.Extension extension_init () { | ||
831 | 800 | return new ExternalApplications.Manager (); | ||
832 | 801 | } | ||
833 | 802 | |||
834 | 0 | 803 | ||
835 | === modified file 'extensions/transfers.vala' | |||
836 | --- extensions/transfers.vala 2014-01-06 21:51:09 +0000 | |||
837 | +++ extensions/transfers.vala 2014-02-25 19:27:20 +0000 | |||
838 | @@ -14,7 +14,6 @@ | |||
839 | 14 | } | 14 | } |
840 | 15 | 15 | ||
841 | 16 | namespace Sokoke { | 16 | namespace Sokoke { |
842 | 17 | extern static bool show_uri (Gdk.Screen screen, string uri, uint32 timestamp) throws Error; | ||
843 | 18 | extern static void widget_get_text_size (Gtk.Widget widget, string sample, out int width, out int height); | 17 | extern static void widget_get_text_size (Gtk.Widget widget, string sample, out int width, out int height); |
844 | 19 | } | 18 | } |
845 | 20 | 19 | ||
846 | @@ -214,12 +213,8 @@ | |||
847 | 214 | menuitem = new Gtk.ImageMenuItem.with_mnemonic (_("Open Destination _Folder")); | 213 | menuitem = new Gtk.ImageMenuItem.with_mnemonic (_("Open Destination _Folder")); |
848 | 215 | menuitem.image = new Gtk.Image.from_stock (Gtk.STOCK_DIRECTORY, Gtk.IconSize.MENU); | 214 | menuitem.image = new Gtk.Image.from_stock (Gtk.STOCK_DIRECTORY, Gtk.IconSize.MENU); |
849 | 216 | menuitem.activate.connect (() => { | 215 | menuitem.activate.connect (() => { |
856 | 217 | try { | 216 | var folder = GLib.File.new_for_uri (transfer.destination); |
857 | 218 | var folder = GLib.File.new_for_uri (transfer.destination); | 217 | (Midori.Browser.get_for_widget (this).tab as Midori.Tab).open_uri (folder.get_parent ().get_uri ()); |
852 | 219 | Sokoke.show_uri (get_screen (), folder.get_parent ().get_uri (), 0); | ||
853 | 220 | } catch (Error error_folder) { | ||
854 | 221 | GLib.warning (_("Failed to open download: %s"), error_folder.message); | ||
855 | 222 | } | ||
858 | 223 | }); | 218 | }); |
859 | 224 | menu.append (menuitem); | 219 | menu.append (menuitem); |
860 | 225 | menuitem = new Gtk.ImageMenuItem.with_mnemonic (_("Copy Link Loc_ation")); | 220 | menuitem = new Gtk.ImageMenuItem.with_mnemonic (_("Copy Link Loc_ation")); |
861 | 226 | 221 | ||
862 | === modified file 'katze/katze-utils.c' | |||
863 | --- katze/katze-utils.c 2013-11-05 21:51:18 +0000 | |||
864 | +++ katze/katze-utils.c 2014-02-25 19:27:20 +0000 | |||
865 | @@ -101,78 +101,12 @@ | |||
866 | 101 | } | 101 | } |
867 | 102 | #endif | 102 | #endif |
868 | 103 | 103 | ||
869 | 104 | static const gchar* | ||
870 | 105 | katze_app_info_get_commandline (GAppInfo* info) | ||
871 | 106 | { | ||
872 | 107 | const gchar* exe; | ||
873 | 108 | |||
874 | 109 | exe = g_app_info_get_commandline (info); | ||
875 | 110 | if (!exe) | ||
876 | 111 | exe = g_app_info_get_executable (info); | ||
877 | 112 | if (!exe) | ||
878 | 113 | exe = g_app_info_get_name (info); | ||
879 | 114 | return exe; | ||
880 | 115 | } | ||
881 | 116 | |||
882 | 117 | static gboolean | 104 | static gboolean |
883 | 118 | proxy_entry_focus_out_event_cb (GtkEntry* entry, | 105 | proxy_entry_focus_out_event_cb (GtkEntry* entry, |
884 | 119 | GdkEventFocus* event, | 106 | GdkEventFocus* event, |
885 | 120 | GObject* object); | 107 | GObject* object); |
886 | 121 | 108 | ||
887 | 122 | static void | 109 | static void |
888 | 123 | proxy_combo_box_apps_changed_cb (GtkComboBox* button, | ||
889 | 124 | GObject* object) | ||
890 | 125 | { | ||
891 | 126 | guint active = gtk_combo_box_get_active (button); | ||
892 | 127 | GtkTreeModel* model = gtk_combo_box_get_model (button); | ||
893 | 128 | GtkTreeIter iter; | ||
894 | 129 | |||
895 | 130 | if (gtk_tree_model_iter_nth_child (model, &iter, NULL, active)) | ||
896 | 131 | { | ||
897 | 132 | GAppInfo* info; | ||
898 | 133 | gboolean use_entry; | ||
899 | 134 | GtkWidget* child; | ||
900 | 135 | const gchar* exe; | ||
901 | 136 | const gchar* property = g_object_get_data (G_OBJECT (button), "property"); | ||
902 | 137 | |||
903 | 138 | gtk_tree_model_get (model, &iter, 0, &info, -1); | ||
904 | 139 | |||
905 | 140 | use_entry = info && !g_app_info_get_icon (info); | ||
906 | 141 | child = gtk_bin_get_child (GTK_BIN (button)); | ||
907 | 142 | if (use_entry && GTK_IS_CELL_VIEW (child)) | ||
908 | 143 | { | ||
909 | 144 | GtkWidget* entry = gtk_entry_new (); | ||
910 | 145 | exe = g_app_info_get_executable (info); | ||
911 | 146 | if (exe && *exe && strcmp (exe, "%f")) | ||
912 | 147 | gtk_entry_set_text (GTK_ENTRY (entry), exe); | ||
913 | 148 | gtk_widget_show (entry); | ||
914 | 149 | gtk_container_add (GTK_CONTAINER (button), entry); | ||
915 | 150 | gtk_widget_grab_focus (entry); | ||
916 | 151 | g_signal_connect (entry, "focus-out-event", | ||
917 | 152 | G_CALLBACK (proxy_entry_focus_out_event_cb), object); | ||
918 | 153 | g_object_set_data_full (G_OBJECT (entry), "property", | ||
919 | 154 | g_strdup (property), g_free); | ||
920 | 155 | } | ||
921 | 156 | else if (!use_entry && GTK_IS_ENTRY (child)) | ||
922 | 157 | { | ||
923 | 158 | /* Force the combo to change the item again */ | ||
924 | 159 | gtk_widget_destroy (child); | ||
925 | 160 | gtk_combo_box_set_active (button, 0); | ||
926 | 161 | gtk_combo_box_set_active_iter (button, &iter); | ||
927 | 162 | } | ||
928 | 163 | |||
929 | 164 | if (info) | ||
930 | 165 | { | ||
931 | 166 | exe = katze_app_info_get_commandline (info); | ||
932 | 167 | g_object_set (object, property, exe, NULL); | ||
933 | 168 | g_object_unref (info); | ||
934 | 169 | } | ||
935 | 170 | else | ||
936 | 171 | g_object_set (object, property, "", NULL); | ||
937 | 172 | } | ||
938 | 173 | } | ||
939 | 174 | |||
940 | 175 | static void | ||
941 | 176 | proxy_entry_activate_cb (GtkEntry* entry, | 110 | proxy_entry_activate_cb (GtkEntry* entry, |
942 | 177 | GObject* object) | 111 | GObject* object) |
943 | 178 | { | 112 | { |
944 | @@ -326,130 +260,6 @@ | |||
945 | 326 | proxy_object_notify_string_cb, proxy); | 260 | proxy_object_notify_string_cb, proxy); |
946 | 327 | } | 261 | } |
947 | 328 | 262 | ||
948 | 329 | static GList* | ||
949 | 330 | katze_app_info_get_all_for_category (const gchar* category) | ||
950 | 331 | { | ||
951 | 332 | #ifdef _WIN32 | ||
952 | 333 | /* FIXME: Real filtering by category would be better */ | ||
953 | 334 | const gchar* content_type = g_content_type_from_mime_type (category); | ||
954 | 335 | GList* all_apps = g_app_info_get_all_for_type (content_type); | ||
955 | 336 | #else | ||
956 | 337 | GList* all_apps = g_app_info_get_all (); | ||
957 | 338 | #endif | ||
958 | 339 | GList* apps = NULL; | ||
959 | 340 | GList* app; | ||
960 | 341 | for (app = apps; app; app = g_list_next (app)) | ||
961 | 342 | { | ||
962 | 343 | GAppInfo* info = app->data; | ||
963 | 344 | #ifdef GDK_WINDOWING_X11 | ||
964 | 345 | gchar* filename = g_strconcat ("applications/", g_app_info_get_id (info), NULL); | ||
965 | 346 | GKeyFile* file = g_key_file_new (); | ||
966 | 347 | |||
967 | 348 | if (g_key_file_load_from_data_dirs (file, filename, NULL, G_KEY_FILE_NONE, NULL)) | ||
968 | 349 | { | ||
969 | 350 | gchar* cat = g_key_file_get_string (file, "Desktop Entry", | ||
970 | 351 | "Categories", NULL); | ||
971 | 352 | if (cat && g_strrstr (cat, category)) | ||
972 | 353 | apps = g_list_append (apps, info); | ||
973 | 354 | |||
974 | 355 | g_free (cat); | ||
975 | 356 | } | ||
976 | 357 | g_key_file_free (file); | ||
977 | 358 | g_free (filename); | ||
978 | 359 | #else | ||
979 | 360 | apps = g_list_append (apps, info); | ||
980 | 361 | #endif | ||
981 | 362 | } | ||
982 | 363 | g_list_free (all_apps); | ||
983 | 364 | return apps; | ||
984 | 365 | } | ||
985 | 366 | |||
986 | 367 | static gboolean | ||
987 | 368 | proxy_populate_apps (GtkWidget* widget) | ||
988 | 369 | { | ||
989 | 370 | const gchar* property = g_object_get_data (G_OBJECT (widget), "property"); | ||
990 | 371 | GObject* object = g_object_get_data (G_OBJECT (widget), "object"); | ||
991 | 372 | gchar* string = katze_object_get_string (object, property); | ||
992 | 373 | if (!g_strcmp0 (string, "")) | ||
993 | 374 | katze_assign (string, NULL); | ||
994 | 375 | GtkSettings* settings = gtk_widget_get_settings (widget); | ||
995 | 376 | gint icon_width = 16; | ||
996 | 377 | if (settings == NULL) | ||
997 | 378 | settings = gtk_settings_get_for_screen (gdk_screen_get_default ()); | ||
998 | 379 | gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, | ||
999 | 380 | &icon_width, NULL); | ||
1000 | 381 | |||
1001 | 382 | GtkComboBox* combo = GTK_COMBO_BOX (widget); | ||
1002 | 383 | GtkListStore* model = GTK_LIST_STORE (gtk_combo_box_get_model (combo)); | ||
1003 | 384 | GtkTreeIter iter_none; | ||
1004 | 385 | gtk_list_store_insert_with_values (model, &iter_none, 0, | ||
1005 | 386 | 0, NULL, 1, NULL, 2, _("None"), 3, icon_width, -1); | ||
1006 | 387 | |||
1007 | 388 | const gchar* app_type = g_object_get_data (G_OBJECT (widget), "app-type"); | ||
1008 | 389 | GList* apps = g_app_info_get_all_for_type (app_type); | ||
1009 | 390 | GAppInfo* info; | ||
1010 | 391 | if (!apps) | ||
1011 | 392 | apps = katze_app_info_get_all_for_category (app_type); | ||
1012 | 393 | if (apps != NULL) | ||
1013 | 394 | { | ||
1014 | 395 | GList* app; | ||
1015 | 396 | for (app = apps; app; app = g_list_next (app)) | ||
1016 | 397 | { | ||
1017 | 398 | info = app->data; | ||
1018 | 399 | const gchar* name = g_app_info_get_name (info); | ||
1019 | 400 | GIcon* icon = g_app_info_get_icon (info); | ||
1020 | 401 | gchar* icon_name; | ||
1021 | 402 | GtkTreeIter iter; | ||
1022 | 403 | |||
1023 | 404 | if (!g_app_info_should_show (info)) | ||
1024 | 405 | continue; | ||
1025 | 406 | |||
1026 | 407 | icon_name = icon ? g_icon_to_string (icon) : NULL; | ||
1027 | 408 | gtk_list_store_insert_with_values (model, &iter, G_MAXINT, | ||
1028 | 409 | 0, info, 1, icon_name, 2, name, 3, icon_width, -1); | ||
1029 | 410 | if (string && !strcmp (katze_app_info_get_commandline (info), string)) | ||
1030 | 411 | gtk_combo_box_set_active_iter (combo, &iter); | ||
1031 | 412 | |||
1032 | 413 | g_free (icon_name); | ||
1033 | 414 | } | ||
1034 | 415 | g_list_free (apps); | ||
1035 | 416 | } | ||
1036 | 417 | |||
1037 | 418 | info = g_app_info_create_from_commandline ("", | ||
1038 | 419 | "", G_APP_INFO_CREATE_NONE, NULL); | ||
1039 | 420 | gtk_list_store_insert_with_values (model, NULL, G_MAXINT, | ||
1040 | 421 | 0, info, 1, NULL, 2, _("Custom…"), 3, icon_width, -1); | ||
1041 | 422 | g_object_unref (info); | ||
1042 | 423 | |||
1043 | 424 | if (gtk_combo_box_get_active (combo) == -1) | ||
1044 | 425 | { | ||
1045 | 426 | if (string) | ||
1046 | 427 | { | ||
1047 | 428 | GtkWidget* entry; | ||
1048 | 429 | const gchar* exe; | ||
1049 | 430 | |||
1050 | 431 | info = g_app_info_create_from_commandline (string, | ||
1051 | 432 | NULL, G_APP_INFO_CREATE_NONE, NULL); | ||
1052 | 433 | entry = gtk_entry_new (); | ||
1053 | 434 | exe = g_app_info_get_executable (info); | ||
1054 | 435 | if (exe && *exe && strcmp (exe, "%f")) | ||
1055 | 436 | gtk_entry_set_text (GTK_ENTRY (entry), string); | ||
1056 | 437 | gtk_widget_show (entry); | ||
1057 | 438 | gtk_container_add (GTK_CONTAINER (combo), entry); | ||
1058 | 439 | g_object_unref (info); | ||
1059 | 440 | g_signal_connect (entry, "focus-out-event", | ||
1060 | 441 | G_CALLBACK (proxy_entry_focus_out_event_cb), object); | ||
1061 | 442 | g_object_set_data_full (G_OBJECT (entry), "property", | ||
1062 | 443 | g_strdup (property), g_free); | ||
1063 | 444 | } | ||
1064 | 445 | else | ||
1065 | 446 | gtk_combo_box_set_active_iter (combo, &iter_none); | ||
1066 | 447 | } | ||
1067 | 448 | g_signal_connect (widget, "changed", | ||
1068 | 449 | G_CALLBACK (proxy_combo_box_apps_changed_cb), object); | ||
1069 | 450 | return G_SOURCE_REMOVE; | ||
1070 | 451 | } | ||
1071 | 452 | |||
1072 | 453 | /** | 263 | /** |
1073 | 454 | * katze_property_proxy: | 264 | * katze_property_proxy: |
1074 | 455 | * @object: a #GObject | 265 | * @object: a #GObject |
1075 | @@ -483,6 +293,7 @@ | |||
1076 | 483 | * for choosing an application to open TYPE files, ie. "text/plain". | 293 | * for choosing an application to open TYPE files, ie. "text/plain". |
1077 | 484 | * "application-CATEGORY": the widget created will be particularly suitable | 294 | * "application-CATEGORY": the widget created will be particularly suitable |
1078 | 485 | * for choosing an application to open CATEGORY files, ie. "Network". | 295 | * for choosing an application to open CATEGORY files, ie. "Network". |
1079 | 296 | * Since 0.5.8 the CATEGORY hint is no longer supported. | ||
1080 | 486 | * "custom-PROPERTY": the last value of an enumeration will be the "custom" | 297 | * "custom-PROPERTY": the last value of an enumeration will be the "custom" |
1081 | 487 | * value, where the user may enter text freely, which then updates | 298 | * value, where the user may enter text freely, which then updates |
1082 | 488 | * the property PROPERTY instead. This applies only to enumerations. | 299 | * the property PROPERTY instead. This applies only to enumerations. |
1083 | @@ -652,27 +463,6 @@ | |||
1084 | 652 | g_free (families); | 463 | g_free (families); |
1085 | 653 | #endif | 464 | #endif |
1086 | 654 | } | 465 | } |
1087 | 655 | else if (type == G_TYPE_PARAM_STRING && hint && g_str_has_prefix (hint, "application-")) | ||
1088 | 656 | { | ||
1089 | 657 | GtkListStore* model; | ||
1090 | 658 | GtkCellRenderer* renderer; | ||
1091 | 659 | const gchar* app_type = &hint[12]; | ||
1092 | 660 | |||
1093 | 661 | model = gtk_list_store_new (4, G_TYPE_APP_INFO, G_TYPE_STRING, | ||
1094 | 662 | G_TYPE_STRING, G_TYPE_INT); | ||
1095 | 663 | widget = gtk_combo_box_new_with_model (GTK_TREE_MODEL (model)); | ||
1096 | 664 | renderer = gtk_cell_renderer_pixbuf_new (); | ||
1097 | 665 | gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), renderer, FALSE); | ||
1098 | 666 | gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (widget), renderer, "icon-name", 1); | ||
1099 | 667 | gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (widget), renderer, "width", 3); | ||
1100 | 668 | renderer = gtk_cell_renderer_text_new (); | ||
1101 | 669 | gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), renderer, TRUE); | ||
1102 | 670 | gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (widget), renderer, "text", 2); | ||
1103 | 671 | |||
1104 | 672 | g_object_set_data_full (G_OBJECT (widget), "app-type", g_strdup (app_type), g_free); | ||
1105 | 673 | g_object_set_data_full (G_OBJECT (widget), "object", g_object_ref (object), g_object_unref); | ||
1106 | 674 | g_idle_add_full (G_PRIORITY_LOW, (GSourceFunc)proxy_populate_apps, widget, NULL); | ||
1107 | 675 | } | ||
1108 | 676 | else if (type == G_TYPE_PARAM_STRING) | 466 | else if (type == G_TYPE_PARAM_STRING) |
1109 | 677 | { | 467 | { |
1110 | 678 | gchar* notify_property; | 468 | gchar* notify_property; |
1111 | 679 | 469 | ||
1112 | === modified file 'katze/katze.vapi' | |||
1113 | --- katze/katze.vapi 2013-09-22 16:22:10 +0000 | |||
1114 | +++ katze/katze.vapi 2014-02-25 19:27:20 +0000 | |||
1115 | @@ -36,5 +36,12 @@ | |||
1116 | 36 | public unowned string? get_meta_string (string key); | 36 | public unowned string? get_meta_string (string key); |
1117 | 37 | public void set_meta_string (string key, string value); | 37 | public void set_meta_string (string key, string value); |
1118 | 38 | } | 38 | } |
1119 | 39 | |||
1120 | 40 | [CCode (cheader_filename = "katze/katze.h")] | ||
1121 | 41 | public class Preferences : Gtk.Dialog { | ||
1122 | 42 | public unowned Gtk.Box add_category (string label, string icon); | ||
1123 | 43 | public void add_group (string? label); | ||
1124 | 44 | public void add_widget (Gtk.Widget widget, string type); | ||
1125 | 45 | } | ||
1126 | 39 | } | 46 | } |
1127 | 40 | 47 | ||
1128 | 41 | 48 | ||
1129 | === modified file 'katze/midori-uri.vala' | |||
1130 | --- katze/midori-uri.vala 2014-01-06 21:51:09 +0000 | |||
1131 | +++ katze/midori-uri.vala 2014-02-25 19:27:20 +0000 | |||
1132 | @@ -16,6 +16,8 @@ | |||
1133 | 16 | 16 | ||
1134 | 17 | namespace Midori { | 17 | namespace Midori { |
1135 | 18 | public class URI : Object { | 18 | public class URI : Object { |
1136 | 19 | static string? fork_uri = null; | ||
1137 | 20 | |||
1138 | 19 | public static string? parse_hostname (string? uri, out string path) { | 21 | public static string? parse_hostname (string? uri, out string path) { |
1139 | 20 | path = null; | 22 | path = null; |
1140 | 21 | if (uri == null) | 23 | if (uri == null) |
1141 | @@ -205,5 +207,20 @@ | |||
1142 | 205 | label = display; | 207 | label = display; |
1143 | 206 | return type; | 208 | return type; |
1144 | 207 | } | 209 | } |
1145 | 210 | |||
1146 | 211 | /* | ||
1147 | 212 | Protects against recursive invokations of Midori with the same URI. | ||
1148 | 213 | Consider a tel:// URI opened via Tab.open_uri, being handed off to GIO, | ||
1149 | 214 | which in turns calls exo-open, which in turn can't open tel:// and falls | ||
1150 | 215 | back to the browser ie. Midori. | ||
1151 | 216 | So: code opening URIs calls this function with %true, #Midori.App passes %false. | ||
1152 | 217 | |||
1153 | 218 | Since: 0.5.8 | ||
1154 | 219 | */ | ||
1155 | 220 | public static bool recursive_fork_protection (string uri, bool set_uri) { | ||
1156 | 221 | if (set_uri) | ||
1157 | 222 | fork_uri = uri; | ||
1158 | 223 | return fork_uri != uri; | ||
1159 | 224 | } | ||
1160 | 208 | } | 225 | } |
1161 | 209 | } | 226 | } |
1162 | 210 | 227 | ||
1163 | === modified file 'midori/midori-app.c' | |||
1164 | --- midori/midori-app.c 2014-02-24 11:33:50 +0000 | |||
1165 | +++ midori/midori-app.c 2014-02-25 19:27:20 +0000 | |||
1166 | @@ -535,7 +535,7 @@ | |||
1167 | 535 | for (i = 0; i < n_files; i++) | 535 | for (i = 0; i < n_files; i++) |
1168 | 536 | { | 536 | { |
1169 | 537 | gchar* uri = g_file_get_uri (files[i]); | 537 | gchar* uri = g_file_get_uri (files[i]); |
1171 | 538 | if (sokoke_recursive_fork_protection (uri, FALSE)) | 538 | if (midori_uri_recursive_fork_protection (uri, FALSE)) |
1172 | 539 | { | 539 | { |
1173 | 540 | if (first) | 540 | if (first) |
1174 | 541 | { | 541 | { |
1175 | 542 | 542 | ||
1176 | === modified file 'midori/midori-browser.c' | |||
1177 | --- midori/midori-browser.c 2014-02-12 22:56:28 +0000 | |||
1178 | +++ midori/midori-browser.c 2014-02-25 19:27:20 +0000 | |||
1179 | @@ -1496,7 +1496,11 @@ | |||
1180 | 1496 | MidoriNewView where) | 1496 | MidoriNewView where) |
1181 | 1497 | { | 1497 | { |
1182 | 1498 | if (midori_paths_get_runtime_mode () == MIDORI_RUNTIME_MODE_APP) | 1498 | if (midori_paths_get_runtime_mode () == MIDORI_RUNTIME_MODE_APP) |
1184 | 1499 | return sokoke_show_uri (gtk_widget_get_screen (view), uri, 0, NULL); | 1499 | { |
1185 | 1500 | gboolean handled = FALSE; | ||
1186 | 1501 | g_signal_emit_by_name (view, "open-uri", uri, &handled); | ||
1187 | 1502 | return handled; | ||
1188 | 1503 | } | ||
1189 | 1500 | else if (midori_paths_get_runtime_mode () == MIDORI_RUNTIME_MODE_PRIVATE) | 1504 | else if (midori_paths_get_runtime_mode () == MIDORI_RUNTIME_MODE_PRIVATE) |
1190 | 1501 | { | 1505 | { |
1191 | 1502 | if (where == MIDORI_NEW_VIEW_WINDOW) | 1506 | if (where == MIDORI_NEW_VIEW_WINDOW) |
1192 | @@ -1613,37 +1617,6 @@ | |||
1193 | 1613 | } | 1617 | } |
1194 | 1614 | } | 1618 | } |
1195 | 1615 | 1619 | ||
1196 | 1616 | static void | ||
1197 | 1617 | midori_browser_download_status_cb (WebKitDownload* download, | ||
1198 | 1618 | GParamSpec* pspec, | ||
1199 | 1619 | GtkWidget* widget) | ||
1200 | 1620 | { | ||
1201 | 1621 | #ifndef HAVE_WEBKIT2 | ||
1202 | 1622 | const gchar* uri = webkit_download_get_destination_uri (download); | ||
1203 | 1623 | switch (webkit_download_get_status (download)) | ||
1204 | 1624 | { | ||
1205 | 1625 | case WEBKIT_DOWNLOAD_STATUS_FINISHED: | ||
1206 | 1626 | if (!sokoke_show_uri (gtk_widget_get_screen (widget), uri, 0, NULL)) | ||
1207 | 1627 | { | ||
1208 | 1628 | sokoke_message_dialog (GTK_MESSAGE_ERROR, | ||
1209 | 1629 | _("Error opening the image!"), | ||
1210 | 1630 | _("Can not open selected image in a default viewer."), FALSE); | ||
1211 | 1631 | } | ||
1212 | 1632 | break; | ||
1213 | 1633 | case WEBKIT_DOWNLOAD_STATUS_ERROR: | ||
1214 | 1634 | webkit_download_cancel (download); | ||
1215 | 1635 | sokoke_message_dialog (GTK_MESSAGE_ERROR, | ||
1216 | 1636 | _("Error downloading the image!"), | ||
1217 | 1637 | _("Can not download selected image."), FALSE); | ||
1218 | 1638 | break; | ||
1219 | 1639 | case WEBKIT_DOWNLOAD_STATUS_CREATED: | ||
1220 | 1640 | case WEBKIT_DOWNLOAD_STATUS_STARTED: | ||
1221 | 1641 | case WEBKIT_DOWNLOAD_STATUS_CANCELLED: | ||
1222 | 1642 | break; | ||
1223 | 1643 | } | ||
1224 | 1644 | #endif | ||
1225 | 1645 | } | ||
1226 | 1646 | |||
1227 | 1647 | #ifdef HAVE_WEBKIT2 | 1620 | #ifdef HAVE_WEBKIT2 |
1228 | 1648 | static void | 1621 | static void |
1229 | 1649 | midori_browser_close_tab_idle (GObject* resource, | 1622 | midori_browser_close_tab_idle (GObject* resource, |
1230 | @@ -1679,18 +1652,6 @@ | |||
1231 | 1679 | { | 1652 | { |
1232 | 1680 | handled = FALSE; | 1653 | handled = FALSE; |
1233 | 1681 | } | 1654 | } |
1234 | 1682 | else if (type == MIDORI_DOWNLOAD_OPEN_IN_VIEWER) | ||
1235 | 1683 | { | ||
1236 | 1684 | gchar* destination_uri = | ||
1237 | 1685 | midori_download_prepare_destination_uri (download, NULL); | ||
1238 | 1686 | midori_browser_prepare_download (browser, download, destination_uri); | ||
1239 | 1687 | g_signal_connect (download, "notify::status", | ||
1240 | 1688 | G_CALLBACK (midori_browser_download_status_cb), GTK_WIDGET (browser)); | ||
1241 | 1689 | g_free (destination_uri); | ||
1242 | 1690 | #ifndef HAVE_WEBKIT2 | ||
1243 | 1691 | webkit_download_start (download); | ||
1244 | 1692 | #endif | ||
1245 | 1693 | } | ||
1246 | 1694 | #ifdef HAVE_WEBKIT2 | 1655 | #ifdef HAVE_WEBKIT2 |
1247 | 1695 | else if (!webkit_download_get_destination (download)) | 1656 | else if (!webkit_download_get_destination (download)) |
1248 | 1696 | #else | 1657 | #else |
1249 | 1697 | 1658 | ||
1250 | === modified file 'midori/midori-dialog.vala' | |||
1251 | --- midori/midori-dialog.vala 2014-01-25 21:04:57 +0000 | |||
1252 | +++ midori/midori-dialog.vala 2014-02-25 19:27:20 +0000 | |||
1253 | @@ -103,6 +103,20 @@ | |||
1254 | 103 | } | 103 | } |
1255 | 104 | } | 104 | } |
1256 | 105 | 105 | ||
1257 | 106 | public static void show_message_dialog (Gtk.MessageType type, string short, string detailed, bool modal) { | ||
1258 | 107 | var dialog = new Gtk.MessageDialog (null, 0, type, Gtk.ButtonsType.OK, "%s", short); | ||
1259 | 108 | dialog.format_secondary_text ("%s", detailed); | ||
1260 | 109 | if (modal) { | ||
1261 | 110 | dialog.run (); | ||
1262 | 111 | dialog.destroy (); | ||
1263 | 112 | } else { | ||
1264 | 113 | dialog.response.connect ((response) => { | ||
1265 | 114 | dialog.destroy (); | ||
1266 | 115 | }); | ||
1267 | 116 | dialog.show (); | ||
1268 | 117 | } | ||
1269 | 118 | } | ||
1270 | 119 | |||
1271 | 106 | public class FileChooserDialog : Gtk.FileChooserDialog { | 120 | public class FileChooserDialog : Gtk.FileChooserDialog { |
1272 | 107 | public FileChooserDialog (string title, Gtk.Window? window, Gtk.FileChooserAction action) { | 121 | public FileChooserDialog (string title, Gtk.Window? window, Gtk.FileChooserAction action) { |
1273 | 108 | /* Creates a new file chooser dialog to Open or Save and Cancel. | 122 | /* Creates a new file chooser dialog to Open or Save and Cancel. |
1274 | 109 | 123 | ||
1275 | === modified file 'midori/midori-download.vala' | |||
1276 | --- midori/midori-download.vala 2014-01-06 21:51:09 +0000 | |||
1277 | +++ midori/midori-download.vala 2014-02-25 19:27:20 +0000 | |||
1278 | @@ -11,7 +11,6 @@ | |||
1279 | 11 | 11 | ||
1280 | 12 | namespace Sokoke { | 12 | namespace Sokoke { |
1281 | 13 | #if !HAVE_WEBKIT2 | 13 | #if !HAVE_WEBKIT2 |
1282 | 14 | extern static bool show_uri (Gdk.Screen screen, string uri, uint32 timestamp) throws Error; | ||
1283 | 15 | extern static bool message_dialog (Gtk.MessageType type, string short, string detailed, bool modal); | 14 | extern static bool message_dialog (Gtk.MessageType type, string short, string detailed, bool modal); |
1284 | 16 | #endif | 15 | #endif |
1285 | 17 | } | 16 | } |
1286 | @@ -212,9 +211,13 @@ | |||
1287 | 212 | 211 | ||
1288 | 213 | public static bool open (WebKit.Download download, Gtk.Widget widget) throws Error { | 212 | public static bool open (WebKit.Download download, Gtk.Widget widget) throws Error { |
1289 | 214 | #if !HAVE_WEBKIT2 | 213 | #if !HAVE_WEBKIT2 |
1293 | 215 | if (!has_wrong_checksum (download)) | 214 | if (!has_wrong_checksum (download)) { |
1294 | 216 | return Sokoke.show_uri (widget.get_screen (), | 215 | var browser = widget.get_toplevel (); |
1295 | 217 | download.destination_uri, Gtk.get_current_event_time ()); | 216 | Tab? tab = null; |
1296 | 217 | browser.get ("tab", tab); | ||
1297 | 218 | if (tab != null) | ||
1298 | 219 | tab.open_uri (download.destination_uri); | ||
1299 | 220 | } | ||
1300 | 218 | 221 | ||
1301 | 219 | Sokoke.message_dialog (Gtk.MessageType.WARNING, | 222 | Sokoke.message_dialog (Gtk.MessageType.WARNING, |
1302 | 220 | _("The downloaded file is erroneous."), | 223 | _("The downloaded file is erroneous."), |
1303 | 221 | 224 | ||
1304 | === modified file 'midori/midori-extension.c' | |||
1305 | --- midori/midori-extension.c 2013-12-09 19:49:15 +0000 | |||
1306 | +++ midori/midori-extension.c 2014-02-25 19:27:20 +0000 | |||
1307 | @@ -563,6 +563,7 @@ | |||
1308 | 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)); |
1309 | 564 | g_assert (midori_extension_activate_gracefully (app, extension_path, "libdelayed-load." G_MODULE_SUFFIX, activate)); | 564 | g_assert (midori_extension_activate_gracefully (app, extension_path, "libdelayed-load." G_MODULE_SUFFIX, activate)); |
1310 | 565 | g_assert (midori_extension_activate_gracefully (app, extension_path, "libtabby." G_MODULE_SUFFIX, activate)); | 565 | g_assert (midori_extension_activate_gracefully (app, extension_path, "libtabby." G_MODULE_SUFFIX, activate)); |
1311 | 566 | g_assert (midori_extension_activate_gracefully (app, extension_path, "libopen-with." G_MODULE_SUFFIX, activate)); | ||
1312 | 566 | g_assert (midori_extension_activate_gracefully (app, extension_path, "libflummi." G_MODULE_SUFFIX, activate)); | 567 | g_assert (midori_extension_activate_gracefully (app, extension_path, "libflummi." G_MODULE_SUFFIX, activate)); |
1313 | 567 | } | 568 | } |
1314 | 568 | else | 569 | else |
1315 | @@ -679,6 +680,7 @@ | |||
1316 | 679 | && strcmp (filename, "libapps." G_MODULE_SUFFIX) | 680 | && strcmp (filename, "libapps." G_MODULE_SUFFIX) |
1317 | 680 | && strcmp (filename, "libdelayed-load." G_MODULE_SUFFIX) | 681 | && strcmp (filename, "libdelayed-load." G_MODULE_SUFFIX) |
1318 | 681 | && strcmp (filename, "libtabby." G_MODULE_SUFFIX) | 682 | && strcmp (filename, "libtabby." G_MODULE_SUFFIX) |
1319 | 683 | && strcmp (filename, "libopen-with." G_MODULE_SUFFIX) | ||
1320 | 682 | && strcmp (filename, "libflummi." G_MODULE_SUFFIX)) | 684 | && strcmp (filename, "libflummi." G_MODULE_SUFFIX)) |
1321 | 683 | katze_array_add_item (extensions, extension); | 685 | katze_array_add_item (extensions, extension); |
1322 | 684 | 686 | ||
1323 | 685 | 687 | ||
1324 | === modified file 'midori/midori-frontend.c' | |||
1325 | --- midori/midori-frontend.c 2013-11-29 16:29:02 +0000 | |||
1326 | +++ midori/midori-frontend.c 2014-02-25 19:27:20 +0000 | |||
1327 | @@ -239,6 +239,7 @@ | |||
1328 | 239 | 239 | ||
1329 | 240 | /* FIXME need proper stock extension mechanism */ | 240 | /* FIXME need proper stock extension mechanism */ |
1330 | 241 | midori_browser_activate_action (browser, "libtransfers." G_MODULE_SUFFIX "=true"); | 241 | midori_browser_activate_action (browser, "libtransfers." G_MODULE_SUFFIX "=true"); |
1331 | 242 | midori_browser_activate_action (browser, "libopen-with." G_MODULE_SUFFIX "=true"); | ||
1332 | 242 | g_assert (g_module_error () == NULL); | 243 | g_assert (g_module_error () == NULL); |
1333 | 243 | 244 | ||
1334 | 244 | return browser; | 245 | return browser; |
1335 | @@ -301,7 +302,7 @@ | |||
1336 | 301 | gchar* crash_log) | 302 | gchar* crash_log) |
1337 | 302 | { | 303 | { |
1338 | 303 | GError* error = NULL; | 304 | GError* error = NULL; |
1340 | 304 | if (!sokoke_show_uri (gtk_widget_get_screen (button), crash_log, 0, &error)) | 305 | if (!gtk_show_uri (gtk_widget_get_screen (button), crash_log, 0, &error)) |
1341 | 305 | { | 306 | { |
1342 | 306 | sokoke_message_dialog (GTK_MESSAGE_ERROR, | 307 | sokoke_message_dialog (GTK_MESSAGE_ERROR, |
1343 | 307 | _("Could not run external program."), | 308 | _("Could not run external program."), |
1344 | 308 | 309 | ||
1345 | === modified file 'midori/midori-preferences.c' | |||
1346 | --- midori/midori-preferences.c 2013-12-09 11:40:39 +0000 | |||
1347 | +++ midori/midori-preferences.c 2014-02-25 19:27:20 +0000 | |||
1348 | @@ -490,18 +490,6 @@ | |||
1349 | 490 | gtk_button_set_label (GTK_BUTTON (button), _("Open tabs in the background")); | 490 | gtk_button_set_label (GTK_BUTTON (button), _("Open tabs in the background")); |
1350 | 491 | SPANNED_ADD (button); | 491 | SPANNED_ADD (button); |
1351 | 492 | 492 | ||
1352 | 493 | INDENTED_ADD (gtk_label_new (NULL)); | ||
1353 | 494 | label = gtk_label_new (_("Text Editor")); | ||
1354 | 495 | gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); | ||
1355 | 496 | INDENTED_ADD (label); | ||
1356 | 497 | entry = katze_property_proxy (settings, "text-editor", "application-text/plain"); | ||
1357 | 498 | SPANNED_ADD (entry); | ||
1358 | 499 | label = gtk_label_new (_("News Aggregator")); | ||
1359 | 500 | gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); | ||
1360 | 501 | INDENTED_ADD (label); | ||
1361 | 502 | entry = katze_property_proxy (settings, "news-aggregator", "application-News"); | ||
1362 | 503 | SPANNED_ADD (entry); | ||
1363 | 504 | |||
1364 | 505 | /* Page "Network" */ | 493 | /* Page "Network" */ |
1365 | 506 | PAGE_NEW (GTK_STOCK_NETWORK, _("Network")); | 494 | PAGE_NEW (GTK_STOCK_NETWORK, _("Network")); |
1366 | 507 | FRAME_NEW (NULL); | 495 | FRAME_NEW (NULL); |
1367 | 508 | 496 | ||
1368 | === modified file 'midori/midori-tab.vala' | |||
1369 | --- midori/midori-tab.vala 2013-12-09 20:23:03 +0000 | |||
1370 | +++ midori/midori-tab.vala 2014-02-25 19:27:20 +0000 | |||
1371 | @@ -88,6 +88,8 @@ | |||
1372 | 88 | } | 88 | } |
1373 | 89 | } | 89 | } |
1374 | 90 | 90 | ||
1375 | 91 | /* Since: 0.5.8 */ | ||
1376 | 92 | public signal bool open_uri (string uri); | ||
1377 | 91 | public signal void console_message (string message, int line, string source_id); | 93 | public signal void console_message (string message, int line, string source_id); |
1378 | 92 | public signal void attach_inspector (WebKit.WebView inspector_view); | 94 | public signal void attach_inspector (WebKit.WebView inspector_view); |
1379 | 93 | /* Emitted when an open inspector that was previously | 95 | /* Emitted when an open inspector that was previously |
1380 | 94 | 96 | ||
1381 | === modified file 'midori/midori-view.c' | |||
1382 | --- midori/midori-view.c 2013-12-09 20:23:03 +0000 | |||
1383 | +++ midori/midori-view.c 2014-02-25 19:27:20 +0000 | |||
1384 | @@ -558,19 +558,6 @@ | |||
1385 | 558 | g_free (new_uri); | 558 | g_free (new_uri); |
1386 | 559 | return TRUE; | 559 | return TRUE; |
1387 | 560 | } | 560 | } |
1388 | 561 | else if (sokoke_external_uri (uri)) | ||
1389 | 562 | { | ||
1390 | 563 | if (sokoke_show_uri (gtk_widget_get_screen (GTK_WIDGET (web_view)), | ||
1391 | 564 | uri, GDK_CURRENT_TIME, NULL)) | ||
1392 | 565 | { | ||
1393 | 566 | #ifdef HAVE_WEBKIT2 | ||
1394 | 567 | webkit_policy_decision_ignore (decision); | ||
1395 | 568 | #else | ||
1396 | 569 | webkit_web_policy_decision_ignore (decision); | ||
1397 | 570 | #endif | ||
1398 | 571 | return TRUE; | ||
1399 | 572 | } | ||
1400 | 573 | } | ||
1401 | 574 | else if (g_str_has_prefix (uri, "data:image/")) | 561 | else if (g_str_has_prefix (uri, "data:image/")) |
1402 | 575 | { | 562 | { |
1403 | 576 | /* For security reasons, main content served as data: is limited to images | 563 | /* For security reasons, main content served as data: is limited to images |
1404 | @@ -2109,16 +2096,6 @@ | |||
1405 | 2109 | } | 2096 | } |
1406 | 2110 | 2097 | ||
1407 | 2111 | static void | 2098 | static void |
1408 | 2112 | midori_web_view_open_in_viewer_cb (GtkAction* action, | ||
1409 | 2113 | gpointer user_data) | ||
1410 | 2114 | { | ||
1411 | 2115 | MidoriView* view = user_data; | ||
1412 | 2116 | gchar* uri = katze_object_get_string (view->hit_test, "image-uri"); | ||
1413 | 2117 | midori_view_download_uri (view, MIDORI_DOWNLOAD_OPEN_IN_VIEWER, uri); | ||
1414 | 2118 | g_free (uri); | ||
1415 | 2119 | } | ||
1416 | 2120 | |||
1417 | 2121 | static void | ||
1418 | 2122 | midori_web_view_menu_video_copy_activate_cb (GtkAction* action, | 2099 | midori_web_view_menu_video_copy_activate_cb (GtkAction* action, |
1419 | 2123 | gpointer user_data) | 2100 | gpointer user_data) |
1420 | 2124 | { | 2101 | { |
1421 | @@ -2146,8 +2123,8 @@ | |||
1422 | 2146 | MidoriView* view = user_data; | 2123 | MidoriView* view = user_data; |
1423 | 2147 | gchar* data = (gchar*)g_object_get_data (G_OBJECT (action), "uri"); | 2124 | gchar* data = (gchar*)g_object_get_data (G_OBJECT (action), "uri"); |
1424 | 2148 | gchar* uri = g_strconcat ("mailto:", data, NULL); | 2125 | gchar* uri = g_strconcat ("mailto:", data, NULL); |
1427 | 2149 | sokoke_show_uri (gtk_widget_get_screen (view->web_view), | 2126 | gboolean handled = FALSE; |
1428 | 2150 | uri, GDK_CURRENT_TIME, NULL); | 2127 | g_signal_emit_by_name (view, "open-uri", uri, &handled); |
1429 | 2151 | g_free (uri); | 2128 | g_free (uri); |
1430 | 2152 | } | 2129 | } |
1431 | 2153 | #endif | 2130 | #endif |
1432 | @@ -2358,8 +2335,6 @@ | |||
1433 | 2358 | midori_web_view_menu_image_copy_activate_cb, view); | 2335 | midori_web_view_menu_image_copy_activate_cb, view); |
1434 | 2359 | midori_context_action_add_simple (menu, "SaveImage", _("Save I_mage"), NULL, GTK_STOCK_SAVE, | 2336 | midori_context_action_add_simple (menu, "SaveImage", _("Save I_mage"), NULL, GTK_STOCK_SAVE, |
1435 | 2360 | midori_web_view_menu_image_save_activate_cb, view); | 2337 | midori_web_view_menu_image_save_activate_cb, view); |
1436 | 2361 | midori_context_action_add_simple (menu, "OpenImageInViewer", _("Open in Image _Viewer"), NULL, GTK_STOCK_OPEN, | ||
1437 | 2362 | midori_web_view_open_in_viewer_cb, view); | ||
1438 | 2363 | } | 2338 | } |
1439 | 2364 | 2339 | ||
1440 | 2365 | if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA) | 2340 | if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA) |
1441 | @@ -4013,12 +3988,19 @@ | |||
1442 | 4013 | g_free (exception); | 3988 | g_free (exception); |
1443 | 4014 | } | 3989 | } |
1444 | 4015 | } | 3990 | } |
1445 | 4016 | else if (sokoke_external_uri (uri)) | ||
1446 | 4017 | { | ||
1447 | 4018 | sokoke_show_uri (NULL, uri, GDK_CURRENT_TIME, NULL); | ||
1448 | 4019 | } | ||
1449 | 4020 | else | 3991 | else |
1450 | 4021 | { | 3992 | { |
1451 | 3993 | if (sokoke_external_uri (uri)) | ||
1452 | 3994 | { | ||
1453 | 3995 | gboolean handled = FALSE; | ||
1454 | 3996 | g_signal_emit_by_name (view, "open-uri", uri, &handled); | ||
1455 | 3997 | if (handled) | ||
1456 | 3998 | { | ||
1457 | 3999 | g_free (temporary_uri); | ||
1458 | 4000 | return; | ||
1459 | 4001 | } | ||
1460 | 4002 | } | ||
1461 | 4003 | |||
1462 | 4022 | midori_tab_set_uri (MIDORI_TAB (view), uri); | 4004 | midori_tab_set_uri (MIDORI_TAB (view), uri); |
1463 | 4023 | katze_item_set_uri (view->item, midori_tab_get_uri (MIDORI_TAB (view))); | 4005 | katze_item_set_uri (view->item, midori_tab_get_uri (MIDORI_TAB (view))); |
1464 | 4024 | katze_assign (view->title, NULL); | 4006 | katze_assign (view->title, NULL); |
1465 | 4025 | 4007 | ||
1466 | === modified file 'midori/midori.vapi' | |||
1467 | --- midori/midori.vapi 2014-01-30 21:43:31 +0000 | |||
1468 | +++ midori/midori.vapi 2014-02-25 19:27:20 +0000 | |||
1469 | @@ -118,6 +118,7 @@ | |||
1470 | 118 | public signal void quit (); | 118 | public signal void quit (); |
1471 | 119 | public signal void send_notification (string title, string message); | 119 | public signal void send_notification (string title, string message); |
1472 | 120 | public static void update_history (Katze.Item item, string type, string event); | 120 | public static void update_history (Katze.Item item, string type, string event); |
1473 | 121 | public signal void show_preferences (Katze.Preferences preferences); | ||
1474 | 121 | } | 122 | } |
1475 | 122 | 123 | ||
1476 | 123 | [CCode (cheader_filename = "midori/midori.h")] | 124 | [CCode (cheader_filename = "midori/midori.h")] |
1477 | 124 | 125 | ||
1478 | === modified file 'midori/sokoke.c' | |||
1479 | --- midori/sokoke.c 2013-10-28 23:36:29 +0000 | |||
1480 | +++ midori/sokoke.c 2014-02-25 19:27:20 +0000 | |||
1481 | @@ -37,6 +37,7 @@ | |||
1482 | 37 | #ifdef G_OS_WIN32 | 37 | #ifdef G_OS_WIN32 |
1483 | 38 | #include <windows.h> | 38 | #include <windows.h> |
1484 | 39 | #include <shlobj.h> | 39 | #include <shlobj.h> |
1485 | 40 | #include <gdk/gdkwin32.h> | ||
1486 | 40 | #endif | 41 | #endif |
1487 | 41 | 42 | ||
1488 | 42 | static gchar* | 43 | static gchar* |
1489 | @@ -109,39 +110,8 @@ | |||
1490 | 109 | const gchar* detailed_message, | 110 | const gchar* detailed_message, |
1491 | 110 | gboolean modal) | 111 | gboolean modal) |
1492 | 111 | { | 112 | { |
1526 | 112 | GtkWidget* dialog = gtk_message_dialog_new ( | 113 | midori_show_message_dialog (message_type, short_message, detailed_message, modal); |
1527 | 113 | NULL, 0, message_type, GTK_BUTTONS_OK, "%s", short_message); | 114 | } |
1495 | 114 | gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), | ||
1496 | 115 | "%s", detailed_message); | ||
1497 | 116 | if (modal) | ||
1498 | 117 | { | ||
1499 | 118 | gtk_dialog_run (GTK_DIALOG (dialog)); | ||
1500 | 119 | gtk_widget_destroy (dialog); | ||
1501 | 120 | } | ||
1502 | 121 | else | ||
1503 | 122 | { | ||
1504 | 123 | g_signal_connect_swapped (dialog, "response", | ||
1505 | 124 | G_CALLBACK (gtk_widget_destroy), dialog); | ||
1506 | 125 | gtk_widget_show (dialog); | ||
1507 | 126 | } | ||
1508 | 127 | |||
1509 | 128 | } | ||
1510 | 129 | |||
1511 | 130 | #ifndef G_OS_WIN32 | ||
1512 | 131 | static void | ||
1513 | 132 | sokoke_open_with_response_cb (GtkWidget* dialog, | ||
1514 | 133 | gint response, | ||
1515 | 134 | GtkEntry* entry) | ||
1516 | 135 | { | ||
1517 | 136 | if (response == GTK_RESPONSE_ACCEPT) | ||
1518 | 137 | { | ||
1519 | 138 | const gchar* command = gtk_entry_get_text (entry); | ||
1520 | 139 | const gchar* uri = g_object_get_data (G_OBJECT (dialog), "uri"); | ||
1521 | 140 | sokoke_spawn_program (command, FALSE, uri, TRUE, FALSE); | ||
1522 | 141 | } | ||
1523 | 142 | gtk_widget_destroy (dialog); | ||
1524 | 143 | } | ||
1525 | 144 | #endif | ||
1528 | 145 | 115 | ||
1529 | 146 | GAppInfo* | 116 | GAppInfo* |
1530 | 147 | sokoke_default_for_uri (const gchar* uri, | 117 | sokoke_default_for_uri (const gchar* uri, |
1531 | @@ -164,86 +134,6 @@ | |||
1532 | 164 | } | 134 | } |
1533 | 165 | 135 | ||
1534 | 166 | /** | 136 | /** |
1535 | 167 | * sokoke_show_uri: | ||
1536 | 168 | * @screen: a #GdkScreen, or %NULL | ||
1537 | 169 | * @uri: the URI to show | ||
1538 | 170 | * @timestamp: the timestamp of the event | ||
1539 | 171 | * @error: the location of a #GError, or %NULL | ||
1540 | 172 | * | ||
1541 | 173 | * Shows the specified URI with an application or xdg-open. | ||
1542 | 174 | * x-scheme-handler is supported for GLib < 2.28 as of 0.3.3. | ||
1543 | 175 | * | ||
1544 | 176 | * Return value: %TRUE on success, %FALSE if an error occurred | ||
1545 | 177 | **/ | ||
1546 | 178 | gboolean | ||
1547 | 179 | sokoke_show_uri (GdkScreen* screen, | ||
1548 | 180 | const gchar* uri, | ||
1549 | 181 | guint32 timestamp, | ||
1550 | 182 | GError** error) | ||
1551 | 183 | { | ||
1552 | 184 | #ifdef G_OS_WIN32 | ||
1553 | 185 | CoInitializeEx (NULL, COINIT_APARTMENTTHREADED); | ||
1554 | 186 | SHELLEXECUTEINFO info = { sizeof (info) }; | ||
1555 | 187 | info.nShow = SW_SHOWNORMAL; | ||
1556 | 188 | info.lpFile = uri; | ||
1557 | 189 | |||
1558 | 190 | return ShellExecuteEx (&info); | ||
1559 | 191 | #else | ||
1560 | 192 | |||
1561 | 193 | GtkWidget* dialog; | ||
1562 | 194 | GtkWidget* box; | ||
1563 | 195 | gchar* filename; | ||
1564 | 196 | gchar* ms; | ||
1565 | 197 | GtkWidget* entry; | ||
1566 | 198 | |||
1567 | 199 | g_return_val_if_fail (GDK_IS_SCREEN (screen) || !screen, FALSE); | ||
1568 | 200 | g_return_val_if_fail (uri != NULL, FALSE); | ||
1569 | 201 | g_return_val_if_fail (!error || !*error, FALSE); | ||
1570 | 202 | |||
1571 | 203 | sokoke_recursive_fork_protection (uri, TRUE); | ||
1572 | 204 | |||
1573 | 205 | /* g_app_info_launch_default_for_uri, gdk_display_get_app_launch_context */ | ||
1574 | 206 | if (gtk_show_uri (screen, uri, timestamp, error)) | ||
1575 | 207 | return TRUE; | ||
1576 | 208 | |||
1577 | 209 | { | ||
1578 | 210 | gchar* command = g_strconcat ("xdg-open ", uri, NULL); | ||
1579 | 211 | gboolean result = g_spawn_command_line_async (command, error); | ||
1580 | 212 | g_free (command); | ||
1581 | 213 | if (result) | ||
1582 | 214 | return TRUE; | ||
1583 | 215 | if (error) | ||
1584 | 216 | *error = NULL; | ||
1585 | 217 | } | ||
1586 | 218 | |||
1587 | 219 | dialog = gtk_dialog_new_with_buttons (_("Open with"), NULL, 0, | ||
1588 | 220 | GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | ||
1589 | 221 | GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); | ||
1590 | 222 | box = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); | ||
1591 | 223 | if (g_str_has_prefix (uri, "file:///")) | ||
1592 | 224 | filename = g_filename_from_uri (uri, NULL, NULL); | ||
1593 | 225 | else | ||
1594 | 226 | filename = g_strdup (uri); | ||
1595 | 227 | ms = g_strdup_printf (_("Choose an application or command to open \"%s\":"), | ||
1596 | 228 | filename); | ||
1597 | 229 | gtk_box_pack_start (GTK_BOX (box), gtk_label_new (ms), TRUE, FALSE, 4); | ||
1598 | 230 | g_free (ms); | ||
1599 | 231 | entry = gtk_entry_new (); | ||
1600 | 232 | gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); | ||
1601 | 233 | gtk_box_pack_start (GTK_BOX (box), entry, TRUE, FALSE, 4); | ||
1602 | 234 | g_signal_connect (dialog, "response", | ||
1603 | 235 | G_CALLBACK (sokoke_open_with_response_cb), entry); | ||
1604 | 236 | g_object_set_data_full (G_OBJECT (dialog), "uri", | ||
1605 | 237 | filename, (GDestroyNotify)g_free); | ||
1606 | 238 | gtk_widget_show_all (dialog); | ||
1607 | 239 | gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); | ||
1608 | 240 | gtk_widget_grab_focus (entry); | ||
1609 | 241 | |||
1610 | 242 | return TRUE; | ||
1611 | 243 | #endif | ||
1612 | 244 | } | ||
1613 | 245 | |||
1614 | 246 | /** | ||
1615 | 247 | * sokoke_prepare_command: | 137 | * sokoke_prepare_command: |
1616 | 248 | * @command: the command, properly quoted | 138 | * @command: the command, properly quoted |
1617 | 249 | * @argument: any arguments, properly quoted | 139 | * @argument: any arguments, properly quoted |
1618 | @@ -919,36 +809,6 @@ | |||
1619 | 919 | #endif | 809 | #endif |
1620 | 920 | } | 810 | } |
1621 | 921 | 811 | ||
1622 | 922 | /** | ||
1623 | 923 | * sokoke_recursive_fork_protection | ||
1624 | 924 | * @uri: the URI to check | ||
1625 | 925 | * @set_uri: if TRUE the URI will be saved | ||
1626 | 926 | * | ||
1627 | 927 | * Protects against recursive invokations of the Midori executable | ||
1628 | 928 | * with the same URI. | ||
1629 | 929 | * | ||
1630 | 930 | * As an example, consider having an URI starting with 'tel://'. You | ||
1631 | 931 | * could attempt to open it with sokoke_show_uri. In turn, 'exo-open' | ||
1632 | 932 | * might be called. Now quite possibly 'exo-open' is unable to handle | ||
1633 | 933 | * 'tel://' and might well fall back to 'midori' as default browser. | ||
1634 | 934 | * | ||
1635 | 935 | * To protect against this scenario, call this function with the | ||
1636 | 936 | * URI and %TRUE before calling any external tool. | ||
1637 | 937 | * #MidoriApp calls sokoke_recursive_fork_protection() with %FALSE | ||
1638 | 938 | * and bails out if %FALSE is returned. | ||
1639 | 939 | * | ||
1640 | 940 | * Return value: %TRUE if @uri is new, %FALSE on recursion | ||
1641 | 941 | **/ | ||
1642 | 942 | gboolean | ||
1643 | 943 | sokoke_recursive_fork_protection (const gchar* uri, | ||
1644 | 944 | gboolean set_uri) | ||
1645 | 945 | { | ||
1646 | 946 | static gchar* fork_uri = NULL; | ||
1647 | 947 | if (set_uri) | ||
1648 | 948 | katze_assign (fork_uri, g_strdup (uri)); | ||
1649 | 949 | return g_strcmp0 (fork_uri, uri) == 0 ? FALSE : TRUE; | ||
1650 | 950 | } | ||
1651 | 951 | |||
1652 | 952 | static void | 812 | static void |
1653 | 953 | sokoke_widget_clipboard_owner_clear_func (GtkClipboard* clipboard, | 813 | sokoke_widget_clipboard_owner_clear_func (GtkClipboard* clipboard, |
1654 | 954 | gpointer user_data) | 814 | gpointer user_data) |
1655 | @@ -1121,4 +981,23 @@ | |||
1656 | 1121 | g_free (lnk_path); | 981 | g_free (lnk_path); |
1657 | 1122 | g_free (launcher_type); | 982 | g_free (launcher_type); |
1658 | 1123 | } | 983 | } |
1659 | 984 | |||
1660 | 985 | GdkPixbuf* | ||
1661 | 986 | sokoke_get_gdk_pixbuf_from_win32_executable (gchar* path) | ||
1662 | 987 | { | ||
1663 | 988 | if (path == NULL) | ||
1664 | 989 | return NULL; | ||
1665 | 990 | |||
1666 | 991 | GdkPixbuf* pixbuf = NULL; | ||
1667 | 992 | HICON hIcon = NULL; | ||
1668 | 993 | HINSTANCE hInstance = NULL; | ||
1669 | 994 | hIcon = ExtractIcon (hInstance, (LPCSTR)path, 0); | ||
1670 | 995 | if (hIcon == NULL) | ||
1671 | 996 | return NULL; | ||
1672 | 997 | |||
1673 | 998 | pixbuf = gdk_win32_icon_to_pixbuf_libgtk_only (hIcon, NULL, NULL); | ||
1674 | 999 | DestroyIcon (hIcon); | ||
1675 | 1000 | |||
1676 | 1001 | return pixbuf; | ||
1677 | 1002 | } | ||
1678 | 1124 | #endif | 1003 | #endif |
1679 | 1125 | 1004 | ||
1680 | === modified file 'midori/sokoke.h' | |||
1681 | --- midori/sokoke.h 2013-08-02 16:40:27 +0000 | |||
1682 | +++ midori/sokoke.h 2014-02-25 19:27:20 +0000 | |||
1683 | @@ -29,19 +29,6 @@ | |||
1684 | 29 | const gchar* detailed_message, | 29 | const gchar* detailed_message, |
1685 | 30 | gboolean modal); | 30 | gboolean modal); |
1686 | 31 | 31 | ||
1687 | 32 | gboolean | ||
1688 | 33 | sokoke_show_uri_with_mime_type (GdkScreen* screen, | ||
1689 | 34 | const gchar* uri, | ||
1690 | 35 | const gchar* mime_type, | ||
1691 | 36 | guint32 timestamp, | ||
1692 | 37 | GError** error); | ||
1693 | 38 | |||
1694 | 39 | gboolean | ||
1695 | 40 | sokoke_show_uri (GdkScreen* screen, | ||
1696 | 41 | const gchar* uri, | ||
1697 | 42 | guint32 timestamp, | ||
1698 | 43 | GError** error); | ||
1699 | 44 | |||
1700 | 45 | gchar* | 32 | gchar* |
1701 | 46 | sokoke_prepare_command (const gchar* command, | 33 | sokoke_prepare_command (const gchar* command, |
1702 | 47 | gboolean quote_command, | 34 | gboolean quote_command, |
1703 | @@ -112,10 +99,6 @@ | |||
1704 | 112 | gboolean | 99 | gboolean |
1705 | 113 | sokoke_resolve_hostname (const gchar* hostname); | 100 | sokoke_resolve_hostname (const gchar* hostname); |
1706 | 114 | 101 | ||
1707 | 115 | gboolean | ||
1708 | 116 | sokoke_recursive_fork_protection (const gchar* uri, | ||
1709 | 117 | gboolean set_uri); | ||
1710 | 118 | |||
1711 | 119 | void | 102 | void |
1712 | 120 | sokoke_widget_copy_clipboard (GtkWidget* widget, | 103 | sokoke_widget_copy_clipboard (GtkWidget* widget, |
1713 | 121 | const gchar* text, | 104 | const gchar* text, |
1714 | 122 | 105 | ||
1715 | === modified file 'po/POTFILES.in' | |||
1716 | --- po/POTFILES.in 2014-02-20 20:30:42 +0000 | |||
1717 | +++ po/POTFILES.in 2014-02-25 19:27:20 +0000 | |||
1718 | @@ -45,6 +45,7 @@ | |||
1719 | 45 | extensions/delayed-load.vala | 45 | extensions/delayed-load.vala |
1720 | 46 | extensions/devpet.vala | 46 | extensions/devpet.vala |
1721 | 47 | extensions/external-download-manager.vala | 47 | extensions/external-download-manager.vala |
1722 | 48 | extensions/open-with.vala | ||
1723 | 48 | extensions/feed-panel/feed-atom.c | 49 | extensions/feed-panel/feed-atom.c |
1724 | 49 | extensions/feed-panel/feed-panel.c | 50 | extensions/feed-panel/feed-panel.c |
1725 | 50 | extensions/feed-panel/feed-parse.c | 51 | extensions/feed-panel/feed-parse.c |