summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Dywan <christian@twotoasts.de>2018-09-07 13:28:10 +0200
committerGitHub <noreply@github.com>2018-09-07 13:28:10 +0200
commit2e94e9866b42e2ccf7cd0fa7677b7ecb11de151f (patch)
treed5bc1120874de4bb1bd8c9591737c1de1bf1924c
parentadeb99a063e2364e137e78968276de1860101d98 (diff)
downloadmidori-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.txt1
-rw-r--r--core/CMakeLists.txt20
-rw-r--r--core/about.vala2
-rw-r--r--core/app.vala9
-rw-r--r--core/browser.vala10
-rw-r--r--core/clear-private-data.vala2
-rw-r--r--core/completion.vala12
-rw-r--r--core/database.vala41
-rw-r--r--core/plugins.vala29
-rw-r--r--core/tab.vala13
-rw-r--r--extensions/CMakeLists.txt52
-rw-r--r--snap/snapcraft.yaml3
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