837 lines
26 KiB
C
837 lines
26 KiB
C
#include <glib-unix.h>
|
|
#include "shell.h"
|
|
#include "wayland.h"
|
|
#include "virtual-keyboard.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>
|
|
#include <gtk4-session-lock.h>
|
|
|
|
#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
|
|
{
|
|
NO_PROP,
|
|
PROP_SHELL_WAYLAND,
|
|
PROP_SHELL_APP,
|
|
PROP_SHELL_NAME,
|
|
PROP_SHELL_THEME,
|
|
PROP_SHELL_IDLE_TO,
|
|
PROP_SHELL_LOCK,
|
|
N_PROPERTIES
|
|
};
|
|
|
|
static GParamSpec *shell_properties[N_PROPERTIES] = {0};
|
|
|
|
typedef struct _DiyaShellPrivate
|
|
{
|
|
DiyaObject parent;
|
|
DiyaWayland *wayland;
|
|
GtkApplication *app;
|
|
gchar *name;
|
|
GHashTable *vkbs;
|
|
GtkCssProvider *css_provider;
|
|
DiyaInput *input;
|
|
DiyaHook *files_hook;
|
|
gchar *theme;
|
|
DiyaIdleNotification *idle_notif;
|
|
GtkSessionLockInstance *lock;
|
|
} DiyaShellPrivate;
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE(DiyaShell, diya_shell, DIYA_TYPE_OBJECT);
|
|
|
|
static void diya_shell_finalize(GObject *object)
|
|
{
|
|
g_debug("diya_shell_finalize: %s", diya_object_to_string(object));
|
|
DiyaShell *self = DIYA_SHELL(object);
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
|
|
if (priv->name)
|
|
{
|
|
g_free(priv->name);
|
|
priv->name = NULL;
|
|
}
|
|
if (priv->theme)
|
|
{
|
|
g_free(priv->theme);
|
|
priv->name = NULL;
|
|
}
|
|
g_hash_table_destroy(priv->vkbs);
|
|
G_OBJECT_CLASS(diya_shell_parent_class)->finalize(object);
|
|
}
|
|
|
|
static void diya_shell_dispose(GObject *object)
|
|
{
|
|
g_debug("diya_shell_dispose: %s", diya_object_to_string(object));
|
|
DiyaShell *self = DIYA_SHELL(object);
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
|
|
if (priv->idle_notif)
|
|
{
|
|
g_object_unref(priv->idle_notif);
|
|
priv->idle_notif = NULL;
|
|
}
|
|
if (priv->lock)
|
|
{
|
|
if (gtk_session_lock_instance_is_locked(priv->lock))
|
|
{
|
|
gtk_session_lock_instance_unlock(priv->lock);
|
|
}
|
|
g_object_unref(priv->lock);
|
|
}
|
|
if (priv->wayland)
|
|
{
|
|
g_object_unref(priv->wayland);
|
|
}
|
|
if (priv->css_provider)
|
|
{
|
|
g_object_unref(priv->css_provider);
|
|
}
|
|
if (priv->input)
|
|
{
|
|
g_object_unref(priv->input);
|
|
}
|
|
if (priv->files_hook)
|
|
{
|
|
g_object_unref(priv->files_hook);
|
|
priv->files_hook = NULL;
|
|
}
|
|
G_OBJECT_CLASS(diya_shell_parent_class)->dispose(object);
|
|
if (priv->app)
|
|
{
|
|
g_application_quit(G_APPLICATION(priv->app));
|
|
}
|
|
}
|
|
|
|
static void diya_shell_reload_theme(DiyaShell *shell)
|
|
{
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
|
|
|
|
if (priv->css_provider)
|
|
{
|
|
gtk_style_context_remove_provider_for_display(gdk_display_get_default(), GTK_STYLE_PROVIDER(priv->css_provider));
|
|
g_object_unref(priv->css_provider);
|
|
priv->css_provider = NULL;
|
|
}
|
|
priv->css_provider = gtk_css_provider_new();
|
|
|
|
gchar *css_file = diya_shell_config_theme(priv);
|
|
g_debug("diya_shell_reload_theme: Looking for css file: %s", css_file);
|
|
if (g_file_test(css_file, G_FILE_TEST_EXISTS))
|
|
{
|
|
GFile *file = g_file_new_for_path(css_file);
|
|
gtk_css_provider_load_from_file(priv->css_provider, file);
|
|
g_object_unref(file);
|
|
}
|
|
else
|
|
{
|
|
g_warning("diya_shell_reload_theme: Unable to load CSS from file: %s. Fallback to default theme", css_file);
|
|
gchar *css_resource = g_strconcat("/dev/iohub/diya/shell/css/", priv->name, ".css", NULL);
|
|
gtk_css_provider_load_from_resource(priv->css_provider, css_resource);
|
|
g_free(css_resource);
|
|
}
|
|
g_free(css_file);
|
|
gtk_style_context_add_provider_for_display(
|
|
gdk_display_get_default(),
|
|
GTK_STYLE_PROVIDER(priv->css_provider),
|
|
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
|
}
|
|
|
|
void diya_shell_reload(DiyaShell *self)
|
|
{
|
|
diya_shell_reload_theme(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);
|
|
g_debug("%s event %x", fpath, evtype);
|
|
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_theme(shell);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
g_free(fpath);
|
|
}
|
|
|
|
static void diya_shell_idle(DiyaIdleNotification *notif, DiyaShell *shell)
|
|
{
|
|
assert(DIYA_IS_IDLE_NOTIFICATION(notif));
|
|
g_signal_emit_by_name(shell, DIYA_SIGNAL_SHELL_IDLE);
|
|
}
|
|
|
|
static void diya_shell_resume(DiyaIdleNotification *notif, DiyaShell *shell)
|
|
{
|
|
assert(DIYA_IS_IDLE_NOTIFICATION(notif));
|
|
g_signal_emit_by_name(shell, DIYA_SIGNAL_SHELL_RESUME);
|
|
}
|
|
|
|
static void on_gtk_app_startup(GtkApplication *app, void *data)
|
|
{
|
|
(void)app;
|
|
DiyaShell *shell = data;
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
|
|
priv->wayland = diya_wayland_new(DIYA_SHELL(shell));
|
|
DiyaShellClass *class = DIYA_SHELL_GET_CLASS(shell);
|
|
|
|
// log all environment variables in debug
|
|
for (gchar **env = g_get_environ(); *env != NULL; env++)
|
|
{
|
|
g_debug("ENV: %s", *env);
|
|
}
|
|
|
|
// diya_shell_reload(shell);
|
|
if (class->startup_handle)
|
|
{
|
|
class->startup_handle(shell);
|
|
}
|
|
/*
|
|
if (class->monitor_changed_handle)
|
|
{
|
|
GListModel *monitor_list = gdk_display_get_monitors(gdk_display_get_default());
|
|
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)
|
|
{
|
|
(void)app;
|
|
DiyaShell *shell = data;
|
|
DiyaShellClass *class = DIYA_SHELL_GET_CLASS(shell);
|
|
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)
|
|
{
|
|
g_object_unref(DIYA_SHELL(data));
|
|
return true;
|
|
}
|
|
|
|
static gboolean diya_shell_sighub_handle(DiyaShell *self)
|
|
{
|
|
// reload css file
|
|
diya_shell_reload(self);
|
|
DiyaShellClass *class = DIYA_SHELL_GET_CLASS(self);
|
|
if (class->reload_handle)
|
|
{
|
|
class->reload_handle(self);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void init_gtk_application(DiyaShell *self)
|
|
{
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
|
|
if (priv->app)
|
|
{
|
|
return;
|
|
}
|
|
priv->app = gtk_application_new(priv->name, G_APPLICATION_DEFAULT_FLAGS);
|
|
g_signal_connect(priv->app, "startup", G_CALLBACK(on_gtk_app_startup), (void *)self);
|
|
g_signal_connect(priv->app, "activate", G_CALLBACK(on_gtk_app_active), (void *)self);
|
|
g_unix_signal_add(SIGINT, (GSourceFunc)diya_shell_sigint_handle, (void *)self);
|
|
g_unix_signal_add(SIGHUP, (GSourceFunc)diya_shell_sighub_handle, (void *)self);
|
|
}
|
|
|
|
static void diya_shell_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
|
|
{
|
|
DiyaShell *self = DIYA_SHELL(object);
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_SHELL_NAME:
|
|
if (priv->name)
|
|
{
|
|
return;
|
|
}
|
|
priv->name = g_strdup(g_value_get_string(value));
|
|
init_gtk_application(self);
|
|
break;
|
|
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));
|
|
g_signal_connect(priv->idle_notif, DIYA_SIGNAL_IDLE_NOTIF_IDLE, G_CALLBACK(diya_shell_idle), self);
|
|
g_signal_connect(priv->idle_notif, DIYA_SIGNAL_IDLE_NOTIF_RESUME, G_CALLBACK(diya_shell_resume), self);
|
|
break;
|
|
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;
|
|
}
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void diya_shell_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
|
|
{
|
|
DiyaShell *self = DIYA_SHELL(object);
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
|
|
switch (property_id)
|
|
{
|
|
case PROP_SHELL_WAYLAND:
|
|
g_value_set_pointer(value, priv->wayland);
|
|
break;
|
|
case PROP_SHELL_APP:
|
|
g_value_set_pointer(value, priv->app);
|
|
break;
|
|
case PROP_SHELL_NAME:
|
|
g_value_set_string(value, priv->name);
|
|
break;
|
|
case PROP_SHELL_THEME:
|
|
g_value_set_string(value, priv->theme);
|
|
break;
|
|
case PROP_SHELL_LOCK:
|
|
// assert(priv->lock);
|
|
g_value_set_pointer(value, priv->lock);
|
|
break;
|
|
case PROP_SHELL_IDLE_TO:
|
|
if(priv->idle_notif)
|
|
{
|
|
g_value_set_uint(value, diya_idle_notification_get_timeout(priv->idle_notif));
|
|
}
|
|
else
|
|
{
|
|
g_value_set_uint(value, 0);
|
|
}
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static void on_shell_locked(GtkSessionLockInstance *lock, DiyaShell *shell)
|
|
{
|
|
(void)lock;
|
|
assert(shell);
|
|
g_message("Shell locked successfully");
|
|
g_signal_emit_by_name(shell, DIYA_SIGNAL_SHELL_LOCKED);
|
|
}
|
|
|
|
static void on_shell_unlocked(GtkSessionLockInstance *lock, DiyaShell *shell)
|
|
{
|
|
(void)lock;
|
|
assert(shell);
|
|
g_message("Shell unlocked");
|
|
g_signal_emit_by_name(shell, DIYA_SIGNAL_SHELL_UNLOCKED);
|
|
}
|
|
|
|
static void on_shell_lock_failed(GtkSessionLockInstance *lock, DiyaShell *shell)
|
|
{
|
|
(void)lock;
|
|
assert(shell);
|
|
g_critical("Unable to lock shell");
|
|
g_signal_emit_by_name(shell, DIYA_SIGNAL_SHELL_LOCK_FAILED);
|
|
}
|
|
|
|
static void on_monitor_present(GtkSessionLockInstance* lock, GdkMonitor *monitor, DiyaShell *shell)
|
|
{
|
|
assert(shell);
|
|
g_debug("Build lock window for monitor");
|
|
DiyaShellClass *class = DIYA_SHELL_GET_CLASS(shell);
|
|
if(class->build_lock_window)
|
|
{
|
|
GtkWindow* window = class->build_lock_window(shell);
|
|
gtk_session_lock_instance_assign_window_to_monitor(lock, window, monitor);
|
|
}
|
|
}
|
|
|
|
|
|
static void diya_shell_init_lock(DiyaShell* self)
|
|
{
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
|
|
if(priv->lock)
|
|
{
|
|
return;
|
|
}
|
|
priv->lock = gtk_session_lock_instance_new();
|
|
g_signal_connect(priv->lock, DIYA_SIGNAL_SHELL_LOCKED, G_CALLBACK(on_shell_locked), self);
|
|
g_signal_connect(priv->lock, "failed", G_CALLBACK(on_shell_lock_failed), self);
|
|
g_signal_connect(priv->lock, DIYA_SIGNAL_SHELL_UNLOCKED, G_CALLBACK(on_shell_unlocked), self);
|
|
g_signal_connect(priv->lock, "monitor", G_CALLBACK(on_monitor_present), self);
|
|
|
|
}
|
|
|
|
static void diya_shell_init(DiyaShell *self)
|
|
{
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
|
|
priv->wayland = NULL;
|
|
priv->app = NULL;
|
|
priv->name = NULL;
|
|
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_hook = NULL;
|
|
priv->theme = NULL;
|
|
priv->idle_notif = NULL;
|
|
priv->lock = NULL;
|
|
}
|
|
|
|
DiyaWayland *diya_shell_get_wayland(DiyaShell *shell)
|
|
{
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
|
|
assert(DIYA_IS_WAYLAND(priv->wayland));
|
|
return priv->wayland;
|
|
}
|
|
|
|
GtkApplication *diya_shell_get_application(DiyaShell *shell)
|
|
{
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
|
|
assert(GTK_IS_APPLICATION(priv->app));
|
|
return priv->app;
|
|
}
|
|
|
|
const char *diya_shell_get_name(DiyaShell *shell)
|
|
{
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
|
|
return priv->name;
|
|
}
|
|
|
|
static const gchar *diya_shell_to_string(DiyaObject *object)
|
|
{
|
|
return diya_shell_get_name(DIYA_SHELL(object));
|
|
}
|
|
|
|
static void diya_shell_class_init(DiyaShellClass *class)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
|
|
gobject_class->dispose = diya_shell_dispose;
|
|
gobject_class->finalize = diya_shell_finalize;
|
|
gobject_class->set_property = diya_shell_set_property;
|
|
gobject_class->get_property = diya_shell_get_property;
|
|
|
|
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
|
|
base_class->to_string = diya_shell_to_string;
|
|
|
|
class->foreign_register = NULL;
|
|
class->virtual_keyboard_register = diya_virtual_keyboard_register;
|
|
class->build_lock_window = NULL;
|
|
class->startup_handle = NULL;
|
|
class->active_handle = NULL;
|
|
class->reload_handle = NULL;
|
|
|
|
shell_properties[PROP_SHELL_WAYLAND] = g_param_spec_pointer(DIYA_PROP_SHELL_WAYLAND, NULL, "Shell wayland", G_PARAM_READABLE); //
|
|
shell_properties[PROP_SHELL_NAME] = g_param_spec_string(DIYA_PROP_SHELL_NAME, NULL, "Shell name", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
|
shell_properties[PROP_SHELL_APP] = g_param_spec_pointer(DIYA_PROP_SHELL_APPLICATION, NULL, "Shell application", G_PARAM_READABLE);
|
|
shell_properties[PROP_SHELL_THEME] = g_param_spec_string(DIYA_PROP_SHELL_THEME, NULL, "Shell theme", NULL, G_PARAM_READWRITE);
|
|
shell_properties[PROP_SHELL_IDLE_TO] = g_param_spec_uint(DIYA_PROP_SHELL_IDLE_TIMEOUT, NULL, "Shell IDLE timeout", 0, UINT32_MAX ,DEFAULT_IDLE_TIMEOUT, G_PARAM_READWRITE);
|
|
shell_properties[PROP_SHELL_LOCK] = g_param_spec_pointer(DIYA_PROP_SHELL_LOCK, NULL, "Shell lock", G_PARAM_READABLE);
|
|
|
|
g_object_class_install_properties(gobject_class, N_PROPERTIES, shell_properties);
|
|
|
|
// define signals
|
|
g_signal_new(DIYA_SIGNAL_SHELL_KEYBOARD_ENTER,
|
|
DIYA_TYPE_SHELL,
|
|
G_SIGNAL_DETAILED |
|
|
G_SIGNAL_ACTION |
|
|
G_SIGNAL_RUN_FIRST,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
G_TYPE_NONE,
|
|
3,
|
|
G_TYPE_POINTER,
|
|
G_TYPE_POINTER,
|
|
G_TYPE_POINTER);
|
|
g_signal_new(DIYA_SIGNAL_SHELL_KEYBOARD_MODIFIER_CHANGED,
|
|
DIYA_TYPE_SHELL,
|
|
G_SIGNAL_DETAILED |
|
|
G_SIGNAL_ACTION |
|
|
G_SIGNAL_RUN_FIRST,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
G_TYPE_NONE,
|
|
2,
|
|
G_TYPE_POINTER,
|
|
G_TYPE_POINTER);
|
|
g_signal_new(DIYA_SIGNAL_SHELL_KEYBOARD_LEAVE,
|
|
DIYA_TYPE_SHELL,
|
|
G_SIGNAL_DETAILED |
|
|
G_SIGNAL_ACTION |
|
|
G_SIGNAL_RUN_FIRST,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
G_TYPE_NONE,
|
|
0);
|
|
g_signal_new(DIYA_SIGNAL_SHELL_KEY_PRESSED,
|
|
DIYA_TYPE_SHELL,
|
|
G_SIGNAL_DETAILED |
|
|
G_SIGNAL_ACTION |
|
|
G_SIGNAL_RUN_FIRST,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
G_TYPE_NONE,
|
|
4,
|
|
G_TYPE_POINTER,
|
|
G_TYPE_POINTER,
|
|
G_TYPE_UINT,
|
|
G_TYPE_UINT);
|
|
|
|
g_signal_new(DIYA_SIGNAL_SHELL_KEY_RELEASED,
|
|
DIYA_TYPE_SHELL,
|
|
G_SIGNAL_DETAILED |
|
|
G_SIGNAL_ACTION |
|
|
G_SIGNAL_RUN_FIRST,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
G_TYPE_NONE,
|
|
4,
|
|
G_TYPE_POINTER,
|
|
G_TYPE_POINTER,
|
|
G_TYPE_UINT,
|
|
G_TYPE_UINT);
|
|
g_signal_new(DIYA_SIGNAL_SHELL_IDLE,
|
|
DIYA_TYPE_SHELL,
|
|
G_SIGNAL_DETAILED |
|
|
G_SIGNAL_ACTION |
|
|
G_SIGNAL_RUN_FIRST,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
G_TYPE_NONE,
|
|
0);
|
|
g_signal_new(DIYA_SIGNAL_SHELL_RESUME,
|
|
DIYA_TYPE_SHELL,
|
|
G_SIGNAL_DETAILED |
|
|
G_SIGNAL_ACTION |
|
|
G_SIGNAL_RUN_FIRST,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
G_TYPE_NONE,
|
|
0);
|
|
g_signal_new(DIYA_SIGNAL_SHELL_WINDOW_ENTER,
|
|
DIYA_TYPE_SHELL,
|
|
G_SIGNAL_DETAILED |
|
|
G_SIGNAL_ACTION |
|
|
G_SIGNAL_RUN_FIRST,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
G_TYPE_NONE,
|
|
1,
|
|
G_TYPE_POINTER);
|
|
g_signal_new(DIYA_SIGNAL_SHELL_WINDOW_LEAVE,
|
|
DIYA_TYPE_SHELL,
|
|
G_SIGNAL_DETAILED |
|
|
G_SIGNAL_ACTION |
|
|
G_SIGNAL_RUN_FIRST,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
G_TYPE_NONE,
|
|
1,
|
|
G_TYPE_POINTER);
|
|
g_signal_new(DIYA_SIGNAL_SHELL_LOCKED,
|
|
DIYA_TYPE_SHELL,
|
|
G_SIGNAL_DETAILED |
|
|
G_SIGNAL_ACTION |
|
|
G_SIGNAL_RUN_FIRST,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
G_TYPE_NONE,
|
|
0);
|
|
g_signal_new(DIYA_SIGNAL_SHELL_UNLOCKED,
|
|
DIYA_TYPE_SHELL,
|
|
G_SIGNAL_DETAILED |
|
|
G_SIGNAL_ACTION |
|
|
G_SIGNAL_RUN_FIRST,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
G_TYPE_NONE,
|
|
0);
|
|
g_signal_new(DIYA_SIGNAL_SHELL_LOCK_FAILED,
|
|
DIYA_TYPE_SHELL,
|
|
G_SIGNAL_DETAILED |
|
|
G_SIGNAL_ACTION |
|
|
G_SIGNAL_RUN_FIRST,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
G_TYPE_NONE,
|
|
0);
|
|
}
|
|
|
|
static int diya_shell_handle_local_options(GApplication *application, GVariantDict *options, gpointer user_data)
|
|
{
|
|
(void)application;
|
|
(void)user_data;
|
|
#ifdef __SHELL_VERSION__
|
|
guint32 count;
|
|
if (g_variant_dict_lookup(options, "version", "b", &count))
|
|
{
|
|
g_print("Shell version: %s\n", __SHELL_VERSION__);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
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);
|
|
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);
|
|
const GOptionEntry cmd_params[] =
|
|
{
|
|
#ifdef __SHELL_VERSION__
|
|
{
|
|
.long_name = "version",
|
|
.short_name = 'v',
|
|
.flags = G_OPTION_FLAG_NONE,
|
|
.arg = G_OPTION_ARG_NONE,
|
|
.arg_data = NULL,
|
|
.description = "Show version information",
|
|
.arg_description = NULL,
|
|
},
|
|
#endif
|
|
{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);
|
|
g_object_unref(app);
|
|
return status;
|
|
}
|
|
|
|
DiyaVirtualKeyboard *diya_shell_get_virtual_keyboard(DiyaShell *shell, const gchar *name)
|
|
{
|
|
DiyaVirtualKeyboard *vkb = NULL;
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(shell);
|
|
if (name)
|
|
{
|
|
if (g_hash_table_contains(priv->vkbs, name))
|
|
{
|
|
g_debug("diya_shell_get_virtual_keyboard: Getting keyboard %s from cache", name);
|
|
vkb = g_hash_table_lookup(priv->vkbs, name);
|
|
}
|
|
else
|
|
{
|
|
gchar *keymap_file = g_strconcat(g_get_user_config_dir(), "/diya/xkb/", name, ".keymap", NULL);
|
|
g_debug("diya_shell_get_virtual_keyboard: Looking for keymap file: %s", keymap_file);
|
|
if (g_file_test(keymap_file, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))
|
|
{
|
|
vkb = diya_virtual_keyboard_new(shell, keymap_file);
|
|
if (vkb)
|
|
{
|
|
g_debug("diya_shell_get_virtual_keyboard: add new keyboard %s to cache", name);
|
|
g_hash_table_insert(priv->vkbs, (gpointer)g_strdup(name), vkb);
|
|
}
|
|
}
|
|
free(keymap_file);
|
|
}
|
|
}
|
|
|
|
if (!vkb)
|
|
{
|
|
g_debug("Fallback to default virtual key board");
|
|
if (!g_hash_table_contains(priv->vkbs, "default"))
|
|
{
|
|
g_debug("Add new keyboard instance to cache");
|
|
g_hash_table_insert(priv->vkbs, (gpointer)g_strdup("default"), diya_virtual_keyboard_new(shell, NULL));
|
|
}
|
|
vkb = g_hash_table_lookup(priv->vkbs, "default");
|
|
}
|
|
|
|
return vkb;
|
|
}
|
|
void diya_shell_monitor_input(DiyaShell *self)
|
|
{
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
|
|
if (priv->input)
|
|
{
|
|
return;
|
|
}
|
|
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_hook)
|
|
{
|
|
priv->files_hook = diya_hook_new();
|
|
}
|
|
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_hook)
|
|
{
|
|
diya_hook_uninstall(priv->files_hook, file);
|
|
}
|
|
}
|
|
|
|
void diya_shell_launch(DiyaShell *self, GAppInfo *app)
|
|
{
|
|
GError *error = NULL;
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
|
|
GAppLaunchContext *context = g_app_launch_context_new();
|
|
if (priv->theme)
|
|
{
|
|
g_app_launch_context_setenv(context, "GTK_THEME", priv->theme);
|
|
}
|
|
g_app_info_launch(app, NULL, context, &error);
|
|
g_object_unref(context);
|
|
if (error)
|
|
{
|
|
g_critical("Unable to launch application: %s", error->message);
|
|
g_error_free(error);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void diya_shell_power_display(DiyaShell* self, gboolean mode)
|
|
{
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
|
|
struct zwlr_output_power_manager_v1 * mngr = diya_wayland_get_output_mngr(priv->wayland);
|
|
if(!mngr)
|
|
{
|
|
g_warning("Output power manager protocol is not available");
|
|
return;
|
|
}
|
|
GdkDisplay *display = gdk_display_get_default();
|
|
GListModel *monitors = gdk_display_get_monitors(display);
|
|
guint n_monitors = g_list_model_get_n_items(monitors);
|
|
|
|
for (guint i = 0; i < n_monitors; ++i)
|
|
{
|
|
GdkMonitor *monitor = g_list_model_get_item(monitors, i);
|
|
struct wl_output * output = gdk_wayland_monitor_get_wl_output(monitor);
|
|
struct zwlr_output_power_v1 * output_power = zwlr_output_power_manager_v1_get_output_power(mngr, output);
|
|
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);
|
|
}
|
|
|
|
void diya_shell_lock(DiyaShell* self)
|
|
{
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
|
|
if(!priv->lock)
|
|
{
|
|
diya_shell_init_lock(self);
|
|
}
|
|
if(gtk_session_lock_instance_is_locked(priv->lock))
|
|
{
|
|
g_warning("Shell session is already locked, doing nothing");
|
|
return;
|
|
}
|
|
if(!gtk_session_lock_instance_lock(priv->lock))
|
|
{
|
|
g_error("gtk_session_lock_instance_lock:Unable to lock the current session");
|
|
return;
|
|
}
|
|
}
|
|
void diya_shell_unlock(DiyaShell* self)
|
|
{
|
|
DiyaShellPrivate *priv = diya_shell_get_instance_private(self);
|
|
if(priv->lock)
|
|
{
|
|
gtk_session_lock_instance_unlock(priv->lock);
|
|
g_debug("gtk_session_lock_instance_unlock: Shell unlocked");
|
|
}
|
|
} |