Merge lp:~midori/midori/openWith into lp:midori

Proposed by Cris Dywan
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
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

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
=== modified file 'extensions/addons.c'
--- extensions/addons.c 2013-06-21 23:18:01 +0000
+++ extensions/addons.c 2014-02-25 19:27:20 +0000
@@ -485,8 +485,8 @@
485 else485 else
486 {486 {
487 gchar* element_uri = g_filename_to_uri (element->fullpath, NULL, NULL);487 gchar* element_uri = g_filename_to_uri (element->fullpath, NULL, NULL);
488 sokoke_show_uri (NULL, element_uri,488 gboolean handled = FALSE;
489 gtk_get_current_event_time (), NULL);489 g_signal_emit_by_name (midori_browser_get_current_tab (browser), "open-uri", element_uri, &handled);
490 g_free (element_uri);490 g_free (element_uri);
491 }491 }
492492
@@ -522,8 +522,9 @@
522 folder_uri = g_filename_to_uri (folder, NULL, NULL);522 folder_uri = g_filename_to_uri (folder, NULL, NULL);
523 g_free (folder);523 g_free (folder);
524524
525 sokoke_show_uri (gtk_widget_get_screen (GTK_WIDGET (addons->treeview)),525 MidoriBrowser* browser = midori_browser_get_for_widget (addons->treeview);
526 folder_uri, gtk_get_current_event_time (), NULL);526 gboolean handled = FALSE;
527 g_signal_emit_by_name (midori_browser_get_current_tab (browser), "open-uri", folder_uri, &handled);
527 g_free (folder_uri);528 g_free (folder_uri);
528}529}
529530
530531
=== added file 'extensions/open-with.vala'
--- extensions/open-with.vala 1970-01-01 00:00:00 +0000
+++ extensions/open-with.vala 2014-02-25 19:27:20 +0000
@@ -0,0 +1,802 @@
1/*
2 Copyright (C) 2014 Christian Dywan <christian@twotoasts.de>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 See the file COPYING for the full license text.
10*/
11
12#if HAVE_WIN32
13namespace Sokoke {
14 extern static Gdk.Pixbuf get_gdk_pixbuf_from_win32_executable (string path);
15}
16#endif
17
18namespace ExternalApplications {
19 bool open_app_info (AppInfo app_info, string uri, string content_type) {
20 Midori.URI.recursive_fork_protection (uri, true);
21
22 try {
23 var uris = new List<File> ();
24 uris.append (File.new_for_uri (uri));
25 app_info.launch (uris, null);
26 new Associations ().remember (content_type, app_info);
27 return true;
28 } catch (Error error) {
29 warning ("Failed to open \"%s\": %s", uri, error.message);
30 return false;
31 }
32 }
33
34 class Associations : Object {
35#if HAVE_WIN32
36 string config_dir;
37 string filename;
38 KeyFile keyfile;
39
40 public Associations () {
41 config_dir = Midori.Paths.get_extension_config_dir ("open-with");
42 filename = Path.build_filename (config_dir, "config");
43 keyfile = new KeyFile ();
44
45 try {
46 keyfile.load_from_file (filename, KeyFileFlags.NONE);
47 } catch (FileError.NOENT exist_error) {
48 /* It's no error if no config file exists */
49 } catch (Error error) {
50 warning ("Failed to load associations: %s", error.message);
51 }
52 }
53
54 public bool open (string content_type, string uri) {
55 Midori.URI.recursive_fork_protection (uri, true);
56 try {
57 string commandline = keyfile.get_string ("mimes", content_type);
58 if ("%u" in commandline)
59 commandline = commandline.replace ("%u", Shell.quote (uri));
60 else if ("%F" in commandline)
61 commandline = commandline.replace ("%F", Shell.quote (Filename.from_uri (uri)));
62 return Process.spawn_command_line_async (commandline);
63 } catch (KeyFileError error) {
64 /* Not remembered before */
65 return false;
66 } catch (Error error) {
67 warning ("Failed to open \"%s\": %s", uri, error.message);
68 return false;
69 }
70 }
71
72 public void remember (string content_type, AppInfo app_info) throws Error {
73 keyfile.set_string ("mimes", content_type, get_commandline (app_info));
74 FileUtils.set_contents (filename, keyfile.to_data ());
75 }
76
77 public void custom (string content_type, string commandline, string name, string uri) {
78 keyfile.set_string ("mimes", content_type, commandline);
79 try {
80 FileUtils.set_contents (filename, keyfile.to_data ());
81 } catch (Error error) {
82 warning ("Failed to add remember custom command line for \"%s\": %s", uri, error.message);
83 }
84 open (content_type, uri);
85 }
86 }
87#else
88 public Associations () {
89 }
90
91 public bool open (string content_type, string uri) {
92 var app_info = AppInfo.get_default_for_type (content_type, false);
93 if (app_info == null)
94 return false;
95 return open_app_info (app_info, uri, content_type);
96 }
97
98 public void remember (string content_type, AppInfo app_info) throws Error {
99 app_info.set_as_last_used_for_type (content_type);
100 app_info.set_as_default_for_type (content_type);
101 }
102
103 public void custom (string content_type, string commandline, string name, string uri) {
104 try {
105 var app_info = AppInfo.create_from_commandline (commandline, name,
106 "%u" in commandline ? AppInfoCreateFlags.SUPPORTS_URIS : AppInfoCreateFlags.NONE);
107 open_app_info (app_info, uri, content_type);
108 } catch (Error error) {
109 warning ("Failed to add custom command line for \"%s\": %s", uri, error.message);
110 }
111 }
112 }
113#endif
114
115 static string get_commandline (AppInfo app_info) {
116 return app_info.get_commandline () ?? app_info.get_executable ();
117 }
118
119 static string describe_app_info (AppInfo app_info) {
120 string name = app_info.get_display_name () ?? (Path.get_basename (app_info.get_executable ()));
121 string desc = app_info.get_description () ?? get_commandline (app_info);
122 return Markup.printf_escaped ("<b>%s</b>\n%s", name, desc);
123 }
124
125 static Icon? app_info_get_icon (AppInfo app_info) {
126 #if HAVE_WIN32
127 return Sokoke.get_gdk_pixbuf_from_win32_executable (app_info.get_executable ());
128 #else
129 return app_info.get_icon ();
130 #endif
131 }
132
133 class CustomizerDialog : Gtk.Dialog {
134 public Gtk.Entry name_entry;
135 public Gtk.Entry commandline_entry;
136
137 public CustomizerDialog (AppInfo app_info, Gtk.Widget widget) {
138 var browser = Midori.Browser.get_for_widget (widget);
139 transient_for = browser;
140
141 title = _("Custom…");
142#if !HAVE_GTK3
143 has_separator = false;
144#endif
145 destroy_with_parent = true;
146 set_icon_name (Gtk.STOCK_OPEN);
147 resizable = false;
148 add_buttons (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
149 Gtk.STOCK_SAVE, Gtk.ResponseType.ACCEPT);
150
151 var vbox = new Gtk.VBox (false, 8);
152 vbox.border_width = 8;
153 (get_content_area () as Gtk.Box).pack_start (vbox, true, true, 8);
154
155 var sizegroup = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL);
156 var label = new Gtk.Label (_("Name:"));
157 sizegroup.add_widget (label);
158 label.set_alignment (0.0f, 0.5f);
159 vbox.pack_start (label, false, false, 0);
160 name_entry = new Gtk.Entry ();
161 name_entry.activates_default = true;
162 sizegroup.add_widget (name_entry);
163 vbox.pack_start (name_entry, true, true, 0);
164
165 label = new Gtk.Label (_("Command Line:"));
166 sizegroup.add_widget (label);
167 label.set_alignment (0.0f, 0.5f);
168 vbox.pack_start (label, false, false, 0);
169 commandline_entry = new Gtk.Entry ();
170 commandline_entry.activates_default = true;
171 sizegroup.add_widget (name_entry);
172 sizegroup.add_widget (commandline_entry);
173 vbox.pack_start (commandline_entry, true, true, 0);
174 get_content_area ().show_all ();
175 set_default_response (Gtk.ResponseType.ACCEPT);
176
177 name_entry.text = app_info.get_name ();
178 commandline_entry.text = get_commandline (app_info);
179 }
180 }
181
182 private class Chooser : Gtk.VBox {
183 Gtk.ListStore store = new Gtk.ListStore (1, typeof (AppInfo));
184 Gtk.TreeView treeview;
185 List<AppInfo> available;
186 string content_type;
187 string uri;
188
189 public Chooser (string uri, string content_type) {
190 this.content_type = content_type;
191 this.uri = uri;
192
193 Gtk.TreeViewColumn column;
194
195 treeview = new Gtk.TreeView.with_model (store);
196 treeview.headers_visible = false;
197
198 store.set_sort_column_id (0, Gtk.SortType.ASCENDING);
199 store.set_sort_func (0, tree_sort_func);
200
201 column = new Gtk.TreeViewColumn ();
202 Gtk.CellRendererPixbuf renderer_icon = new Gtk.CellRendererPixbuf ();
203 column.pack_start (renderer_icon, false);
204 column.set_cell_data_func (renderer_icon, on_render_icon);
205 treeview.append_column (column);
206
207 column = new Gtk.TreeViewColumn ();
208 column.set_sizing (Gtk.TreeViewColumnSizing.AUTOSIZE);
209 Gtk.CellRendererText renderer_text = new Gtk.CellRendererText ();
210 column.pack_start (renderer_text, true);
211 column.set_expand (true);
212 column.set_cell_data_func (renderer_text, on_render_text);
213 treeview.append_column (column);
214
215 treeview.row_activated.connect (row_activated);
216 treeview.show ();
217 var scrolled = new Gtk.ScrolledWindow (null, null);
218 scrolled.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
219 scrolled.add (treeview);
220 pack_start (scrolled);
221 int height;
222 treeview.create_pango_layout ("a\nb").get_pixel_size (null, out height);
223 scrolled.set_size_request (-1, height * 5);
224 treeview.button_release_event.connect (button_released);
225 treeview.tooltip_text = _("Right-click a suggestion to customize it");
226
227 available = new List<AppInfo> ();
228 foreach (var app_info in AppInfo.get_all_for_type (content_type))
229 launcher_added (app_info, uri);
230
231 if (store.iter_n_children (null) < 1) {
232 foreach (var app_info in AppInfo.get_all ())
233 launcher_added (app_info, uri);
234 }
235 }
236
237 bool button_released (Gdk.EventButton event) {
238 if (event.button == 3)
239 return show_popup_menu (event);
240 return false;
241 }
242
243 bool show_popup_menu (Gdk.EventButton? event) {
244 Gtk.TreeIter iter;
245 if (treeview.get_selection ().get_selected (null, out iter)) {
246 AppInfo app_info;
247 store.get (iter, 0, out app_info);
248
249 var menu = new Gtk.Menu ();
250 var menuitem = new Gtk.ImageMenuItem.with_mnemonic (_("Custom…"));
251 menuitem.image = new Gtk.Image.from_stock (Gtk.STOCK_EDIT, Gtk.IconSize.MENU);
252 menuitem.activate.connect (() => {
253 customize_app_info (app_info, content_type, uri);
254 });
255 menu.append (menuitem);
256 menu.show_all ();
257 Katze.widget_popup (treeview, menu, null, Katze.MenuPos.CURSOR);
258
259 return true;
260 }
261 return false;
262 }
263
264 void customize_app_info (AppInfo app_info, string content_type, string uri) {
265 var dialog = new CustomizerDialog (app_info, this);
266 bool accept = dialog.run () == Gtk.ResponseType.ACCEPT;
267 if (accept) {
268 string name = dialog.name_entry.text;
269 string commandline = dialog.commandline_entry.text;
270 new Associations ().custom (content_type, commandline, name, uri);
271 customized (app_info, content_type, uri);
272 }
273 dialog.destroy ();
274 }
275
276 public List<AppInfo> get_available () {
277 return available.copy ();
278 }
279
280 public AppInfo get_app_info () {
281 Gtk.TreeIter iter;
282 if (treeview.get_selection ().get_selected (null, out iter)) {
283 AppInfo app_info;
284 store.get (iter, 0, out app_info);
285 return app_info;
286 }
287 assert_not_reached ();
288 }
289
290 void on_render_icon (Gtk.CellLayout column, Gtk.CellRenderer renderer,
291 Gtk.TreeModel model, Gtk.TreeIter iter) {
292
293 AppInfo app_info;
294 model.get (iter, 0, out app_info);
295
296 renderer.set ("gicon", app_info_get_icon (app_info),
297 "stock-size", Gtk.IconSize.DIALOG,
298 "xpad", 4);
299 }
300
301 void on_render_text (Gtk.CellLayout column, Gtk.CellRenderer renderer,
302 Gtk.TreeModel model, Gtk.TreeIter iter) {
303
304 AppInfo app_info;
305 model.get (iter, 0, out app_info);
306 renderer.set ("markup", describe_app_info (app_info),
307 "ellipsize", Pango.EllipsizeMode.END);
308 }
309
310 void launcher_added (AppInfo app_info, string uri) {
311 if (!app_info.should_show ())
312 return;
313
314 Gtk.TreeIter iter;
315 store.append (out iter);
316 store.set (iter, 0, app_info);
317
318 available.append (app_info);
319 }
320
321 int tree_sort_func (Gtk.TreeModel model, Gtk.TreeIter a, Gtk.TreeIter b) {
322 AppInfo app_info1, app_info2;
323 model.get (a, 0, out app_info1);
324 model.get (b, 0, out app_info2);
325 return strcmp (app_info1.get_display_name (), app_info2.get_display_name ());
326 }
327
328 void row_activated (Gtk.TreePath path, Gtk.TreeViewColumn column) {
329 Gtk.TreeIter iter;
330 if (store.get_iter (out iter, path)) {
331 AppInfo app_info;
332 store.get (iter, 0, out app_info);
333 selected (app_info);
334 }
335 }
336
337 public signal void selected (AppInfo app_info);
338 public signal void customized (AppInfo app_info, string content_type, string uri);
339 }
340
341 class ChooserDialog : Gtk.Dialog {
342 public Chooser chooser { get; private set; }
343
344 public ChooserDialog (string uri, string content_type, Gtk.Widget widget) {
345 string filename;
346 if (uri.has_prefix ("file://"))
347 filename = Midori.Download.get_basename_for_display (uri);
348 else
349 filename = uri;
350
351 var browser = Midori.Browser.get_for_widget (widget);
352 transient_for = browser;
353
354 title = _("Choose application");
355#if !HAVE_GTK3
356 has_separator = false;
357#endif
358 destroy_with_parent = true;
359 set_icon_name (Gtk.STOCK_OPEN);
360 resizable = false;
361 add_buttons (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
362 Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT);
363
364 var vbox = new Gtk.VBox (false, 8);
365 vbox.border_width = 8;
366 (get_content_area () as Gtk.Box).pack_start (vbox, true, true, 8);
367 var label = new Gtk.Label (_("Select an application to open \"%s\"".printf (filename)));
368 label.ellipsize = Pango.EllipsizeMode.MIDDLE;
369 vbox.pack_start (label, false, false, 0);
370 if (uri == "")
371 label.no_show_all = true;
372 chooser = new Chooser (uri, content_type);
373 vbox.pack_start (chooser, true, true, 0);
374
375 get_content_area ().show_all ();
376 set_default_response (Gtk.ResponseType.ACCEPT);
377 chooser.selected.connect ((app_info) => {
378 response (Gtk.ResponseType.ACCEPT);
379 });
380 chooser.customized.connect ((app_info, content_type, uri) => {
381 response (Gtk.ResponseType.CANCEL);
382 });
383 }
384
385 public AppInfo? open_with () {
386 show ();
387 bool accept = run () == Gtk.ResponseType.ACCEPT;
388 hide ();
389
390 if (!accept)
391 return null;
392 return chooser.get_app_info ();
393 }
394 }
395
396 class ChooserButton : Gtk.Button {
397 public AppInfo? app_info { get; set; }
398 public string? commandline { get; set; }
399 ChooserDialog dialog;
400 Gtk.Label app_name;
401 Gtk.Image icon;
402
403 public ChooserButton (string mime_type, string? commandline) {
404 string content_type = ContentType.from_mime_type (mime_type);
405 dialog = new ChooserDialog ("", content_type, this);
406 app_info = null;
407 foreach (var candidate in dialog.chooser.get_available ()) {
408 if (get_commandline (candidate) == commandline)
409 app_info = candidate;
410 }
411
412 var hbox = new Gtk.HBox (false, 4);
413 icon = new Gtk.Image ();
414 hbox.pack_start (icon, false, false, 0);
415 app_name = new Gtk.Label (null);
416 app_name.use_markup = true;
417 app_name.ellipsize = Pango.EllipsizeMode.END;
418 hbox.pack_start (app_name, true, true, 0);
419 add (hbox);
420 show_all ();
421 update_label ();
422
423 clicked.connect (() => {
424 app_info = dialog.open_with ();
425 string new_commandline = app_info != null ? get_commandline (app_info) : null;
426 commandline = new_commandline;
427 selected (new_commandline);
428 update_label ();
429 });
430 }
431
432 void update_label () {
433 app_name.label = app_info != null ? describe_app_info (app_info).replace ("\n", " ") : _("None");
434 icon.set_from_gicon (app_info != null ? app_info_get_icon (app_info) : null, Gtk.IconSize.BUTTON);
435 }
436
437 public signal void selected (string? commandline);
438 }
439
440 class Types : Gtk.VBox {
441 public Gtk.ListStore store = new Gtk.ListStore (2, typeof (string), typeof (AppInfo));
442 Gtk.TreeView treeview;
443
444 public Types () {
445 Gtk.TreeViewColumn column;
446
447 treeview = new Gtk.TreeView.with_model (store);
448 treeview.headers_visible = false;
449
450 store.set_sort_column_id (0, Gtk.SortType.ASCENDING);
451 store.set_sort_func (0, tree_sort_func);
452
453 column = new Gtk.TreeViewColumn ();
454 column.set_sizing (Gtk.TreeViewColumnSizing.AUTOSIZE);
455 Gtk.CellRendererPixbuf renderer_type_icon = new Gtk.CellRendererPixbuf ();
456 column.pack_start (renderer_type_icon, false);
457 column.set_cell_data_func (renderer_type_icon, on_render_type_icon);
458 treeview.append_column (column);
459
460 column = new Gtk.TreeViewColumn ();
461 column.set_sizing (Gtk.TreeViewColumnSizing.AUTOSIZE);
462 Gtk.CellRendererText renderer_type_text = new Gtk.CellRendererText ();
463 column.pack_start (renderer_type_text, true);
464 column.set_cell_data_func (renderer_type_text, on_render_type_text);
465 treeview.append_column (column);
466
467 column = new Gtk.TreeViewColumn ();
468 column.set_sizing (Gtk.TreeViewColumnSizing.AUTOSIZE);
469 Gtk.CellRendererPixbuf renderer_icon = new Gtk.CellRendererPixbuf ();
470 column.pack_start (renderer_icon, false);
471 column.set_cell_data_func (renderer_icon, on_render_icon);
472 treeview.append_column (column);
473
474 column = new Gtk.TreeViewColumn ();
475 column.set_sizing (Gtk.TreeViewColumnSizing.AUTOSIZE);
476 Gtk.CellRendererText renderer_text = new Gtk.CellRendererText ();
477 column.pack_start (renderer_text, true);
478 column.set_expand (true);
479 column.set_cell_data_func (renderer_text, on_render_text);
480 treeview.append_column (column);
481
482 treeview.row_activated.connect (row_activated);
483 treeview.show ();
484 var scrolled = new Gtk.ScrolledWindow (null, null);
485 scrolled.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
486 scrolled.add (treeview);
487 pack_start (scrolled);
488 int height;
489 treeview.create_pango_layout ("a\nb").get_pixel_size (null, out height);
490 scrolled.set_size_request (-1, height * 5);
491
492 foreach (string content_type in ContentType.list_registered ())
493 launcher_added (content_type);
494 foreach (string scheme in Vfs.get_default ().get_supported_uri_schemes ())
495 launcher_added ("x-scheme-handler/" + scheme);
496
497 treeview.size_allocate.connect_after ((allocation) => {
498 treeview.columns_autosize ();
499 });
500 }
501
502 void on_render_type_icon (Gtk.CellLayout column, Gtk.CellRenderer renderer,
503 Gtk.TreeModel model, Gtk.TreeIter iter) {
504
505 string content_type;
506 store.get (iter, 0, out content_type);
507
508 renderer.set ("gicon", ContentType.get_icon (content_type),
509 "stock-size", Gtk.IconSize.BUTTON,
510 "xpad", 4);
511 }
512
513 void on_render_type_text (Gtk.CellLayout column, Gtk.CellRenderer renderer,
514 Gtk.TreeModel model, Gtk.TreeIter iter) {
515
516 string content_type;
517 AppInfo app_info;
518 store.get (iter, 0, out content_type, 1, out app_info);
519
520 string desc, mime_type;
521 if (content_type.has_prefix ("x-scheme-handler/")) {
522 desc = content_type.split ("/")[1] + "://";
523 mime_type = "";
524 } else {
525 desc = ContentType.get_description (content_type);
526 mime_type = ContentType.get_mime_type (content_type);
527 }
528
529 renderer.set ("markup",
530 Markup.printf_escaped ("<b>%s</b>\n%s",
531 desc, mime_type),
532#if HAVE_GTK3
533 "max-width-chars", 30,
534#else
535 "width-chars", 30,
536#endif
537 "ellipsize", Pango.EllipsizeMode.END);
538 }
539
540 void on_render_icon (Gtk.CellLayout column, Gtk.CellRenderer renderer,
541 Gtk.TreeModel model, Gtk.TreeIter iter) {
542
543 AppInfo app_info;
544 model.get (iter, 1, out app_info);
545
546 renderer.set ("gicon", app_info_get_icon (app_info),
547 "stock-size", Gtk.IconSize.MENU,
548 "xpad", 4);
549 }
550
551 void on_render_text (Gtk.CellLayout column, Gtk.CellRenderer renderer,
552 Gtk.TreeModel model, Gtk.TreeIter iter) {
553
554 AppInfo app_info;
555 model.get (iter, 1, out app_info);
556 renderer.set ("markup", describe_app_info (app_info),
557 "ellipsize", Pango.EllipsizeMode.END);
558 }
559
560 void launcher_added (string content_type) {
561 var app_info = AppInfo.get_default_for_type (content_type, false);
562 if (app_info == null)
563 return;
564
565 Gtk.TreeIter iter;
566 store.append (out iter);
567 store.set (iter, 0, content_type, 1, app_info);
568 }
569
570 int tree_sort_func (Gtk.TreeModel model, Gtk.TreeIter a, Gtk.TreeIter b) {
571 string content_type1, content_type2;
572 model.get (a, 0, out content_type1);
573 model.get (b, 0, out content_type2);
574 return strcmp (content_type1, content_type2);
575 }
576
577 void row_activated (Gtk.TreePath path, Gtk.TreeViewColumn column) {
578 Gtk.TreeIter iter;
579 if (store.get_iter (out iter, path)) {
580 string content_type;
581 store.get (iter, 0, out content_type);
582 selected (content_type, iter);
583 }
584 }
585
586 public signal void selected (string content_type, Gtk.TreeIter iter);
587 }
588
589
590 private class Manager : Midori.Extension {
591 enum NextStep {
592 TRY_OPEN,
593 OPEN_WITH
594 }
595
596 bool open_uri (Midori.Tab tab, string uri) {
597 return open_with_type (uri, get_content_type (uri, null), tab, NextStep.TRY_OPEN);
598 }
599
600 bool navigation_requested (WebKit.WebView web_view, WebKit.WebFrame frame, WebKit.NetworkRequest request,
601 WebKit.WebNavigationAction action, WebKit.WebPolicyDecision decision) {
602
603 string uri = request.uri;
604 if (Midori.URI.is_http (uri) || Midori.URI.is_blank (uri))
605 return false;
606
607 decision.ignore ();
608
609 string content_type = get_content_type (uri, null);
610 open_with_type (uri, content_type, web_view, NextStep.TRY_OPEN);
611 return true;
612 }
613
614 string get_content_type (string uri, string? mime_type) {
615 if (!uri.has_prefix ("file://") && !Midori.URI.is_http (uri)) {
616 string protocol = uri.split(":", 2)[0];
617 return "x-scheme-handler/" + protocol;
618 } else if (mime_type == null) {
619 string filename;
620 bool uncertain;
621 try {
622 filename = Filename.from_uri (uri);
623 } catch (Error error) {
624 filename = uri;
625 }
626 return ContentType.guess (filename, null, out uncertain);
627 }
628 return ContentType.from_mime_type (mime_type);
629 }
630
631 bool open_with_type (string uri, string content_type, Gtk.Widget widget, NextStep next_step) {
632 #if HAVE_WEBKIT2
633 return open_now (uri, content_type, widget, next_step);
634 #else
635 if (!Midori.URI.is_http (uri))
636 return open_now (uri, content_type, widget, next_step);
637
638 var download = new WebKit.Download (new WebKit.NetworkRequest (uri));
639 download.destination_uri = Midori.Download.prepare_destination_uri (download, null);
640 if (!Midori.Download.has_enough_space (download, download.destination_uri))
641 return false;
642
643 download.notify["status"].connect ((pspec) => {
644 if (download.status == WebKit.DownloadStatus.FINISHED) {
645 open_now (download.destination_uri, content_type, widget, next_step);
646 }
647 else if (download.status == WebKit.DownloadStatus.ERROR)
648 Midori.show_message_dialog (Gtk.MessageType.ERROR,
649 _("Error downloading the image!"),
650 _("Can not download selected image."), false);
651 });
652 download.start ();
653 return true;
654 #endif
655 }
656
657 bool open_now (string uri, string content_type, Gtk.Widget widget, NextStep next_step) {
658 if (next_step == NextStep.TRY_OPEN && (new Associations ()).open (content_type, uri))
659 return true;
660 if (open_with (uri, content_type, widget) != null)
661 return true;
662 return false;
663 }
664
665 AppInfo? open_with (string uri, string content_type, Gtk.Widget widget) {
666 var dialog = new ChooserDialog (uri, content_type, widget);
667
668 var app_info = dialog.open_with ();
669 dialog.destroy ();
670
671 if (uri == "")
672 return app_info;
673
674 if (app_info == null)
675 return app_info;
676
677 return open_app_info (app_info, uri, content_type) ? app_info : null;
678 }
679
680 void context_menu (Midori.Tab tab, WebKit.HitTestResult hit_test_result, Midori.ContextAction menu) {
681 if ((hit_test_result.context & WebKit.HitTestResultContext.LINK) != 0) {
682 string uri = hit_test_result.link_uri;
683 var action = new Gtk.Action ("OpenWith", _("Open _with…"), null, null);
684 action.activate.connect ((action) => {
685 open_with_type (uri, get_content_type (uri, null), tab, NextStep.OPEN_WITH);
686 });
687 menu.add (action);
688 }
689#if !HAVE_WEBKIT2
690 if ((hit_test_result.context & WebKit.HitTestResultContext.IMAGE) != 0) {
691 string uri = hit_test_result.image_uri;
692 var action = new Gtk.Action ("OpenImageInViewer", _("Open in Image _Viewer"), null, null);
693 action.activate.connect ((action) => {
694 open_with_type (uri, get_content_type (uri, null), tab, NextStep.TRY_OPEN);
695 });
696 menu.add (action);
697 }
698#endif
699 }
700
701 void show_preferences (Katze.Preferences preferences) {
702 var settings = get_app ().settings;
703 var category = preferences.add_category (_("File Types"), Gtk.STOCK_FILE);
704 preferences.add_group (null);
705
706 var sizegroup = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL);
707 var label = new Gtk.Label (_("Text Editor"));
708 sizegroup.add_widget (label);
709 label.set_alignment (0.0f, 0.5f);
710 preferences.add_widget (label, "indented");
711 var entry = new ChooserButton ("text/plain", settings.text_editor);
712 sizegroup.add_widget (entry);
713 entry.selected.connect ((commandline) => {
714 settings.text_editor = commandline;
715 });
716 preferences.add_widget (entry, "spanned");
717
718 label = new Gtk.Label (_("News Aggregator"));
719 sizegroup.add_widget (label);
720 label.set_alignment (0.0f, 0.5f);
721 preferences.add_widget (label, "indented");
722 entry = new ChooserButton ("application/rss+xml", settings.news_aggregator);
723 sizegroup.add_widget (entry);
724 entry.selected.connect ((commandline) => {
725 settings.news_aggregator = commandline;
726 });
727 preferences.add_widget (entry, "spanned");
728
729 var types = new Types ();
730 types.selected.connect ((content_type, iter) => {
731 var app_info = open_with ("", content_type, preferences);
732 if (app_info == null)
733 return;
734 try {
735 app_info.set_as_default_for_type (content_type);
736 types.store.set (iter, 1, app_info);
737 } catch (Error error) {
738 warning ("Failed to select default for \"%s\": %s", content_type, error.message);
739 }
740 });
741 category.pack_start (types, true, true, 0);
742 types.show_all ();
743 }
744
745 public void tab_added (Midori.Browser browser, Midori.View view) {
746 view.web_view.navigation_policy_decision_requested.connect (navigation_requested);
747 view.open_uri.connect (open_uri);
748 view.context_menu.connect (context_menu);
749 }
750
751 public void tab_removed (Midori.Browser browser, Midori.View view) {
752 view.web_view.navigation_policy_decision_requested.disconnect (navigation_requested);
753 view.open_uri.disconnect (open_uri);
754 view.context_menu.disconnect (context_menu);
755 }
756
757 void browser_added (Midori.Browser browser) {
758 foreach (var tab in browser.get_tabs ())
759 tab_added (browser, tab);
760 browser.add_tab.connect (tab_added);
761 browser.remove_tab.connect (tab_removed);
762 browser.show_preferences.connect (show_preferences);
763 }
764
765 void activated (Midori.App app) {
766 foreach (var browser in app.get_browsers ())
767 browser_added (browser);
768 app.add_browser.connect (browser_added);
769 }
770
771 void browser_removed (Midori.Browser browser) {
772 foreach (var tab in browser.get_tabs ())
773 tab_removed (browser, tab);
774 browser.add_tab.disconnect (tab_added);
775 browser.remove_tab.disconnect (tab_removed);
776 browser.show_preferences.disconnect (show_preferences);
777 }
778
779 void deactivated () {
780 var app = get_app ();
781 foreach (var browser in app.get_browsers ())
782 browser_removed (browser);
783 app.add_browser.disconnect (browser_added);
784
785 }
786
787 internal Manager () {
788 GLib.Object (name: "External Applications",
789 description: "Choose what to open unknown file types with",
790 version: "0.1" + Midori.VERSION_SUFFIX,
791 authors: "Christian Dywan <christian@twotoasts.de>");
792
793 this.activate.connect (activated);
794 this.deactivate.connect (deactivated);
795 }
796 }
797}
798
799public Midori.Extension extension_init () {
800 return new ExternalApplications.Manager ();
801}
802
0803
=== modified file 'extensions/transfers.vala'
--- extensions/transfers.vala 2014-01-06 21:51:09 +0000
+++ extensions/transfers.vala 2014-02-25 19:27:20 +0000
@@ -14,7 +14,6 @@
14}14}
1515
16namespace Sokoke {16namespace Sokoke {
17 extern static bool show_uri (Gdk.Screen screen, string uri, uint32 timestamp) throws Error;
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);
19}18}
2019
@@ -214,12 +213,8 @@
214 menuitem = new Gtk.ImageMenuItem.with_mnemonic (_("Open Destination _Folder"));213 menuitem = new Gtk.ImageMenuItem.with_mnemonic (_("Open Destination _Folder"));
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);
216 menuitem.activate.connect (() => {215 menuitem.activate.connect (() => {
217 try {216 var folder = GLib.File.new_for_uri (transfer.destination);
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 ());
219 Sokoke.show_uri (get_screen (), folder.get_parent ().get_uri (), 0);
220 } catch (Error error_folder) {
221 GLib.warning (_("Failed to open download: %s"), error_folder.message);
222 }
223 });218 });
224 menu.append (menuitem);219 menu.append (menuitem);
225 menuitem = new Gtk.ImageMenuItem.with_mnemonic (_("Copy Link Loc_ation"));220 menuitem = new Gtk.ImageMenuItem.with_mnemonic (_("Copy Link Loc_ation"));
226221
=== modified file 'katze/katze-utils.c'
--- katze/katze-utils.c 2013-11-05 21:51:18 +0000
+++ katze/katze-utils.c 2014-02-25 19:27:20 +0000
@@ -101,78 +101,12 @@
101}101}
102#endif102#endif
103103
104static const gchar*
105katze_app_info_get_commandline (GAppInfo* info)
106{
107 const gchar* exe;
108
109 exe = g_app_info_get_commandline (info);
110 if (!exe)
111 exe = g_app_info_get_executable (info);
112 if (!exe)
113 exe = g_app_info_get_name (info);
114 return exe;
115}
116
117static gboolean104static gboolean
118proxy_entry_focus_out_event_cb (GtkEntry* entry,105proxy_entry_focus_out_event_cb (GtkEntry* entry,
119 GdkEventFocus* event,106 GdkEventFocus* event,
120 GObject* object);107 GObject* object);
121108
122static void109static void
123proxy_combo_box_apps_changed_cb (GtkComboBox* button,
124 GObject* object)
125{
126 guint active = gtk_combo_box_get_active (button);
127 GtkTreeModel* model = gtk_combo_box_get_model (button);
128 GtkTreeIter iter;
129
130 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, active))
131 {
132 GAppInfo* info;
133 gboolean use_entry;
134 GtkWidget* child;
135 const gchar* exe;
136 const gchar* property = g_object_get_data (G_OBJECT (button), "property");
137
138 gtk_tree_model_get (model, &iter, 0, &info, -1);
139
140 use_entry = info && !g_app_info_get_icon (info);
141 child = gtk_bin_get_child (GTK_BIN (button));
142 if (use_entry && GTK_IS_CELL_VIEW (child))
143 {
144 GtkWidget* entry = gtk_entry_new ();
145 exe = g_app_info_get_executable (info);
146 if (exe && *exe && strcmp (exe, "%f"))
147 gtk_entry_set_text (GTK_ENTRY (entry), exe);
148 gtk_widget_show (entry);
149 gtk_container_add (GTK_CONTAINER (button), entry);
150 gtk_widget_grab_focus (entry);
151 g_signal_connect (entry, "focus-out-event",
152 G_CALLBACK (proxy_entry_focus_out_event_cb), object);
153 g_object_set_data_full (G_OBJECT (entry), "property",
154 g_strdup (property), g_free);
155 }
156 else if (!use_entry && GTK_IS_ENTRY (child))
157 {
158 /* Force the combo to change the item again */
159 gtk_widget_destroy (child);
160 gtk_combo_box_set_active (button, 0);
161 gtk_combo_box_set_active_iter (button, &iter);
162 }
163
164 if (info)
165 {
166 exe = katze_app_info_get_commandline (info);
167 g_object_set (object, property, exe, NULL);
168 g_object_unref (info);
169 }
170 else
171 g_object_set (object, property, "", NULL);
172 }
173}
174
175static void
176proxy_entry_activate_cb (GtkEntry* entry,110proxy_entry_activate_cb (GtkEntry* entry,
177 GObject* object)111 GObject* object)
178{112{
@@ -326,130 +260,6 @@
326 proxy_object_notify_string_cb, proxy);260 proxy_object_notify_string_cb, proxy);
327}261}
328262
329static GList*
330katze_app_info_get_all_for_category (const gchar* category)
331{
332 #ifdef _WIN32
333 /* FIXME: Real filtering by category would be better */
334 const gchar* content_type = g_content_type_from_mime_type (category);
335 GList* all_apps = g_app_info_get_all_for_type (content_type);
336 #else
337 GList* all_apps = g_app_info_get_all ();
338 #endif
339 GList* apps = NULL;
340 GList* app;
341 for (app = apps; app; app = g_list_next (app))
342 {
343 GAppInfo* info = app->data;
344 #ifdef GDK_WINDOWING_X11
345 gchar* filename = g_strconcat ("applications/", g_app_info_get_id (info), NULL);
346 GKeyFile* file = g_key_file_new ();
347
348 if (g_key_file_load_from_data_dirs (file, filename, NULL, G_KEY_FILE_NONE, NULL))
349 {
350 gchar* cat = g_key_file_get_string (file, "Desktop Entry",
351 "Categories", NULL);
352 if (cat && g_strrstr (cat, category))
353 apps = g_list_append (apps, info);
354
355 g_free (cat);
356 }
357 g_key_file_free (file);
358 g_free (filename);
359 #else
360 apps = g_list_append (apps, info);
361 #endif
362 }
363 g_list_free (all_apps);
364 return apps;
365}
366
367static gboolean
368proxy_populate_apps (GtkWidget* widget)
369{
370 const gchar* property = g_object_get_data (G_OBJECT (widget), "property");
371 GObject* object = g_object_get_data (G_OBJECT (widget), "object");
372 gchar* string = katze_object_get_string (object, property);
373 if (!g_strcmp0 (string, ""))
374 katze_assign (string, NULL);
375 GtkSettings* settings = gtk_widget_get_settings (widget);
376 gint icon_width = 16;
377 if (settings == NULL)
378 settings = gtk_settings_get_for_screen (gdk_screen_get_default ());
379 gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
380 &icon_width, NULL);
381
382 GtkComboBox* combo = GTK_COMBO_BOX (widget);
383 GtkListStore* model = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
384 GtkTreeIter iter_none;
385 gtk_list_store_insert_with_values (model, &iter_none, 0,
386 0, NULL, 1, NULL, 2, _("None"), 3, icon_width, -1);
387
388 const gchar* app_type = g_object_get_data (G_OBJECT (widget), "app-type");
389 GList* apps = g_app_info_get_all_for_type (app_type);
390 GAppInfo* info;
391 if (!apps)
392 apps = katze_app_info_get_all_for_category (app_type);
393 if (apps != NULL)
394 {
395 GList* app;
396 for (app = apps; app; app = g_list_next (app))
397 {
398 info = app->data;
399 const gchar* name = g_app_info_get_name (info);
400 GIcon* icon = g_app_info_get_icon (info);
401 gchar* icon_name;
402 GtkTreeIter iter;
403
404 if (!g_app_info_should_show (info))
405 continue;
406
407 icon_name = icon ? g_icon_to_string (icon) : NULL;
408 gtk_list_store_insert_with_values (model, &iter, G_MAXINT,
409 0, info, 1, icon_name, 2, name, 3, icon_width, -1);
410 if (string && !strcmp (katze_app_info_get_commandline (info), string))
411 gtk_combo_box_set_active_iter (combo, &iter);
412
413 g_free (icon_name);
414 }
415 g_list_free (apps);
416 }
417
418 info = g_app_info_create_from_commandline ("",
419 "", G_APP_INFO_CREATE_NONE, NULL);
420 gtk_list_store_insert_with_values (model, NULL, G_MAXINT,
421 0, info, 1, NULL, 2, _("Custom…"), 3, icon_width, -1);
422 g_object_unref (info);
423
424 if (gtk_combo_box_get_active (combo) == -1)
425 {
426 if (string)
427 {
428 GtkWidget* entry;
429 const gchar* exe;
430
431 info = g_app_info_create_from_commandline (string,
432 NULL, G_APP_INFO_CREATE_NONE, NULL);
433 entry = gtk_entry_new ();
434 exe = g_app_info_get_executable (info);
435 if (exe && *exe && strcmp (exe, "%f"))
436 gtk_entry_set_text (GTK_ENTRY (entry), string);
437 gtk_widget_show (entry);
438 gtk_container_add (GTK_CONTAINER (combo), entry);
439 g_object_unref (info);
440 g_signal_connect (entry, "focus-out-event",
441 G_CALLBACK (proxy_entry_focus_out_event_cb), object);
442 g_object_set_data_full (G_OBJECT (entry), "property",
443 g_strdup (property), g_free);
444 }
445 else
446 gtk_combo_box_set_active_iter (combo, &iter_none);
447 }
448 g_signal_connect (widget, "changed",
449 G_CALLBACK (proxy_combo_box_apps_changed_cb), object);
450 return G_SOURCE_REMOVE;
451}
452
453/**263/**
454 * katze_property_proxy:264 * katze_property_proxy:
455 * @object: a #GObject265 * @object: a #GObject
@@ -483,6 +293,7 @@
483 * for choosing an application to open TYPE files, ie. "text/plain".293 * for choosing an application to open TYPE files, ie. "text/plain".
484 * "application-CATEGORY": the widget created will be particularly suitable294 * "application-CATEGORY": the widget created will be particularly suitable
485 * for choosing an application to open CATEGORY files, ie. "Network".295 * for choosing an application to open CATEGORY files, ie. "Network".
296 * Since 0.5.8 the CATEGORY hint is no longer supported.
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"
487 * value, where the user may enter text freely, which then updates298 * value, where the user may enter text freely, which then updates
488 * the property PROPERTY instead. This applies only to enumerations.299 * the property PROPERTY instead. This applies only to enumerations.
@@ -652,27 +463,6 @@
652 g_free (families);463 g_free (families);
653 #endif464 #endif
654 }465 }
655 else if (type == G_TYPE_PARAM_STRING && hint && g_str_has_prefix (hint, "application-"))
656 {
657 GtkListStore* model;
658 GtkCellRenderer* renderer;
659 const gchar* app_type = &hint[12];
660
661 model = gtk_list_store_new (4, G_TYPE_APP_INFO, G_TYPE_STRING,
662 G_TYPE_STRING, G_TYPE_INT);
663 widget = gtk_combo_box_new_with_model (GTK_TREE_MODEL (model));
664 renderer = gtk_cell_renderer_pixbuf_new ();
665 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), renderer, FALSE);
666 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (widget), renderer, "icon-name", 1);
667 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (widget), renderer, "width", 3);
668 renderer = gtk_cell_renderer_text_new ();
669 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), renderer, TRUE);
670 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (widget), renderer, "text", 2);
671
672 g_object_set_data_full (G_OBJECT (widget), "app-type", g_strdup (app_type), g_free);
673 g_object_set_data_full (G_OBJECT (widget), "object", g_object_ref (object), g_object_unref);
674 g_idle_add_full (G_PRIORITY_LOW, (GSourceFunc)proxy_populate_apps, widget, NULL);
675 }
676 else if (type == G_TYPE_PARAM_STRING)466 else if (type == G_TYPE_PARAM_STRING)
677 {467 {
678 gchar* notify_property;468 gchar* notify_property;
679469
=== modified file 'katze/katze.vapi'
--- katze/katze.vapi 2013-09-22 16:22:10 +0000
+++ katze/katze.vapi 2014-02-25 19:27:20 +0000
@@ -36,5 +36,12 @@
36 public unowned string? get_meta_string (string key);36 public unowned string? get_meta_string (string key);
37 public void set_meta_string (string key, string value);37 public void set_meta_string (string key, string value);
38 }38 }
39
40 [CCode (cheader_filename = "katze/katze.h")]
41 public class Preferences : Gtk.Dialog {
42 public unowned Gtk.Box add_category (string label, string icon);
43 public void add_group (string? label);
44 public void add_widget (Gtk.Widget widget, string type);
45 }
39}46}
4047
4148
=== modified file 'katze/midori-uri.vala'
--- katze/midori-uri.vala 2014-01-06 21:51:09 +0000
+++ katze/midori-uri.vala 2014-02-25 19:27:20 +0000
@@ -16,6 +16,8 @@
1616
17namespace Midori {17namespace Midori {
18 public class URI : Object {18 public class URI : Object {
19 static string? fork_uri = null;
20
19 public static string? parse_hostname (string? uri, out string path) {21 public static string? parse_hostname (string? uri, out string path) {
20 path = null;22 path = null;
21 if (uri == null)23 if (uri == null)
@@ -205,5 +207,20 @@
205 label = display;207 label = display;
206 return type;208 return type;
207 }209 }
210
211 /*
212 Protects against recursive invokations of Midori with the same URI.
213 Consider a tel:// URI opened via Tab.open_uri, being handed off to GIO,
214 which in turns calls exo-open, which in turn can't open tel:// and falls
215 back to the browser ie. Midori.
216 So: code opening URIs calls this function with %true, #Midori.App passes %false.
217
218 Since: 0.5.8
219 */
220 public static bool recursive_fork_protection (string uri, bool set_uri) {
221 if (set_uri)
222 fork_uri = uri;
223 return fork_uri != uri;
224 }
208 }225 }
209}226}
210227
=== modified file 'midori/midori-app.c'
--- midori/midori-app.c 2014-02-24 11:33:50 +0000
+++ midori/midori-app.c 2014-02-25 19:27:20 +0000
@@ -535,7 +535,7 @@
535 for (i = 0; i < n_files; i++)535 for (i = 0; i < n_files; i++)
536 {536 {
537 gchar* uri = g_file_get_uri (files[i]);537 gchar* uri = g_file_get_uri (files[i]);
538 if (sokoke_recursive_fork_protection (uri, FALSE))538 if (midori_uri_recursive_fork_protection (uri, FALSE))
539 {539 {
540 if (first)540 if (first)
541 {541 {
542542
=== modified file 'midori/midori-browser.c'
--- midori/midori-browser.c 2014-02-12 22:56:28 +0000
+++ midori/midori-browser.c 2014-02-25 19:27:20 +0000
@@ -1496,7 +1496,11 @@
1496 MidoriNewView where)1496 MidoriNewView where)
1497{1497{
1498 if (midori_paths_get_runtime_mode () == MIDORI_RUNTIME_MODE_APP)1498 if (midori_paths_get_runtime_mode () == MIDORI_RUNTIME_MODE_APP)
1499 return sokoke_show_uri (gtk_widget_get_screen (view), uri, 0, NULL);1499 {
1500 gboolean handled = FALSE;
1501 g_signal_emit_by_name (view, "open-uri", uri, &handled);
1502 return handled;
1503 }
1500 else if (midori_paths_get_runtime_mode () == MIDORI_RUNTIME_MODE_PRIVATE)1504 else if (midori_paths_get_runtime_mode () == MIDORI_RUNTIME_MODE_PRIVATE)
1501 {1505 {
1502 if (where == MIDORI_NEW_VIEW_WINDOW)1506 if (where == MIDORI_NEW_VIEW_WINDOW)
@@ -1613,37 +1617,6 @@
1613 }1617 }
1614}1618}
16151619
1616static void
1617midori_browser_download_status_cb (WebKitDownload* download,
1618 GParamSpec* pspec,
1619 GtkWidget* widget)
1620{
1621#ifndef HAVE_WEBKIT2
1622 const gchar* uri = webkit_download_get_destination_uri (download);
1623 switch (webkit_download_get_status (download))
1624 {
1625 case WEBKIT_DOWNLOAD_STATUS_FINISHED:
1626 if (!sokoke_show_uri (gtk_widget_get_screen (widget), uri, 0, NULL))
1627 {
1628 sokoke_message_dialog (GTK_MESSAGE_ERROR,
1629 _("Error opening the image!"),
1630 _("Can not open selected image in a default viewer."), FALSE);
1631 }
1632 break;
1633 case WEBKIT_DOWNLOAD_STATUS_ERROR:
1634 webkit_download_cancel (download);
1635 sokoke_message_dialog (GTK_MESSAGE_ERROR,
1636 _("Error downloading the image!"),
1637 _("Can not download selected image."), FALSE);
1638 break;
1639 case WEBKIT_DOWNLOAD_STATUS_CREATED:
1640 case WEBKIT_DOWNLOAD_STATUS_STARTED:
1641 case WEBKIT_DOWNLOAD_STATUS_CANCELLED:
1642 break;
1643 }
1644#endif
1645}
1646
1647#ifdef HAVE_WEBKIT21620#ifdef HAVE_WEBKIT2
1648static void1621static void
1649midori_browser_close_tab_idle (GObject* resource,1622midori_browser_close_tab_idle (GObject* resource,
@@ -1679,18 +1652,6 @@
1679 {1652 {
1680 handled = FALSE;1653 handled = FALSE;
1681 }1654 }
1682 else if (type == MIDORI_DOWNLOAD_OPEN_IN_VIEWER)
1683 {
1684 gchar* destination_uri =
1685 midori_download_prepare_destination_uri (download, NULL);
1686 midori_browser_prepare_download (browser, download, destination_uri);
1687 g_signal_connect (download, "notify::status",
1688 G_CALLBACK (midori_browser_download_status_cb), GTK_WIDGET (browser));
1689 g_free (destination_uri);
1690 #ifndef HAVE_WEBKIT2
1691 webkit_download_start (download);
1692 #endif
1693 }
1694 #ifdef HAVE_WEBKIT21655 #ifdef HAVE_WEBKIT2
1695 else if (!webkit_download_get_destination (download))1656 else if (!webkit_download_get_destination (download))
1696 #else1657 #else
16971658
=== modified file 'midori/midori-dialog.vala'
--- midori/midori-dialog.vala 2014-01-25 21:04:57 +0000
+++ midori/midori-dialog.vala 2014-02-25 19:27:20 +0000
@@ -103,6 +103,20 @@
103 }103 }
104 }104 }
105105
106 public static void show_message_dialog (Gtk.MessageType type, string short, string detailed, bool modal) {
107 var dialog = new Gtk.MessageDialog (null, 0, type, Gtk.ButtonsType.OK, "%s", short);
108 dialog.format_secondary_text ("%s", detailed);
109 if (modal) {
110 dialog.run ();
111 dialog.destroy ();
112 } else {
113 dialog.response.connect ((response) => {
114 dialog.destroy ();
115 });
116 dialog.show ();
117 }
118 }
119
106 public class FileChooserDialog : Gtk.FileChooserDialog {120 public class FileChooserDialog : Gtk.FileChooserDialog {
107 public FileChooserDialog (string title, Gtk.Window? window, Gtk.FileChooserAction action) {121 public FileChooserDialog (string title, Gtk.Window? window, Gtk.FileChooserAction action) {
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.
109123
=== modified file 'midori/midori-download.vala'
--- midori/midori-download.vala 2014-01-06 21:51:09 +0000
+++ midori/midori-download.vala 2014-02-25 19:27:20 +0000
@@ -11,7 +11,6 @@
1111
12namespace Sokoke {12namespace Sokoke {
13#if !HAVE_WEBKIT213#if !HAVE_WEBKIT2
14 extern static bool show_uri (Gdk.Screen screen, string uri, uint32 timestamp) throws Error;
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);
16#endif15#endif
17}16}
@@ -212,9 +211,13 @@
212211
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 {
214#if !HAVE_WEBKIT2213#if !HAVE_WEBKIT2
215 if (!has_wrong_checksum (download))214 if (!has_wrong_checksum (download)) {
216 return Sokoke.show_uri (widget.get_screen (),215 var browser = widget.get_toplevel ();
217 download.destination_uri, Gtk.get_current_event_time ());216 Tab? tab = null;
217 browser.get ("tab", tab);
218 if (tab != null)
219 tab.open_uri (download.destination_uri);
220 }
218221
219 Sokoke.message_dialog (Gtk.MessageType.WARNING,222 Sokoke.message_dialog (Gtk.MessageType.WARNING,
220 _("The downloaded file is erroneous."),223 _("The downloaded file is erroneous."),
221224
=== modified file 'midori/midori-extension.c'
--- midori/midori-extension.c 2013-12-09 19:49:15 +0000
+++ midori/midori-extension.c 2014-02-25 19:27:20 +0000
@@ -563,6 +563,7 @@
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));
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));
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));
566 g_assert (midori_extension_activate_gracefully (app, extension_path, "libopen-with." G_MODULE_SUFFIX, activate));
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));
567 }568 }
568 else569 else
@@ -679,6 +680,7 @@
679 && strcmp (filename, "libapps." G_MODULE_SUFFIX)680 && strcmp (filename, "libapps." G_MODULE_SUFFIX)
680 && strcmp (filename, "libdelayed-load." G_MODULE_SUFFIX)681 && strcmp (filename, "libdelayed-load." G_MODULE_SUFFIX)
681 && strcmp (filename, "libtabby." G_MODULE_SUFFIX)682 && strcmp (filename, "libtabby." G_MODULE_SUFFIX)
683 && strcmp (filename, "libopen-with." G_MODULE_SUFFIX)
682 && strcmp (filename, "libflummi." G_MODULE_SUFFIX))684 && strcmp (filename, "libflummi." G_MODULE_SUFFIX))
683 katze_array_add_item (extensions, extension);685 katze_array_add_item (extensions, extension);
684686
685687
=== modified file 'midori/midori-frontend.c'
--- midori/midori-frontend.c 2013-11-29 16:29:02 +0000
+++ midori/midori-frontend.c 2014-02-25 19:27:20 +0000
@@ -239,6 +239,7 @@
239239
240 /* FIXME need proper stock extension mechanism */240 /* FIXME need proper stock extension mechanism */
241 midori_browser_activate_action (browser, "libtransfers." G_MODULE_SUFFIX "=true");241 midori_browser_activate_action (browser, "libtransfers." G_MODULE_SUFFIX "=true");
242 midori_browser_activate_action (browser, "libopen-with." G_MODULE_SUFFIX "=true");
242 g_assert (g_module_error () == NULL);243 g_assert (g_module_error () == NULL);
243244
244 return browser;245 return browser;
@@ -301,7 +302,7 @@
301 gchar* crash_log)302 gchar* crash_log)
302{303{
303 GError* error = NULL;304 GError* error = NULL;
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))
305 {306 {
306 sokoke_message_dialog (GTK_MESSAGE_ERROR,307 sokoke_message_dialog (GTK_MESSAGE_ERROR,
307 _("Could not run external program."),308 _("Could not run external program."),
308309
=== modified file 'midori/midori-preferences.c'
--- midori/midori-preferences.c 2013-12-09 11:40:39 +0000
+++ midori/midori-preferences.c 2014-02-25 19:27:20 +0000
@@ -490,18 +490,6 @@
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"));
491 SPANNED_ADD (button);491 SPANNED_ADD (button);
492492
493 INDENTED_ADD (gtk_label_new (NULL));
494 label = gtk_label_new (_("Text Editor"));
495 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
496 INDENTED_ADD (label);
497 entry = katze_property_proxy (settings, "text-editor", "application-text/plain");
498 SPANNED_ADD (entry);
499 label = gtk_label_new (_("News Aggregator"));
500 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
501 INDENTED_ADD (label);
502 entry = katze_property_proxy (settings, "news-aggregator", "application-News");
503 SPANNED_ADD (entry);
504
505 /* Page "Network" */493 /* Page "Network" */
506 PAGE_NEW (GTK_STOCK_NETWORK, _("Network"));494 PAGE_NEW (GTK_STOCK_NETWORK, _("Network"));
507 FRAME_NEW (NULL);495 FRAME_NEW (NULL);
508496
=== modified file 'midori/midori-tab.vala'
--- midori/midori-tab.vala 2013-12-09 20:23:03 +0000
+++ midori/midori-tab.vala 2014-02-25 19:27:20 +0000
@@ -88,6 +88,8 @@
88 }88 }
89 }89 }
9090
91 /* Since: 0.5.8 */
92 public signal bool open_uri (string uri);
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);
92 public signal void attach_inspector (WebKit.WebView inspector_view);94 public signal void attach_inspector (WebKit.WebView inspector_view);
93 /* Emitted when an open inspector that was previously95 /* Emitted when an open inspector that was previously
9496
=== modified file 'midori/midori-view.c'
--- midori/midori-view.c 2013-12-09 20:23:03 +0000
+++ midori/midori-view.c 2014-02-25 19:27:20 +0000
@@ -558,19 +558,6 @@
558 g_free (new_uri);558 g_free (new_uri);
559 return TRUE;559 return TRUE;
560 }560 }
561 else if (sokoke_external_uri (uri))
562 {
563 if (sokoke_show_uri (gtk_widget_get_screen (GTK_WIDGET (web_view)),
564 uri, GDK_CURRENT_TIME, NULL))
565 {
566 #ifdef HAVE_WEBKIT2
567 webkit_policy_decision_ignore (decision);
568 #else
569 webkit_web_policy_decision_ignore (decision);
570 #endif
571 return TRUE;
572 }
573 }
574 else if (g_str_has_prefix (uri, "data:image/"))561 else if (g_str_has_prefix (uri, "data:image/"))
575 {562 {
576 /* For security reasons, main content served as data: is limited to images563 /* For security reasons, main content served as data: is limited to images
@@ -2109,16 +2096,6 @@
2109}2096}
21102097
2111static void2098static void
2112midori_web_view_open_in_viewer_cb (GtkAction* action,
2113 gpointer user_data)
2114{
2115 MidoriView* view = user_data;
2116 gchar* uri = katze_object_get_string (view->hit_test, "image-uri");
2117 midori_view_download_uri (view, MIDORI_DOWNLOAD_OPEN_IN_VIEWER, uri);
2118 g_free (uri);
2119}
2120
2121static void
2122midori_web_view_menu_video_copy_activate_cb (GtkAction* action,2099midori_web_view_menu_video_copy_activate_cb (GtkAction* action,
2123 gpointer user_data)2100 gpointer user_data)
2124{2101{
@@ -2146,8 +2123,8 @@
2146 MidoriView* view = user_data;2123 MidoriView* view = user_data;
2147 gchar* data = (gchar*)g_object_get_data (G_OBJECT (action), "uri");2124 gchar* data = (gchar*)g_object_get_data (G_OBJECT (action), "uri");
2148 gchar* uri = g_strconcat ("mailto:", data, NULL);2125 gchar* uri = g_strconcat ("mailto:", data, NULL);
2149 sokoke_show_uri (gtk_widget_get_screen (view->web_view),2126 gboolean handled = FALSE;
2150 uri, GDK_CURRENT_TIME, NULL);2127 g_signal_emit_by_name (view, "open-uri", uri, &handled);
2151 g_free (uri);2128 g_free (uri);
2152}2129}
2153#endif2130#endif
@@ -2358,8 +2335,6 @@
2358 midori_web_view_menu_image_copy_activate_cb, view);2335 midori_web_view_menu_image_copy_activate_cb, view);
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,
2360 midori_web_view_menu_image_save_activate_cb, view);2337 midori_web_view_menu_image_save_activate_cb, view);
2361 midori_context_action_add_simple (menu, "OpenImageInViewer", _("Open in Image _Viewer"), NULL, GTK_STOCK_OPEN,
2362 midori_web_view_open_in_viewer_cb, view);
2363 }2338 }
23642339
2365 if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA)2340 if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA)
@@ -4013,12 +3988,19 @@
4013 g_free (exception);3988 g_free (exception);
4014 }3989 }
4015 }3990 }
4016 else if (sokoke_external_uri (uri))
4017 {
4018 sokoke_show_uri (NULL, uri, GDK_CURRENT_TIME, NULL);
4019 }
4020 else3991 else
4021 {3992 {
3993 if (sokoke_external_uri (uri))
3994 {
3995 gboolean handled = FALSE;
3996 g_signal_emit_by_name (view, "open-uri", uri, &handled);
3997 if (handled)
3998 {
3999 g_free (temporary_uri);
4000 return;
4001 }
4002 }
4003
4022 midori_tab_set_uri (MIDORI_TAB (view), uri);4004 midori_tab_set_uri (MIDORI_TAB (view), uri);
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)));
4024 katze_assign (view->title, NULL);4006 katze_assign (view->title, NULL);
40254007
=== modified file 'midori/midori.vapi'
--- midori/midori.vapi 2014-01-30 21:43:31 +0000
+++ midori/midori.vapi 2014-02-25 19:27:20 +0000
@@ -118,6 +118,7 @@
118 public signal void quit ();118 public signal void quit ();
119 public signal void send_notification (string title, string message);119 public signal void send_notification (string title, string message);
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);
121 public signal void show_preferences (Katze.Preferences preferences);
121 }122 }
122123
123 [CCode (cheader_filename = "midori/midori.h")]124 [CCode (cheader_filename = "midori/midori.h")]
124125
=== modified file 'midori/sokoke.c'
--- midori/sokoke.c 2013-10-28 23:36:29 +0000
+++ midori/sokoke.c 2014-02-25 19:27:20 +0000
@@ -37,6 +37,7 @@
37#ifdef G_OS_WIN3237#ifdef G_OS_WIN32
38#include <windows.h>38#include <windows.h>
39#include <shlobj.h>39#include <shlobj.h>
40#include <gdk/gdkwin32.h>
40#endif41#endif
4142
42static gchar*43static gchar*
@@ -109,39 +110,8 @@
109 const gchar* detailed_message,110 const gchar* detailed_message,
110 gboolean modal)111 gboolean modal)
111{112{
112 GtkWidget* dialog = gtk_message_dialog_new (113 midori_show_message_dialog (message_type, short_message, detailed_message, modal);
113 NULL, 0, message_type, GTK_BUTTONS_OK, "%s", short_message);114}
114 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
115 "%s", detailed_message);
116 if (modal)
117 {
118 gtk_dialog_run (GTK_DIALOG (dialog));
119 gtk_widget_destroy (dialog);
120 }
121 else
122 {
123 g_signal_connect_swapped (dialog, "response",
124 G_CALLBACK (gtk_widget_destroy), dialog);
125 gtk_widget_show (dialog);
126 }
127
128}
129
130#ifndef G_OS_WIN32
131static void
132sokoke_open_with_response_cb (GtkWidget* dialog,
133 gint response,
134 GtkEntry* entry)
135{
136 if (response == GTK_RESPONSE_ACCEPT)
137 {
138 const gchar* command = gtk_entry_get_text (entry);
139 const gchar* uri = g_object_get_data (G_OBJECT (dialog), "uri");
140 sokoke_spawn_program (command, FALSE, uri, TRUE, FALSE);
141 }
142 gtk_widget_destroy (dialog);
143}
144#endif
145115
146GAppInfo*116GAppInfo*
147sokoke_default_for_uri (const gchar* uri,117sokoke_default_for_uri (const gchar* uri,
@@ -164,86 +134,6 @@
164}134}
165135
166/**136/**
167 * sokoke_show_uri:
168 * @screen: a #GdkScreen, or %NULL
169 * @uri: the URI to show
170 * @timestamp: the timestamp of the event
171 * @error: the location of a #GError, or %NULL
172 *
173 * Shows the specified URI with an application or xdg-open.
174 * x-scheme-handler is supported for GLib < 2.28 as of 0.3.3.
175 *
176 * Return value: %TRUE on success, %FALSE if an error occurred
177 **/
178gboolean
179sokoke_show_uri (GdkScreen* screen,
180 const gchar* uri,
181 guint32 timestamp,
182 GError** error)
183{
184 #ifdef G_OS_WIN32
185 CoInitializeEx (NULL, COINIT_APARTMENTTHREADED);
186 SHELLEXECUTEINFO info = { sizeof (info) };
187 info.nShow = SW_SHOWNORMAL;
188 info.lpFile = uri;
189
190 return ShellExecuteEx (&info);
191 #else
192
193 GtkWidget* dialog;
194 GtkWidget* box;
195 gchar* filename;
196 gchar* ms;
197 GtkWidget* entry;
198
199 g_return_val_if_fail (GDK_IS_SCREEN (screen) || !screen, FALSE);
200 g_return_val_if_fail (uri != NULL, FALSE);
201 g_return_val_if_fail (!error || !*error, FALSE);
202
203 sokoke_recursive_fork_protection (uri, TRUE);
204
205 /* g_app_info_launch_default_for_uri, gdk_display_get_app_launch_context */
206 if (gtk_show_uri (screen, uri, timestamp, error))
207 return TRUE;
208
209 {
210 gchar* command = g_strconcat ("xdg-open ", uri, NULL);
211 gboolean result = g_spawn_command_line_async (command, error);
212 g_free (command);
213 if (result)
214 return TRUE;
215 if (error)
216 *error = NULL;
217 }
218
219 dialog = gtk_dialog_new_with_buttons (_("Open with"), NULL, 0,
220 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
221 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
222 box = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
223 if (g_str_has_prefix (uri, "file:///"))
224 filename = g_filename_from_uri (uri, NULL, NULL);
225 else
226 filename = g_strdup (uri);
227 ms = g_strdup_printf (_("Choose an application or command to open \"%s\":"),
228 filename);
229 gtk_box_pack_start (GTK_BOX (box), gtk_label_new (ms), TRUE, FALSE, 4);
230 g_free (ms);
231 entry = gtk_entry_new ();
232 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
233 gtk_box_pack_start (GTK_BOX (box), entry, TRUE, FALSE, 4);
234 g_signal_connect (dialog, "response",
235 G_CALLBACK (sokoke_open_with_response_cb), entry);
236 g_object_set_data_full (G_OBJECT (dialog), "uri",
237 filename, (GDestroyNotify)g_free);
238 gtk_widget_show_all (dialog);
239 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
240 gtk_widget_grab_focus (entry);
241
242 return TRUE;
243 #endif
244}
245
246/**
247 * sokoke_prepare_command:137 * sokoke_prepare_command:
248 * @command: the command, properly quoted138 * @command: the command, properly quoted
249 * @argument: any arguments, properly quoted139 * @argument: any arguments, properly quoted
@@ -919,36 +809,6 @@
919#endif809#endif
920}810}
921811
922/**
923 * sokoke_recursive_fork_protection
924 * @uri: the URI to check
925 * @set_uri: if TRUE the URI will be saved
926 *
927 * Protects against recursive invokations of the Midori executable
928 * with the same URI.
929 *
930 * As an example, consider having an URI starting with 'tel://'. You
931 * could attempt to open it with sokoke_show_uri. In turn, 'exo-open'
932 * might be called. Now quite possibly 'exo-open' is unable to handle
933 * 'tel://' and might well fall back to 'midori' as default browser.
934 *
935 * To protect against this scenario, call this function with the
936 * URI and %TRUE before calling any external tool.
937 * #MidoriApp calls sokoke_recursive_fork_protection() with %FALSE
938 * and bails out if %FALSE is returned.
939 *
940 * Return value: %TRUE if @uri is new, %FALSE on recursion
941 **/
942gboolean
943sokoke_recursive_fork_protection (const gchar* uri,
944 gboolean set_uri)
945{
946 static gchar* fork_uri = NULL;
947 if (set_uri)
948 katze_assign (fork_uri, g_strdup (uri));
949 return g_strcmp0 (fork_uri, uri) == 0 ? FALSE : TRUE;
950}
951
952static void812static void
953sokoke_widget_clipboard_owner_clear_func (GtkClipboard* clipboard,813sokoke_widget_clipboard_owner_clear_func (GtkClipboard* clipboard,
954 gpointer user_data)814 gpointer user_data)
@@ -1121,4 +981,23 @@
1121 g_free (lnk_path);981 g_free (lnk_path);
1122 g_free (launcher_type);982 g_free (launcher_type);
1123}983}
984
985GdkPixbuf*
986sokoke_get_gdk_pixbuf_from_win32_executable (gchar* path)
987{
988 if (path == NULL)
989 return NULL;
990
991 GdkPixbuf* pixbuf = NULL;
992 HICON hIcon = NULL;
993 HINSTANCE hInstance = NULL;
994 hIcon = ExtractIcon (hInstance, (LPCSTR)path, 0);
995 if (hIcon == NULL)
996 return NULL;
997
998 pixbuf = gdk_win32_icon_to_pixbuf_libgtk_only (hIcon, NULL, NULL);
999 DestroyIcon (hIcon);
1000
1001 return pixbuf;
1002}
1124#endif1003#endif
11251004
=== modified file 'midori/sokoke.h'
--- midori/sokoke.h 2013-08-02 16:40:27 +0000
+++ midori/sokoke.h 2014-02-25 19:27:20 +0000
@@ -29,19 +29,6 @@
29 const gchar* detailed_message,29 const gchar* detailed_message,
30 gboolean modal);30 gboolean modal);
3131
32gboolean
33sokoke_show_uri_with_mime_type (GdkScreen* screen,
34 const gchar* uri,
35 const gchar* mime_type,
36 guint32 timestamp,
37 GError** error);
38
39gboolean
40sokoke_show_uri (GdkScreen* screen,
41 const gchar* uri,
42 guint32 timestamp,
43 GError** error);
44
45gchar*32gchar*
46sokoke_prepare_command (const gchar* command,33sokoke_prepare_command (const gchar* command,
47 gboolean quote_command,34 gboolean quote_command,
@@ -112,10 +99,6 @@
112gboolean99gboolean
113sokoke_resolve_hostname (const gchar* hostname);100sokoke_resolve_hostname (const gchar* hostname);
114101
115gboolean
116sokoke_recursive_fork_protection (const gchar* uri,
117 gboolean set_uri);
118
119void102void
120sokoke_widget_copy_clipboard (GtkWidget* widget,103sokoke_widget_copy_clipboard (GtkWidget* widget,
121 const gchar* text,104 const gchar* text,
122105
=== modified file 'po/POTFILES.in'
--- po/POTFILES.in 2014-02-20 20:30:42 +0000
+++ po/POTFILES.in 2014-02-25 19:27:20 +0000
@@ -45,6 +45,7 @@
45extensions/delayed-load.vala45extensions/delayed-load.vala
46extensions/devpet.vala46extensions/devpet.vala
47extensions/external-download-manager.vala47extensions/external-download-manager.vala
48extensions/open-with.vala
48extensions/feed-panel/feed-atom.c49extensions/feed-panel/feed-atom.c
49extensions/feed-panel/feed-panel.c50extensions/feed-panel/feed-panel.c
50extensions/feed-panel/feed-parse.c51extensions/feed-panel/feed-parse.c

Subscribers

People subscribed via source and target branches

to all changes: