feat: Add hook mechanism + use gsettings:

- Allow to install hooks that execute lua scripts on changes of watched files
- Use gsetting to store shell parameters such as: theme, idle-timeout, etc.
This commit is contained in:
DL
2025-10-13 18:08:50 +02:00
parent 8579a78404
commit 377eaf7d84
22 changed files with 721 additions and 63 deletions

View File

@@ -0,0 +1,9 @@
local compiled_schemas = diya.system.user_config_dir() .. "/diya/schemas/gschemas.compiled"
if not diya.system.file_exists(compiled_schemas) then
diya.system.log_info("Regenerating "..compiled_schemas)
local script_path = debug.getinfo(1, "S").source:sub(2)
local script_dir = script_path:match("(.*/)")
local script_compile_schemas = script_dir .. "/compile_schemas.lua"
dofile(script_compile_schemas)
end

21
hooks/compile_schemas.lua Normal file
View File

@@ -0,0 +1,21 @@
local schemas_dir = diya.system.user_data_dir() .. "/glib-2.0/schemas"
local target_dir = diya.system.user_config_dir() .. "/diya/schemas/"
local session_schemas = schemas_dir.."/dev.iohub.diya.session.gschema.xml"
if not diya.system.file_exists(session_schemas) then
-- copy session schemas if not exists
diya.system.save_resource("/dev/iohub/diya/shell/schemas/session.gschema.xml", session_schemas)
return
end
-- create the compiled schemas dir if not exists
diya.system.mkdir(target_dir)
local cmd = "/usr/bin/glib-compile-schemas --targetdir="..target_dir.." "..schemas_dir -- .." &"
diya.system.log_info("Executing: "..cmd)
local handle = io.popen(cmd)
local result = handle:read("*a") -- Reads all output
handle:close()
diya.system.log_info(result)

21
hooks/hooks.lua Normal file
View File

@@ -0,0 +1,21 @@
local script_path = debug.getinfo(1, "S").source:sub(2)
local script_dir = script_path:match("(.*/)")
local schemas_dir = diya.system.user_data_dir() .. "/glib-2.0/schemas"
-- create the schemas dir if not exists
diya.system.mkdir(schemas_dir)
local script_compile_schemas = script_dir .. "/compile_schemas.lua"
-- install hook on schemas dir
diya.hook.changed(schemas_dir, script_compile_schemas, false)
local session_schemas = schemas_dir.."/dev.iohub.diya.session.gschema.xml"
if not diya.system.file_exists(session_schemas) then
-- copy session schemas if not exists
diya.system.save_resource("/dev/iohub/diya/shell/schemas/session.gschema.xml", session_schemas)
end
local compiled_schemas = diya.system.user_config_dir() .. "/diya/schemas/gschemas.compiled"
local script_check_schema = script_dir .. "/check_compiled_schemas.lua"
diya.hook.changed(compiled_schemas, script_check_schema, true)

View File

@@ -28,6 +28,7 @@ wayland_protocols = dependency('wayland-protocols', version: '>=1.16')
wl_protocol_dir = wayland_protocols.get_variable('pkgdatadir')
lua = dependency('lua')
# pkg_config = import('pkgconfig')
# gnome = import('gnome')
@@ -68,6 +69,7 @@ base = [
'src/widgets/virtual-keyboard-widgets.c',
'src/files-monitor.c',
'src/idle.c',
'src/hook.c',
wayland_targets
]
@@ -84,15 +86,29 @@ dm_src = [
'src/widgets/dashboard-widget.c',
]
buil_dep = [gtk, gtk_layer_shell, wayland_client, xkbcommon]
build_dep = [gtk, gtk_layer_shell, wayland_client, xkbcommon, lua]
session_resource = gnome.compile_resources('session-resources','resources/gresource-session.xml')
session_schemas_files = [
'resources/schemas/dev.iohub.diya.session.gschema.xml',
]
session_schema = custom_target('gschemas.compiled',
output: 'gschemas.compiled',
command: [
find_program('glib-compile-schemas'),
'--targetdir='+meson.current_build_dir(),
meson.current_source_dir() / 'resources/schemas'
],
depend_files: session_schemas_files,
build_by_default: true,
install: false,
)
executable(
'diya-shell',
dm_src,
session_resource,
dependencies: buil_dep,
session_schema,
dependencies: build_dep,
include_directories : incdir)
login_src = [
@@ -107,5 +123,5 @@ executable(
'diya-login-shell',
login_src,
login_resource,
dependencies: buil_dep,
dependencies: build_dep,
include_directories : incdir)

View File

@@ -12,7 +12,8 @@ diya-dashboard
#diya_shell_background
{
background-image:url("file:///etc/xdg/labwc/wpp.jpg");
/*background-image:url("file:///etc/xdg/labwc/wpp.jpg");*/
background-color: violet;
background-size: cover;
}

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/dev/iohub/diya/shell/css">
<file alias="dev.iohub.diya.login-shell.css">resources/css/login-shell.css</file>
<file alias="dev.iohub.diya.login.css">resources/css/login-shell.css</file>
<file alias="virtual-keyboard.css">resources/css/virtual-keyboard.css</file>
</gresource>
<gresource prefix="/dev/iohub/diya/shell/vkb">

View File

@@ -8,9 +8,12 @@
<file alias="taskbar.ui">resources/ui/taskbar.ui</file>
</gresource>
<gresource prefix="/dev/iohub/diya/shell/css">
<file alias="dev.iohub.diya.session-shell.css">resources/css/session-shell.css</file>
<file alias="dev.iohub.diya.session.css">resources/css/session-shell.css</file>
<file alias="virtual-keyboard.css">resources/css/virtual-keyboard.css</file>
</gresource>
<gresource prefix="/dev/iohub/diya/shell/schemas">
<file alias="session.gschema.xml">resources/schemas/dev.iohub.diya.session.gschema.xml</file>
</gresource>
<gresource prefix="/dev/iohub/diya/shell/icons/scalable">
<file alias="gear">resources/icons/scalable/gear.svg</file>
</gresource>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
<schema path="/dev/iohub/diya/session/" id="dev.iohub.diya.session">
<key name="idle-timeout" type="i">
<default>60000</default>
<summary>Idle timeout</summary>
<description>The time in milliseconds before the session is considered idle.</description>
</key>
<key name="theme" type="s">
<default>'diya'</default>
<summary>System theme</summary>
<description>The system theme used for the session.</description>
</key>
</schema>
</schemalist>

View File

@@ -28,6 +28,14 @@
</object>
</child>
<child>
<object class="GtkToggleButton" id="btn_test">
<property name="visible">1</property>
<property name="label" translatable="yes">Test</property>
<!--signal name="toggled" handler="diya_dashboard_toggle"/-->
</object>
</child>
</object>
</child>
</template>

View File

@@ -10,5 +10,5 @@ G_DECLARE_FINAL_TYPE (DiyaFilesMonitor, diya_files_monitor, DIYA, FILES_MONITOR,
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);
gboolean diya_files_monitor_is_watched(DiyaFilesMonitor* monitor, const gchar* file);
#endif

View File

@@ -55,37 +55,51 @@ DiyaFilesMonitor* diya_files_monitor_new()
return self;
}
gboolean diya_files_monitor_watch(DiyaFilesMonitor* self, const gchar* path, GCallback callback, gpointer userdata)
gboolean diya_files_monitor_watch(DiyaFilesMonitor* self, const gchar* any_path, GCallback callback, gpointer userdata)
{
GFileMonitor* fm = NULL;
if(!g_hash_table_contains(self->watch_table, path))
char* abs_path = g_canonicalize_filename(any_path, NULL);
if(!g_hash_table_contains(self->watch_table, abs_path))
{
GError *err = NULL;
GFile* file = g_file_new_for_path(path);
GFile* file = g_file_new_for_path(abs_path);
fm = g_file_monitor(file, G_FILE_MONITOR_WATCH_MOVES, NULL, &err);
g_object_unref(file);
if (err)
{
g_warning("Unable to watch file %s: %s", path, err->message);
g_warning("Unable to watch file %s: %s", abs_path, err->message);
g_error_free(err);
g_free(abs_path);
return false;
}
g_info("DiyaFilesMonitor: watch new file: %s", path);
g_hash_table_insert(self->watch_table, (gpointer)g_strdup(path), fm);
g_info("DiyaFilesMonitor: watch new file: %s", abs_path);
g_hash_table_insert(self->watch_table, (gpointer)g_strdup(abs_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_info("File %s is already watched, register callback handle to the existing watcher", abs_path);
fm = g_hash_table_lookup(self->watch_table, abs_path);
}
g_signal_connect(G_OBJECT(fm), "changed", callback, userdata);
g_free(abs_path);
return true;
}
void diya_files_monitor_unwatch(DiyaFilesMonitor* self, const gchar* path)
void diya_files_monitor_unwatch(DiyaFilesMonitor* self, const gchar* any_path)
{
if(!g_hash_table_contains(self->watch_table, path))
gchar* abs_path = g_canonicalize_filename(any_path, NULL);
g_debug("Unwatching: %s", abs_path);
if(g_hash_table_contains(self->watch_table, abs_path))
{
g_hash_table_remove(self->watch_table, (gconstpointer)path);
g_hash_table_remove(self->watch_table, (gconstpointer)abs_path);
}
g_free(abs_path);
}
gboolean diya_files_monitor_is_watched(DiyaFilesMonitor* self, const gchar* file)
{
gchar* abs_path = g_canonicalize_filename(file, NULL);
gboolean watched = g_hash_table_contains(self->watch_table, abs_path);
g_free(abs_path);
return watched;
}

419
src/hook.c Normal file
View File

@@ -0,0 +1,419 @@
#include <glib-unix.h>
#include <gio/gio.h>
#include "hook.h"
#include "files-monior.h"
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
struct _DiyaHookHandle
{
DiyaObject parent;
DiyaHook* hook;
gchar* script;
};
G_DEFINE_FINAL_TYPE(DiyaHookHandle, diya_hook_handle, DIYA_TYPE_OBJECT)
static void diya_hook_handle_finalize(GObject* object)
{
DiyaHookHandle* self = DIYA_HOOK_HANDLE(object);
g_debug("diya_hook_handle_finalize: %s", diya_object_to_string(object));
if(self->script)
{
g_free(self->script);
}
}
static void diya_hook_handle_dispose(GObject* object)
{
(void) object;
g_debug("diya_hook_disponse: %s", diya_object_to_string(object));
}
static void diya_hook_handle_init(DiyaHookHandle* self)
{
self->hook = NULL;
self->script = NULL;
}
struct _DiyaHook
{
DiyaObject parent;
DiyaFilesMonitor *files_watchdog;
GHashTable* lua_hooks;
};
static const gchar *diya_hook_handle_to_string(DiyaObject *object)
{
DiyaHookHandle* self = DIYA_HOOK_HANDLE(object);
return self->script;
}
static void diya_hook_handle_class_init(DiyaHookHandleClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->finalize = diya_hook_handle_finalize;
gobject_class->dispose = diya_hook_handle_dispose;
base_class->to_string = diya_hook_handle_to_string;
}
static DiyaHookHandle* diya_hook_handle_new(DiyaHook* hook, const gchar* script)
{
DiyaHookHandle* self = DIYA_HOOK_HANDLE(g_object_new(DIYA_TYPE_HOOK_HANDLE, NULL));
self->hook = hook;
self->script = g_strdup(script);
return self;
}
G_DEFINE_FINAL_TYPE(DiyaHook, diya_hook, DIYA_TYPE_OBJECT)
static void execute_hook_script(DiyaHook* self, const gchar* script, gboolean allow_install_hook);
static void diya_hook_finalize(GObject *object)
{
DiyaHook *self = DIYA_HOOK(object);
g_debug("diya_hook_finalize: %s", diya_object_to_string(object));
if(self->lua_hooks)
{
g_hash_table_destroy(self->lua_hooks);
}
G_OBJECT_CLASS(diya_hook_parent_class)->finalize(object);
}
static void diya_hook_dispose(GObject *object)
{
DiyaHook *self = DIYA_HOOK(object);
g_debug("diya_hook_dispose: %s", diya_object_to_string(object));
if(self->files_watchdog)
{
g_object_unref(self->files_watchdog);
self->files_watchdog = NULL;
}
G_OBJECT_CLASS(diya_hook_parent_class)->dispose(object);
}
static void diya_hook_init(DiyaHook *self)
{
self->files_watchdog = diya_files_monitor_new();
self->lua_hooks = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_hash_table_destroy);
}
static const gchar *diya_hook_to_string(DiyaObject *object)
{
(void) object;
return "Diya Hook";
}
static void diya_hook_class_init(DiyaHookClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->finalize = diya_hook_finalize;
gobject_class->dispose = diya_hook_dispose;
base_class->to_string = diya_hook_to_string;
}
DiyaHook* diya_hook_new()
{
DiyaHook* self = DIYA_HOOK(g_object_new(DIYA_TYPE_HOOK, NULL));
return self;
}
static void reset_lua_hook(DiyaHook* self, const gchar* hook, gboolean init)
{
gchar* abs_path = g_canonicalize_filename(hook, NULL);
if(g_hash_table_contains(self->lua_hooks, abs_path))
{
GHashTableIter iter;
gchar* target;
DiyaHookHandle* handle;
g_hash_table_iter_init (&iter, g_hash_table_lookup(self->lua_hooks, abs_path));
while (g_hash_table_iter_next(&iter, (gpointer) &target, (gpointer) &handle))
{
g_info("Remove lua hook %s for: %s", handle->script, target);
diya_files_monitor_unwatch(self->files_watchdog, target);
}
g_hash_table_remove(self->lua_hooks, abs_path);
}
if(init)
{
g_hash_table_insert(self->lua_hooks,abs_path, g_hash_table_new_full(g_str_hash,g_str_equal,g_free,g_object_unref));
}
}
void on_diya_hook_on_file_changed(GFileMonitor *monitor, GFile *file, GFile *other, GFileMonitorEvent evtype, gpointer user_data)
{
(void)monitor;
(void)other;
DiyaHookHandle* handle = (DiyaHookHandle*) user_data;
char *path = g_file_get_path(file);
g_debug("on_diya_hook_on_file_changed: %s event %x", path, evtype);
switch (evtype)
{
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
case G_FILE_MONITOR_EVENT_MOVED_IN:
// case G_FILE_MONITOR_EVENT_CHANGED:
//case G_FILE_MONITOR_EVENT_CREATED:
case G_FILE_MONITOR_EVENT_DELETED:
case G_FILE_MONITOR_EVENT_RENAMED:
case G_FILE_MONITOR_EVENT_MOVED_OUT:
execute_hook_script(handle->hook,handle->script, false);
default:
break;
}
g_free(path);
}
static int l_on_file_changed(lua_State *L)
{
gchar *target = g_canonicalize_filename((const char*)luaL_checkstring(L, 1), NULL);
const char *script = (const char*)luaL_checkstring(L, 2);
gboolean exec_on_start = (gboolean) lua_toboolean(L, 3);
// get global table on top of stack
lua_getglobal(L, "diya");
lua_getfield(L, -1, "handle");
DiyaHook* self = (DiyaHook*)lua_touserdata(L, -1);
// remove the hook object
lua_pop(L, 1);
lua_getfield(L,-1,"trigger");
const char* trigger = (const char*) luaL_checkstring(L,-1);
lua_pop(L, 1);
// remove global table on top of stack
lua_pop(L, 1);
g_debug("Install file watchdog for %s: script %s from trigger %s", target, script, trigger);
if(!g_hash_table_contains(self->lua_hooks, trigger))
{
g_critical("Unknow trigger: %s for target %s (%s)", trigger, target, script);
lua_pushboolean(L, 0);
lua_pushstring(L, "Trigger file unknown");
g_free(target);
return 2;
}
GHashTable* lookup = g_hash_table_lookup(self->lua_hooks, trigger);
if(g_hash_table_contains(lookup, target))
{
g_hash_table_remove(lookup, target);
diya_files_monitor_unwatch(self->files_watchdog, target);
}
DiyaHookHandle* handle = diya_hook_handle_new(self, script);
if(!diya_files_monitor_watch(self->files_watchdog, target, G_CALLBACK(on_diya_hook_on_file_changed), handle))
{
g_critical("Unable to setup watchdog for target %s (%s)", target, script);
lua_pushboolean(L, 0);
lua_pushstring(L, "Unable to setup watchdog");
g_free(target);
g_object_unref(handle);
return 2;
}
g_hash_table_insert(lookup, target, handle);
if(exec_on_start)
{
execute_hook_script(self, script, false);
}
lua_pushboolean(L, 1);
return 1;
}
static const struct luaL_Reg hook_module [] = {
{"changed", l_on_file_changed},
{NULL,NULL}
};
static int l_log_info(lua_State *L)
{
const char* msg = (const char*)luaL_checkstring(L, 1);
g_info("%s", msg);
return 0;
}
static int l_log_warning(lua_State *L)
{
const char* msg = (const char*)luaL_checkstring(L, 1);
g_warning("%s", msg);
return 0;
}
static int l_log_error(lua_State *L)
{
const char* msg = (const char*)luaL_checkstring(L, 1);
g_critical("%s", msg);
return 0;
}
static int l_user_home(lua_State *L)
{
lua_pushstring(L, g_get_home_dir());
return 1;
}
static int l_user_config_dir(lua_State *L)
{
lua_pushstring(L, g_get_user_config_dir());
return 1;
}
static int l_user_data_dir(lua_State *L)
{
lua_pushstring(L, g_get_user_data_dir());
return 1;
}
static int l_save_resource(lua_State *L)
{
const char* resource = (const char*) luaL_checkstring(L,1);
const char* path = (const char*) luaL_checkstring(L,2);
GError *error = NULL;
g_info("Saving resource %s to %s", resource, path);
GBytes *bytes = g_resources_lookup_data(resource, 0, &error);
if (error != NULL)
{
g_critical("Unable to read resource %s", error->message);
g_error_free(error);
lua_pushboolean(L, 0);
return 1;
}
g_file_set_contents(path, g_bytes_get_data(bytes, NULL), g_bytes_get_size(bytes), &error);
g_bytes_unref(bytes);
if (error != NULL)
{
g_critical("Unable to read write resource %s to file %s: %s", resource, path, error->message);
g_error_free(error);
lua_pushboolean(L, 0);
return 1;
}
lua_pushboolean(L, 1);
return 1;
}
static int l_file_exists(lua_State *L)
{
const char* path = (const char*) luaL_checkstring(L,1);
lua_pushboolean(L, g_file_test(path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK));
return 1;
}
static int l_mkdir(lua_State *L)
{
const char* path = (const char*) luaL_checkstring(L,1);
lua_pushboolean(L, g_mkdir_with_parents((const gchar *)path, 0755) == 0);
return 1;
}
static const struct luaL_Reg system_module [] = {
{"log_info", l_log_info},
{"log_warning", l_log_warning},
{"log_error", l_log_error},
{"user_home", l_user_home},
{"user_config_dir", l_user_config_dir},
{"user_data_dir", l_user_data_dir},
{"save_resource", l_save_resource},
{"file_exists", l_file_exists},
{"mkdir", l_mkdir},
{NULL, NULL}
};
static void execute_hook_script(DiyaHook* self, const gchar* script, gboolean allow_install_hook)
{
lua_State* L = NULL;
L = luaL_newstate();
luaL_openlibs(L);
if(L)
{
g_debug("Executing %s", script);
// install custom lib to lua state
lua_newtable(L);
lua_pushstring(L,"system");
luaL_newlib(L, system_module);
lua_settable(L, -3);
if(allow_install_hook)
{
lua_pushstring(L,"hook");
luaL_newlib(L, hook_module);
lua_settable(L, -3);
lua_pushstring(L, "trigger");
lua_pushstring(L, script);
lua_settable(L, -3);
}
lua_pushstring(L,"handle");
lua_pushlightuserdata(L, self);
lua_settable(L, -3);
lua_setglobal(L, "diya");
if (luaL_loadfile(L, script) || lua_pcall(L, 0, 0, 0))
{
g_critical("cannot execute hook script: [%s] %s", script, lua_tostring(L, -1));
}
lua_close(L);
}
}
void on_diya_hook_lua_script_changed(GFileMonitor *monitor, GFile *file, GFile *other, GFileMonitorEvent evtype, gpointer user_data)
{
(void)monitor;
(void)other;
DiyaHook *self = user_data;
char *path = g_file_get_path(file);
g_debug("on_diya_hook_lua_script_changed: %s event %x", path, evtype);
switch (evtype)
{
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
case G_FILE_MONITOR_EVENT_MOVED_IN:
// case G_FILE_MONITOR_EVENT_CHANGED:
// case G_FILE_MONITOR_EVENT_CREATED:
// unwatched all watched files installed by this script
reset_lua_hook(self, path, true);
// re-execute the script to install additional hook
execute_hook_script(self,path, true);
break;
case G_FILE_MONITOR_EVENT_DELETED:
case G_FILE_MONITOR_EVENT_RENAMED:
case G_FILE_MONITOR_EVENT_MOVED_OUT:
reset_lua_hook(self, path, false);
break;
default:
break;
}
g_free(path);
}
gboolean diya_hook_install_lua(DiyaHook* self, const gchar* script)
{
// unwatch the file
reset_lua_hook(self, script, true);
diya_files_monitor_unwatch(self->files_watchdog, script);
execute_hook_script(self, script, true);
return diya_files_monitor_watch(self->files_watchdog, script, G_CALLBACK(on_diya_hook_lua_script_changed), self);
}
void diya_hook_uninstall(DiyaHook* self, const gchar* file)
{
reset_lua_hook(self, file, false);
diya_files_monitor_unwatch(self->files_watchdog, file);
}
gboolean diya_hook_install(DiyaHook* self, const gchar* file, GCallback callback, gpointer userdata, gboolean singleton)
{
if(singleton)
{
// unwatch previously watch of the same file
diya_files_monitor_unwatch(self->files_watchdog, file);
}
return diya_files_monitor_watch(self->files_watchdog, file, callback, userdata);
}

18
src/hook.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef DIYA_HOOK_H
#define DIYA_HOOK_H
#include "base.h"
#define DIYA_TYPE_HOOK (diya_hook_get_type ())
G_DECLARE_FINAL_TYPE (DiyaHook, diya_hook, DIYA, HOOK, DiyaObject)
#define DIYA_TYPE_HOOK_HANDLE (diya_hook_handle_get_type())
G_DECLARE_FINAL_TYPE (DiyaHookHandle, diya_hook_handle, DIYA, HOOK_HANDLE, DiyaObject)
DiyaHook* diya_hook_new();
gboolean diya_hook_install(DiyaHook* self, const gchar* file, GCallback callback, gpointer userdata, gboolean singleton);
gboolean diya_hook_install_lua(DiyaHook* self, const gchar* script);
void diya_hook_uninstall(DiyaHook* self, const gchar* file);
#endif

View File

@@ -123,6 +123,7 @@ DiyaIdleNotification* diya_shell_get_idle_notification(DiyaShell* shell, guint t
DiyaIdleNotification* self = g_object_new(DIYA_TYPE_IDLE_NOTIFICATION, "shell", shell, NULL);
struct wl_seat *seat = diya_wayland_get_seat(wayland);
self->timeout = timeout_ms;
g_info("Set IDLE notification for timeout %d", timeout_ms);
self->notification = ext_idle_notifier_v1_get_idle_notification(mngr, timeout_ms, seat);
ext_idle_notification_v1_add_listener(self->notification, &g_idle_listener_impl, self);
return self;

View File

@@ -310,6 +310,11 @@ static void diya_login_on_shell_resume(DiyaShell* shell)
diya_shell_power_display(shell, true);
}
static void diya_login_shell_active(DiyaShell *shell)
{
g_object_set(shell, DIYA_PROP_SHELL_IDLE_TIMEOUT, DEFAULT_IDLE_TIMEOUT, NULL);
}
static void diya_login_shell_startup(DiyaShell *shell)
{
DiyaLoginShell *self = DIYA_LOGIN_SHELL(shell);
@@ -340,5 +345,6 @@ static void diya_login_shell_class_init(DiyaLoginShellClass *class)
DiyaShellClass *base_shell_class = DIYA_SHELL_CLASS(class);
base_shell_class->monitor_changed_handle = on_monitor_changed;
base_shell_class->startup_handle = diya_login_shell_startup;
base_shell_class->active_handle = diya_login_shell_active;
// base_shell_class->foreign_register = diya_session_shell_foreign_toplevel_register;
}

View File

@@ -6,6 +6,6 @@
int main(int argc, char *argv[])
{
DiyaLoginShell* shell = DIYA_LOGIN_SHELL(g_object_new(DIYA_TYPE_LOGIN_SHELL, "name", "dev.iohub.diya.login-shell", NULL));
DiyaLoginShell* shell = DIYA_LOGIN_SHELL(g_object_new(DIYA_TYPE_LOGIN_SHELL, "name", "dev.iohub.diya.login", NULL));
return diya_shell_run(DIYA_SHELL(shell), argc, argv);
}

View File

@@ -10,6 +10,9 @@
#include "launcher.h"
#include "session-lock.h"
#include "idle.h"
#define compiled_schema_path() (g_strconcat(g_getenv("GSETTINGS_SCHEMA_DIR"), "/gschemas.compiled", NULL))
enum
{
NO_PROP,
@@ -29,6 +32,7 @@ struct _DiyaSessionShell
DiyaLauncher *launcher;
GHashTable *windows;
GtkSessionLockInstance *lock;
GSettings *settings;
};
G_DEFINE_FINAL_TYPE(DiyaSessionShell, diya_session_shell, DIYA_TYPE_SHELL)
@@ -57,6 +61,10 @@ static void diya_session_shell_dispose(GObject *object)
{
g_object_unref(self->launcher);
}
if(self->settings)
{
g_object_unref(self->settings);
}
G_OBJECT_CLASS(diya_session_shell_parent_class)->dispose(object);
}
@@ -150,9 +158,66 @@ static void diya_session_on_shell_resume(DiyaShell* shell)
diya_shell_power_display(shell, true);
}
void diya_session_init_settings(DiyaSessionShell* self)
{
g_return_if_fail(DIYA_IS_SESSION_SHELL(self));
if(self->settings)
{
g_debug("Setting is already initialized. Nothing todo");
return;
}
GSettingsSchemaSource* source = g_settings_schema_source_get_default();
if (!source)
{
g_warning("No gsetting schema source found");
return;
}
// Look up the schema ID
GSettingsSchema* schema = g_settings_schema_source_lookup(source, SESSION_SHELL_SCHEMA_ID, TRUE);
if (schema)
{
g_debug("Loading setting from compiled schema");
self->settings = g_settings_new(SESSION_SHELL_SCHEMA_ID);
g_settings_bind(self->settings, DIYA_PROP_SHELL_IDLE_TIMEOUT, DIYA_SHELL(self), DIYA_PROP_SHELL_IDLE_TIMEOUT, G_SETTINGS_BIND_DEFAULT);
g_settings_bind(self->settings, DIYA_PROP_SHELL_THEME, DIYA_SHELL(self), DIYA_PROP_SHELL_THEME, G_SETTINGS_BIND_DEFAULT);
g_settings_schema_unref(schema);
}
else
{
g_warning("Unable to find schema ID %s", SESSION_SHELL_SCHEMA_ID);
}
}
static void diya_session_shell_startup(DiyaShell *shell)
{
DiyaSessionShell* self = DIYA_SESSION_SHELL(shell);
const gchar* const* dirs = g_get_system_config_dirs();
gchar* path = NULL;
gboolean hook_found = false;
for (int i = 0; dirs[i] != NULL; i++)
{
path = g_strconcat(dirs[0], "/diya/hooks/hooks.lua", NULL);
g_debug("Looking for hook scripts: %s", path);
if (g_file_test(path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))
{
//hook script path
g_debug("Install LUA hook at: %s", path);
diya_shell_watch_script(shell, path);
hook_found = true;
}
g_free(path);
}
if(!hook_found)
{
path = g_strconcat(g_get_user_config_dir(), "/diya/hooks/hooks.lua", NULL);
g_debug("No system hook found. Install local hook at: %s", path);
diya_shell_watch_script(shell, path);
g_free(path);
}
diya_session_shell_init_background(self);
diya_session_shell_launcher_init(self);
g_signal_connect(shell, DIYA_SIGNAL_SHELL_KEY_PRESSED, G_CALLBACK(diya_session_on_key_pressed), NULL);
@@ -162,6 +227,7 @@ static void diya_session_shell_startup(DiyaShell *shell)
static void diya_session_shell_active(DiyaShell *shell)
{
diya_session_init_settings(DIYA_SESSION_SHELL(shell));
diya_shell_monitor_input(shell);
}
@@ -282,6 +348,7 @@ static void diya_session_shell_init(DiyaSessionShell *self)
// self->app = NULL;
self->background = NULL;
self->launcher = NULL;
self->settings = NULL;
self->lock = gtk_session_lock_instance_new();
g_signal_connect(self->lock, "locked", G_CALLBACK(on_session_locked), self);
// g_signal_connect(lock, "failed", G_CALLBACK(failed), NULL);

View File

@@ -17,6 +17,8 @@
#define DIYA_PROP_SESSION_LOCK "session-lock"
#define DIYA_PROP_SESSION_WINDOWS "windows"
#define SESSION_SHELL_SCHEMA_ID "dev.iohub.diya.session"
#define DIYA_TYPE_SESSION_SHELL (diya_session_shell_get_type ())
G_DECLARE_FINAL_TYPE (DiyaSessionShell, diya_session_shell, DIYA, SESSION_SHELL, DiyaShell)

View File

@@ -18,7 +18,7 @@ static void session_unlocked(DiyaSessionShell* shell, void* data)
int main(int argc, char *argv[])
{
DiyaSessionShell *shell = DIYA_SESSION_SHELL(g_object_new(DIYA_TYPE_SESSION_SHELL, "name","dev.iohub.diya.session-shell", NULL));
DiyaSessionShell *shell = DIYA_SESSION_SHELL(g_object_new(DIYA_TYPE_SESSION_SHELL, "name","dev.iohub.diya.session", NULL));
g_signal_connect(shell, DIYA_SIGNAL_SESSION_LOCKED, G_CALLBACK(session_locked), NULL);
g_signal_connect(shell, DIYA_SIGNAL_SESSION_UNLOCKED, G_CALLBACK(session_unlocked), NULL);
return diya_shell_run(DIYA_SHELL(shell), argc, argv);

View File

@@ -2,15 +2,13 @@
#include "shell.h"
#include "wayland.h"
#include "virtual-keyboard.h"
#include "files-monior.h"
#include "input.h"
#include "idle.h"
#include "wlr-output-power-management-unstable-v1.h"
#include "hook.h"
#include <wayland-client-protocol.h>
#include <gdk/wayland/gdkwayland.h>
#define DEFAULT_IDLE_TIMEOUT 60*1000 // 1m
#define diya_shell_config_theme(priv) (g_strconcat(g_get_home_dir(), "/.themes/", priv->theme ? priv->theme : "default", "/gtk-4.0/gtk.css", NULL))
#define diya_shell_config_theme_dir(priv) (g_strconcat(g_get_home_dir(), "/.themes/", priv->theme ? priv->theme : "default", "/gtk-4.0", NULL))
enum
@@ -35,7 +33,7 @@ typedef struct _DiyaShellPrivate
GHashTable *vkbs;
GtkCssProvider *css_provider;
DiyaInput *input;
DiyaFilesMonitor *files_watchdog;
DiyaHook *files_hook;
gchar *theme;
DiyaIdleNotification *idle_notif;
} DiyaShellPrivate;
@@ -78,10 +76,10 @@ static void diya_shell_dispose(GObject *object)
{
g_object_unref(priv->input);
}
if (priv->files_watchdog)
if (priv->files_hook)
{
g_object_unref(priv->files_watchdog);
priv->files_watchdog = NULL;
g_object_unref(priv->files_hook);
priv->files_hook = NULL;
}
if (priv->idle_notif)
{
@@ -137,14 +135,10 @@ void diya_shell_reload(DiyaShell *self)
void on_diya_shell_theme_file_changed(GFileMonitor *monitor, GFile *file, GFile *other, GFileMonitorEvent evtype, gpointer user_data)
{
(void)monitor;
(void)other;
DiyaShell *shell = user_data;
char *fpath = g_file_get_path(file);
char *opath = NULL;
g_debug("%s event %x", fpath, evtype);
if (other)
{
opath = g_file_get_path(other);
}
switch (evtype)
{
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
@@ -152,17 +146,13 @@ void on_diya_shell_theme_file_changed(GFileMonitor *monitor, GFile *file, GFile
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:
// case G_FILE_MONITOR_EVENT_CHANGED:
//case G_FILE_MONITOR_EVENT_CREATED:
diya_shell_reload_theme(shell);
break;
default:
break;
}
if (opath)
{
g_free(opath);
}
g_free(fpath);
}
@@ -186,18 +176,13 @@ static void on_gtk_app_startup(GtkApplication *app, void *data)
priv->wayland = diya_wayland_new(DIYA_SHELL(shell));
DiyaShellClass *class = DIYA_SHELL_GET_CLASS(shell);
// read envar
const char *default_theme = g_getenv(DIYA_ENV_THEME);
if (default_theme)
// log all environment variables in debug
for (gchar **env = g_get_environ(); *env != NULL; env++)
{
priv->theme = g_strdup(default_theme);
g_debug("ENV: %s", *env);
}
gchar *dir = diya_shell_config_theme_dir(priv);
diya_shell_watch_file(shell, dir, G_CALLBACK(on_diya_shell_theme_file_changed), (gpointer)shell);
g_free(dir);
diya_shell_reload(shell);
// diya_shell_reload(shell);
if (class->startup_handle)
{
class->startup_handle(shell);
@@ -208,6 +193,7 @@ static void on_gtk_app_startup(GtkApplication *app, void *data)
g_debug("listen to monitor changed");
g_signal_connect(monitor_list, "items-changed", G_CALLBACK(class->monitor_changed_handle), shell);
}
}
static void on_gtk_app_active(GtkApplication *app, void *data)
@@ -215,16 +201,22 @@ static void on_gtk_app_active(GtkApplication *app, void *data)
(void)app;
DiyaShell *shell = data;
DiyaShellClass *class = DIYA_SHELL_GET_CLASS(shell);
// DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
/**
* TODO: read timeout from setting
*/
g_object_set(shell, DIYA_PROP_SHELL_IDLE_TIMEOUT, DEFAULT_IDLE_TIMEOUT, NULL);
if (class->active_handle)
{
class->active_handle(shell);
}
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
if(!priv->theme)
{
// read envar
const char *default_theme = g_getenv(DIYA_ENV_THEME);
if (!default_theme)
{
default_theme = "default";
}
g_object_set(shell, DIYA_PROP_SHELL_THEME, default_theme, NULL);
}
}
static gboolean diya_shell_sigint_handle(gpointer data)
@@ -277,6 +269,7 @@ static void diya_shell_set_property(GObject *object, guint property_id, const GV
case PROP_SHELL_IDLE_TO:
if(priv->idle_notif)
{
g_signal_emit_by_name(self, DIYA_SIGNAL_SHELL_RESUME);
g_object_unref(priv->idle_notif);
}
priv->idle_notif = diya_shell_get_idle_notification(self, g_value_get_uint(value));
@@ -286,13 +279,21 @@ static void diya_shell_set_property(GObject *object, guint property_id, const GV
case PROP_SHELL_THEME:
{
const gchar *theme = g_value_get_string(value);
gchar* dir = NULL;
if (!priv->theme || !g_str_equal(priv->theme, theme))
{
if (priv->theme)
{
dir = diya_shell_config_theme_dir(priv);
diya_shell_unwatch_file(self, dir);
g_free(dir);
g_free(priv->theme);
}
priv->theme = g_strdup(theme);
dir = diya_shell_config_theme_dir(priv);
g_mkdir_with_parents((const gchar *)dir, 0755);
diya_shell_watch_file(self, dir, G_CALLBACK(on_diya_shell_theme_file_changed), (gpointer)self);
g_free(dir);
diya_shell_reload_theme(self);
}
break;
@@ -346,7 +347,7 @@ static void diya_shell_init(DiyaShell *self)
priv->vkbs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref);
priv->css_provider = NULL;
priv->input = NULL;
priv->files_watchdog = NULL;
priv->files_hook = NULL;
priv->theme = NULL;
priv->idle_notif = NULL;
}
@@ -516,7 +517,14 @@ int diya_shell_run(DiyaShell *shell, int argc, char **argv)
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
assert(GTK_IS_APPLICATION(priv->app));
GtkApplication *app = priv->app;
gchar *path = NULL;
if(g_getenv("GSETTINGS_SCHEMA_DIR") == NULL)
{
path = g_strconcat(g_get_user_config_dir(), "/diya/schemas/", NULL);
g_mkdir_with_parents((const gchar *)path, 0755);
g_setenv("GSETTINGS_SCHEMA_DIR", path, FALSE);
g_free(path);
}
/*
// theme dir
gchar *path = g_strconcat(g_get_user_config_dir(), "/diya/themes/", NULL);
@@ -525,7 +533,7 @@ int diya_shell_run(DiyaShell *shell, int argc, char **argv)
*/
// keymap dir
gchar *path = g_strconcat(g_get_user_config_dir(), "/diya/xkb/", NULL);
path = g_strconcat(g_get_user_config_dir(), "/diya/xkb/", NULL);
g_mkdir_with_parents((const gchar *)path, 0755);
g_free(path);
const GOptionEntry cmd_params[] =
@@ -541,7 +549,8 @@ int diya_shell_run(DiyaShell *shell, int argc, char **argv)
.arg_description = NULL,
},
#endif
{NULL}};
{NULL}
};
g_application_add_main_option_entries(G_APPLICATION(app), cmd_params);
g_signal_connect(app, "handle-local-options", G_CALLBACK(diya_shell_handle_local_options), shell);
int status = g_application_run(G_APPLICATION(app), argc, argv);
@@ -603,19 +612,19 @@ void diya_shell_monitor_input(DiyaShell *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)
if (!priv->files_hook)
{
priv->files_watchdog = diya_files_monitor_new();
priv->files_hook = diya_hook_new();
}
return diya_files_monitor_watch(priv->files_watchdog, file, callback, userdata);
return diya_hook_install(priv->files_hook, file, callback, userdata, true);
}
void diya_shell_unwatch_file(DiyaShell *self, const gchar *file)
{
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
if (priv->files_watchdog)
if (priv->files_hook)
{
diya_files_monitor_unwatch(priv->files_watchdog, file);
diya_hook_uninstall(priv->files_hook, file);
}
}
@@ -659,4 +668,14 @@ void diya_shell_power_display(DiyaShell* self, gboolean mode)
zwlr_output_power_v1_set_mode(output_power, mode? ZWLR_OUTPUT_POWER_V1_MODE_ON: ZWLR_OUTPUT_POWER_V1_MODE_OFF);
zwlr_output_power_v1_destroy(output_power);
}
}
gboolean diya_shell_watch_script(DiyaShell* self, const gchar* script)
{
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
if (!priv->files_hook)
{
priv->files_hook = diya_hook_new();
}
return diya_hook_install_lua(priv->files_hook, script);
}

