feat: add virtual keyboard ui

This commit is contained in:
DanyLE 2025-03-13 00:54:14 +01:00
parent 4da1db3bd4
commit 8020954fed
22 changed files with 2086 additions and 1706 deletions

View File

@ -71,7 +71,7 @@ dm_src = [
buil_dep = [gtk, gtk_layer_shell, wayland_client, xkbcommon]
session_resource = gnome.compile_resources('session-resources','resources/session-shell/gresource.xml')
session_resource = gnome.compile_resources('session-resources','resources/gresource-session.xml')
executable(
'diya-shell',
@ -85,7 +85,7 @@ login_src = [
'src/login.c'
]
login_resource = gnome.compile_resources('login-resources','resources/login-shell/gresource.xml')
login_resource = gnome.compile_resources('login-resources','resources/gresource-login.xml')
executable(
'diya-login-shell',

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/dev/iohub/diya/shell">
<file alias="login-shell.css">resources/login-shell.css</file>
<file alias="virtual-keyboard.css">resources/virtual-keyboard.css</file>
<file alias="default.keymap">resources/default.keymap</file>
<!--file alias="virtuail-keyboard.ui">resources/ui/virtual-keyboard.ui</file-->
</gresource>
</gresources>

11
resources/login-shell.css Normal file
View File

@ -0,0 +1,11 @@
@import url("resource:///dev/iohub/diya/shell/virtual-keyboard.css");
.diya-login-header {
font-size: 16px;
font-weight: bold;
}
.diya-login-status {
font-size: 12px;
color: red;
}

View File

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

View File

@ -1,9 +0,0 @@
.header {
font-size: 16px;
font-weight: bold;
}
.status {
font-size: 12px;
color: red;
}

View File

@ -0,0 +1,38 @@
.diya-vkb
{
background-color: transparent;
border: 1px solid orangered;
}
.diya-vkb-btn {
background-color: white;
border: 1px solid #CDC7C2;
border-radius: 3px;
min-width: 20px;
/*min-height: 30px;*/
}
.diya-vkb-btn:hover
{
background-color: #E7E6E2;
}
/*
.diya-vkb-btn label {
border: 1px solid #b81f2b;
}*/
.diya-vkb-btn-level-1 {
color: black;
}
.diya-vkb-btn-level-2 {
color: gray;
font-size: 10px;
padding-left: 3px;
}
.diya-vkb-btn-level-3 {
color: gray;
font-size: 10px;
padding-right: 3px;
}

View File

@ -37,10 +37,12 @@ static void diya_foreign_window_dispose(GObject* object)
if(self->appid)
{
g_free(self->appid);
self->appid = NULL;
}
if(self->title)
{
g_free(self->title);
self->title = NULL;
}
G_OBJECT_CLASS(diya_foreign_window_parent_class)->dispose(object);
}

View File

@ -12,12 +12,13 @@
struct _DiyaLoginShell
{
DiyaShell parent_object;
GtkApplication *app;
GtkSessionLockInstance *lock;
GtkWidget *username;
GtkWidget *password;
GtkWidget *status;
guint bus_watch_id;
//GtkWindow *window;
GList * windows;
};
G_DEFINE_FINAL_TYPE(DiyaLoginShell, diya_login_shell, DIYA_TYPE_SHELL);
@ -34,46 +35,37 @@ static void diya_login_shell_dispose(GObject *object)
}
g_object_unref(self->lock);
}
if(self->windows)
{
// destroyed all windows and free list
GList * it = NULL;
for(it = self->windows; it; it = it->next)
{
if(it->data)
{
gtk_window_destroy(GTK_WINDOW(it->data));
}
}
g_list_free(self->windows);
}
if (self->bus_watch_id > 0)
{
g_bus_unwatch_name(self->bus_watch_id);
}
if (self->app)
{
g_object_unref(self->app);
}
G_OBJECT_CLASS(diya_login_shell_parent_class)->dispose(object);
}
static void diya_login_shell_init(DiyaLoginShell *self)
{
self->app = NULL;
g_debug("diya_login_shell_init");
self->lock = gtk_session_lock_instance_new();
self->username = NULL;
self->password = NULL;
self->status = NULL;
self->windows = NULL;
self->bus_watch_id = 0;
}
static const gchar *diya_login_shell_to_string(DiyaObject *object)
{
(void)object;
return "Diya Login Shell";
}
static void diya_login_shell_class_init(DiyaLoginShellClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->dispose = diya_login_shell_dispose;
// gobject_class->set_property = diya_lock_session_set_property;
// gobject_class->get_property = diya_lock_session_get_property;
//DiyaShellClass *base_shell_class = DIYA_SHELL_CLASS(class)
//base_shell_class->foreign_register = diya_session_shell_foreign_toplevel_register;
base_class->to_string = diya_login_shell_to_string;
}
static void on_method_call_return(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
@ -103,7 +95,7 @@ static void on_method_call_return(GObject *source_object, GAsyncResult *res, gpo
if (success)
{
gtk_label_set_text(GTK_LABEL(self->status), "Login successful");
g_application_quit(G_APPLICATION(self->app));
g_object_unref(self);
}
else
{
@ -191,101 +183,122 @@ static void open_vkb(GtkButton *button, DiyaLoginShell *self)
g_object_unref(vkb);
}
DiyaLoginShell *diya_login_shell_new()
static void add_new_monitor(DiyaLoginShell* self, GdkMonitor* monitor, gint position)
{
return g_object_new(DIYA_TYPE_LOGIN_SHELL, NULL);
GtkWindow* window = GTK_WINDOW(gtk_application_window_new(diya_shell_get_application(DIYA_SHELL(self))));
gtk_session_lock_instance_assign_window_to_monitor(self->lock, window, monitor);
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_halign(box, GTK_ALIGN_CENTER);
gtk_widget_set_valign(box, GTK_ALIGN_CENTER);
gtk_box_set_spacing(GTK_BOX(box), 10);
GtkWidget *label;
label = gtk_label_new("Please login");
gtk_box_append(GTK_BOX(box), label);
gtk_widget_add_css_class(label, "diya-login-header");
GtkWidget *user_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_valign(user_box, GTK_ALIGN_CENTER);
gtk_widget_set_halign(user_box, GTK_ALIGN_END);
gtk_box_set_spacing(GTK_BOX(user_box), 10);
label = gtk_label_new("Username");
gtk_box_append(GTK_BOX(user_box), label);
self->username = gtk_entry_new();
gtk_box_append(GTK_BOX(user_box), GTK_WIDGET(self->username));
gtk_box_append(GTK_BOX(box), user_box);
GtkWidget *password_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_valign(password_box, GTK_ALIGN_CENTER);
gtk_widget_set_halign(password_box, GTK_ALIGN_END);
gtk_box_set_spacing(GTK_BOX(password_box), 10);
label = gtk_label_new("Password");
gtk_box_append(GTK_BOX(password_box), label);
self->password = gtk_password_entry_new();
gtk_box_append(GTK_BOX(password_box), GTK_WIDGET(self->password));
gtk_box_append(GTK_BOX(box), password_box);
g_signal_connect(self->username, "activate", G_CALLBACK(do_login), self);
g_signal_connect(self->password, "activate", G_CALLBACK(do_login), self);
GtkWidget *button = gtk_button_new_with_label("Login");
g_signal_connect(button, "clicked", G_CALLBACK(do_login), self);
//gtk_widget_set_can_focus(GTK_WIDGET(button), false);
gtk_box_append(GTK_BOX(box), button);
// Not displayed, but allows testing that creating popups doesn't crash GTK
gtk_widget_set_tooltip_text(button, "Login");
self->status = gtk_label_new(NULL);
gtk_box_append(GTK_BOX(box), self->status);
gtk_widget_add_css_class(self->status, "diya-login-status");
button = gtk_button_new_with_label("Show virtual keyboard");
g_signal_connect(button, "clicked", G_CALLBACK(open_vkb), self);
gtk_widget_set_can_focus(GTK_WIDGET(button), false);
gtk_box_append(GTK_BOX(box), button);
DiyaVirtualKeyboardWidget* vkb_widget = diya_virtual_keyboard_widget_new();
gtk_box_append(GTK_BOX(box), GTK_WIDGET(vkb_widget));
gtk_window_set_child(GTK_WINDOW(window), box);
gtk_window_present(window);
self->windows = g_list_insert(self->windows,window, position);
}
void diya_login_shell_attach(DiyaLoginShell *self, GtkApplication *app)
static void on_monitor_changed(GListModel* monitor_lists,guint position, guint removed,guint added, gpointer object)
{
self->app = app;
g_debug("Monitor list changed at %d: added %d, removed %d", position, added, removed);
DiyaLoginShell* self = DIYA_LOGIN_SHELL(object);
if(removed > 0)
{
for (guint i = 0; i < removed; i++)
{
GtkWindow* win = GTK_WINDOW(g_list_nth(self->windows, position));
if(win)
{
gtk_window_destroy(win);
self->windows = g_list_remove(self->windows, win);
}
}
}
if(added > 0)
{
for (guint i = 0; i < added; i++)
{
GdkMonitor * monitor = g_list_model_get_item(monitor_lists,position + i);
add_new_monitor(self, monitor, position + i);
}
}
}
static void diya_login_shell_startup(DiyaShell* shell)
{
DiyaLoginShell* self = DIYA_LOGIN_SHELL(shell);
if (!gtk_session_lock_instance_lock(self->lock))
{
g_error("gtk_session_lock_instance_lock: Unable to lock the display");
g_object_unref(self);
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);
GtkWindow *gtk_window = GTK_WINDOW(gtk_application_window_new(app));
gtk_session_lock_instance_assign_window_to_monitor(self->lock, gtk_window, monitor);
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_halign(box, GTK_ALIGN_CENTER);
gtk_widget_set_valign(box, GTK_ALIGN_CENTER);
gtk_box_set_spacing(GTK_BOX(box), 10);
GtkWidget *label;
label = gtk_label_new("Please login");
gtk_box_append(GTK_BOX(box), label);
gtk_widget_add_css_class(label, "header");
GtkWidget *user_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_valign(user_box, GTK_ALIGN_CENTER);
gtk_widget_set_halign(user_box, GTK_ALIGN_END);
gtk_box_set_spacing(GTK_BOX(user_box), 10);
label = gtk_label_new("Username");
gtk_box_append(GTK_BOX(user_box), label);
self->username = gtk_entry_new();
gtk_box_append(GTK_BOX(user_box), GTK_WIDGET(self->username));
gtk_box_append(GTK_BOX(box), user_box);
GtkWidget *password_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_valign(password_box, GTK_ALIGN_CENTER);
gtk_widget_set_halign(password_box, GTK_ALIGN_END);
gtk_box_set_spacing(GTK_BOX(password_box), 10);
label = gtk_label_new("Password");
gtk_box_append(GTK_BOX(password_box), label);
self->password = gtk_password_entry_new();
gtk_box_append(GTK_BOX(password_box), GTK_WIDGET(self->password));
gtk_box_append(GTK_BOX(box), password_box);
g_signal_connect(self->username, "activate", G_CALLBACK(do_login), self);
g_signal_connect(self->password, "activate", G_CALLBACK(do_login), self);
GtkWidget *button = gtk_button_new_with_label("Login");
g_signal_connect(button, "clicked", G_CALLBACK(do_login), self);
//gtk_widget_set_can_focus(GTK_WIDGET(button), false);
gtk_box_append(GTK_BOX(box), button);
// Not displayed, but allows testing that creating popups doesn't crash GTK
gtk_widget_set_tooltip_text(button, "Login");
self->status = gtk_label_new(NULL);
gtk_box_append(GTK_BOX(box), self->status);
gtk_widget_add_css_class(self->status, "status");
button = gtk_button_new_with_label("Show virtual keyboard");
g_signal_connect(button, "clicked", G_CALLBACK(open_vkb), self);
gtk_widget_set_can_focus(GTK_WIDGET(button), false);
gtk_box_append(GTK_BOX(box), button);
gtk_window_set_child(GTK_WINDOW(gtk_window), box);
gtk_window_present(gtk_window);
}
// load xml content from gresource
GError *err = NULL;
GBytes *bytes = g_resources_lookup_data("/dev/iohub/diya/shell/login-shell.css", 0, &err);
if (err != NULL)
{
g_critical("Unable to load CSS resource: %s", err->message);
g_error_free(err);
return;
// continue without stylesheet
}
else
{
@ -299,4 +312,24 @@ void diya_login_shell_attach(DiyaLoginShell *self, GtkApplication *app)
GTK_STYLE_PROVIDER_PRIORITY_USER);
g_bytes_unref(bytes);
}
GListModel * list = gdk_display_get_monitors(gdk_display_get_default());
for(guint i = 0; i < g_list_model_get_n_items(list); i++)
{
GdkMonitor * monitor = g_list_model_get_item(list,i);
add_new_monitor(self, monitor, -1);
}
}
static void diya_login_shell_class_init(DiyaLoginShellClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_login_shell_dispose;
// gobject_class->set_property = diya_lock_session_set_property;
// gobject_class->get_property = diya_lock_session_get_property;
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->foreign_register = diya_session_shell_foreign_toplevel_register;
}

View File

@ -8,8 +8,4 @@
#define DIYA_TYPE_LOGIN_SHELL (diya_login_shell_get_type())
G_DECLARE_FINAL_TYPE(DiyaLoginShell, diya_login_shell, DIYA, LOGIN_SHELL, DiyaShell);
DiyaLoginShell *diya_login_shell_new();
void diya_login_shell_attach(DiyaLoginShell *self, GtkApplication *app);
#endif

View File

@ -2,16 +2,9 @@
#include <assert.h>
#include "login-shell.h"
#include "wayland.h"
static gchar **g_shell_argv;
static void activate(GtkApplication *app, void *data)
{
(void)app;
(void)data;
}
static gboolean restart(gpointer d)
{
(void)d;
@ -29,15 +22,6 @@ static gboolean restart(gpointer d)
return FALSE;
}
static void startup(GtkApplication *app, DiyaLoginShell* shell)
{
diya_shell_wayland_init(DIYA_SHELL(shell));
g_unix_signal_add(SIGHUP, (GSourceFunc)restart, NULL);
g_unix_signal_add(SIGINT,(GSourceFunc)g_application_quit,(void*)app);
diya_login_shell_attach(shell, app);
}
int main(int argc, char *argv[])
{
g_shell_argv = g_malloc0(sizeof(gchar *) * (argc + 1));
@ -45,15 +29,7 @@ int main(int argc, char *argv[])
{
g_shell_argv[i] = argv[i];
}
GtkApplication* app = gtk_application_new("dev.iohub.diya.login-shell", G_APPLICATION_DEFAULT_FLAGS);
DiyaLoginShell* shell = diya_login_shell_new();
g_signal_connect(app, "startup", G_CALLBACK(startup), shell);
g_signal_connect(app, "activate", G_CALLBACK(activate), shell);
// g_signal_connect(app, "shutdown", G_CALLBACK(shutdown), (void*)shell);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_warning("Exiting SHELL");
g_object_unref(shell);
return status;
g_unix_signal_add(SIGHUP, (GSourceFunc)restart, NULL);
DiyaLoginShell* shell = DIYA_LOGIN_SHELL(g_object_new(DIYA_TYPE_LOGIN_SHELL, "name", "dev.iohub.diya.login-shell", NULL));
return diya_shell_run(DIYA_SHELL(shell), argc, argv);
}

