diff options
author | Christian Dywan <christian@twotoasts.de> | 2018-09-07 13:28:10 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-09-07 13:28:10 +0200 |
commit | 2e94e9866b42e2ccf7cd0fa7677b7ecb11de151f (patch) | |
tree | d5bc1120874de4bb1bd8c9591737c1de1bf1924c | |
parent | adeb99a063e2364e137e78968276de1860101d98 (diff) | |
download | midori-git-2e94e9866b42e2ccf7cd0fa7677b7ecb11de151f.tar.gz |
More fine-grained Activatable interfaces (#42)
* `Plugins.plug` now takes a type and property, consumer connects signals.
* Generation of a GIR file.
* Preparation for built-in extensions in `extensions` folder.
* Tweaks to `Database` to avoid exposing `Sqlite` namespace in public API.
Note: Avoiding `owned get; construct;` with `Activatable` interfaces as
used in the definition of `Peas.Activatable` because it triggers a lot
of internal compiler assertions at build time.
Fixes: #35
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | core/CMakeLists.txt | 20 | ||||
-rw-r--r-- | core/about.vala | 2 | ||||
-rw-r--r-- | core/app.vala | 9 | ||||
-rw-r--r-- | core/browser.vala | 10 | ||||
-rw-r--r-- | core/clear-private-data.vala | 2 | ||||
-rw-r--r-- | core/completion.vala | 12 | ||||
-rw-r--r-- | core/database.vala | 41 | ||||
-rw-r--r-- | core/plugins.vala | 29 | ||||
-rw-r--r-- | core/tab.vala | 13 | ||||
-rw-r--r-- | extensions/CMakeLists.txt | 52 | ||||
-rw-r--r-- | snap/snapcraft.yaml | 3 |
12 files changed, 159 insertions, 35 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index fb461cb9..c1ae0918 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,6 +81,7 @@ set(DESKTOP_ICON "${CMAKE_PROJECT_NAME}" CACHE STRING "The Icon value to be used add_subdirectory (core) add_subdirectory (web) +add_subdirectory (extensions) enable_testing() add_subdirectory (tests) add_subdirectory (po) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index d12f5fb7..ff30f54e 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,7 +1,8 @@ # Copyright (C) 2013-2018 Christian Dywan <christian@twotoasts.de> -set(LIBCORE_VERSION ${CORE_VERSION}) +set(LIBCORE_VERSION 0.6) set(LIBCORE_SOVERSION 0) +set(LIBCORE_GIR Midori-${LIBCORE_VERSION}) file(GLOB LIBCORE_SOURCE *.vala) list(REMOVE_ITEM LIBCORE_SOURCE "main.vala") @@ -21,6 +22,8 @@ CUSTOM_VAPIS ${EXTRA_VAPIS} GENERATE_VAPI "${LIBCORE}" +GENERATE_GIR + ${LIBCORE_GIR} GENERATE_HEADER "${LIBCORE}" ) @@ -33,10 +36,6 @@ OPTIONS ${VALAFLAGS} CUSTOM_VAPIS ${EXTRA_VAPIS} -GENERATE_VAPI - "${CMAKE_PROJECT_NAME}" -GENERATE_HEADER - "${CMAKE_PROJECT_NAME}" ) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/resources.c @@ -60,6 +59,17 @@ set_target_properties("${LIBCORE}" PROPERTIES VERSION ${LIBCORE_VERSION} ) +find_program (GIR_COMPILER_BIN g-ir-compiler) +add_custom_target("g-ir-compiler_${LIBCORE}" ALL + ${GIR_COMPILER_BIN} ${CMAKE_CURRENT_BINARY_DIR}/${LIBCORE_GIR}.gir + --output ${CMAKE_CURRENT_BINARY_DIR}/${LIBCORE_GIR}.typelib + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + DEPENDS ${LIBCORE_GIR}.gir) +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${LIBCORE_GIR}.gir" + DESTINATION "${CMAKE_INSTALL_DATADIR}/gir-1.0/") +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${LIBCORE_GIR}.typelib" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/girepository-1.0/") + include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/core/about.vala b/core/about.vala index a0662716..bfc87260 100644 --- a/core/about.vala +++ b/core/about.vala @@ -11,7 +11,7 @@ namespace Midori { [GtkTemplate (ui = "/ui/about.ui")] - public class About : Gtk.AboutDialog { + class About : Gtk.AboutDialog { public About (Gtk.Window parent) { Object (transient_for: parent, website: Config.PROJECT_WEBSITE, diff --git a/core/app.vala b/core/app.vala index 07b06926..a495effc 100644 --- a/core/app.vala +++ b/core/app.vala @@ -10,6 +10,11 @@ */ namespace Midori { + public interface AppActivatable : Peas.ExtensionBase { + public abstract App app { owned get; set; } + public abstract void activate (); + } + public class App : Gtk.Application { public File? exec_path { get; protected set; default = null; } @@ -119,6 +124,10 @@ namespace Midori { if (!Gtk.Settings.get_default ().gtk_shell_shows_app_menu){ app_menu = null; } + + var extensions = Plugins.get_default ().plug<AppActivatable> ("app", this); + extensions.extension_added.connect ((info, extension) => ((AppActivatable)extension).activate ()); + extensions.foreach ((extensions, info, extension) => { extensions.extension_added (info, extension); }); } async void internal_scheme (WebKit.URISchemeRequest request) { diff --git a/core/browser.vala b/core/browser.vala index f64eda2d..c22b2417 100644 --- a/core/browser.vala +++ b/core/browser.vala @@ -10,6 +10,11 @@ */ namespace Midori { + public interface BrowserActivatable : Object { + public abstract Browser browser { owned get; set; } + public abstract void activate (); + } + [GtkTemplate (ui = "/ui/browser.ui")] public class Browser : Gtk.ApplicationWindow { public WebKit.WebContext web_context { get; construct set; } @@ -224,7 +229,10 @@ namespace Midori { // Reveal panel toggle after panels are added panel.add.connect ((widget) => { panel_toggle.show (); }); - Plugins.get_default ().plug (panel); + + var extensions = Plugins.get_default ().plug<BrowserActivatable> ("browser", this); + extensions.extension_added.connect ((info, extension) => ((BrowserActivatable)extension).activate ()); + extensions.foreach ((extensions, info, extension) => { extensions.extension_added (info, extension); }); } void update_decoration_layout () { diff --git a/core/clear-private-data.vala b/core/clear-private-data.vala index f2f33036..edf2181b 100644 --- a/core/clear-private-data.vala +++ b/core/clear-private-data.vala @@ -11,7 +11,7 @@ namespace Midori { [GtkTemplate (ui = "/ui/clear-private-data.ui")] - public class ClearPrivateData : Gtk.Dialog { + class ClearPrivateData : Gtk.Dialog { [GtkChild] Gtk.ComboBoxText timerange; [GtkChild] diff --git a/core/completion.vala b/core/completion.vala index ddb9c0a3..fe6e726a 100644 --- a/core/completion.vala +++ b/core/completion.vala @@ -23,6 +23,11 @@ namespace Midori { } } + public interface CompletionActivatable : Peas.ExtensionBase { + public abstract Completion completion { owned get; set; } + public abstract void activate (); + } + public class Completion : Object, ListModel { List<ListModel> models = new List<ListModel> (); public string? key { get; set; default = null; } @@ -38,7 +43,10 @@ namespace Midori { } catch (DatabaseError error) { debug ("Failed to initialize completion model: %s", error.message); } - Plugins.get_default ().plug (this); + + var extensions = Plugins.get_default ().plug<CompletionActivatable> ("completion", this); + extensions.extension_added.connect ((info, extension) => ((CompletionActivatable)extension).activate ()); + extensions.foreach ((extensions, info, extension) => { extensions.extension_added (info, extension); }); } public Completion () { @@ -48,7 +56,7 @@ namespace Midori { * Add a model to complete from. Items need to be based on DatabaseItem * and filtered by key if set. */ - public virtual signal void add (ListModel model) { + public void add (ListModel model) { if (model is Database) { bind_property ("key", model, "key"); } diff --git a/core/database.vala b/core/database.vala index f47f96a7..748f54c3 100644 --- a/core/database.vala +++ b/core/database.vala @@ -22,11 +22,11 @@ namespace Midori { public delegate bool DatabaseCallback () throws DatabaseError; public class DatabaseStatement : Object, Initable { - public Sqlite.Statement? stmt { get { return _stmt; } } - protected Sqlite.Statement _stmt = null; + Sqlite.Statement stmt = null; + int64 last_row_id = -1; + public Database? database { get; set construct; } public string? query { get; set construct; } - private int64 last_row_id = -1; public DatabaseStatement (Database database, string query) throws DatabaseError { Object (database: database, query: query); @@ -34,9 +34,9 @@ namespace Midori { } public virtual bool init (Cancellable? cancellable = null) throws DatabaseError { - int result = database.db.prepare_v2 (query, -1, out _stmt, null); + int result = database.db.prepare_v2 (query, -1, out stmt, null); if (result != Sqlite.OK) - throw new DatabaseError.COMPILE ("Failed to compile statement '%s': %s".printf (query, database.db.errmsg ())); + throw new DatabaseError.COMPILE ("Failed to compile statement '%s': %s".printf (query, database.errmsg)); return true; } @@ -84,8 +84,8 @@ namespace Midori { public bool step () throws DatabaseError { int result = stmt.step (); if (result != Sqlite.DONE && result != Sqlite.ROW) - throw new DatabaseError.EXECUTE (database.db.errmsg ()); - last_row_id = database.db.last_insert_rowid (); + throw new DatabaseError.EXECUTE (database.errmsg); + last_row_id = database.last_row_id; return result == Sqlite.ROW; } @@ -187,12 +187,12 @@ namespace Midori { } public class Database : Object, Initable, ListModel, Loggable { - public Sqlite.Database? db { get { return _db; } } - protected Sqlite.Database? _db = null; - public string? table { get; protected set; default = null; } - public string path { get; protected set; default = ":memory:"; } + internal Sqlite.Database? db = null; string? _key = null; Cancellable? populate_cancellable = null; + + public string? table { get; protected set; default = null; } + public string path { get; protected set; default = ":memory:"; } public string? key { get { return _key; } set { _key = value; if (populate_cancellable != null) { @@ -209,6 +209,16 @@ namespace Midori { public bool first_use { get; protected set; default = false; } /* + * The ID of the last inserted row. + */ + public int64 last_row_id { get { return db.last_insert_rowid (); } } + + /* + * The error message of the last failed operation. + */ + public string errmsg { get { return db.errmsg (); } } + + /* * If a filename is passed it's assumed to be in the config folder. * Otherwise the database is in memory only (useful for private browsing). */ @@ -250,9 +260,10 @@ namespace Midori { flags |= Sqlite.OPEN_READWRITE; } - if (Sqlite.Database.open_v2 (real_path, out _db, flags) != Sqlite.OK) { + if (Sqlite.Database.open_v2 (real_path, out db, flags) != Sqlite.OK) { throw new DatabaseError.OPEN ("Failed to open database %s".printf (real_path)); } + set_data<unowned Sqlite.Database> ("db", db); if (logging) { debug ("Tracing %s", path); @@ -274,9 +285,9 @@ namespace Midori { int64 user_version; Sqlite.Statement stmt; if (db.prepare_v2 ("PRAGMA user_version;", -1, out stmt, null) != Sqlite.OK) - throw new DatabaseError.EXECUTE ("Failed to compile statement %s".printf (db.errmsg ())); + throw new DatabaseError.EXECUTE ("Failed to compile statement %s".printf (errmsg)); if (stmt.step () != Sqlite.ROW) - throw new DatabaseError.EXECUTE ("Failed to get row %s".printf (db.errmsg ())); + throw new DatabaseError.EXECUTE ("Failed to get row %s".printf (errmsg)); user_version = stmt.column_int64 (0); if (user_version == 0) { @@ -325,7 +336,7 @@ namespace Midori { public bool exec (string query) throws DatabaseError { if (db.exec (query) != Sqlite.OK) - throw new DatabaseError.EXECUTE (db.errmsg ()); + throw new DatabaseError.EXECUTE (errmsg); return true; } diff --git a/core/plugins.vala b/core/plugins.vala index e10de4bc..a434da31 100644 --- a/core/plugins.vala +++ b/core/plugins.vala @@ -22,10 +22,25 @@ namespace Midori { Plugins () { enable_loader ("python"); - string source_path = Path.build_path (Path.DIR_SEPARATOR_S, + // Plugins installed by the user + string user_path = Path.build_path (Path.DIR_SEPARATOR_S, Environment.get_user_data_dir (), Environment.get_prgname (), "extensions"); - debug ("Loading plugins from %s", source_path); - add_search_path (source_path, null); + add_search_path (user_path, null); + debug ("Loading plugins from %s", user_path); + + var exec_path = ((App)Application.get_default ()).exec_path; + // Try and load plugins from build folder + var build_path = exec_path.get_parent ().get_child ("extensions"); + if (build_path.query_exists (null)) { + debug ("Loading plugins from %s", build_path.get_path ()); + add_search_path (build_path.get_path (), user_path); + } + // System-wide plugins + var system_path = exec_path.get_parent ().get_parent ().get_child ("lib").get_child (Environment.get_prgname ()); + if (system_path.query_exists (null)) { + debug ("Loading plugins from %s", system_path.get_path ()); + add_search_path (system_path.get_path (), user_path); + } foreach (var plugin in get_plugin_list ()) { debug ("Found plugin %s", plugin.get_name ()); if (!try_load_plugin (plugin)) { @@ -37,12 +52,10 @@ namespace Midori { /* * Plug the instance of the given object to make it extensible via Peas. */ - public void plug (Object object) { - var extensions = new Peas.ExtensionSet (this, typeof (Peas.Activatable), "object", object, null); - extensions.extension_added.connect ((info, extension) => { ((Peas.Activatable)extension).activate (); }); - extensions.extension_removed.connect ((info, extension) => { ((Peas.Activatable)extension).deactivate (); }); - extensions.foreach ((extensions, info, extension) => { extensions.extension_added (info, extension); }); + public Peas.ExtensionSet plug<T> (string name, Object object) { + var extensions = new Peas.ExtensionSet (this, typeof (T), name, object, null); object.set_data<Object> ("midori-plug", extensions); + return extensions; } } } diff --git a/core/tab.vala b/core/tab.vala index f2d8bbd5..e920d864 100644 --- a/core/tab.vala +++ b/core/tab.vala @@ -10,6 +10,11 @@ */ namespace Midori { + public interface TabActivatable : Peas.ExtensionBase { + public abstract Tab tab { owned get; set; } + public abstract void activate (); + } + [GtkTemplate (ui = "/ui/tab.ui")] public class Tab : WebKit.WebView { public string id { owned get { return "%p".printf (this); } } @@ -57,8 +62,10 @@ namespace Midori { settings.enable_developer_extras = true; if (pinned) { + var extensions = Plugins.get_default ().plug<TabActivatable> ("tab", this); + extensions.extension_added.connect ((info, extension) => ((TabActivatable)extension).activate ()); + extensions.foreach ((extensions, info, extension) => { extensions.extension_added (info, extension); }); load_uri (uri ?? "internal:speed-dial"); - Plugins.get_default ().plug (this); } else { load_uri_delayed.begin (uri, title); } @@ -86,8 +93,10 @@ namespace Midori { public override bool focus_in_event (Gdk.EventFocus event) { // Delayed load on focus if (display_uri != uri) { + var extensions = Plugins.get_default ().plug<TabActivatable> ("tab", this); + extensions.extension_added.connect ((info, extension) => ((TabActivatable)extension).activate ()); + extensions.foreach ((extensions, info, extension) => { extensions.extension_added (info, extension); }); load_uri (display_uri); - Plugins.get_default ().plug (this); } return true; } diff --git a/extensions/CMakeLists.txt b/extensions/CMakeLists.txt new file mode 100644 index 00000000..aec67acb --- /dev/null +++ b/extensions/CMakeLists.txt @@ -0,0 +1,52 @@ +# Copyright (C) 2013-2018 Christian Dywan <christian@twotoasts.de> + +set(EXTENSIONDIR "${CMAKE_INSTALL_FULL_LIBDIR}/${CMAKE_PROJECT_NAME}") +include_directories( + "${CMAKE_SOURCE_DIR}" + "${CMAKE_SOURCE_DIR}/core" + ${DEPS_INCLUDE_DIRS} + ${DEPS_GTK_INCLUDE_DIRS} + ${CMAKE_BINARY_DIR} + "${CMAKE_BINARY_DIR}/core" + ) +file(GLOB EXTENSIONS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.c *.vala) +foreach(UNIT_SRC ${EXTENSIONS}) + if (${UNIT_SRC} MATCHES "(.vala)$") + string(REPLACE ".vala" "" UNIT ${UNIT_SRC}) + include(ValaPrecompile) + vala_precompile(UNIT_SRC_C ${UNIT} + ${UNIT_SRC} + PACKAGES + ${PKGS} + OPTIONS + ${VALAFLAGS} + CUSTOM_VAPIS + ${CMAKE_BINARY_DIR}/core/${LIBCORE}.vapi + ${EXTRA_VAPIS} + ) + + add_library(${UNIT} MODULE ${UNIT_SRC_C}) + set_target_properties(${UNIT} PROPERTIES + COMPILE_FLAGS "${VALA_CFLAGS}" + ) + else() + string(REPLACE ".c" "" UNIT ${UNIT_SRC}) + add_library(${UNIT} MODULE ${UNIT_SRC}) + set_target_properties(${UNIT} PROPERTIES + COMPILE_FLAGS ${CFLAGS} + ) + endif() + target_link_libraries(${UNIT} + ${DEPS_LIBRARIES} + ${DEPS_GTK_LIBRARIES} + ${LIBCORE} + ) + install(TARGETS ${UNIT} + LIBRARY DESTINATION ${EXTENSIONDIR} + ) + set(MANIFEST "${UNIT}.plugin") + configure_file(${MANIFEST}.in ${MANIFEST}) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${MANIFEST} + DESTINATION ${EXTENSIONDIR} + ) +endforeach () diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 6d390dc8..a34b715c 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -99,7 +99,10 @@ parts: - gstreamer1.0-libav - pulseaudio-module-x11 - libmirclient9 + organize: + lib/girepository-1.0/Midori-0.6.typelib: usr/lib/girepository-1.0/Midori-0.6.typelib stage: + - -usr/share/gir-1.0/Midori-0.6.gir - -usr/lib/*/libcups.so.2 - -usr/share/doc/libcups2/changelog.Debian.gz - -usr/lib/*/libsoup-2.4.so.1.7.0 |