Add base support to virtual keyboard wayland extension protocol

This commit is contained in:
DanyLE 2025-03-11 00:00:28 +01:00
parent 0e8bb9027f
commit 4da1db3bd4
26 changed files with 2320 additions and 326 deletions

View File

@ -17,6 +17,7 @@ add_project_arguments(
gtk = dependency('gtk4')
wayland_client = dependency('wayland-client', version: '>=1.10.0')
xkbcommon = dependency('xkbcommon')
# wayland_scanner is required, but we can find it without pkg-config
wayland_scanner = find_program('wayland-scanner')
@ -52,24 +53,31 @@ endforeach
gnome=import('gnome')
base = [
'src/base.c'
'src/base.c',
'src/shell.c',
'src/wayland.c',
'src/virtual-keyboard.c',
wayland_targets
]
dm_src = [
base,
'src/launcher.c',
'src/background.c',
'src/shell.c',
'src/session-shell.c',
'src/foreign.c',
'src/session-lock.c',
'src/wayland.c',
'src/session.c',
wayland_targets]
'src/session.c']
buil_dep = [gtk, gtk_layer_shell, wayland_client, xkbcommon]
session_resource = gnome.compile_resources('session-resources','resources/session-shell/gresource.xml')
executable(
'diya-shell',
dm_src,
dependencies: [gtk, gtk_layer_shell, wayland_client])
session_resource,
dependencies: buil_dep)
login_src = [
base,
@ -77,10 +85,10 @@ login_src = [
'src/login.c'
]
login_resource = gnome.compile_resources('resources','resources/login-shell/gresource.xml')
login_resource = gnome.compile_resources('login-resources','resources/login-shell/gresource.xml')
executable(
'diya-login-shell',
login_src,
login_resource,
dependencies: [gtk, gtk_layer_shell, wayland_client])
dependencies: buil_dep)

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="virtual_keyboard_unstable_v1">
<copyright>
Copyright © 2008-2011 Kristian Høgsberg
Copyright © 2010-2013 Intel Corporation
Copyright © 2012-2013 Collabora, Ltd.
Copyright © 2018 Purism SPC
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
</copyright>
<interface name="zwp_virtual_keyboard_v1" version="1">
<description summary="virtual keyboard">
The virtual keyboard provides an application with requests which emulate
the behaviour of a physical keyboard.
This interface can be used by clients on its own to provide raw input
events, or it can accompany the input method protocol.
</description>
<request name="keymap">
<description summary="keyboard mapping">
Provide a file descriptor to the compositor which can be
memory-mapped to provide a keyboard mapping description.
Format carries a value from the keymap_format enumeration.
</description>
<arg name="format" type="uint" summary="keymap format"/>
<arg name="fd" type="fd" summary="keymap file descriptor"/>
<arg name="size" type="uint" summary="keymap size, in bytes"/>
</request>
<enum name="error">
<entry name="no_keymap" value="0" summary="No keymap was set"/>
</enum>
<request name="key">
<description summary="key event">
A key was pressed or released.
The time argument is a timestamp with millisecond granularity, with an
undefined base. All requests regarding a single object must share the
same clock.
Keymap must be set before issuing this request.
State carries a value from the key_state enumeration.
</description>
<arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
<arg name="key" type="uint" summary="key that produced the event"/>
<arg name="state" type="uint" summary="physical state of the key"/>
</request>
<request name="modifiers">
<description summary="modifier and group state">
Notifies the compositor that the modifier and/or group state has
changed, and it should update state.
The client should use wl_keyboard.modifiers event to synchronize its
internal state with seat state.
Keymap must be set before issuing this request.
</description>
<arg name="mods_depressed" type="uint" summary="depressed modifiers"/>
<arg name="mods_latched" type="uint" summary="latched modifiers"/>
<arg name="mods_locked" type="uint" summary="locked modifiers"/>
<arg name="group" type="uint" summary="keyboard layout"/>
</request>
<request name="destroy" type="destructor" since="1">
<description summary="destroy the virtual keyboard keyboard object"/>
</request>
</interface>
<interface name="zwp_virtual_keyboard_manager_v1" version="1">
<description summary="virtual keyboard manager">
A virtual keyboard manager allows an application to provide keyboard
input events as if they came from a physical keyboard.
</description>
<enum name="error">
<entry name="unauthorized" value="0" summary="client not authorized to use the interface"/>
</enum>
<request name="create_virtual_keyboard">
<description summary="Create a new virtual keyboard">
Creates a new virtual keyboard associated to a seat.
If the compositor enables a keyboard to perform arbitrary actions, it
should present an error when an untrusted client requests a new
keyboard.
</description>
<arg name="seat" type="object" interface="wl_seat"/>
<arg name="id" type="new_id" interface="zwp_virtual_keyboard_v1"/>
</request>
</interface>
</protocol>

1461
resources/default.keymap Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2,5 +2,6 @@
<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

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

View File

@ -9,7 +9,7 @@ static void on_background_destroy(GtkWindow *window, GApplication *_data)
//g_application_quit (G_APPLICATION (gtk_window_get_application (window)));
}
void diya_shell_init_background(DiyaShell * shell)
void diya_session_shell_init_background(DiyaSessionShell * shell)
{
GtkApplication * app;
g_object_get(shell, "application", &app, NULL);

View File

@ -1,8 +1,8 @@
#ifndef DIYA_SHELL_BACKGROUND_H
#define DIYA_SHELL_BACKGROUND_H
#include "shell.h"
#include "session-shell.h"
void diya_shell_init_background(DiyaShell * shell);
void diya_session_shell_init_background(DiyaSessionShell * shell);
#endif

View File

@ -2,6 +2,7 @@
#define DIYA_OBJECT_H
#include <glib-object.h>
#include <assert.h>
/**
* Base class object

View File

@ -1,5 +1,6 @@
#include <assert.h>
#include <inttypes.h>
#include "wlr-foreign-toplevel-management-unstable-v1.h"
#include "foreign.h"
/**
@ -19,7 +20,7 @@ enum
static GParamSpec *win_properties[N_PROPERTIES] = {0};
struct _DiyaForeignWindow
{
DiyaObject parent;
DiyaShellObject parent;
gchar * appid;
gpointer handle;
gchar* title;
@ -155,9 +156,9 @@ static void toplevel_handle_title(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle,
const char *title)
{
DiyaShell *shell = (DiyaShell *)data;
DiyaSessionShell *shell = (DiyaSessionShell *)data;
assert(shell);
DiyaForeignWindow *win = diya_shell_get_window(shell, handle);
DiyaForeignWindow *win = diya_session_shell_get_window(shell, handle);
assert(win);
g_object_set(win, "title", title, NULL);
g_debug("New title for: %s", diya_object_to_string(win));
@ -166,9 +167,9 @@ static void toplevel_handle_app_id(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle,
const char *app_id)
{
DiyaShell *shell = (DiyaShell *)data;
DiyaSessionShell *shell = (DiyaSessionShell *)data;
assert(shell);
DiyaForeignWindow *win = diya_shell_get_window(shell, handle);
DiyaForeignWindow *win = diya_session_shell_get_window(shell, handle);
assert(win);
g_object_set(win, "appid", app_id, NULL);
g_debug("New appid for: %s", diya_object_to_string(win));
@ -186,9 +187,9 @@ static void toplevel_handle_state(void *data,
struct wl_array *state)
{
uint32_t *entry;
DiyaShell *shell = (DiyaShell *)data;
DiyaSessionShell *shell = (DiyaSessionShell *)data;
assert(shell);
DiyaForeignWindow *win = diya_shell_get_window(shell, handle);
DiyaForeignWindow *win = diya_session_shell_get_window(shell, handle);
assert(win);
enum diya_win_state wstate = DIYA_WIN_STATE_NONE;
wl_array_for_each(entry, state) switch (*entry)
@ -211,21 +212,21 @@ static void toplevel_handle_state(void *data,
static void toplevel_handle_done(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle)
{
DiyaShell *shell = (DiyaShell *)data;
DiyaSessionShell *shell = (DiyaSessionShell *)data;
assert(shell);
DiyaForeignWindow *win = diya_shell_get_window(shell, handle);
DiyaForeignWindow *win = diya_session_shell_get_window(shell, handle);
assert(win);
g_signal_emit_by_name(shell, "foreign-window-changed", (void *)win);
}
static void toplevel_handle_closed(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle)
{
DiyaShell *shell = (DiyaShell *)data;
DiyaSessionShell *shell = (DiyaSessionShell *)data;
assert(shell);
DiyaForeignWindow *win = diya_shell_get_window(shell, handle);
DiyaForeignWindow *win = diya_session_shell_get_window(shell, handle);
assert(win);
g_signal_emit_by_name(shell, "foreign-window-removed", (void *)win);
diya_shell_remove_window(shell, win);
diya_session_shell_remove_window(shell, win);
zwlr_foreign_toplevel_handle_v1_destroy(handle);
}
static void toplevel_handle_parent(void *data,
@ -237,10 +238,10 @@ static void toplevel_handle_parent(void *data,
return;
}
assert(handle != parent);
DiyaShell *shell = (DiyaShell *)data;
DiyaSessionShell *shell = (DiyaSessionShell *)data;
assert(shell);
DiyaForeignWindow *child_win = diya_shell_get_window(shell, handle);
DiyaForeignWindow *parent_win = diya_shell_get_window(shell, parent);
DiyaForeignWindow *child_win = diya_session_shell_get_window(shell, handle);
DiyaForeignWindow *parent_win = diya_session_shell_get_window(shell, parent);
assert(child_win);
assert(parent_win);
assert(child_win != parent_win);
@ -260,11 +261,11 @@ static const struct zwlr_foreign_toplevel_handle_v1_listener g_toplevel_impl = {
.parent = toplevel_handle_parent
};
static DiyaForeignWindow * diya_shell_foreign_window_new(DiyaShell* shell, gpointer handle)
static DiyaForeignWindow * diya_session_shell_foreign_window_new(DiyaSessionShell* shell, gpointer handle)
{
DiyaForeignWindow *win = DIYA_FOREIGN_WINDOW(g_object_new(DIYA_TYPE_FOREIGN_WINDOW,"handle", handle, "shell", shell, NULL));
//g_object_set(win, "shell", shell, NULL);
diya_shell_add_window(shell, win);
diya_session_shell_add_window(shell, win);
g_debug("Add new window 0x%" PRIXPTR, (uintptr_t)handle);
return win;
}
@ -272,9 +273,9 @@ static DiyaForeignWindow * diya_shell_foreign_window_new(DiyaShell* shell, gpoin
static void toplevel_manager_handle_toplevel(void *data, struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager, struct zwlr_foreign_toplevel_handle_v1 *tl)
{
(void) toplevel_manager;
DiyaShell *shell = (DiyaShell *)data;
DiyaSessionShell *shell = (DiyaSessionShell *)data;
assert(shell);
DiyaForeignWindow *win = diya_shell_get_window(shell, tl);
DiyaForeignWindow *win = diya_session_shell_get_window(shell, tl);
if (win)
{
@ -282,15 +283,15 @@ static void toplevel_manager_handle_toplevel(void *data, struct zwlr_foreign_top
return;
}
// TODO: different between windows
win = diya_shell_foreign_window_new(shell, tl);
win = diya_session_shell_foreign_window_new(shell, tl);
zwlr_foreign_toplevel_handle_v1_add_listener(tl, &g_toplevel_impl, data);
}
static void toplevel_manager_handle_finished(void *data,
struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager)
{
DiyaShell *shell = (DiyaShell *)data;
diya_shell_remove_all_windows(shell);
DiyaSessionShell *shell = (DiyaSessionShell *)data;
diya_session_shell_remove_all_windows(shell);
// remove table entry
zwlr_foreign_toplevel_manager_v1_destroy(toplevel_manager);
}
@ -301,8 +302,9 @@ static const struct zwlr_foreign_toplevel_manager_v1_listener g_toplevel_manager
.finished = toplevel_manager_handle_finished,
};
void diya_shell_foreign_toplevel_register(struct wl_registry *registry, uint32_t name, DiyaShell *shell)
void diya_session_shell_foreign_toplevel_register(struct wl_registry *registry, uint32_t name, DiyaShell *shell)
{
DiyaSessionShell* session_shell = DIYA_SESSION_SHELL(shell);
g_toplevel_manager = wl_registry_bind(registry, name, &zwlr_foreign_toplevel_manager_v1_interface, 3);
zwlr_foreign_toplevel_manager_v1_add_listener(g_toplevel_manager, &g_toplevel_manager_impl, (void *)shell);
zwlr_foreign_toplevel_manager_v1_add_listener(g_toplevel_manager, &g_toplevel_manager_impl, (void *)session_shell);
}

View File

@ -1,7 +1,16 @@
#ifndef DIYA_SHELL_FOREIGN_H
#define DIYA_SHELL_FOREIGN_H
#include "wlr-foreign-toplevel-management-unstable-v1.h"
#include "shell.h"
#include "session-shell.h"
enum diya_win_state
{
DIYA_WIN_STATE_NONE = 0,
DIYA_WIN_STATE_MINIMIZE = 1 << 0,
DIYA_WIN_STATE_MAXIMIZE = 1 << 1,
DIYA_WIN_STATE_FULLSCREEN = 1 << 2,
DIYA_WIN_STATE_FOCUS = 1 << 3,
};
void diya_session_shell_foreign_toplevel_register(struct wl_registry *registry, uint32_t name, DiyaShell * shell);
void diya_shell_foreign_toplevel_register(struct wl_registry *registry, uint32_t name, DiyaShell * shell);
#endif

View File

@ -12,7 +12,7 @@ static void on_launcher_destroy(GtkWindow *window, GApplication *_data)
//g_application_quit (G_APPLICATION (gtk_window_get_application (window)));
}
static void on_foreign_window_change(DiyaShell* shell, DiyaForeignWindow * win, gpointer data)
static void on_foreign_window_change(DiyaSessionShell* shell, DiyaForeignWindow * win, gpointer data)
{
(void) data;
assert(win);
@ -20,7 +20,7 @@ static void on_foreign_window_change(DiyaShell* shell, DiyaForeignWindow * win,
g_warning("on_foreign_window_change: WINDOW CHANGE %s, shell %s", diya_object_to_string(DIYA_OBJECT(win)), diya_object_to_string(DIYA_OBJECT(shell)));
}
static void on_foreign_window_removed(DiyaShell* shell, DiyaForeignWindow * win, gpointer data)
static void on_foreign_window_removed(DiyaSessionShell* shell, DiyaForeignWindow * win, gpointer data)
{
(void) data;
assert(win);
@ -32,10 +32,10 @@ static void session_lock(GtkWidget *widget,gpointer data)
{
(void) widget;
g_warning("Enter session lock");
diya_shell_lock(data);
diya_session_shell_lock(data);
}
void diya_shell_launcher_init(DiyaShell * shell)
void diya_session_shell_launcher_init(DiyaSessionShell * shell)
{
assert(shell);
GtkApplication * app;

View File

@ -1,9 +1,9 @@
#ifndef DIYA_SHELL_LAUNCHER_H
#define DIYA_SHELL_LAUNCHER_H
#include "shell.h"
#include "session-shell.h"
void diya_shell_launcher_init(DiyaShell * shell);
void diya_session_shell_launcher_init(DiyaSessionShell * shell);
#endif

View File

@ -1,17 +1,17 @@
#include "login-shell.h"
#include <gtk4-layer-shell.h>
#include <gtk4-session-lock.h>
#include <gio/gio.h>
#include "login-shell.h"
#include "virtual-keyboard.h"
#define DBUS_SERVER_NAME "dev.iohub.diya.SessionManager"
#define DBUS_SERVER_PATH "/dev/iohub/diya/SessionManager"
#define DBUS_SERVER_ERROR_NAME "dev.iohub.diya.SessionManager.Error"
struct _DiyaLoginShell
{
DiyaObject parent_object;
DiyaShell parent_object;
GtkApplication *app;
GtkSessionLockInstance *lock;
GtkWidget *username;
@ -20,7 +20,7 @@ struct _DiyaLoginShell
guint bus_watch_id;
};
G_DEFINE_FINAL_TYPE(DiyaLoginShell, diya_login_shell, DIYA_TYPE_OBJECT);
G_DEFINE_FINAL_TYPE(DiyaLoginShell, diya_login_shell, DIYA_TYPE_SHELL);
static void diya_login_shell_dispose(GObject *object)
{
@ -67,6 +67,11 @@ static void diya_login_shell_class_init(DiyaLoginShellClass *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;
}
@ -169,6 +174,23 @@ static void do_login(GtkButton *button, DiyaLoginShell *self)
// g_application_quit(G_APPLICATION(self->app));
}
static void open_vkb(GtkButton *button, DiyaLoginShell *self)
{
(void) button;
DiyaVirtualKeyboard* vkb = diya_virtual_keyboard_new(DIYA_SHELL(self), NULL);
if(!vkb)
{
return;
}
g_warning("Sending A to: %s", diya_object_to_string(DIYA_OBJECT(vkb)));
diya_virtual_keyboard_send_key(vkb,30, VKB_KEY_STATE_PRESSED);
g_usleep(10000);
diya_virtual_keyboard_send_key(vkb,30, VKB_KEY_STATE_RELEASED);
g_usleep(10000);
// send example key
g_object_unref(vkb);
}
DiyaLoginShell *diya_login_shell_new()
{
return g_object_new(DIYA_TYPE_LOGIN_SHELL, NULL);
@ -232,10 +254,12 @@ void diya_login_shell_attach(DiyaLoginShell *self, GtkApplication *app)
gtk_box_append(GTK_BOX(box), password_box);
GtkWidget *button = gtk_button_new_with_label("Login");
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
@ -245,6 +269,11 @@ void diya_login_shell_attach(DiyaLoginShell *self, GtkApplication *app)
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);

View File

@ -3,9 +3,10 @@
#include <gtk/gtk.h>
#include "base.h"
#include "shell.h"
#define DIYA_TYPE_LOGIN_SHELL (diya_login_shell_get_type())
G_DECLARE_FINAL_TYPE(DiyaLoginShell, diya_login_shell, DIYA, LOGIN_SHELL, DiyaObject);
G_DECLARE_FINAL_TYPE(DiyaLoginShell, diya_login_shell, DIYA, LOGIN_SHELL, DiyaShell);
DiyaLoginShell *diya_login_shell_new();

View File

@ -2,6 +2,7 @@
#include <assert.h>
#include "login-shell.h"
#include "wayland.h"
static gchar **g_shell_argv;
@ -31,6 +32,7 @@ static gboolean restart(gpointer d)
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);

View File

@ -3,14 +3,14 @@
#include <gtk/gtk.h>
#include "session-lock.h"
static void unlock_session(GtkButton *button, DiyaShell *shell)
static void unlock_session(GtkButton *button, DiyaSessionShell *shell)
{
(void)button;
assert(shell);
diya_shell_unlock(shell);
diya_session_shell_unlock(shell);
}
void diya_shell_lock(DiyaShell* shell)
void diya_session_shell_lock(DiyaSessionShell* shell)
{
assert(shell);
GtkSessionLockInstance * lock;
@ -60,7 +60,7 @@ void diya_shell_lock(DiyaShell* shell)
gtk_window_present(gtk_window);
}
}
void diya_shell_unlock(DiyaShell* shell)
void diya_session_shell_unlock(DiyaSessionShell* shell)
{
assert(shell);
GtkSessionLockInstance * lock;

View File

@ -1,9 +1,9 @@
#ifndef DIYA_SESSION_LOCK_H
#define DIYA_SESSION_LOCK_H
#include "shell.h"
#include "session-shell.h"
void diya_shell_lock(DiyaShell* shell);
void diya_shell_unlock(DiyaShell* shell);
void diya_session_shell_lock(DiyaSessionShell* shell);
void diya_session_shell_unlock(DiyaSessionShell* shell);
#endif

273
src/session-shell.c Normal file
View File

@ -0,0 +1,273 @@
#include "session-shell.h"
#include <assert.h>
#include <gtk4-session-lock.h>
#include "shell.h"
#include "foreign.h"
#define SHELL_DESCRIPTION "Diya GTK shell for wayland (diyac)"
enum
{
NO_PROP,
SHELL_APP,
SHELL_BACKGROUND_WIDGET,
SHELL_LAUNCHPAD_WIDGET,
SHELL_LOCK_SESSION,
SHELL_WINDOWS,
N_PROPERTIES
};
static GParamSpec *shell_properties[N_PROPERTIES] = {0};
struct _DiyaSessionShell
{
DiyaShell parent;
GtkApplication* app;
GtkWindow* background;
GtkWindow* launcher;
GHashTable* windows;
GtkSessionLockInstance* lock;
};
G_DEFINE_FINAL_TYPE(DiyaSessionShell, diya_session_shell, DIYA_TYPE_SHELL)
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");
if(self->lock)
{
g_object_unref(self->lock);
}
G_OBJECT_CLASS(diya_session_shell_parent_class)->dispose(object);
}
static void diya_session_shell_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{
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;
case SHELL_LAUNCHPAD_WIDGET:
self->launcher = g_value_get_pointer(value);
break;
case SHELL_WINDOWS:
//self->windows = g_value_get_pointer(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void diya_session_shell_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
{
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;
case SHELL_LAUNCHPAD_WIDGET:
assert(self->launcher);
g_value_set_pointer(value, self->launcher);
break;
case SHELL_LOCK_SESSION:
assert(self->lock);
g_value_set_pointer(value, self->lock);
break;
case SHELL_WINDOWS:
g_value_set_pointer(value, self->windows);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static const gchar* diya_session_shell_to_string(DiyaObject* object)
{
(void) object;
return SHELL_DESCRIPTION;
}
static void diya_session_shell_class_init(DiyaSessionShellClass *class)
{
GObjectClass *gobject_class = G_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_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 );
shell_properties[SHELL_WINDOWS] = g_param_spec_pointer("windows", NULL, "Shell foreign windows", G_PARAM_READABLE);
g_object_class_install_properties (gobject_class, N_PROPERTIES, shell_properties);
g_signal_new("foreign-window-changed",
DIYA_TYPE_SESSION_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("foreign-window-removed",
DIYA_TYPE_SESSION_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("session-locked",
DIYA_TYPE_SESSION_SHELL,
G_SIGNAL_DETAILED |
G_SIGNAL_ACTION |
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0);
g_signal_new("session-unlocked",
DIYA_TYPE_SESSION_SHELL,
G_SIGNAL_DETAILED |
G_SIGNAL_ACTION |
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0);
}
static void on_session_locked(GtkSessionLockInstance *lock, DiyaSessionShell *shell) {
(void)lock;
assert(shell);
g_message("Session locked successfully");
g_signal_emit_by_name(shell, "session-locked");
}
/*
static void failed(GtkSessionLockInstance *lock, void *data) {
(void)lock;
(void)data;
g_critical("The session could not be locked");
g_application_quit(G_APPLICATION(app));
}
*/
static void on_session_unlocked(GtkSessionLockInstance *lock, DiyaSessionShell *shell) {
(void)lock;
assert(shell);
g_message("Session unlocked");
g_signal_emit_by_name(shell, "session-unlocked");
}
static void diya_session_shell_init(DiyaSessionShell *self)
{
//self->app = NULL;
self->background = NULL;
self->launcher = 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);
g_signal_connect(self->lock, "unlocked", G_CALLBACK(on_session_unlocked), self);
self->windows = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref);
}
DiyaForeignWindow* diya_session_shell_get_window(DiyaSessionShell * shell, gpointer handle)
{
return g_hash_table_lookup(shell->windows, handle);
}
gboolean diya_session_shell_add_window(DiyaSessionShell * shell, DiyaForeignWindow * win)
{
gpointer handle;
g_object_get(win, "handle", &handle, NULL);
assert(handle);
return g_hash_table_insert(shell->windows,handle, win);
}
gboolean diya_session_shell_remove_window(DiyaSessionShell * shell, DiyaForeignWindow * win)
{
gpointer handle;
g_object_get(win, "handle", &handle, NULL);
assert(handle);
return g_hash_table_remove(shell->windows,handle);
}
void diya_session_shell_remove_all_windows(DiyaSessionShell * shell)
{
g_hash_table_destroy(shell->windows);
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)
{
(void)window;
GtkOrientation orient_toplevel, orient_sub;
orient_toplevel = GTK_ORIENTATION_HORIZONTAL;
orient_sub = GTK_ORIENTATION_VERTICAL;
switch (orientation) {
case WINDOW_ORIENTATION_HORIZONTAL:
orient_toplevel = GTK_ORIENTATION_HORIZONTAL;
orient_sub = GTK_ORIENTATION_HORIZONTAL;
break;
case WINDOW_ORIENTATION_VERTICAL:
orient_toplevel = GTK_ORIENTATION_VERTICAL;
orient_sub = GTK_ORIENTATION_VERTICAL;
break;
case WINDOW_ORIENTATION_NONE:
orient_toplevel = GTK_ORIENTATION_HORIZONTAL;
orient_sub = GTK_ORIENTATION_VERTICAL;
break;
}
gtk_orientable_set_orientation (GTK_ORIENTABLE (data->toplevel_box), orient_toplevel);
gtk_orientable_set_orientation (GTK_ORIENTABLE (data->first_box), orient_sub);
gtk_orientable_set_orientation (GTK_ORIENTABLE (data->second_box), orient_sub);
//gtk_window_resize (window, 1, 1); // force the window to shrink to the smallest size it can
}
*/
/*
static void before_destroy (GtkWidget *win, GtkCssProvider *provider) {
GdkDisplay *display = gdk_display_get_default ();
gtk_style_context_remove_provider_for_display (display, GTK_STYLE_PROVIDER (provider));
}
*/

20
src/session-shell.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef DIYA_SESSION_SHELL_H
#define DIYA_SESSION_SHELL_H
#include <gtk4-layer-shell.h>
#include "shell.h"
#include "base.h"
#define DIYA_TYPE_SESSION_SHELL (diya_session_shell_get_type ())
G_DECLARE_FINAL_TYPE (DiyaSessionShell, diya_session_shell, DIYA, SESSION_SHELL, DiyaShell)
#define DIYA_TYPE_FOREIGN_WINDOW (diya_foreign_window_get_type ())
G_DECLARE_FINAL_TYPE (DiyaForeignWindow, diya_foreign_window, DIYA, FOREIGN_WINDOW, DiyaShellObject)
DiyaForeignWindow* diya_session_shell_get_window(DiyaSessionShell * shell, gpointer handle);
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

@ -14,8 +14,8 @@ static void activate(GtkApplication *app, void *data)
(void)app;
(void)data;
DiyaShell *shell = data;
diya_shell_lock(shell);
DiyaSessionShell *shell = data;
diya_session_shell_lock(shell);
}
static gboolean restart(gpointer d)
@ -37,11 +37,11 @@ static gboolean restart(gpointer d)
static void startup(GtkApplication *app, void *data)
{
DiyaShell *shell = data;
DiyaSessionShell *shell = data;
diya_shell_launcher_init(shell);
diya_shell_wayland_init(shell);
diya_shell_init_background(shell);
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;}";
@ -57,14 +57,14 @@ static void startup(GtkApplication *app, void *data)
g_unix_signal_add(SIGINT,(GSourceFunc)g_application_quit,(void*)app);
}
static void session_locked(DiyaShell* shell, void* data)
static void session_locked(DiyaSessionShell* shell, void* data)
{
(void)data;
assert(shell);
g_warning("session_locked callback triggered");
}
static void session_unlocked(DiyaShell* shell, void* data)
static void session_unlocked(DiyaSessionShell* shell, void* data)
{
(void)data;
assert(shell);
@ -79,7 +79,7 @@ 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);
DiyaShell *shell = diya_shell_new(app);
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_signal_connect(shell, "session-locked", G_CALLBACK(session_locked), NULL);

View File

@ -1,47 +1,35 @@
#include <assert.h>
#include <gtk4-session-lock.h>
#include "shell.h"
#define SHELL_DESCRIPTION "Diya GTK shell for wayland (diyac)"
#include "wayland.h"
#include "virtual-keyboard.h"
enum
{
NO_PROP,
SHELL_APP,
SHELL_BACKGROUND_WIDGET,
SHELL_LAUNCHPAD_WIDGET,
SHELL_LOCK_SESSION,
SHELL_WINDOWS,
SHELL_WAYLAND,
PROP_SHELL_WAYLAND,
N_PROPERTIES
};
static GParamSpec *shell_properties[N_PROPERTIES] = {0};
struct _DiyaShell
typedef struct _DiyaShellPrivate
{
DiyaObject parent;
GtkApplication* app;
GtkWindow* background;
GtkWindow* launcher;
GHashTable* windows;
GtkSessionLockInstance* lock;
DiyaWayland * wayland;
};
G_DEFINE_FINAL_TYPE(DiyaShell, diya_shell, DIYA_TYPE_OBJECT)
DiyaVirtualKeyboard* vkb;
} DiyaShellPrivate;
G_DEFINE_TYPE_WITH_PRIVATE(DiyaShell, diya_shell, DIYA_TYPE_OBJECT);
static void diya_shell_dispose(GObject* object)
{
g_debug("diya_shell_dispose: %s", diya_object_to_string(object));
DiyaShell * self = DIYA_SHELL(object);
g_hash_table_destroy(self->windows);
g_debug("diya_shell_dispose");
if(self->wayland)
DiyaShellPrivate* priv = diya_shell_get_instance_private(self);
if(priv->wayland)
{
g_object_unref(self->wayland);
}
if(self->lock)
{
g_object_unref(self->lock);
g_object_unref(priv->wayland);
}
G_OBJECT_CLASS(diya_shell_parent_class)->dispose(object);
}
@ -49,23 +37,12 @@ static void diya_shell_dispose(GObject* object)
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 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;
case SHELL_LAUNCHPAD_WIDGET:
self->launcher = g_value_get_pointer(value);
break;
case SHELL_WAYLAND:
self->wayland = g_value_get_pointer(value);
break;
case SHELL_WINDOWS:
//self->windows = g_value_get_pointer(value);
case PROP_SHELL_WAYLAND:
priv->wayland = g_value_get_pointer(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@ -76,27 +53,11 @@ static void diya_shell_set_property(GObject *object, guint property_id, const GV
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 SHELL_APP:
g_value_set_pointer(value, self->app);
break;
case SHELL_BACKGROUND_WIDGET:
g_value_set_pointer(value, self->background);
break;
case SHELL_LAUNCHPAD_WIDGET:
assert(self->launcher);
g_value_set_pointer(value, self->launcher);
break;
case SHELL_LOCK_SESSION:
assert(self->lock);
g_value_set_pointer(value, self->lock);
break;
case SHELL_WAYLAND:
g_value_set_pointer(value, self->wayland);
break;
case SHELL_WINDOWS:
g_value_set_pointer(value, self->windows);
case PROP_SHELL_WAYLAND:
g_value_set_pointer(value, priv->wayland);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@ -104,145 +65,11 @@ static void diya_shell_get_property(GObject *object, guint property_id, GValue *
}
}
static const gchar* diya_shell_to_string(DiyaObject* object)
{
(void) object;
return SHELL_DESCRIPTION;
}
static void diya_shell_class_init(DiyaShellClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
base_class->to_string = diya_shell_to_string;
gobject_class->dispose = diya_shell_dispose;
gobject_class->set_property = diya_shell_set_property;
gobject_class->get_property = diya_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 );
shell_properties[SHELL_WINDOWS] = g_param_spec_pointer("windows", NULL, "Shell foreign windows", G_PARAM_READABLE);
shell_properties[SHELL_WAYLAND] = g_param_spec_pointer("wayland", NULL, "Shell wayland", G_PARAM_READWRITE );
g_object_class_install_properties (gobject_class, N_PROPERTIES, shell_properties);
g_signal_new("foreign-window-changed",
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("foreign-window-removed",
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("session-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("session-unlocked",
DIYA_TYPE_SHELL,
G_SIGNAL_DETAILED |
G_SIGNAL_ACTION |
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0);
}
static void on_session_locked(GtkSessionLockInstance *lock, DiyaShell *shell) {
(void)lock;
assert(shell);
g_message("Session locked successfully");
g_signal_emit_by_name(shell, "session-locked");
}
/*
static void failed(GtkSessionLockInstance *lock, void *data) {
(void)lock;
(void)data;
g_critical("The session could not be locked");
g_application_quit(G_APPLICATION(app));
}
*/
static void on_session_unlocked(GtkSessionLockInstance *lock, DiyaShell *shell) {
(void)lock;
assert(shell);
g_message("Session unlocked");
g_signal_emit_by_name(shell, "session-unlocked");
}
static void diya_shell_init(DiyaShell *self)
{
//self->app = NULL;
self->background = NULL;
self->launcher = NULL;
self->wayland = 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);
g_signal_connect(self->lock, "unlocked", G_CALLBACK(on_session_unlocked), self);
self->windows = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref);
}
DiyaForeignWindow* diya_shell_get_window(DiyaShell * shell, gpointer handle)
{
return g_hash_table_lookup(shell->windows, handle);
}
gboolean diya_shell_add_window(DiyaShell * shell, DiyaForeignWindow * win)
{
gpointer handle;
g_object_get(win, "handle", &handle, NULL);
assert(handle);
return g_hash_table_insert(shell->windows,handle, win);
}
gboolean diya_shell_remove_window(DiyaShell * shell, DiyaForeignWindow * win)
{
gpointer handle;
g_object_get(win, "handle", &handle, NULL);
assert(handle);
return g_hash_table_remove(shell->windows,handle);
}
void diya_shell_remove_all_windows(DiyaShell * shell)
{
g_hash_table_destroy(shell->windows);
shell->windows = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref);
}
DiyaShell * diya_shell_new(GtkApplication * app)
{
return DIYA_SHELL(g_object_new(DIYA_TYPE_SHELL,"application",app, NULL));
DiyaShellPrivate* priv = diya_shell_get_instance_private(self);
priv->wayland = NULL;
}
DiyaWayland * diya_shell_get_wayland(DiyaShell* shell)
@ -252,38 +79,17 @@ DiyaWayland * diya_shell_get_wayland(DiyaShell* shell)
assert(DIYA_IS_WAYLAND(wayland));
return wayland;
}
/*
static void on_orientation_changed (GtkWindow *window, WindowOrientation orientation, ToplevelData *data)
static void diya_shell_class_init(DiyaShellClass *class)
{
(void)window;
GtkOrientation orient_toplevel, orient_sub;
orient_toplevel = GTK_ORIENTATION_HORIZONTAL;
orient_sub = GTK_ORIENTATION_VERTICAL;
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_shell_dispose;
gobject_class->set_property = diya_shell_set_property;
gobject_class->get_property = diya_shell_get_property;
switch (orientation) {
case WINDOW_ORIENTATION_HORIZONTAL:
orient_toplevel = GTK_ORIENTATION_HORIZONTAL;
orient_sub = GTK_ORIENTATION_HORIZONTAL;
break;
case WINDOW_ORIENTATION_VERTICAL:
orient_toplevel = GTK_ORIENTATION_VERTICAL;
orient_sub = GTK_ORIENTATION_VERTICAL;
break;
case WINDOW_ORIENTATION_NONE:
orient_toplevel = GTK_ORIENTATION_HORIZONTAL;
orient_sub = GTK_ORIENTATION_VERTICAL;
break;
}
gtk_orientable_set_orientation (GTK_ORIENTABLE (data->toplevel_box), orient_toplevel);
gtk_orientable_set_orientation (GTK_ORIENTABLE (data->first_box), orient_sub);
gtk_orientable_set_orientation (GTK_ORIENTABLE (data->second_box), orient_sub);
//gtk_window_resize (window, 1, 1); // force the window to shrink to the smallest size it can
}
*/
class->foreign_register = NULL;
class->virtual_keyboard_register = diya_virtual_keyboard_register;
/*
static void before_destroy (GtkWidget *win, GtkCssProvider *provider) {
GdkDisplay *display = gdk_display_get_default ();
gtk_style_context_remove_provider_for_display (display, GTK_STYLE_PROVIDER (provider));
shell_properties[PROP_SHELL_WAYLAND] = g_param_spec_pointer("wayland", NULL, "Shell wayland", G_PARAM_READWRITE); //
g_object_class_install_properties (gobject_class, N_PROPERTIES, shell_properties);
}
*/

View File

@ -1,31 +1,27 @@
#ifndef DIYA_SHELL_H
#define DIYA_SHELL_H
#include <gtk4-layer-shell.h>
#include <stdint.h>
#include "base.h"
enum diya_win_state
{
DIYA_WIN_STATE_NONE = 0,
DIYA_WIN_STATE_MINIMIZE = 1 << 0,
DIYA_WIN_STATE_MAXIMIZE = 1 << 1,
DIYA_WIN_STATE_FULLSCREEN = 1 << 2,
DIYA_WIN_STATE_FOCUS = 1 << 3,
};
#define DIYA_TYPE_SHELL (diya_shell_get_type())
G_DECLARE_FINAL_TYPE (DiyaShell, diya_shell, DIYA, SHELL, DiyaObject)
G_DECLARE_DERIVABLE_TYPE(DiyaShell, diya_shell, DIYA, SHELL, DiyaObject)
#define DIYA_TYPE_WAYLAND (diya_wayland_get_type ())
G_DECLARE_FINAL_TYPE (DiyaWayland, diya_wayland, DIYA, WAYLAND, DiyaShellObject)
#define DIYA_TYPE_FOREIGN_WINDOW (diya_foreign_window_get_type ())
G_DECLARE_FINAL_TYPE (DiyaForeignWindow, diya_foreign_window, DIYA, FOREIGN_WINDOW, DiyaShellObject)
struct wl_registry;
DiyaForeignWindow* diya_shell_get_window(DiyaShell * shell, gpointer handle);
gboolean diya_shell_add_window(DiyaShell * shell, DiyaForeignWindow * win);
gboolean diya_shell_remove_window(DiyaShell * shell, DiyaForeignWindow * win);
void diya_shell_remove_all_windows(DiyaShell * shell);
typedef void (*wl_protocol_manager_register_t)(struct wl_registry*, uint32_t,DiyaShell*);
DiyaShell * diya_shell_new(GtkApplication * app);
struct _DiyaShellClass
{
DiyaObjectClass parent_class;
wl_protocol_manager_register_t foreign_register;
wl_protocol_manager_register_t virtual_keyboard_register;
};
void diya_shell_wayland_init(DiyaShell *shell);
DiyaWayland * diya_shell_get_wayland(DiyaShell* shell);
#endif

View File

@ -0,0 +1,220 @@
#include <xkbcommon/xkbcommon.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <gio/gio.h>
#include "virtual-keyboard-unstable-v1.h"
#include "virtual-keyboard.h"
#include "wayland.h"
static struct zwp_virtual_keyboard_manager_v1 *g_virtual_keyboard_manager = NULL;
struct _DiyaVirtualKeyboard
{
DiyaShellObject parent;
struct zwp_virtual_keyboard_v1 *keyboard;
};
G_DEFINE_FINAL_TYPE(DiyaVirtualKeyboard, diya_virtual_keyboard, DIYA_TYPE_SHELL_OBJECT);
static void diya_virtual_keyboard_dispose(GObject *object)
{
DiyaVirtualKeyboard *self = DIYA_VIRTUAL_KEYBOARD(object);
g_debug("diya_virtual_keyboard_dispose");
if (self->keyboard)
{
zwp_virtual_keyboard_v1_destroy(self->keyboard);
}
G_OBJECT_CLASS(diya_virtual_keyboard_parent_class)->dispose(object);
}
static void diya_virtual_keyboard_init(DiyaVirtualKeyboard *self)
{
self->keyboard = NULL;
}
static const gchar *diya_virtual_keyboard_to_string(DiyaObject *object)
{
(void)object;
return "Diya virtual keyboard instance";
}
static void diya_virtual_keyboard_class_init(DiyaVirtualKeyboardClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->dispose = diya_virtual_keyboard_dispose;
// gobject_class->set_property = diya_lock_session_set_property;
// gobject_class->get_property = diya_lock_session_get_property;
base_class->to_string = diya_virtual_keyboard_to_string;
}
/*
static void randname(char *buf)
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
long r = ts.tv_nsec;
for (int i = 0; i < 6; ++i)
{
buf[i] = 'A' + (r & 15) + (r & 16) * 2;
r >>= 5;
}
}
*/
static int create_keymap_fd(off_t size)
{
static const char name[] = "/diya-shell-keymap-XXXXXX";
const char *base;
char *path;
int fd;
int ret;
// randname(name + sizeof(name) - 7);
base = getenv("XDG_RUNTIME_DIR");
if (!base)
{
errno = ENOENT;
return -1;
}
path = malloc(strlen(base) + sizeof(name) + 1);
if (!path)
return -1;
strcpy(path, base);
strcat(path, name);
g_debug("Create temp file for keymap: %s", path);
fd = mkstemp(path);
if (fd >= 0)
{
long flags;
flags = fcntl(fd, F_GETFD);
if (flags == -1)
{
g_critical("fcntl Unable to F_GETFD: %s", strerror(errno));
close(fd);
fd = -1;
}
else if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
{
g_critical("fcntl Unable to F_SETFD(FD_CLOEXEC): %s", strerror(errno));
close(fd);
fd = -1;
}
unlink(path);
}
else
{
g_critical("mkstemp Unable to create temp file %s: %s", path, strerror(errno));
}
free(path);
if (fd < 0)
return -1;
do
{
ret = ftruncate(fd, size);
} while (ret < 0 && errno == EINTR);
if (ret < 0)
{
close(fd);
return -1;
}
return fd;
}
DiyaVirtualKeyboard *diya_virtual_keyboard_new(DiyaShell *shell, const gchar *keymap_file)
{
gchar *content = NULL;
GError *error = NULL;
GBytes *bytes = NULL;
gsize len = 0;
if (keymap_file)
{
g_file_get_contents(keymap_file, &content, &len, &error);
if (error != NULL)
{
g_critical("diya_virtual_keyboard_new: Unable to read file %s: %s", keymap_file, error->message);
g_error_free(error);
return NULL;
}
}
else
{
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)
{
g_critical("Unable to read keymap file from resource %s", error->message);
g_error_free(error);
return NULL;
}
content = (gchar*)g_bytes_get_data(bytes, &len);
}
int fd = create_keymap_fd(len);
if (fd == -1)
{
g_critical("diya_virtual_keyboard_new: create temp file");
if(bytes)
{
g_bytes_unref(bytes);
content = NULL;
}
if(content)
{
g_free(content);
}
}
void *ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == (void *)-1)
{
g_critical("diya_virtual_keyboard_new: error mmap: %s", strerror(errno));
close(fd);
if(bytes)
{
g_bytes_unref(bytes);
content = NULL;
}
if(content)
{
g_free(content);
}
}
strcpy((char *)ptr, content);
DiyaVirtualKeyboard *vkb = g_object_new(DIYA_TYPE_VIRTUAL_KEYBOARD, "shell", shell, NULL);
DiyaWayland *wayland = diya_shell_get_wayland(shell);
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;
}
void diya_virtual_keyboard_register(struct wl_registry *registry, uint32_t name, DiyaShell *shell)
{
(void)shell;
g_virtual_keyboard_manager = wl_registry_bind(registry, name, &zwp_virtual_keyboard_manager_v1_interface, 1);
}
void diya_virtual_keyboard_send_key(DiyaVirtualKeyboard *self, uint32_t key, diya_vkb_state_t state)
{
GDateTime *now = g_date_time_new_now_local();
uint32_t current_time_ms = g_date_time_get_microsecond(now) / 1000;
g_date_time_unref(now);
zwp_virtual_keyboard_v1_key(self->keyboard, current_time_ms, key, (uint32_t)state);
}

