no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
Previous revisionLast revision | |||
— | midori:tutorial [2014/03/04 18:36] – [Add an app menu item] axlrose | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Midori - Tutorial ====== | ||
+ | **This document is licensed under the LGPL 2.1.** | ||
+ | |||
+ | ===== Writing a new extension ===== | ||
+ | |||
+ | ====== Check out the sources ====== | ||
+ | |||
+ | <code bash>bzr branch lp: | ||
+ | |||
+ | To develop and build extensions you need a source tree, typically it is a good idea to use the latest trunk to benefit from the latest and greatest features or bug fixes. So if your extension uncovers a bug you can easily report it and get it fixed. | ||
+ | For more details see [[contribute]] which also covers how to make a branch and codying style in detail. | ||
+ | |||
+ | |||
+ | ====== Add a new extension ===== | ||
+ | |||
+ | The minimum starting point is a new .vala file in ./ | ||
+ | |||
+ | The code to start with is this: | ||
+ | <code vala> | ||
+ | namespace Sandcat { | ||
+ | private class Manager : Midori.Extension { | ||
+ | |||
+ | internal Manager () { | ||
+ | GLib.Object (name: _(" | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public Midori.Extension extension_init () { | ||
+ | return new Sandcat.Manager (); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Now let's proceed to run our rather empty extension. | ||
+ | |||
+ | **__The first instrruction__** | ||
+ | <code bash> | ||
+ | user@host: | ||
+ | user@host: | ||
+ | user@host: | ||
+ | After any modifiction in " | ||
+ | <code bash> | ||
+ | If you add a new extentioon you run : | ||
+ | <code bash> | ||
+ | user@host: | ||
+ | and after you use the **__The first instrruction__**. | ||
+ | |||
+ | Inside Midori, open the Preferences, | ||
+ | ====== Activating the extension ====== | ||
+ | |||
+ | A basic principle is that each extension is loaded at first to describe what it does and to be shown in the preferences. At that point it doesn' | ||
+ | |||
+ | <code vala> | ||
+ | namespace Sandcat { | ||
+ | private class Manager : Midori.Extension { | ||
+ | |||
+ | internal Manager () { | ||
+ | GLib.Object (name: _(" | ||
+ | | ||
+ | | ||
+ | | ||
+ | activate.connect (this.activated); | ||
+ | deactivate.connect (this.deactivated); | ||
+ | } | ||
+ | |||
+ | void browser_added (Midori.Browser browser) { | ||
+ | stdout.printf ("a new browser was added, yay\n" | ||
+ | } | ||
+ | |||
+ | void activated (Midori.App app) { | ||
+ | foreach (var browser in app.get_browsers ()) | ||
+ | browser_added (browser); | ||
+ | app.add_browser.connect (browser_added); | ||
+ | } | ||
+ | |||
+ | void deactivated () { | ||
+ | var app = get_app (); | ||
+ | app.add_browser.disconnect (browser_added); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public Midori.Extension extension_init () { | ||
+ | return new Sandcat.Manager (); | ||
+ | } | ||
+ | </ | ||
+ | You'll see how when activated the extension gets an " | ||
+ | |||
+ | ====== Working with (web) views ===== | ||
+ | |||
+ | <code vala> | ||
+ | namespace Sandcat { | ||
+ | private class Manager : Midori.Extension { | ||
+ | |||
+ | internal Manager () { | ||
+ | GLib.Object (name: _(" | ||
+ | | ||
+ | | ||
+ | | ||
+ | activate.connect (this.activated); | ||
+ | deactivate.connect (this.deactivated); | ||
+ | } | ||
+ | |||
+ | void tab_added (Midori.Browser browser, Midori.Tab tab) { | ||
+ | stdout.printf ("New tab added\n" | ||
+ | } | ||
+ | |||
+ | void tab_switched (Midori.View? | ||
+ | var title = new_view.get_display_title(); | ||
+ | var uri = new_view.get_display_uri(); | ||
+ | stdout.printf (" | ||
+ | } | ||
+ | |||
+ | void tab_removed () { | ||
+ | stdout.printf ("tab removed\n" | ||
+ | } | ||
+ | |||
+ | void browser_added (Midori.Browser browser) { | ||
+ | | ||
+ | tab_added (browser, tab); | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | void activated (Midori.App app) { | ||
+ | foreach (var browser in app.get_browsers ()) | ||
+ | browser_added (browser); | ||
+ | app.add_browser.connect (browser_added); | ||
+ | } | ||
+ | |||
+ | void browser_removed (Midori.Browser browser) { | ||
+ | foreach (var tab in browser.get_tabs ()) { | ||
+ | browser.add_tab.disconnect (tab_added); | ||
+ | browser.switch_tab.disconnect (tab_switched); | ||
+ | browser.remove_tab.disconnect (tab_removed); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void deactivated () { | ||
+ | var app = get_app (); | ||
+ | app.add_browser.disconnect (browser_added); | ||
+ | foreach (var browser in app.get_browsers ()) | ||
+ | browser_removed (browser); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public Midori.Extension extension_init () { | ||
+ | return new Sandcat.Manager (); | ||
+ | } | ||
+ | </ | ||
+ | When you open a new tab you will see in a message "New tab added", | ||
+ | ====== Add a context menu item ====== | ||
+ | |||
+ | <code vala> | ||
+ | namespace Sandcat { | ||
+ | private class Manager : Midori.Extension { | ||
+ | |||
+ | internal Manager () { | ||
+ | GLib.Object (name: _(" | ||
+ | | ||
+ | | ||
+ | | ||
+ | activate.connect (this.activated); | ||
+ | deactivate.connect (this.deactivated); | ||
+ | } | ||
+ | |||
+ | void tab_added (Midori.Browser browser, Midori.Tab tab) { | ||
+ | tab.context_menu.connect (add_menu_items); | ||
+ | } | ||
+ | |||
+ | void add_menu_items (WebKit.HitTestResult hit_test_result, | ||
+ | if ((hit_test_result.context & WebKit.HitTestResultContext.SELECTION) == 0) | ||
+ | return; | ||
+ | |||
+ | var action1 = new Gtk.Action (" | ||
+ | var action2 = new Gtk.Action (" | ||
+ | action1.activate.connect (() => { | ||
+ | stdout.printf ("my menu item1 rocks\n" | ||
+ | }); | ||
+ | action2.activate.connect (() => { | ||
+ | stdout.printf ("my menu item2 rocks\n" | ||
+ | }); | ||
+ | menu.add (action1); | ||
+ | menu.add (action2); | ||
+ | | ||
+ | //Add group of submenu | ||
+ | var submenu = new Midori.ContextAction(" | ||
+ | var listsubmenu = new List< | ||
+ | for (int i = 0; i < 10; i++) | ||
+ | listsubmenu.append(new Gtk.Action(" | ||
+ | |||
+ | |||
+ | listsubmenu.foreach ((entry) => { | ||
+ | entry.activate.connect(() => { | ||
+ | stdout.printf ("I am a submenu\n" | ||
+ | }); | ||
+ | submenu.add(entry); | ||
+ | }); | ||
+ | menu.add (submenu); | ||
+ | } | ||
+ | |||
+ | void browser_added (Midori.Browser browser) { | ||
+ | | ||
+ | tab_added (browser, tab); | ||
+ | | ||
+ | |||
+ | } | ||
+ | |||
+ | void activated (Midori.App app) { | ||
+ | foreach (var browser in app.get_browsers ()) | ||
+ | browser_added (browser); | ||
+ | app.add_browser.connect (browser_added); | ||
+ | } | ||
+ | |||
+ | void browser_removed (Midori.Browser browser) { | ||
+ | foreach (var tab in browser.get_tabs ()) { | ||
+ | browser.add_tab.disconnect (tab_added); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void deactivated () { | ||
+ | var app = get_app (); | ||
+ | app.add_browser.disconnect (browser_added); | ||
+ | foreach (var browser in app.get_browsers ()) | ||
+ | browser_removed (browser); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public Midori.Extension extension_init () { | ||
+ | return new Sandcat.Manager (); | ||
+ | } | ||
+ | </ | ||
+ | In the Web page try to select a word or a sentence right click and you are going to see three menu item which were added, click on one of them and you will see the magic in the terminal :) . | ||
+ | ====== Add an app menu item ====== | ||
+ | <code vala> | ||
+ | namespace Sandcat { | ||
+ | private class Manager : Midori.Extension { | ||
+ | internal Manager () { | ||
+ | GLib.Object (name: _(" | ||
+ | | ||
+ | | ||
+ | | ||
+ | activate.connect (this.activated); | ||
+ | deactivate.connect (this.deactivated); | ||
+ | } | ||
+ | void tool_menu_populated (Gtk.Menu menu) { | ||
+ | var item = new Gtk.MenuItem.with_label(" | ||
+ | menu.add(item); | ||
+ | item.show(); | ||
+ | } | ||
+ | |||
+ | void browser_added (Midori.Browser browser) { | ||
+ | browser.populate_tool_menu.connect(tool_menu_populated); | ||
+ | } | ||
+ | |||
+ | void activated (Midori.App app) { | ||
+ | foreach (var browser in app.get_browsers ()) | ||
+ | browser_added (browser); | ||
+ | app.add_browser.connect (browser_added); | ||
+ | } | ||
+ | |||
+ | void deactivated () { | ||
+ | var app = get_app (); | ||
+ | app.add_browser.disconnect (browser_added); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public Midori.Extension extension_init () { | ||
+ | return new Sandcat.Manager (); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Here you are enjoy, it is easy, isn't it ? :-) | ||
+ | ====== Modify resources or webpages loaded ====== | ||
+ | |||
+ | whatever | ||
+ | |||
+ | ====== Add a statusbar item ====== | ||
+ | |||
+ | <code vala> | ||
+ | namespace Sandcat { | ||
+ | private class Manager : Midori.Extension { | ||
+ | |||
+ | internal Manager () { | ||
+ | GLib.Object (name: _(" | ||
+ | | ||
+ | | ||
+ | | ||
+ | activate.connect (this.activated); | ||
+ | deactivate.connect (this.deactivated); | ||
+ | } | ||
+ | |||
+ | void browser_added (Midori.Browser browser) { | ||
+ | var button = new Gtk.Button.with_label (" | ||
+ | var click_counter = 0; | ||
+ | browser.statusbar.pack_start (button, false, false, 3); | ||
+ | button.clicked.connect (() => { | ||
+ | button.label = "You Clicked me (%d) time(s)" | ||
+ | }); | ||
+ | button.show (); | ||
+ | } | ||
+ | |||
+ | void activated (Midori.App app) { | ||
+ | foreach (var browser in app.get_browsers ()) | ||
+ | browser_added (browser); | ||
+ | app.add_browser.connect (browser_added); | ||
+ | } | ||
+ | |||
+ | void deactivated () { | ||
+ | var app = get_app (); | ||
+ | app.add_browser.disconnect (browser_added); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public Midori.Extension extension_init () { | ||
+ | return new Sandcat.Manager (); | ||
+ | } | ||
+ | </ | ||
+ | Enjoy How much time you click :-), you can add any Gtk widget in this StatusBar. | ||
+ | ====== Add a panel ====== | ||
+ | |||
+ | <code vala> | ||
+ | // in private class Manager : Midori.Extension | ||
+ | GLib.List< | ||
+ | |||
+ | // in deactivated | ||
+ | foreach (var widget in widgets) | ||
+ | widget.destroy (); | ||
+ | |||
+ | // in activated | ||
+ | widgets = new GLib.List< | ||
+ | |||
+ | // in browser_added | ||
+ | var viewable = new Sidebar (); | ||
+ | viewable.show (); | ||
+ | browser.panel.append_page (viewable); | ||
+ | widgets.append (viewable); | ||
+ | </ | ||
+ | |||
+ | Now on to adding a class implementing that panel. | ||
+ | |||
+ | <code vala> | ||
+ | private class Sidebar : Gtk.VBox, Midori.Viewable { | ||
+ | public unowned string get_stock_id () { | ||
+ | return " | ||
+ | } | ||
+ | |||
+ | public unowned string get_label () { | ||
+ | return _(" | ||
+ | } | ||
+ | |||
+ | public Gtk.Widget get_toolbar () { | ||
+ | return null; | ||
+ | } | ||
+ | |||
+ | public Sidebar () { | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ====== Add a dialog ====== | ||
+ | |||
+ | whatever | ||
+ | |||
+ | ====== Add a URL completion ====== | ||
+ | |||
+ | whatever | ||
+ | |||
+ | ====== Unit testing ====== | ||
+ | |||
+ | A basic means of quality control, as humans simply don't write flawless code, is to add some automatable tests that can be run repeatedly to verify the code does what it's expected to. | ||
+ | |||
+ | <code vala> | ||
+ | void test_furry_purr () { | ||
+ | assert (1 == 1); | ||
+ | } | ||
+ | |||
+ | public void extension_test () { | ||
+ | | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | With a simple example it will be like this: | ||
+ | <code vala> | ||
+ | void test_furry_purr () { | ||
+ | assert (1 == 1); | ||
+ | } | ||
+ | |||
+ | public void extension_test () { | ||
+ | | ||
+ | } | ||
+ | |||
+ | void main (string[] args) { | ||
+ | Test.init (ref args); | ||
+ | extension_test(); | ||
+ | Test.run (); | ||
+ | }</ | ||
+ | The output could look like this. | ||
+ | <code bash> | ||
+ | / | ||
+ | </ |