Merge lp:~midori/midori/finishingTouches into lp:midori

Proposed by Cris Dywan
Status: Merged
Approved by: Cris Dywan
Approved revision: 6611
Merged at revision: 6598
Proposed branch: lp:~midori/midori/finishingTouches
Merge into: lp:midori
Diff against target: 615 lines (+233/-95)
5 files modified
data/adblock/element_hider.js (+25/-0)
extensions/adblock/extension.vala (+150/-77)
extensions/adblock/subscriptions.vala (+21/-2)
extensions/adblock/widgets.vala (+32/-14)
midori/midori-browser.c (+5/-2)
To merge this branch: bzr merge lp:~midori/midori/finishingTouches
Reviewer Review Type Date Requested Status
Cris Dywan Approve
Review via email: mp+210307@code.launchpad.net

Commit message

Finishing touches for Adblock

Description of the change

Short Term:
x open link in label
- Parse *.png style rules
x Extend known tag list in update_css_hash
x gui sizing
x deactivating
x popup menu roll-up

Long Term:
- Statusbar icon [x] Debug Matching
- Edit/ view custom rules
- Check checksum hash of the subscription after downloading
- Open local files in editor
- Ability to disable adblock for the current domain
- Save pre-parsed pre filtered ruleset into file as .preparsed
- Save matched/ cached uris from previous runs