View File

@@ -4,6 +4,8 @@
#include <gtk/gtk.h>
#include "base.h"
#define DEFAULT_IDLE_TIMEOUT 60*1000 // 1m
#define DIYA_ENV_THEME "DIYA_DEFAULT_THEME"
#define DIYA_ENV_VKB_KEYMAP "DIYA_VKB_KEYMAP"
@@ -49,6 +51,7 @@ const char* diya_shell_get_name(DiyaShell* shell);
DiyaVirtualKeyboard* diya_shell_get_virtual_keyboard(DiyaShell* shell, const gchar* name);
void diya_shell_monitor_input(DiyaShell* shell);
gboolean diya_shell_watch_file(DiyaShell* shell, const gchar* file, GCallback callback, gpointer userdata);
gboolean diya_shell_watch_script(DiyaShell* shell, const gchar* script);
void diya_shell_unwatch_file(DiyaShell* shell, const gchar* file);
void diya_shell_power_display(DiyaShell* shell, gboolean mode);
void diya_shell_launch(DiyaShell* shell, GAppInfo* app);

View File

@@ -116,6 +116,8 @@ struct _DiyaTaskbarWidget
DiyaTaskbarListModel *model;
GtkListItemFactory *factory;
guint selection_changed_sig_id;
GtkWidget *btn_test;
};
enum
@@ -278,6 +280,16 @@ static void diya_taskbar_list_model_selection_changed_cb(GtkSelectionModel *mode
}
}
static void diya_dashboard_btn_test_clicked(GtkWidget *widget, gpointer user_data)
{
(void) widget;
g_return_if_fail(DIYA_IS_SHELL_WINDOW(user_data));
DiyaShellWindow* self = user_data;
DiyaSessionShell* shell = DIYA_SESSION_SHELL(diya_shell_window_get_shell(self));
g_return_if_fail(DIYA_IS_SESSION_SHELL(shell));
// TODO remove
}
static void diya_taskbar_widget_init(DiyaTaskbarWidget *self)
{
g_debug("diya_taskbar_widget_init");
@@ -323,6 +335,8 @@ static void diya_taskbar_widget_init(DiyaTaskbarWidget *self)
g_signal_connect(controller, "leave", G_CALLBACK(diya_taskbar_applist_leave), self);
gtk_widget_add_controller(GTK_WIDGET(self->apps_list), GTK_EVENT_CONTROLLER(controller));
*/
g_signal_connect(self->btn_test, "clicked", G_CALLBACK(diya_dashboard_btn_test_clicked), self);
}
static void diya_taskbar_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
@@ -392,6 +406,7 @@ static void diya_taskbar_widget_class_init(DiyaTaskbarWidgetClass *class)
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), DiyaTaskbarWidget, btn_toggle);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), DiyaTaskbarWidget, apps_list);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), DiyaTaskbarWidget, btn_test);
// gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), diya_dashboard_toggle);
gtk_widget_class_set_css_name(GTK_WIDGET_CLASS(class), "diya-taskbar");