View File

@ -4,13 +4,13 @@
#include <gtk4-session-lock.h>
#include "shell.h"
#include "foreign.h"
#define SHELL_DESCRIPTION "Diya GTK shell for wayland (diyac)"
#include "background.h"
#include "launcher.h"
#include "session-lock.h"
enum
{
NO_PROP,
SHELL_APP,
SHELL_BACKGROUND_WIDGET,
SHELL_LAUNCHPAD_WIDGET,
SHELL_LOCK_SESSION,
@ -23,7 +23,6 @@ static GParamSpec *shell_properties[N_PROPERTIES] = {0};
struct _DiyaSessionShell
{
DiyaShell parent;
GtkApplication* app;
GtkWindow* background;
GtkWindow* launcher;
GHashTable* windows;
@ -35,11 +34,19 @@ static void diya_session_shell_dispose(GObject* object)
{
DiyaSessionShell * self = DIYA_SESSION_SHELL(object);
g_hash_table_destroy(self->windows);
g_debug("diya_session_shell_dispose");
g_debug("diya_session_shell_dispose: %s", diya_object_to_string(object));
if(self->lock)
{
g_object_unref(self->lock);
}
if(self->background)
{
gtk_window_destroy(self->background);
}
if(self->launcher)
{
gtk_window_destroy(self->launcher);
}
G_OBJECT_CLASS(diya_session_shell_parent_class)->dispose(object);
}
@ -48,10 +55,6 @@ static void diya_session_shell_set_property(GObject *object, guint property_id,
DiyaSessionShell * self = DIYA_SESSION_SHELL(object);
switch (property_id)
{
case SHELL_APP:
self->app = g_value_get_pointer(value);
assert(self->app);
break;
case SHELL_BACKGROUND_WIDGET:
self->background = g_value_get_pointer(value);
break;
@ -72,9 +75,6 @@ static void diya_session_shell_get_property(GObject *object, guint property_id,
DiyaSessionShell * self = DIYA_SESSION_SHELL(object);
switch (property_id)
{
case SHELL_APP:
g_value_set_pointer(value, self->app);
break;
case SHELL_BACKGROUND_WIDGET:
g_value_set_pointer(value, self->background);
break;
@ -95,26 +95,43 @@ static void diya_session_shell_get_property(GObject *object, guint property_id,
}
}
static const gchar* diya_session_shell_to_string(DiyaObject* object)
static void diya_session_shell_startup(DiyaShell* shell)
{
(void) object;
return SHELL_DESCRIPTION;
diya_session_shell_launcher_init(DIYA_SESSION_SHELL(shell));
diya_session_shell_init_background(DIYA_SESSION_SHELL(shell));
GtkCssProvider *provider = gtk_css_provider_new();
const char *css = "#launcher {background-color: red;} #background {background-image:url(\"file:///etc/xdg/labwc/wpp.jpg\");background-size: cover;}";
gtk_css_provider_load_from_string(provider, css);
gtk_style_context_add_provider_for_display(
gdk_display_get_default(), GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
// g_signal_connect (win, "destroy", G_CALLBACK (before_destroy), provider);
g_object_unref(provider);
// CSS support
// set color for it
// g_timeout_add (100,(GSourceFunc )shell_timer,NULL);
}
static void diya_session_shell_active(DiyaShell* shell)
{
diya_session_shell_lock(DIYA_SESSION_SHELL(shell));
}
static void diya_session_shell_class_init(DiyaSessionShellClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
// DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
DiyaShellClass *base_shell_class = DIYA_SHELL_CLASS(class);
base_shell_class->foreign_register = diya_session_shell_foreign_toplevel_register;
base_shell_class->startup_handle = diya_session_shell_startup;
base_shell_class->active_handle = diya_session_shell_active;
base_class->to_string = diya_session_shell_to_string;
///base_class->to_string = diya_session_shell_to_string;
gobject_class->dispose = diya_session_shell_dispose;
gobject_class->set_property = diya_session_shell_set_property;
gobject_class->get_property = diya_session_shell_get_property;
shell_properties[SHELL_APP] = g_param_spec_pointer("application", NULL, "Shell application", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
shell_properties[SHELL_BACKGROUND_WIDGET] = g_param_spec_pointer("background", NULL, "Shell background widget", G_PARAM_READWRITE );
shell_properties[SHELL_LAUNCHPAD_WIDGET] = g_param_spec_pointer("launchpad", NULL, "Shell launchpad", G_PARAM_READWRITE );
shell_properties[SHELL_LOCK_SESSION] = g_param_spec_pointer("session-lock", NULL, "Shell lock session", G_PARAM_READABLE );
@ -232,10 +249,6 @@ void diya_session_shell_remove_all_windows(DiyaSessionShell * shell)
shell->windows = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref);
}
DiyaSessionShell * diya_session_shell_new(GtkApplication * app)
{
return DIYA_SESSION_SHELL(g_object_new(DIYA_TYPE_SESSION_SHELL,"application",app, NULL));
}
/*
static void on_orientation_changed (GtkWindow *window, WindowOrientation orientation, ToplevelData *data)
{

View File

@ -15,6 +15,4 @@ DiyaForeignWindow* diya_session_shell_get_window(DiyaSessionShell * shell, gpoin
gboolean diya_session_shell_add_window(DiyaSessionShell * shell, DiyaForeignWindow * win);
gboolean diya_session_shell_remove_window(DiyaSessionShell * shell, DiyaForeignWindow * win);
void diya_session_shell_remove_all_windows(DiyaSessionShell * shell);
DiyaSessionShell * diya_session_shell_new(GtkApplication * app);
#endif

View File

@ -1,23 +1,10 @@
#include <glib-unix.h>
#include <assert.h>
#include "shell.h"
#include "background.h"
#include "launcher.h"
#include "wayland.h"
#include "foreign.h"
#include "session-lock.h"
#include "session-shell.h"
static gchar **g_shell_argv;
static void activate(GtkApplication *app, void *data)
{
(void)app;
(void)data;
DiyaSessionShell *shell = data;
diya_session_shell_lock(shell);
}
static gboolean restart(gpointer d)
{
(void)d;
@ -35,28 +22,6 @@ static gboolean restart(gpointer d)
return FALSE;
}
static void startup(GtkApplication *app, void *data)
{
DiyaSessionShell *shell = data;
diya_session_shell_launcher_init(shell);
diya_session_shell_init_background(shell);
diya_shell_wayland_init(DIYA_SHELL(shell));
GtkCssProvider *provider = gtk_css_provider_new();
const char *css = "#launcher {background-color: red;} #background {background-image:url(\"file:///etc/xdg/labwc/wpp.jpg\");background-size: cover;}";
gtk_css_provider_load_from_string(provider, css);
gtk_style_context_add_provider_for_display(
gdk_display_get_default(), GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
// g_signal_connect (win, "destroy", G_CALLBACK (before_destroy), provider);
g_object_unref(provider);
// CSS support
// set color for it
// g_timeout_add (100,(GSourceFunc )shell_timer,NULL);
g_unix_signal_add(SIGHUP, (GSourceFunc)restart, NULL);
g_unix_signal_add(SIGINT,(GSourceFunc)g_application_quit,(void*)app);
}
static void session_locked(DiyaSessionShell* shell, void* data)
{
(void)data;
@ -78,16 +43,9 @@ int main(int argc, char *argv[])
{
g_shell_argv[i] = argv[i];
}
GtkApplication *app = gtk_application_new("dev.iohub.diya.shell", G_APPLICATION_DEFAULT_FLAGS);
DiyaSessionShell *shell = diya_session_shell_new(app);
g_signal_connect(app, "startup", G_CALLBACK(startup), (void *)shell);
g_signal_connect(app, "activate", G_CALLBACK(activate), (void *)shell);
g_unix_signal_add(SIGHUP, (GSourceFunc)restart, NULL);
DiyaSessionShell *shell = DIYA_SESSION_SHELL(g_object_new(DIYA_TYPE_SESSION_SHELL, "name","dev.iohub.diya.session-shell", NULL));
g_signal_connect(shell, "session-locked", G_CALLBACK(session_locked), NULL);
g_signal_connect(shell, "session-unlocked", G_CALLBACK(session_unlocked), NULL);
// g_signal_connect(app, "shutdown", G_CALLBACK(shutdown), (void*)shell);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_warning("Exiting SHELL");
g_object_unref(app);
g_object_unref(shell);
return status;
return diya_shell_run(DIYA_SHELL(shell), argc, argv);
}

View File

@ -1,3 +1,4 @@
#include <glib-unix.h>
#include "shell.h"
#include "wayland.h"
#include "virtual-keyboard.h"
@ -5,6 +6,8 @@ enum
{
NO_PROP,
PROP_SHELL_WAYLAND,
PROP_SHELL_APP,
PROP_SHELL_NAME,
N_PROPERTIES
};
@ -15,7 +18,9 @@ typedef struct _DiyaShellPrivate
{
DiyaObject parent;
DiyaWayland * wayland;
GtkApplication* app;
DiyaVirtualKeyboard* vkb;
gchar* name;
} DiyaShellPrivate;
G_DEFINE_TYPE_WITH_PRIVATE(DiyaShell, diya_shell, DIYA_TYPE_OBJECT);
@ -31,7 +36,66 @@ static void diya_shell_dispose(GObject* object)
{
g_object_unref(priv->wayland);
}
if(priv->name)
{
g_free(priv->name);
priv->name = NULL;
}
G_OBJECT_CLASS(diya_shell_parent_class)->dispose(object);
if (priv->app)
{
g_application_quit(G_APPLICATION(priv->app));
}
}
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);
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);
}
}
static gboolean diya_shell_sigint_handle(gpointer data)
{
g_object_unref(DIYA_SHELL(data));
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_signal_connect(priv->app, "shutdown", G_CALLBACK(shutdown), (void*)shell);
}
static void diya_shell_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
@ -41,8 +105,13 @@ static void diya_shell_set_property(GObject *object, guint property_id, const GV
switch (property_id)
{
case PROP_SHELL_WAYLAND:
priv->wayland = g_value_get_pointer(value);
case PROP_SHELL_NAME:
if(priv->name)
{
return;
}
priv->name = g_strdup(g_value_get_string(value));
init_gtk_application(self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@ -59,6 +128,12 @@ static void diya_shell_get_property(GObject *object, guint property_id, GValue *
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;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -70,14 +145,33 @@ static void diya_shell_init(DiyaShell *self)
{
DiyaShellPrivate* priv = diya_shell_get_instance_private(self);
priv->wayland = NULL;
priv->app = NULL;
priv->name = NULL;
}
DiyaWayland * diya_shell_get_wayland(DiyaShell* shell)
{
DiyaWayland * wayland;
g_object_get(shell,"wayland", &wayland, NULL);
assert(DIYA_IS_WAYLAND(wayland));
return wayland;
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)
@ -87,9 +181,27 @@ static void diya_shell_class_init(DiyaShellClass *class)
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->monitor_changed_handle = NULL;
class->startup_handle = NULL;
class->active_handle = NULL;
shell_properties[PROP_SHELL_WAYLAND] = g_param_spec_pointer("wayland", NULL, "Shell wayland", G_PARAM_READWRITE); //
shell_properties[PROP_SHELL_WAYLAND] = g_param_spec_pointer("wayland", NULL, "Shell wayland", G_PARAM_READABLE); //
shell_properties[PROP_SHELL_NAME] = g_param_spec_string("name", NULL, "Shell name", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
shell_properties[PROP_SHELL_APP] = g_param_spec_pointer("application", NULL, "Shell application", G_PARAM_READABLE);
g_object_class_install_properties (gobject_class, N_PROPERTIES, shell_properties);
}
int diya_shell_run(DiyaShell* shell, int argc, char **argv)
{
DiyaShellPrivate* priv = diya_shell_get_instance_private(shell);
assert(GTK_IS_APPLICATION(priv->app));
int status = g_application_run(G_APPLICATION(priv->app),argc,argv);
g_object_unref(priv->app);
return status;
}

View File

@ -1,6 +1,8 @@
#ifndef DIYA_SHELL_H
#define DIYA_SHELL_H
#include <stdint.h>
#include <gio/gio.h>
#include <gtk/gtk.h>
#include "base.h"
#define DIYA_TYPE_SHELL (diya_shell_get_type())
@ -18,10 +20,14 @@ struct _DiyaShellClass
DiyaObjectClass parent_class;
wl_protocol_manager_register_t foreign_register;
wl_protocol_manager_register_t virtual_keyboard_register;
void (*monitor_changed_handle)(GListModel* /*list*/,guint /*position*/, guint /*removed*/,guint /*added*/, gpointer);
void (*startup_handle)(DiyaShell*);
void (*active_handle)(DiyaShell*);
};
void diya_shell_wayland_init(DiyaShell *shell);
DiyaWayland * diya_shell_get_wayland(DiyaShell* shell);
GtkApplication* diya_shell_get_application(DiyaShell* shell);
const char* diya_shell_get_name(DiyaShell* shell);
int diya_shell_run(DiyaShell* shell, int argc, char **argv);
#endif

View File

@ -13,6 +13,230 @@
#include "virtual-keyboard.h"
#include "wayland.h"
/**
* @brief DiyaVkbButton: virtual keyboard button
*/
struct _DiyaVkbButton
{
GtkWidget super;
GtkWidget *labels[3];
};
G_DEFINE_FINAL_TYPE(DiyaVkbButton, diya_vkb_button, GTK_TYPE_WIDGET);
static void diya_vkb_button_dispose(GObject *object)
{
DiyaVkbButton *self = DIYA_VKB_BUTTON(object);
g_debug("diya_vkb_button_dispose");
for (int i = 0; i < 3; i++)
{
g_clear_pointer(&self->labels[i], gtk_widget_unparent);
}
// g_clear_pointer (&demo->label, gtk_widget_unparent);
G_OBJECT_CLASS(diya_vkb_button_parent_class)->dispose(object);
}
static void diya_vkb_button_init(DiyaVkbButton *self)
{
gchar class_name[32]; /*diya-vkb-btn-level-%d */
GtkLayoutManager *grid_layout;
grid_layout = gtk_widget_get_layout_manager(GTK_WIDGET(self));
//gtk_orientable_set_orientation(GTK_ORIENTABLE(box_layout), GTK_ORIENTATION_VERTICAL);
// gtk_box_layout_set_spacing (GTK_BOX_LAYOUT (box_layout), 3);
gtk_widget_add_css_class(GTK_WIDGET(self),"diya-vkb-btn");
gtk_widget_set_can_focus(GTK_WIDGET(self), false);
// init labels
for (int i = 0; i < 3; i++)
{
self->labels[i] = gtk_label_new(i==0?"X":"x");
g_snprintf(class_name, sizeof(class_name),"diya-vkb-btn-level-%d",i + 1);
gtk_widget_add_css_class(self->labels[i], class_name);
gtk_widget_set_hexpand(self->labels[i], true);
gtk_widget_set_parent(self->labels[i], GTK_WIDGET(self));
GtkGridLayoutChild *grid_child = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(grid_layout,self->labels[i]));
switch (i)
{
case 0:
/* code */
gtk_grid_layout_child_set_row(grid_child,0);
gtk_grid_layout_child_set_column(grid_child,0);
gtk_grid_layout_child_set_column_span (grid_child,2);
break;
case 1:
gtk_grid_layout_child_set_row(grid_child,1);
gtk_grid_layout_child_set_column(grid_child,0);
gtk_widget_set_halign(self->labels[i],GTK_ALIGN_START);
break;
case 2:
gtk_grid_layout_child_set_row(grid_child,1);
gtk_grid_layout_child_set_column(grid_child,1);
gtk_widget_set_halign(self->labels[i],GTK_ALIGN_END);
break;
default:
break;
}
}
}
static void diya_vkb_button_class_init(DiyaVkbButtonClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_vkb_button_dispose;
gtk_widget_class_set_layout_manager_type(GTK_WIDGET_CLASS(class), GTK_TYPE_GRID_LAYOUT);
}
DiyaVkbButton* diya_vkb_button_new(/**with prameter */)
{
return DIYA_VKB_BUTTON(g_object_new(DIYA_TYPE_VKB_BUTTON, NULL));
}
/**
* @brief DiyaVirtualKeyboardWidget: Virtual keyboard GTK widget
*
*/
#define VKB_N_CELLS 145
#define VKB_ROW_NUM(i) (i/29)
#define VKB_COL_NUM(i) (i % 29)
struct _DiyaVirtualKeyboardWidget
{
GtkWidget super;
/**
* row 0: 00 - 13
* row 1: 14 - 27
* row 2: 28 - 40
* row 3: 41 - 53
* row 4: 54 - 62
*/
GList *buttons;
};
G_DEFINE_FINAL_TYPE(DiyaVirtualKeyboardWidget, diya_virtual_keyboard_widget, GTK_TYPE_WIDGET);
static void diya_virtual_keyboard_widget_dispose(GObject *object)
{
DiyaVirtualKeyboardWidget *self = DIYA_VIRTUAL_KEYBOARD_WIDGET(object);
g_debug("diya_virtual_keyboard_widget_dispose");
if(self->buttons)
{
GList * it = NULL;
for(it = self->buttons; it; it = it->next)
{
if(it->data)
{
g_clear_pointer(&it->data, gtk_widget_unparent);
}
}
}
// g_clear_pointer (&demo->label, gtk_widget_unparent);
G_OBJECT_CLASS(diya_virtual_keyboard_widget_parent_class)->dispose(object);
}
static void diya_virtual_keyboard_widget_init(DiyaVirtualKeyboardWidget *self)
{
// gtk_widget_set_size_request(GTK_WIDGET(self), 600, 400);
g_debug("diya_virtual_keyboard_widget_init: Create new widget");
GtkLayoutManager *grid_layout;
gtk_widget_add_css_class(GTK_WIDGET(self),"diya-vkb");
grid_layout = gtk_widget_get_layout_manager(GTK_WIDGET(self));
// gtk_orientable_set_orientation(GTK_ORIENTABLE(grid_layout), GTK_ORIENTATION_VERTICAL);
gtk_grid_layout_set_row_spacing(GTK_GRID_LAYOUT(grid_layout), 2);
gtk_grid_layout_set_column_spacing(GTK_GRID_LAYOUT(grid_layout), 2);
//gtk_grid_layout_set_baseline_row(GTK_GRID_LAYOUT(grid_layout), 4);
// init buttons
for (int i = 0; i < VKB_N_CELLS; i++)
{
gboolean skip = false;
int row = VKB_ROW_NUM(i);
int col = VKB_COL_NUM(i);
switch (row)
{
case 0:
skip = (col %2 != 0) || (col > 26);
break;
case 1:
skip = (col == 1) || (col == 2) || (col != 0 && col % 2 == 0);
break;
case 2:
skip = (col == 1) || (col == 2) || (col != 0 && col%2 == 0) || (col > 25);
break;
case 3:
skip = (col > 0 && col < 5) || (col != 0 && col % 2 == 0);
break;
case 4:
skip = (col > 0 && col < 3) || (col == 4) || (col==6) || (col>7 && col < 19) || (col > 19 && col %2 == 0);
break;
default:
break;
}
if(skip)
{
continue;
}
GtkWidget* button = GTK_WIDGET(diya_vkb_button_new());
self->buttons = g_list_append(self->buttons, button);
gtk_widget_set_parent(button, GTK_WIDGET(self));
gtk_widget_set_hexpand(button, true);
GtkGridLayoutChild *grid_child = GTK_GRID_LAYOUT_CHILD(gtk_layout_manager_get_layout_child(grid_layout,button));
gtk_grid_layout_child_set_row(grid_child,row);
gtk_grid_layout_child_set_column(grid_child,col);
switch (i)
{
case 26:
case 29:
case 58:
case 116:
gtk_grid_layout_child_set_column_span (grid_child,3);
break;
case 83:
gtk_grid_layout_child_set_column_span (grid_child,4);
break;
case 87:
gtk_grid_layout_child_set_column_span (grid_child,5);
break;
case 123:
gtk_grid_layout_child_set_column_span (grid_child,12);
break;
default:
if(i > 0)
gtk_grid_layout_child_set_column_span (grid_child,2);
break;
}
}
}
static void diya_virtual_keyboard_widget_class_init(DiyaVirtualKeyboardWidgetClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_virtual_keyboard_widget_dispose;
gtk_widget_class_set_layout_manager_type(GTK_WIDGET_CLASS(class), GTK_TYPE_GRID_LAYOUT);
}
DiyaVirtualKeyboardWidget *diya_virtual_keyboard_widget_new()
{
DiyaVirtualKeyboardWidget *vkb_widget = g_object_new(DIYA_TYPE_VIRTUAL_KEYBOARD_WIDGET, NULL);
return vkb_widget;
}
/**
* @brief DiyaVirtualKeyboard class: lowlevel wayland virtual keyboard handle
*
*/
static struct zwp_virtual_keyboard_manager_v1 *g_virtual_keyboard_manager = NULL;
struct _DiyaVirtualKeyboard
@ -151,7 +375,7 @@ DiyaVirtualKeyboard *diya_virtual_keyboard_new(DiyaShell *shell, const gchar *ke
}
else
{
g_warning("No keymap file specified.Loading default keymap from resource");
g_warning("No keymap file specified. Loading default keymap from resource");
GBytes *bytes = g_resources_lookup_data("/dev/iohub/diya/shell/default.keymap", 0, &error);
if (error != NULL)
{
@ -159,19 +383,19 @@ DiyaVirtualKeyboard *diya_virtual_keyboard_new(DiyaShell *shell, const gchar *ke
g_error_free(error);
return NULL;
}
content = (gchar*)g_bytes_get_data(bytes, &len);
content = (gchar *)g_bytes_get_data(bytes, &len);
}
g_debug("Using default keymap configuration: \n%s", content);
int fd = create_keymap_fd(len);
if (fd == -1)
{
g_critical("diya_virtual_keyboard_new: create temp file");
if(bytes)
if (bytes)
{
g_bytes_unref(bytes);
content = NULL;
}
if(content)
if (content)
{
g_free(content);
}
@ -182,12 +406,12 @@ DiyaVirtualKeyboard *diya_virtual_keyboard_new(DiyaShell *shell, const gchar *ke
{
g_critical("diya_virtual_keyboard_new: error mmap: %s", strerror(errno));
close(fd);
if(bytes)
if (bytes)
{
g_bytes_unref(bytes);
content = NULL;
}
if(content)
if (content)
{
g_free(content);
}
@ -200,7 +424,6 @@ DiyaVirtualKeyboard *diya_virtual_keyboard_new(DiyaShell *shell, const gchar *ke
struct wl_seat *seat = diya_wayland_get_seat(wayland);
vkb->keyboard = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(g_virtual_keyboard_manager, seat);
zwp_virtual_keyboard_v1_keymap(vkb->keyboard, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, fd, len);
return vkb;
}

View File

@ -16,4 +16,16 @@ DiyaVirtualKeyboard* diya_virtual_keyboard_new(DiyaShell* shell, const gchar* ke
void diya_virtual_keyboard_register(struct wl_registry *registry, uint32_t name, DiyaShell *shell);
void diya_virtual_keyboard_send_key(DiyaVirtualKeyboard* vkb, uint32_t key, diya_vkb_state_t state);
#define DIYA_TYPE_VIRTUAL_KEYBOARD_WIDGET (diya_virtual_keyboard_widget_get_type())
G_DECLARE_FINAL_TYPE (DiyaVirtualKeyboardWidget, diya_virtual_keyboard_widget, DIYA, VIRTUAL_KEYBOARD_WIDGET, GtkWidget)
DiyaVirtualKeyboardWidget* diya_virtual_keyboard_widget_new();
#define DIYA_TYPE_VKB_BUTTON (diya_vkb_button_get_type())
G_DECLARE_FINAL_TYPE (DiyaVkbButton, diya_vkb_button, DIYA, VKB_BUTTON, GtkWidget)
DiyaVkbButton* diya_vkb_button_new(/**with prameter */);
#endif

View File

@ -119,7 +119,7 @@ static const struct wl_registry_listener registry_listener =
.global_remove = handle_global_remove
};
void diya_shell_wayland_init(DiyaShell *shell)
DiyaWayland* diya_wayland_new(DiyaShell *shell)
{
struct wl_display *display;
struct wl_registry *registry;
@ -127,20 +127,20 @@ void diya_shell_wayland_init(DiyaShell *shell)
if (!display)
{
g_error("Can't get wayland display");
return;
return NULL;
}
DiyaWayland * wayland = g_object_new(DIYA_TYPE_WAYLAND, "shell", shell, NULL);
g_object_set(shell, "wayland", wayland, NULL);
//g_object_set(wayland, "shell", shell, NULL);
registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, (void*)shell);
wl_display_roundtrip(display);
// wl_display_roundtrip(display);
// wayland_monitor_probe();
// GdkMonitor *mon = wayland_monitor_get_default();
// g_info("default output: %s", (gchar *)g_object_get_data(G_OBJECT(mon), "xdg_name"));
// wl_display_roundtrip(display);
// wl_display_roundtrip(display);
return wayland;
}
struct wl_surface* diya_wayland_create_surface(DiyaWayland * self)

View File

@ -7,4 +7,6 @@ struct wl_surface* diya_wayland_create_surface(DiyaWayland * self);
struct wl_output* diya_wayland_get_output(DiyaWayland * self, int index);
struct wl_shm_pool * diya_wayland_create_shm_pool(DiyaWayland * self, int fd, guint size);
struct wl_seat* diya_wayland_get_seat(DiyaWayland* self);
DiyaWayland* diya_wayland_new(DiyaShell *shell);
#endif