View File

@ -1,8 +1,19 @@
#ifndef DIYA_VIRTUAL_KEYBOARD_H
#define DIYA_VIRTUAL_KEYBOARD_H
#include "virtual-keyboard-unstable-v1.h"
#include "shell.h"
typedef enum
{
VKB_KEY_STATE_RELEASED = 0 /*WL_KEYBOARD_KEY_STATE_RELEASED*/,
VKB_KEY_STATE_PRESSED = 1 /*WL_KEYBOARD_KEY_STATE_PRESSED*/,
} diya_vkb_state_t;
#define DIYA_TYPE_VIRTUAL_KEYBOARD (diya_virtual_keyboard_get_type ())
G_DECLARE_FINAL_TYPE (DiyaVirtualKeyboard, diya_virtual_keyboard, DIYA, VIRTUAL_KEYBOARD, DiyaShellObject)
DiyaVirtualKeyboard* diya_virtual_keyboard_new(DiyaShell* shell, const gchar* keymap_file);
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);
#endif

View File

@ -1,15 +1,17 @@
#include <wayland-client-protocol.h>
#include <gdk/wayland/gdkwayland.h>
#include <assert.h>
#include "wlr-foreign-toplevel-management-unstable-v1.h"
#include "virtual-keyboard-unstable-v1.h"
#include "wayland.h"
#include "foreign.h"
struct _DiyaWayland
{
DiyaObject parent;
DiyaShellObject parent;
struct wl_compositor * compositor;
struct wl_shm * shm;
struct wl_seat * seat;
};
G_DEFINE_FINAL_TYPE(DiyaWayland, diya_wayland, DIYA_TYPE_SHELL_OBJECT)
@ -17,7 +19,7 @@ static void diya_wayland_dispose(GObject* object)
{
(void) object;
//DiyaWayland * self = DIYA_WAYLAND(object);
g_debug("diya_wayland_dispose");
g_debug("diya_wayland_dispose: %s", diya_object_to_string(object));
G_OBJECT_CLASS(diya_wayland_parent_class)->dispose(object);
}
@ -25,17 +27,24 @@ static void diya_wayland_init(DiyaWayland * self)
{
self->compositor = NULL;
self->shm = NULL;
self->seat = NULL;
}
static const gchar* diya_wayland_to_string(DiyaObject* object)
{
(void) object;
return "DiyaWayland - wayland client handle object";
}
static void diya_wayland_class_init(DiyaWaylandClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
//DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->dispose = diya_wayland_dispose;
//gobject_class->set_property = diya_lock_session_set_property;
//gobject_class->get_property = diya_lock_session_get_property;
//base_class->to_string = diya_lock_session_to_string;
base_class->to_string = diya_wayland_to_string;
}
@ -52,18 +61,34 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
*/
(void) version;
DiyaShell * shell = data;
DiyaShellClass * class = DIYA_SHELL_GET_CLASS(shell);
DiyaWayland * wayland;
g_object_get(shell, "wayland", &wayland, NULL);
assert(DIYA_IS_WAYLAND(wayland));
g_debug("WAYLAND GLOBAL: %s", interface);
if (g_strcmp0(interface, zwlr_foreign_toplevel_manager_v1_interface.name) == 0)
{
diya_shell_foreign_toplevel_register(registry, name, data);
if(class->foreign_register)
{
//diya_session_shell_foreign_toplevel_register(registry, name, data);
g_debug("Wayland: register shell foreign top level manager");
class->foreign_register(registry, name, data);
}
}
if (g_strcmp0(interface, zwp_virtual_keyboard_manager_v1_interface.name) == 0)
{
if(class->virtual_keyboard_register)
{
//diya_session_shell_foreign_toplevel_register(registry, name, data);
g_debug("Wayland: register virtual keyboard manager");
class->virtual_keyboard_register(registry, name, data);
}
}
/*
else if(!g_strcmp0(interface, ext_session_lock_manager_v1_interface.name))
{
diya_shell_session_lock_register(registry, name);
diya_session_shell_session_lock_register(registry, name);
}
*/
else if (strcmp(interface, wl_compositor_interface.name) == 0)
@ -74,6 +99,10 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
{
wayland->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
}
else if (strcmp(interface, wl_seat_interface.name) == 0)
{
wayland->seat = wl_registry_bind(registry, name, &wl_seat_interface, 7);
}
}
static void handle_global_remove(void *data, struct wl_registry *registry,
@ -143,3 +172,9 @@ struct wl_shm_pool * diya_wayland_create_shm_pool(DiyaWayland * self, int fd, gu
assert(self->shm);
return wl_shm_create_pool(self->shm, fd, size);
}
struct wl_seat* diya_wayland_get_seat(DiyaWayland* self)
{
assert(self->seat);
return self->seat;
}

View File

@ -3,8 +3,8 @@
#include "shell.h"
void diya_shell_wayland_init(DiyaShell *shell);
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);
#endif