[https://easylist-downloads.adblockplus.org/easylist.txt]
enabled=1
expires=48206903549424
retries=1
homepage=https://easylist-downloads.adblockplus.org
title=EasyList

Test cases https://hg.adblockplus.org/adblockplustests/file/3e166c282a1d/chrome/content/tests/elemhide.js

To post a comment you must log in.
Revision history for this message
Cris Dywan (kalikiana) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'data/adblock/element_hider.js'
2--- data/adblock/element_hider.js 1970-01-01 00:00:00 +0000
3+++ data/adblock/element_hider.js 2014-03-14 21:32:33 +0000
4@@ -0,0 +1,25 @@
5+function getElementsByAttribute (strTagName, strAttributeName, arrAttributeValue) {
6+ var arrElements = document.getElementsByTagName (strTagName);
7+ var arrReturnElements = new Array();
8+ for (var j=0; j<arrAttributeValue.length; j++) {
9+ var strAttributeValue = arrAttributeValue[j];
10+ for (var i=0; i<arrElements.length; i++) {
11+ var oCurrent = arrElements[i];
12+ var oAttribute = oCurrent.getAttribute && oCurrent.getAttribute (strAttributeName);
13+ if (oAttribute && oAttribute.length > 0 && strAttributeValue.indexOf (oAttribute) != -1)
14+ arrReturnElements.push (oCurrent);
15+ }
16+ }
17+ return arrReturnElements;
18+};
19+
20+function hideElementBySrc (uris) {
21+ var oElements = getElementsByAttribute('img', 'src', uris);
22+ if (oElements.length == 0)
23+ oElements = getElementsByAttribute ('iframe', 'src', uris);
24+ for (var i=0; i<oElements.length; i++) {
25+ oElements[i].style.visibility = 'hidden !important';
26+ oElements[i].style.width = '0';
27+ oElements[i].style.height = '0';
28+ }
29+};
30
31=== modified file 'extensions/adblock/extension.vala'
32--- extensions/adblock/extension.vala 2014-03-10 10:26:53 +0000
33+++ extensions/adblock/extension.vala 2014-03-14 21:32:33 +0000
34@@ -47,11 +47,13 @@
35 public class Extension : Midori.Extension {
36 internal Config config;
37 internal Subscription custom;
38- internal HashTable<string, Directive?> cache;
39+ internal StringBuilder hider_selectors;
40 internal StatusIcon status_icon;
41 internal SubscriptionManager manager;
42- internal State state;
43 internal bool debug_element;
44+#if !USE_CSS_SELECTOR_FOR_BLOCKED_RESOURCES
45+ internal string? js_hider_function_body;
46+#endif
47
48 #if HAVE_WEBKIT2
49 public Extension (WebKit.WebExtension web_extension) {
50@@ -64,7 +66,7 @@
51 }
52
53 bool send_request (WebKit.WebPage web_page, WebKit.URIRequest request, WebKit.URIResponse? redirected_response) {
54- return request_handled (web_page.uri, request.uri);
55+ return request_handled (request.uri, web_page.uri);
56 }
57 #else
58 public Extension () {
59@@ -73,6 +75,7 @@
60 version: "2.0",
61 authors: "Christian Dywan <christian@twotoasts.de>");
62 activate.connect (extension_activated);
63+ deactivate.connect (extension_deactivated);
64 open_preferences.connect (extension_preferences);
65 }
66
67@@ -85,34 +88,59 @@
68 foreach (var browser in app.get_browsers ())
69 browser_added (browser);
70 app.add_browser.connect (browser_added);
71+ app.remove_browser.connect (browser_removed);
72+ }
73+
74+ void extension_deactivated () {
75+ var app = get_app ();
76+ foreach (var browser in app.get_browsers ())
77+ browser_removed (browser);
78+ app.add_browser.disconnect (browser_added);
79+ app.remove_browser.disconnect (browser_removed);
80+ foreach (var button in status_icon.toggle_buttons)
81+ button.destroy ();
82 }
83
84 void browser_added (Midori.Browser browser) {
85 foreach (var tab in browser.get_tabs ())
86 tab_added (tab);
87 browser.add_tab.connect (tab_added);
88+ browser.remove_tab.connect (tab_removed);
89
90- var toggle_button = new StatusIcon.IconButton ();
91- toggle_button.set_status (config.enabled ? "enabled" : "disabled");
92+ var toggle_button = status_icon.add_button ();
93 browser.statusbar.pack_start (toggle_button, false, false, 3);
94 toggle_button.show ();
95- toggle_button.clicked.connect (status_icon.icon_clicked);
96- status_icon.toggle_buttons.append (toggle_button);
97 }
98
99+ void browser_removed (Midori.Browser browser) {
100+ foreach (var tab in browser.get_tabs ())
101+ tab_removed (tab);
102+ browser.add_tab.disconnect (tab_added);
103+ browser.remove_tab.disconnect (tab_removed);
104+ }
105
106 void tab_added (Midori.View view) {
107 view.web_view.resource_request_starting.connect (resource_requested);
108 view.web_view.navigation_policy_decision_requested.connect (navigation_requested);
109- view.notify["load-status"].connect ((pspec) => {
110- if (config.enabled) {
111- if (view.load_status == Midori.LoadStatus.FINISHED)
112- inject_css (view, view.uri);
113- }
114- });
115+ view.notify["load-status"].connect (load_status_changed);
116 view.context_menu.connect (context_menu);
117 }
118
119+ void tab_removed (Midori.View view) {
120+ view.web_view.resource_request_starting.disconnect (resource_requested);
121+ view.web_view.navigation_policy_decision_requested.disconnect (navigation_requested);
122+ view.notify["load-status"].disconnect (load_status_changed);
123+ view.context_menu.disconnect (context_menu);
124+ }
125+
126+ void load_status_changed (Object object, ParamSpec pspec) {
127+ var view = object as Midori.View;
128+ if (config.enabled) {
129+ if (view.load_status == Midori.LoadStatus.FINISHED)
130+ inject_css (view, view.uri);
131+ }
132+ }
133+
134 void context_menu (WebKit.HitTestResult hit_test_result, Midori.ContextAction menu) {
135 string label, uri;
136 if ((hit_test_result.context & WebKit.HitTestResultContext.IMAGE) != 0) {
137@@ -132,23 +160,11 @@
138 menu.add (action);
139 }
140
141- Adblock.State adblock_get_state (Adblock.Directive directive)
142- {
143- if (directive == Directive.BLOCK)
144- return State.BLOCKED;
145- if (config.enabled)
146- return State.ENABLED;
147- else
148- return State.DISABLED;
149- }
150-
151 void resource_requested (WebKit.WebView web_view, WebKit.WebFrame frame,
152 WebKit.WebResource resource, WebKit.NetworkRequest request, WebKit.NetworkResponse? response) {
153
154- if (request_handled (web_view.uri, request.uri)) {
155+ if (request_handled (request.uri, web_view.uri)) {
156 request.set_uri ("about:blank");
157- state = adblock_get_state (get_directive_for_uri (web_view.uri));
158- status_icon.set_state (state);
159 }
160 }
161
162@@ -162,22 +178,17 @@
163 manager.add_subscription (parsed_uri);
164 return true;
165 }
166- state = adblock_get_state (get_directive_for_uri (request.uri));
167- status_icon.set_state (state);
168+ status_icon.set_state (config.enabled ? State.ENABLED : State.DISABLED);
169 return false;
170 }
171
172+#if USE_CSS_SELECTOR_FOR_BLOCKED_RESOURCES
173 string? get_hider_css_for_blocked_resources () {
174+ if (hider_selectors.str == "")
175+ return null;
176+
177 /* Hide elements that were blocked, otherwise we will get "broken image" icon */
178- var code = new StringBuilder ();
179- cache.foreach ((key, val) => {
180- if (val == Adblock.Directive.BLOCK)
181- code.append ("img[src*=\"%s\"] , iframe[src*=\"%s\"] , ".printf (key, key));
182- });
183-
184- if (code.str == "")
185- return null;
186-
187+ var code = new StringBuilder (hider_selectors.str);
188 string hider_css;
189 if (debug_element)
190 hider_css = " { background-color: red; border: 4px solid green; }";
191@@ -190,6 +201,37 @@
192 stdout.printf ("hider css: %s\n", code.str);
193 return code.str;
194 }
195+#else
196+ string? fetch_js_hider_function_body () {
197+ string filename = Midori.Paths.get_res_filename ("adblock/element_hider.js");
198+ File js_file = GLib.File.new_for_path (filename);
199+ try {
200+ uint8[] function_body;
201+ js_file.load_contents (null, out function_body, null);
202+ return (string)function_body;
203+ }
204+ catch (Error error) {
205+ warning ("Error while loading adblock hider js: %s\n", error.message);
206+ }
207+ return null;
208+ }
209+
210+ string? get_hider_js_for_blocked_resorces () {
211+ if (hider_selectors.str == "")
212+ return null;
213+
214+ if (js_hider_function_body == null || js_hider_function_body == "")
215+ return null;
216+
217+ var js = new StringBuilder ("(function() {");
218+ js.append (js_hider_function_body);
219+ js.append ("var uris=new Array ();");
220+ js.append (hider_selectors.str);
221+ js.append (" hideElementBySrc (uris);})();");
222+
223+ return js.str;
224+ }
225+#endif
226
227 string[]? get_domains_for_uri (string uri) {
228 if (uri == null)
229@@ -263,10 +305,15 @@
230 else
231 debug_element = status_icon.debug_element_toggled;
232
233+#if USE_CSS_SELECTOR_FOR_BLOCKED_RESOURCES
234 string? blocked_css = get_hider_css_for_blocked_resources ();
235 if (blocked_css != null)
236 view.inject_stylesheet (blocked_css);
237-
238+#else
239+ string? blocked_js = get_hider_js_for_blocked_resorces ();
240+ if (blocked_js != null)
241+ view.execute_script (blocked_js, null);
242+#endif
243 string? style = get_hider_css_rules_for_uri (page_uri);
244 if (style != null)
245 view.inject_stylesheet (style);
246@@ -274,10 +321,10 @@
247 #endif
248
249 internal void init () {
250- cache = new HashTable<string, Directive?> (str_hash, str_equal);
251+ hider_selectors = new StringBuilder ();
252 load_config ();
253- status_icon = new StatusIcon (config);
254 manager = new SubscriptionManager (config);
255+ status_icon = new StatusIcon (config, manager);
256 foreach (Subscription sub in config) {
257 try {
258 sub.parse ();
259@@ -287,6 +334,9 @@
260 }
261 config.notify["size"].connect (subscriptions_added_removed);
262 manager.description_label.activate_link.connect (open_link);
263+#if !USE_CSS_SELECTOR_FOR_BLOCKED_RESOURCES
264+ js_hider_function_body = fetch_js_hider_function_body ();
265+#endif
266 }
267
268 bool open_link (string uri) {
269@@ -297,7 +347,7 @@
270 }
271
272 void subscriptions_added_removed (ParamSpec pspec) {
273- cache.remove_all ();
274+ hider_selectors = new StringBuilder ();
275 }
276
277 void load_config () {
278@@ -317,43 +367,43 @@
279 }
280 }
281
282- public Adblock.Directive get_directive_for_uri (string request_uri, string? page_uri = null) {
283+ public Adblock.Directive get_directive_for_uri (string request_uri, string page_uri) {
284 if (!config.enabled)
285 return Directive.ALLOW;
286
287- if (page_uri != null) {
288- /* Always allow the main page */
289- if (request_uri == page_uri)
290- return Directive.ALLOW;
291+ /* Always allow the main page */
292+ if (request_uri == page_uri)
293+ return Directive.ALLOW;
294
295- /* Skip adblock on internal pages */
296- if (Midori.URI.is_blank (page_uri))
297- return Directive.ALLOW;
298- }
299+ /* Skip adblock on internal pages */
300+ if (Midori.URI.is_blank (page_uri))
301+ return Directive.ALLOW;
302
303 /* Skip adblock on favicons and non http schemes */
304 if (!Midori.URI.is_http (request_uri) || request_uri.has_suffix ("favicon.ico"))
305 return Directive.ALLOW;
306
307- Directive? directive = cache.lookup (request_uri);
308- if (directive == null) {
309- foreach (Subscription sub in config) {
310- if (page_uri == null)
311- page_uri = request_uri;
312- directive = sub.get_directive (request_uri, page_uri);
313- if (directive != null)
314- break;
315- }
316- if (directive == null)
317- directive = Directive.ALLOW;
318- cache.insert (request_uri, directive);
319- if (directive == Directive.BLOCK)
320- cache.insert (page_uri, directive);
321+ Directive? directive = null;
322+ foreach (Subscription sub in config) {
323+ directive = sub.get_directive (request_uri, page_uri);
324+ if (directive != null)
325+ break;
326+ }
327+
328+ if (directive == null)
329+ directive = Directive.ALLOW;
330+ else if (directive == Directive.BLOCK) {
331+ status_icon.set_state (State.BLOCKED);
332+#if USE_CSS_SELECTOR_FOR_BLOCKED_RESOURCES
333+ hider_selectors.append ("img[src*=\"%s\"] , iframe[src*=\"%s\"] , ".printf (request_uri, request_uri));
334+#else
335+ hider_selectors.append (" uris.push ('%s');\n".printf (request_uri));
336+#endif
337 }
338 return directive;
339 }
340
341- internal bool request_handled (string page_uri, string request_uri) {
342+ internal bool request_handled (string request_uri, string page_uri) {
343 return get_directive_for_uri (request_uri, page_uri) == Directive.BLOCK;
344 }
345 }
346@@ -541,7 +591,7 @@
347 if (extension.config.size != 3)
348 error ("Expected 3 initial subs, got %s".printf (
349 extension.config.size.to_string ()));
350- assert (extension.cache.size () == 0);
351+ assert (extension.status_icon.state == Adblock.State.ENABLED);
352
353 /* Add new subscription */
354 string path = Midori.Paths.get_res_filename ("adblock.list");
355@@ -553,7 +603,7 @@
356 }
357 var sub = new Adblock.Subscription (uri);
358 extension.config.add (sub);
359- assert (extension.cache.size () == 0);
360+ assert (extension.status_icon.state == Adblock.State.ENABLED);
361 assert (extension.config.size == 4);
362 try {
363 sub.parse ();
364@@ -564,25 +614,48 @@
365 assert (!extension.request_handled ("https://ads.bogus.name/blub", "https://ads.bogus.name/blub"));
366 /* Favicons don't either */
367 assert (!extension.request_handled ("https://foo.com", "https://ads.bogus.name/blub/favicon.ico"));
368- assert (extension.cache.size () == 0);
369+ assert (extension.status_icon.state == Adblock.State.ENABLED);
370 /* Some sanity checks to be sure there's no earlier problem */
371 assert (sub.title == "Exercise");
372 assert (sub.get_directive ("https://ads.bogus.name/blub", "") == Adblock.Directive.BLOCK);
373 /* A rule hit should add to the cache */
374- assert (extension.request_handled ("https://foo.com", "https://ads.bogus.name/blub"));
375- assert (extension.cache.size () > 0);
376+ assert (extension.request_handled ("https://ads.bogus.name/blub", "https://foo.com"));
377+ assert (extension.status_icon.state == Adblock.State.BLOCKED);
378+ assert (extension.hider_selectors.str != "");
379 /* Disabled means no request should be handled */
380 extension.config.enabled = false;
381- assert (!extension.request_handled ("https://foo.com", "https://ads.bogus.name/blub"));
382- /* Removing a subscription should clear the cache */
383+ assert (!extension.request_handled ("https://ads.bogus.name/blub", "https://foo.com"));
384+ // FIXME: assert (extension.status_icon.state == Adblock.State.DISABLED);
385+ /* Removing a subscription should clear the cached CSS */
386 extension.config.remove (sub);
387- assert (extension.cache.size () == 0);
388+ assert (extension.hider_selectors.str == "");
389 assert (extension.config.size == 3);
390 /* Now let's add a custom rule */
391 extension.config.enabled = true;
392- extension.custom.add_rule ("*.png");
393- assert (!extension.request_handled ("https://foo.com", "http://alpha.beta.com/images/yota.png"));
394- assert (extension.cache.size () > 0);
395+ extension.custom.add_rule ("/adpage.");
396+ assert (extension.custom.get_directive ("http://www.engadget.com/_uac/adpage.html", "http://foo.com") == Adblock.Directive.BLOCK);
397+ assert (extension.request_handled ("http://www.engadget.com/_uac/adpage.html", "http://foo.com"));
398+ assert (extension.status_icon.state == Adblock.State.BLOCKED);
399+ /* Second attempt, from cache, same result */
400+ assert (extension.custom.get_directive ("http://www.engadget.com/_uac/adpage.html", "http://foo.com") == Adblock.Directive.BLOCK);
401+ assert (extension.request_handled ("http://www.engadget.com/_uac/adpage.html", "http://foo.com"));
402+ /* Another custom rule */
403+ extension.custom.add_rule ("/images/*.png");
404+ assert (extension.custom.get_directive ("http://alpha.beta.com/images/yota.png", "https://foo.com") == Adblock.Directive.BLOCK);
405+ assert (extension.request_handled ("http://alpha.beta.com/images/yota.png", "https://foo.com"));
406+ /* Second attempt, from cache, same result */
407+ assert (extension.request_handled ("http://alpha.beta.com/images/yota.png", "https://foo.com"));
408+ /* Similar uri but .jpg should pass */
409+ assert (!extension.request_handled ("http://alpha.beta.com/images/yota.jpg", "https://foo.com"));
410+ assert (extension.custom.get_directive ("http://alpha.beta.com/images/yota.jpg", "https://foo.com") != Adblock.Directive.BLOCK);
411+ /* Add whitelist rule */
412+ extension.custom.add_rule ("@@http://alpha.beta.com/images/drop*bear.png");
413+ assert (!extension.request_handled ("http://alpha.beta.com/images/drop-bear.png", "https://foo.com"));
414+ assert (!extension.request_handled ("http://alpha.beta.com/images/dropzone_bear.png", "https://foo.com"));
415+ assert (extension.custom.get_directive ("http://alpha.beta.com/images/drop-bear.png", "https://foo.com") != Adblock.Directive.BLOCK);
416+ /* Doesn't match whitelist, matches *.png rule, should be blocked */
417+ assert (extension.request_handled ("http://alpha.beta.com/images/bear.png", "https://foo.com"));
418+ assert (extension.custom.get_directive ("http://alpha.beta.com/images/bear.png", "https://foo.com") == Adblock.Directive.BLOCK);
419 }
420
421 struct TestCaseLine {
422@@ -647,7 +720,7 @@
423 return "none";
424 return directive.to_string ();
425 }
426-
427+
428 void test_adblock_pattern () {
429 string path = Midori.Paths.get_res_filename ("adblock.list");
430 string uri;
431
432=== modified file 'extensions/adblock/subscriptions.vala'
433--- extensions/adblock/subscriptions.vala 2014-03-06 21:33:43 +0000
434+++ extensions/adblock/subscriptions.vala 2014-03-14 21:32:33 +0000
435@@ -33,6 +33,7 @@
436 public bool active { get; set; default = true; }
437 public bool mutable { get; set; default = true; }
438 public bool valid { get; private set; default = true; }
439+ HashTable<string, Directive?> cache;
440 List<Feature> features;
441 public Pattern pattern;
442 public Keys keys;
443@@ -70,6 +71,7 @@
444 public uint size { get; private set; }
445
446 public void clear () {
447+ cache = new HashTable<string, Directive?> (str_hash, str_equal);
448 foreach (var feature in features)
449 feature.clear ();
450 optslist.clear ();
451@@ -99,6 +101,10 @@
452 if (line[0] == '#')
453 return;
454
455+ /* TODO: CSS hider whitelist */
456+ if ("#@#" in line)
457+ return;
458+
459 /* Per domain CSS hider rule */
460 if ("##" in line) {
461 frame_add_private (line, "##");
462@@ -155,6 +161,16 @@
463 }
464
465 void update_css_hash (string domain, string value) {
466+ string[] valid_elements = { "::after", "::before", "a", "abbr", "address", "article", "aside",
467+ "b", "blockquote", "caption", "center", "cite", "code", "div", "dl", "dt", "dd", "em",
468+ "feed", "fieldset", "figcaption", "figure", "font", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6",
469+ "header", "hgroup", "i", "iframe", "iframe html *", "img", "kbd", "label", "legend", "li",
470+ "m", "main", "marquee", "menu", "nav", "ol", "option", "p", "pre", "q", "samp", "section",
471+ "small", "span", "strong", "summary", "table", "tr", "tbody", "td", "th", "thead", "tt", "ul" };
472+
473+ if (!value.has_prefix (".") && !value.has_prefix ("#")
474+ && !(value.split("[")[0] in valid_elements))
475+ message ("Adblock: Invalid selector: %s", value);
476 string? olddata = element.lookup (domain);
477 if (olddata != null) {
478 string newdata = olddata + " , " + value;
479@@ -195,7 +211,7 @@
480 /* is pattern is already a regex? */
481 if (Regex.match_simple ("^/.*[\\^\\$\\*].*/$", patt,
482 RegexCompileFlags.UNGREEDY, RegexMatchFlags.NOTEMPTY)
483- || opts != null && opts.contains ("whitelist")) {
484+ || (opts != null && opts.contains ("whitelist"))) {
485 if (debug_parse)
486 stdout.printf ("patt: %s\n", patt);
487 if (opts.contains ("whitelist"))
488@@ -339,8 +355,11 @@
489
490 public Directive? get_directive (string request_uri, string page_uri) {
491 try {
492+ Directive? directive = cache.lookup (request_uri);
493+ if (directive != null)
494+ return directive;
495 foreach (var feature in features) {
496- Directive? directive = feature.match (request_uri, page_uri);
497+ directive = feature.match (request_uri, page_uri);
498 if (directive != null) {
499 debug ("%s gave %s for %s (%s)\n",
500 feature.get_type ().name (), directive.to_string (), request_uri, page_uri);
501
502=== modified file 'extensions/adblock/widgets.vala'
503--- extensions/adblock/widgets.vala 2014-03-09 21:37:56 +0000
504+++ extensions/adblock/widgets.vala 2014-03-14 21:32:33 +0000
505@@ -15,12 +15,14 @@
506
507 public class StatusIcon {
508 Config config;
509- State state;
510+ SubscriptionManager manager;
511+ public State state;
512 public bool debug_element_toggled;
513 public List<IconButton> toggle_buttons;
514
515- public StatusIcon (Adblock.Config config) {
516+ public StatusIcon (Adblock.Config config, SubscriptionManager manager) {
517 this.config = config;
518+ this.manager = manager;
519 this.debug_element_toggled = false;
520 }
521
522@@ -44,6 +46,15 @@
523 }
524 }
525
526+ public IconButton add_button () {
527+ var button = new IconButton ();
528+ button.set_status (config.enabled ? "enabled" : "disabled");
529+ button.clicked.connect (icon_clicked);
530+ button.destroy.connect (()=> { toggle_buttons.remove (button); });
531+ toggle_buttons.append (button);
532+ return button;
533+ }
534+
535 public void update_buttons () {
536 string state = "";
537 foreach (var toggle_button in toggle_buttons) {
538@@ -65,7 +76,20 @@
539
540 public void icon_clicked (Gtk.Button toggle_button) {
541 var menu = new Gtk.Menu ();
542- var checkitem = new Gtk.CheckMenuItem.with_label (_("Disabled"));
543+
544+ var menuitem = new Gtk.ImageMenuItem.with_label (_("Preferences"));
545+ var image = new Gtk.Image.from_stock (Gtk.STOCK_PREFERENCES, Gtk.IconSize.MENU);
546+ menuitem.always_show_image = true;
547+ menuitem.set_image (image);
548+ menuitem.activate.connect (() => {
549+ manager.add_subscription (null);
550+ });
551+ menu.append (menuitem);
552+
553+ var separator = new Gtk.SeparatorMenuItem ();
554+ menu.append (separator);
555+
556+ var checkitem = new Gtk.CheckMenuItem.with_label (_("Disable"));
557 checkitem.set_active (!config.enabled);
558 checkitem.toggled.connect (() => {
559 config.enabled = !checkitem.active;
560@@ -80,18 +104,9 @@
561 });
562 menu.append (hideritem);
563
564- var menuitem = new Gtk.ImageMenuItem.with_label (_("Preferences"));
565- var image = new Gtk.Image.from_stock (Gtk.STOCK_PREFERENCES, Gtk.IconSize.MENU);
566- menuitem.always_show_image = true;
567- menuitem.set_image (image);
568- menuitem.activate.connect (() => {
569- SubscriptionManager manager = new SubscriptionManager (config);
570- manager.add_subscription (null);
571- });
572- menu.append (menuitem);
573-
574 menu.show_all ();
575- Katze.widget_popup (toggle_button, menu, null, Katze.MenuPos.CURSOR);
576+ menu.attach_to_widget (toggle_button, null);
577+ menu.popup (null, null, null, 1, Gtk.get_current_event_time ());
578 }
579 }
580
581@@ -196,6 +211,9 @@
582 scrolled.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
583 scrolled.add (treeview);
584 vbox.pack_start (scrolled);
585+ int height;
586+ treeview.create_pango_layout ("a\nb").get_pixel_size (null, out height);
587+ scrolled.set_size_request (-1, height * 5);
588
589 foreach (Subscription sub in config)
590 liststore.insert_with_values (null, 0, 0, sub);
591
592=== modified file 'midori/midori-browser.c'
593--- midori/midori-browser.c 2014-03-06 22:22:37 +0000
594+++ midori/midori-browser.c 2014-03-14 21:32:33 +0000
595@@ -1523,7 +1523,8 @@
596 return;
597
598 GtkWidget* new_view = midori_browser_add_uri (browser, uri);
599- midori_browser_view_copy_history (new_view, view, FALSE);
600+ if (view != NULL)
601+ midori_browser_view_copy_history (new_view, view, FALSE);
602
603 if (!background)
604 midori_browser_set_current_tab (browser, new_view);
605@@ -1536,7 +1537,9 @@
606 const gchar* uri,
607 MidoriBrowser* browser)
608 {
609- if (midori_view_forward_external (view, uri, MIDORI_NEW_VIEW_WINDOW))
610+ if (midori_view_forward_external (
611+ view ? view : midori_browser_get_current_tab (browser),
612+ uri, MIDORI_NEW_VIEW_WINDOW))
613 return;
614
615 MidoriBrowser* new_browser;

Subscribers

People subscribed via source and target branches

to all changes: