Files
wireplumber/modules/module-file-monitor-api.c
Julian Bouzas c61d1e4245 component-loader: make wp_core_load_component() API asynchronous
This change completely refactors the way components are loaded in wireplumber:
- The module_init() function must return a GObject now. This object is either
a WpPlugin or a WpSiFactory in the current modules.
- When the component loader initializes a module, it automatically registers
the WpPlugin or WpSiFactory with their respective methods. There is no need
to register the WpPlugin or WpSiFactory in the module now.
- The wp_core_load_component() API has been refactored to be asynchronows. This
allows the component loader to automatically activate WpPlugin objects, and
therefore allows the application to directly get the WpPlugin without having
to find it. This simplifies a lot of things.
- The 'ifexists' and 'nofail' component flags now work even if the respective
WpPlugin could not be activated.
- The code that loads components in main.c has also been simplified a lot,
and the option to load dangling components has also been removed.
2023-04-17 07:48:18 -04:00

212 lines
5.6 KiB
C

/* WirePlumber
*
* Copyright © 2021 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <stdio.h>
#include <wp/wp.h>
struct _WpFileMonitorApi
{
WpPlugin parent;
GHashTable *monitors;
};
enum {
ACTION_ADD_WATCH,
ACTION_REMOVE_WATCH,
SIGNAL_CHANGED,
N_SIGNALS
};
static guint signals[N_SIGNALS] = {0};
G_DECLARE_FINAL_TYPE (WpFileMonitorApi, wp_file_monitor_api, WP,
FILE_MONITOR_API, WpPlugin)
G_DEFINE_TYPE (WpFileMonitorApi, wp_file_monitor_api, WP_TYPE_PLUGIN)
static void
wp_file_monitor_api_init (WpFileMonitorApi * self)
{
self->monitors = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
g_object_unref);
}
static void
wp_file_monitor_api_finalize (GObject * object)
{
WpFileMonitorApi * self = WP_FILE_MONITOR_API (object);
g_clear_pointer (&self->monitors, g_hash_table_unref);
G_OBJECT_CLASS (wp_file_monitor_api_parent_class)->finalize (object);
}
static void
on_file_monitor_changed (GFileMonitor *monitor, GFile *file, GFile *other,
GFileMonitorEvent evtype, gpointer data)
{
WpFileMonitorApi * self = WP_FILE_MONITOR_API (data);
g_autofree char *fpath = g_file_get_path (file);
g_autofree char *opath = NULL;
const gchar *evtype_str = NULL;
if (other)
opath = g_file_get_path (other);
switch(evtype) {
case G_FILE_MONITOR_EVENT_CHANGED:
evtype_str = "changed";
break;
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
evtype_str = "changes-done-hint";
break;
case G_FILE_MONITOR_EVENT_DELETED:
evtype_str = "deleted";
break;
case G_FILE_MONITOR_EVENT_CREATED:
evtype_str = "created";
break;
case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
evtype_str = "attribute-changed";
break;
case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
evtype_str = "pre-unmount";
break;
case G_FILE_MONITOR_EVENT_UNMOUNTED:
evtype_str = "unmounted";
break;
case G_FILE_MONITOR_EVENT_MOVED:
evtype_str = "moved";
break;
case G_FILE_MONITOR_EVENT_RENAMED:
evtype_str = "renamed";
break;
case G_FILE_MONITOR_EVENT_MOVED_IN:
evtype_str = "moved-in";
break;
case G_FILE_MONITOR_EVENT_MOVED_OUT:
evtype_str = "moved-out";
break;
default:
wp_warning_object (self, "Unknown event type %d", evtype);
break;
}
g_signal_emit (self, signals[SIGNAL_CHANGED], 0, fpath, opath, evtype_str);
}
static gboolean
wp_file_monitor_api_add_watch (WpFileMonitorApi * self, const gchar *path,
const gchar *flags_str)
{
g_autoptr (GError) e = NULL;
g_autoptr (GFileMonitor) fm = NULL;
g_autoptr (GFile) f = NULL;
GFileMonitorFlags flags = G_FILE_MONITOR_NONE;
/* don't do anything if the path is already being watched */
if (g_hash_table_contains (self->monitors, path))
return TRUE;
/* get path */
f = g_file_new_for_path (path);
if (!f) {
wp_warning_object (self, "Invalid path '%s'", path);
return FALSE;
}
/* parse flags */
for (guint i = 0; flags_str && i < strlen (flags_str); i++) {
switch (flags_str[i]) {
case 'o': flags |= G_FILE_MONITOR_WATCH_MOUNTS; break;
case 's': flags |= G_FILE_MONITOR_SEND_MOVED; break;
case 'h': flags |= G_FILE_MONITOR_WATCH_HARD_LINKS; break;
case 'm': flags |= G_FILE_MONITOR_WATCH_MOVES; break;
default:
break;
}
}
/* create the file monitor for that path */
fm = g_file_monitor (f, flags, NULL, &e);
if (e) {
wp_warning_object (self, "Failed to add watch for path '%s': %s", path,
e->message);
return FALSE;
}
/* handle changed signal and add it to monitors table */
g_signal_connect (fm, "changed", G_CALLBACK (on_file_monitor_changed), self);
g_hash_table_insert (self->monitors, g_strdup (path), g_steal_pointer (&fm));
return TRUE;
}
static void
wp_file_monitor_api_remove_watch (WpFileMonitorApi * self, const gchar *path)
{
g_hash_table_remove (self->monitors, path);
}
static void
wp_file_monitor_api_enable (WpPlugin * plugin, WpTransition * transition)
{
WpFileMonitorApi * self = WP_FILE_MONITOR_API (plugin);
wp_object_update_features (WP_OBJECT (self), WP_PLUGIN_FEATURE_ENABLED, 0);
}
static void
wp_file_monitor_api_disable (WpPlugin * plugin)
{
WpFileMonitorApi * self = WP_FILE_MONITOR_API (plugin);
g_hash_table_remove_all (self->monitors);
}
static void
wp_file_monitor_api_class_init (WpFileMonitorApiClass * klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
WpPluginClass *plugin_class = (WpPluginClass *) klass;
object_class->finalize = wp_file_monitor_api_finalize;
plugin_class->enable = wp_file_monitor_api_enable;
plugin_class->disable = wp_file_monitor_api_disable;
signals[ACTION_ADD_WATCH] = g_signal_new_class_handler (
"add-watch", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
(GCallback) wp_file_monitor_api_add_watch,
NULL, NULL, NULL,
G_TYPE_BOOLEAN, 2, G_TYPE_STRING, G_TYPE_STRING);
signals[ACTION_REMOVE_WATCH] = g_signal_new_class_handler (
"remove-watch", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
(GCallback) wp_file_monitor_api_remove_watch,
NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_STRING);
signals[SIGNAL_CHANGED] = g_signal_new (
"changed", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
}
WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
{
return G_OBJECT (g_object_new (wp_file_monitor_api_get_type (),
"name", "file-monitor-api",
"core", core,
NULL));
}