feat: add files monitor
FilesMonitor allows shell to monitor changes on a set of files. This allows the shell to react in realtime any changes related to its configurations such as: themes, keyboard, setting, etc.
This commit is contained in:
parent
e598847994
commit
224252807a
@ -63,6 +63,7 @@ base = [
|
|||||||
'src/input.c',
|
'src/input.c',
|
||||||
'src/virtual-keyboard.c',
|
'src/virtual-keyboard.c',
|
||||||
'src/widgets/virtual-keyboard-widgets.c',
|
'src/widgets/virtual-keyboard-widgets.c',
|
||||||
|
'src/files-monitor.c',
|
||||||
wayland_targets
|
wayland_targets
|
||||||
]
|
]
|
||||||
|
|
||||||
|
14
src/files-monior.h
Normal file
14
src/files-monior.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef DIYA_FILES_MONITOR_H
|
||||||
|
#define DIYA_FILES_MONITOR_H
|
||||||
|
|
||||||
|
#include "base.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define DIYA_TYPE_FILES_MONITOR (diya_files_monitor_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (DiyaFilesMonitor, diya_files_monitor, DIYA, FILES_MONITOR, DiyaObject)
|
||||||
|
|
||||||
|
DiyaFilesMonitor* diya_files_monitor_new();
|
||||||
|
gboolean diya_files_monitor_watch(DiyaFilesMonitor* monitor, const gchar* file, GCallback callback, gpointer userdata);
|
||||||
|
void diya_files_monitor_unwatch(DiyaFilesMonitor* monitor, const gchar* file);
|
||||||
|
|
||||||
|
#endif
|
83
src/files-monitor.c
Normal file
83
src/files-monitor.c
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#include <glib-unix.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "files-monior.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct _DiyaFilesMonitor
|
||||||
|
{
|
||||||
|
DiyaObject parent;
|
||||||
|
GHashTable *watch_table;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
G_DEFINE_FINAL_TYPE(DiyaFilesMonitor, diya_files_monitor, DIYA_TYPE_OBJECT)
|
||||||
|
|
||||||
|
static void diya_files_monitor_dispose(GObject *object)
|
||||||
|
{
|
||||||
|
DiyaFilesMonitor *self = DIYA_FILES_MONITOR(object);
|
||||||
|
g_debug("diya_files_monitor_dispose: %s", diya_object_to_string(object));
|
||||||
|
g_hash_table_destroy(self->watch_table);
|
||||||
|
G_OBJECT_CLASS(diya_files_monitor_parent_class)->dispose(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void diya_files_monitor_init(DiyaFilesMonitor *self)
|
||||||
|
{
|
||||||
|
self->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const gchar *diya_files_monitor_to_string(DiyaObject *object)
|
||||||
|
{
|
||||||
|
(void) object;
|
||||||
|
return "Diya Files Monitor";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void diya_files_monitor_class_init(DiyaFilesMonitorClass *class)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
|
||||||
|
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
|
||||||
|
|
||||||
|
gobject_class->dispose = diya_files_monitor_dispose;
|
||||||
|
base_class->to_string = diya_files_monitor_to_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyaFilesMonitor* diya_files_monitor_new()
|
||||||
|
{
|
||||||
|
DiyaFilesMonitor* self = DIYA_FILES_MONITOR(g_object_new(DIYA_TYPE_FILES_MONITOR, NULL));
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean diya_files_monitor_watch(DiyaFilesMonitor* self, const gchar* path, GCallback callback, gpointer userdata)
|
||||||
|
{
|
||||||
|
GFileMonitor* fm = NULL;
|
||||||
|
if(!g_hash_table_contains(self->watch_table, path))
|
||||||
|
{
|
||||||
|
GError *err = NULL;
|
||||||
|
GFile* file = g_file_new_for_path(path);
|
||||||
|
fm = g_file_monitor(file, G_FILE_MONITOR_WATCH_MOVES, NULL, &err);
|
||||||
|
g_object_unref(file);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
g_error("Unable to watch file %s: %s", path, err->message);
|
||||||
|
g_error_free(err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
g_info("DiyaFilesMonitor: watch new file: %s", path);
|
||||||
|
g_hash_table_insert(self->watch_table, (gpointer)g_strdup(path), fm);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_info("File %s is already watched, register callback handle to the existing watcher", path);
|
||||||
|
fm = g_hash_table_lookup(self->watch_table, path);
|
||||||
|
}
|
||||||
|
g_signal_connect(G_OBJECT(fm), "changed", callback, userdata);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void diya_files_monitor_unwatch(DiyaFilesMonitor* self, const gchar* path)
|
||||||
|
{
|
||||||
|
if(!g_hash_table_contains(self->watch_table, path))
|
||||||
|
{
|
||||||
|
g_hash_table_remove(self->watch_table, (gconstpointer)path);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
#ifndef DIYA_INPUT_H
|
#ifndef DIYA_INPUT_H
|
||||||
#define DIYA_INPUT_H
|
#define DIYA_INPUT_H
|
||||||
#include "base.h"
|
|
||||||
#include "shell.h"
|
#include "shell.h"
|
||||||
|
|
||||||
#define DIYA_TYPE_INPUT (diya_input_get_type ())
|
#define DIYA_TYPE_INPUT (diya_input_get_type ())
|
||||||
|
88
src/shell.c
88
src/shell.c
@ -3,6 +3,10 @@
|
|||||||
#include "wayland.h"
|
#include "wayland.h"
|
||||||
#include "virtual-keyboard.h"
|
#include "virtual-keyboard.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
#include "files-monior.h"
|
||||||
|
|
||||||
|
#define diya_shell_config_css_file(priv) (g_strconcat(g_get_user_config_dir(), "/diya/themes/", priv->name, ".css", NULL))
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
NO_PROP,
|
NO_PROP,
|
||||||
@ -23,6 +27,7 @@ typedef struct _DiyaShellPrivate
|
|||||||
GHashTable *vkbs;
|
GHashTable *vkbs;
|
||||||
GtkCssProvider *css_provider;
|
GtkCssProvider *css_provider;
|
||||||
DiyaInput *input;
|
DiyaInput *input;
|
||||||
|
DiyaFilesMonitor *files_watchdog;
|
||||||
} DiyaShellPrivate;
|
} DiyaShellPrivate;
|
||||||
|
|
||||||
G_DEFINE_TYPE_WITH_PRIVATE(DiyaShell, diya_shell, DIYA_TYPE_OBJECT);
|
G_DEFINE_TYPE_WITH_PRIVATE(DiyaShell, diya_shell, DIYA_TYPE_OBJECT);
|
||||||
@ -50,6 +55,11 @@ static void diya_shell_dispose(GObject *object)
|
|||||||
g_object_unref(priv->input);
|
g_object_unref(priv->input);
|
||||||
}
|
}
|
||||||
g_hash_table_destroy(priv->vkbs);
|
g_hash_table_destroy(priv->vkbs);
|
||||||
|
if (priv->files_watchdog)
|
||||||
|
{
|
||||||
|
g_object_unref(priv->files_watchdog);
|
||||||
|
priv->files_watchdog = NULL;
|
||||||
|
}
|
||||||
G_OBJECT_CLASS(diya_shell_parent_class)->dispose(object);
|
G_OBJECT_CLASS(diya_shell_parent_class)->dispose(object);
|
||||||
if (priv->app)
|
if (priv->app)
|
||||||
{
|
{
|
||||||
@ -63,10 +73,10 @@ static void diya_shell_reload(DiyaShell *shell)
|
|||||||
GBytes *bytes = NULL;
|
GBytes *bytes = NULL;
|
||||||
gchar *css_string = NULL;
|
gchar *css_string = NULL;
|
||||||
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
|
||||||
gchar *css_file = g_strconcat(g_get_user_config_dir(), "/diya/themes/", priv->name, ".css", NULL);
|
gchar *css_file = diya_shell_config_css_file(priv);
|
||||||
g_debug("diya_shell_reload: Looking for css file: %s", css_file);
|
g_debug("diya_shell_reload: Looking for css file: %s", css_file);
|
||||||
g_file_get_contents(css_file, &css_string, NULL, &err);
|
g_file_get_contents(css_file, &css_string, NULL, &err);
|
||||||
free(css_file);
|
g_free(css_file);
|
||||||
if (err != NULL)
|
if (err != NULL)
|
||||||
{
|
{
|
||||||
g_warning("diya_shell_reload: Unable to load CSS from file: %s", err->message);
|
g_warning("diya_shell_reload: Unable to load CSS from file: %s", err->message);
|
||||||
@ -114,6 +124,38 @@ static void diya_shell_reload(DiyaShell *shell)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void on_diya_shell_theme_file_changed(GFileMonitor *monitor, GFile *file, GFile *other, GFileMonitorEvent evtype, gpointer user_data)
|
||||||
|
{
|
||||||
|
(void)monitor;
|
||||||
|
DiyaShell *shell = user_data;
|
||||||
|
char *fpath = g_file_get_path(file);
|
||||||
|
char *opath = NULL;
|
||||||
|
if (other)
|
||||||
|
{
|
||||||
|
opath = g_file_get_path(other);
|
||||||
|
}
|
||||||
|
switch (evtype)
|
||||||
|
{
|
||||||
|
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
|
||||||
|
case G_FILE_MONITOR_EVENT_DELETED:
|
||||||
|
case G_FILE_MONITOR_EVENT_RENAMED:
|
||||||
|
case G_FILE_MONITOR_EVENT_MOVED_IN:
|
||||||
|
case G_FILE_MONITOR_EVENT_MOVED_OUT:
|
||||||
|
//case G_FILE_MONITOR_EVENT_CHANGED:
|
||||||
|
//case G_FILE_MONITOR_EVENT_CREATED:
|
||||||
|
diya_shell_reload(shell);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_debug("%s event %x", fpath, evtype);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (opath)
|
||||||
|
{
|
||||||
|
g_free(opath);
|
||||||
|
}
|
||||||
|
g_free(fpath);
|
||||||
|
}
|
||||||
|
|
||||||
static void on_gtk_app_startup(GtkApplication *app, void *data)
|
static void on_gtk_app_startup(GtkApplication *app, void *data)
|
||||||
{
|
{
|
||||||
(void)app;
|
(void)app;
|
||||||
@ -121,6 +163,9 @@ static void on_gtk_app_startup(GtkApplication *app, void *data)
|
|||||||
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
|
||||||
priv->wayland = diya_wayland_new(DIYA_SHELL(shell));
|
priv->wayland = diya_wayland_new(DIYA_SHELL(shell));
|
||||||
DiyaShellClass *class = DIYA_SHELL_GET_CLASS(shell);
|
DiyaShellClass *class = DIYA_SHELL_GET_CLASS(shell);
|
||||||
|
gchar *css_file = diya_shell_config_css_file(priv);
|
||||||
|
diya_shell_watch_file(shell, css_file, G_CALLBACK(on_diya_shell_theme_file_changed), (gpointer)shell);
|
||||||
|
g_free(css_file);
|
||||||
diya_shell_reload(shell);
|
diya_shell_reload(shell);
|
||||||
if (class->startup_handle)
|
if (class->startup_handle)
|
||||||
{
|
{
|
||||||
@ -225,9 +270,10 @@ static void diya_shell_init(DiyaShell *self)
|
|||||||
priv->wayland = NULL;
|
priv->wayland = NULL;
|
||||||
priv->app = NULL;
|
priv->app = NULL;
|
||||||
priv->name = NULL;
|
priv->name = NULL;
|
||||||
priv->vkbs = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_object_unref);
|
priv->vkbs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref);
|
||||||
priv->css_provider = NULL;
|
priv->css_provider = NULL;
|
||||||
priv->input = NULL;
|
priv->input = NULL;
|
||||||
|
priv->files_watchdog = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
DiyaWayland *diya_shell_get_wayland(DiyaShell *shell)
|
DiyaWayland *diya_shell_get_wayland(DiyaShell *shell)
|
||||||
@ -284,6 +330,19 @@ int diya_shell_run(DiyaShell *shell, int argc, char **argv)
|
|||||||
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
|
||||||
assert(GTK_IS_APPLICATION(priv->app));
|
assert(GTK_IS_APPLICATION(priv->app));
|
||||||
GtkApplication *app = priv->app;
|
GtkApplication *app = priv->app;
|
||||||
|
/**
|
||||||
|
* create shell config dir if not exists
|
||||||
|
*/
|
||||||
|
// theme dir
|
||||||
|
gchar* path = g_strconcat(g_get_user_config_dir(), "/diya/themes/", NULL);
|
||||||
|
g_mkdir_with_parents((const gchar*)path,0755);
|
||||||
|
g_free(path);
|
||||||
|
|
||||||
|
// keymap dir
|
||||||
|
path = g_strconcat(g_get_user_config_dir(), "/diya/xkb/", NULL);
|
||||||
|
g_mkdir_with_parents((const gchar*)path,0755);
|
||||||
|
g_free(path);
|
||||||
|
|
||||||
int status = g_application_run(G_APPLICATION(app), argc, argv);
|
int status = g_application_run(G_APPLICATION(app), argc, argv);
|
||||||
g_object_unref(app);
|
g_object_unref(app);
|
||||||
return status;
|
return status;
|
||||||
@ -310,7 +369,7 @@ DiyaVirtualKeyboard *diya_shell_get_virtual_keyboard(DiyaShell *shell, const gch
|
|||||||
if (vkb)
|
if (vkb)
|
||||||
{
|
{
|
||||||
g_debug("diya_shell_get_virtual_keyboard: add new keyboard %s to cache", name);
|
g_debug("diya_shell_get_virtual_keyboard: add new keyboard %s to cache", name);
|
||||||
g_hash_table_insert(priv->vkbs, (gpointer)name, vkb);
|
g_hash_table_insert(priv->vkbs, (gpointer)g_strdup(name), vkb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(keymap_file);
|
free(keymap_file);
|
||||||
@ -323,7 +382,7 @@ DiyaVirtualKeyboard *diya_shell_get_virtual_keyboard(DiyaShell *shell, const gch
|
|||||||
if (!g_hash_table_contains(priv->vkbs, "default"))
|
if (!g_hash_table_contains(priv->vkbs, "default"))
|
||||||
{
|
{
|
||||||
g_debug("Add new keyboard instance to cache");
|
g_debug("Add new keyboard instance to cache");
|
||||||
g_hash_table_insert(priv->vkbs, "default", diya_virtual_keyboard_new(shell, NULL));
|
g_hash_table_insert(priv->vkbs, (gpointer)g_strdup("default"), diya_virtual_keyboard_new(shell, NULL));
|
||||||
}
|
}
|
||||||
vkb = g_hash_table_lookup(priv->vkbs, "default");
|
vkb = g_hash_table_lookup(priv->vkbs, "default");
|
||||||
}
|
}
|
||||||
@ -339,3 +398,22 @@ void diya_shell_monitor_input(DiyaShell *self)
|
|||||||
}
|
}
|
||||||
priv->input = diya_input_new(self);
|
priv->input = diya_input_new(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean diya_shell_watch_file(DiyaShell *self, const gchar *file, GCallback callback, gpointer userdata)
|
||||||
|
{
|
||||||
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
|
||||||
|
if (!priv->files_watchdog)
|
||||||
|
{
|
||||||
|
priv->files_watchdog = diya_files_monitor_new();
|
||||||
|
}
|
||||||
|
return diya_files_monitor_watch(priv->files_watchdog, file, callback, userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
void diya_shell_unwatch_file(DiyaShell *self, const gchar *file)
|
||||||
|
{
|
||||||
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
|
||||||
|
if (priv->files_watchdog)
|
||||||
|
{
|
||||||
|
diya_files_monitor_unwatch(priv->files_watchdog, file);
|
||||||
|
}
|
||||||
|
}
|
@ -34,6 +34,8 @@ GtkApplication* diya_shell_get_application(DiyaShell* shell);
|
|||||||
const char* diya_shell_get_name(DiyaShell* shell);
|
const char* diya_shell_get_name(DiyaShell* shell);
|
||||||
DiyaVirtualKeyboard* diya_shell_get_virtual_keyboard(DiyaShell* shell, const gchar* name);
|
DiyaVirtualKeyboard* diya_shell_get_virtual_keyboard(DiyaShell* shell, const gchar* name);
|
||||||
void diya_shell_monitor_input(DiyaShell* shell);
|
void diya_shell_monitor_input(DiyaShell* shell);
|
||||||
|
gboolean diya_shell_watch_file(DiyaShell* shell, const gchar* file, GCallback callback, gpointer userdata);
|
||||||
|
void diya_shell_unwatch_file(DiyaShell* shell, const gchar* file);
|
||||||
|
|
||||||
int diya_shell_run(DiyaShell* shell, int argc, char **argv);
|
int diya_shell_run(DiyaShell* shell, int argc, char **argv);
|
||||||
#endif
|
#endif
|
Loading…
x
Reference in New Issue
Block a user