CasildaCompositor: add clipboard integration support
This commit is contained in:
parent
41a4068de3
commit
c432801b18
7 changed files with 322 additions and 10 deletions
18
CHANGELOG.md
18
CHANGELOG.md
|
|
@ -7,6 +7,24 @@ packaging changes like new dependencies or build system changes.
|
||||||
Casilda used even/odd minor numbers to differentiate between stable and
|
Casilda used even/odd minor numbers to differentiate between stable and
|
||||||
development releases.
|
development releases.
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
- Add clipboard support
|
||||||
|
- Fix modifiers in pointer button press events
|
||||||
|
- Add keyboard Caps/Num/Scroll Lock support
|
||||||
|
- Fix popup of popup crash
|
||||||
|
- Fix maximized/fullscreen state handling
|
||||||
|
- Fix modifiers flags creation (Evgenii Danilin)
|
||||||
|
- Drop cursor surface listeners when the surface is destroyed (Evgenii Danilin)
|
||||||
|
- Close dup'd plane FDs when a dmabuf import fails (Evgenii Danilin)
|
||||||
|
- Advertise a valid output scale to avoid a scale-0 assert (Evgenii Danilin)
|
||||||
|
- Unref the wayland GSource (Evgenii Danilin)
|
||||||
|
- Meson config cleanup (Val Packett)
|
||||||
|
|
||||||
|
### Packaging
|
||||||
|
|
||||||
|
- Add explicit libdrm dependency
|
||||||
|
|
||||||
## 1.4.0
|
## 1.4.0
|
||||||
|
|
||||||
2026-05-22 - Val Packett Release!
|
2026-05-22 - Val Packett Release!
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ gnome = import('gnome')
|
||||||
version_split = meson.project_version().split('.')
|
version_split = meson.project_version().split('.')
|
||||||
|
|
||||||
gtk4_dep = dependency('gtk4', version: '>= 4.22.2')
|
gtk4_dep = dependency('gtk4', version: '>= 4.22.2')
|
||||||
|
gio_unix_dep = dependency('gio-unix-2.0')
|
||||||
libdrm_dep = dependency('libdrm')
|
libdrm_dep = dependency('libdrm')
|
||||||
pixman_dep = dependency('pixman-1', version: '>=0.42.0')
|
pixman_dep = dependency('pixman-1', version: '>=0.42.0')
|
||||||
wayland_server_dep = dependency('wayland-server', version: '>=1.22')
|
wayland_server_dep = dependency('wayland-server', version: '>=1.22')
|
||||||
|
|
|
||||||
255
src/casilda-clipboard.c
Normal file
255
src/casilda-clipboard.c
Normal file
|
|
@ -0,0 +1,255 @@
|
||||||
|
/*
|
||||||
|
* Casilda Clipboard Integration
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 Juan Pablo Ugarte
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License.
|
||||||
|
*
|
||||||
|
* library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Juan Pablo Ugarte <juanpablougarte@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define WLR_USE_UNSTABLE 1
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <glib-unix.h>
|
||||||
|
#include <gio/gunixinputstream.h>
|
||||||
|
#include <wlr/types/wlr_data_device.h>
|
||||||
|
#include "casilda-private.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
struct wlr_data_source base;
|
||||||
|
GdkClipboard *clipboard;
|
||||||
|
GStrv mimes;
|
||||||
|
} CasildaDataSource;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GdkClipboard *clipboard;
|
||||||
|
gchar *mime_type;
|
||||||
|
GByteArray *result;
|
||||||
|
guchar buffer[4096];
|
||||||
|
gint fd;
|
||||||
|
} ClipboardData;
|
||||||
|
|
||||||
|
static ClipboardData *
|
||||||
|
clipboard_data_new (GdkClipboard *clipboard, const gchar *mime_type, gint fd)
|
||||||
|
{
|
||||||
|
ClipboardData *data = g_new0 (ClipboardData, 1);
|
||||||
|
|
||||||
|
data->clipboard = g_object_ref (clipboard);
|
||||||
|
data->mime_type = g_strdup (mime_type);
|
||||||
|
data->result = g_byte_array_new ();
|
||||||
|
data->fd = fd;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clipboard_data_free (ClipboardData *data)
|
||||||
|
{
|
||||||
|
g_object_unref (data->clipboard);
|
||||||
|
g_free (data->mime_type);
|
||||||
|
g_byte_array_free (data->result, TRUE);
|
||||||
|
if (data->fd)
|
||||||
|
close (data->fd);
|
||||||
|
|
||||||
|
g_free (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_clipboard_send_read_all_done (GObject *stream, GAsyncResult *result, gpointer userdata)
|
||||||
|
{
|
||||||
|
ClipboardData *data = userdata;
|
||||||
|
gsize bytes_read;
|
||||||
|
|
||||||
|
g_input_stream_read_all_finish (G_INPUT_STREAM (stream), result, &bytes_read, NULL);
|
||||||
|
|
||||||
|
if (bytes_read)
|
||||||
|
{
|
||||||
|
write (data->fd, data->buffer, bytes_read);
|
||||||
|
g_input_stream_read_all_async (G_INPUT_STREAM (stream),
|
||||||
|
data->buffer,
|
||||||
|
sizeof (data->buffer),
|
||||||
|
G_PRIORITY_DEFAULT,
|
||||||
|
NULL,
|
||||||
|
on_clipboard_send_read_all_done,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clipboard_data_free (data);
|
||||||
|
g_object_unref (stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_clipboard_send_read_done (G_GNUC_UNUSED GObject *obj, GAsyncResult *result, gpointer userdata)
|
||||||
|
{
|
||||||
|
ClipboardData *data = userdata;
|
||||||
|
GInputStream *stream = gdk_clipboard_read_finish (data->clipboard, result, NULL, NULL);
|
||||||
|
|
||||||
|
if (!stream)
|
||||||
|
{
|
||||||
|
clipboard_data_free (data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_input_stream_read_all_async (stream,
|
||||||
|
data->buffer,
|
||||||
|
sizeof(data->buffer),
|
||||||
|
G_PRIORITY_DEFAULT,
|
||||||
|
NULL,
|
||||||
|
on_clipboard_send_read_all_done,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
casilda_data_source_send (struct wlr_data_source *data_source, const char *mime_type, int32_t fd)
|
||||||
|
{
|
||||||
|
CasildaDataSource *source = (CasildaDataSource *)data_source;
|
||||||
|
const gchar *mimes[2] = { mime_type, NULL };
|
||||||
|
|
||||||
|
if (!g_strv_contains ((const gchar * const*)source->mimes, mime_type))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ClipboardData *data = clipboard_data_new (source->clipboard, mime_type, fd);
|
||||||
|
gdk_clipboard_read_async (source->clipboard,
|
||||||
|
mimes,
|
||||||
|
G_PRIORITY_DEFAULT,
|
||||||
|
NULL,
|
||||||
|
on_clipboard_send_read_done,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
casilda_data_source_destroy (struct wlr_data_source *source)
|
||||||
|
{
|
||||||
|
CasildaDataSource *data_source = (CasildaDataSource *)source;
|
||||||
|
|
||||||
|
g_object_unref (data_source->clipboard);
|
||||||
|
g_strfreev (data_source->mimes);
|
||||||
|
g_free (data_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_data_source_impl casilda_data_source_impl = {
|
||||||
|
.send = casilda_data_source_send,
|
||||||
|
.destroy = casilda_data_source_destroy,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static struct wlr_data_source *
|
||||||
|
casilda_data_source_new (GdkClipboard *clipboard)
|
||||||
|
{
|
||||||
|
CasildaDataSource *source = g_new0 (CasildaDataSource, 1);
|
||||||
|
GdkContentFormats *formats = gdk_clipboard_get_formats (clipboard);
|
||||||
|
|
||||||
|
wlr_data_source_init (&source->base, &casilda_data_source_impl);
|
||||||
|
source->clipboard = g_object_ref (clipboard);
|
||||||
|
source->mimes = g_strdupv ((GStrv) gdk_content_formats_get_mime_types (formats, NULL));
|
||||||
|
|
||||||
|
for (gchar **mime = source->mimes; mime && *mime; mime++)
|
||||||
|
{
|
||||||
|
char **dst = wl_array_add (&source->base.mime_types, sizeof(char *));
|
||||||
|
*dst = g_strdup (*mime);
|
||||||
|
}
|
||||||
|
|
||||||
|
return &source->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
casilda_clipboard_seat_set_selection (GdkClipboard *clipboard, struct wlr_seat *seat)
|
||||||
|
{
|
||||||
|
struct wlr_data_source *source = casilda_data_source_new (clipboard);
|
||||||
|
wlr_seat_set_selection (seat, source, wl_display_next_serial (seat->display));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_clipboard_read_done (GObject *source, GAsyncResult *result, gpointer userdata)
|
||||||
|
{
|
||||||
|
ClipboardData *data = userdata;
|
||||||
|
gsize bytes_read;
|
||||||
|
|
||||||
|
g_input_stream_read_all_finish (G_INPUT_STREAM(source), result, &bytes_read, NULL);
|
||||||
|
|
||||||
|
if (bytes_read)
|
||||||
|
{
|
||||||
|
data->result = g_byte_array_append (data->result, data->buffer, bytes_read);
|
||||||
|
g_input_stream_read_all_async (G_INPUT_STREAM(source),
|
||||||
|
data->buffer,
|
||||||
|
sizeof(data->buffer),
|
||||||
|
G_PRIORITY_DEFAULT,
|
||||||
|
NULL,
|
||||||
|
on_clipboard_read_done,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (data->mime_type)
|
||||||
|
{
|
||||||
|
if (g_str_has_prefix (data->mime_type, "text/"))
|
||||||
|
{
|
||||||
|
data->result = g_byte_array_append (data->result, (const guchar *)"\0", 1);
|
||||||
|
gdk_clipboard_set_text (data->clipboard, (gchar *)data->result->data);
|
||||||
|
}
|
||||||
|
else if (g_str_has_prefix (data->mime_type, "image/"))
|
||||||
|
{
|
||||||
|
g_autoptr (GBytes) bytes = g_bytes_new_static (data->result->data, data->result->len);
|
||||||
|
g_autoptr (GdkTexture) texture = gdk_texture_new_from_bytes (bytes, NULL);
|
||||||
|
|
||||||
|
gdk_clipboard_set_texture (data->clipboard, texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clipboard_data_free (data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
casilda_clipboard_set_from_data_source (GdkClipboard *clipboard, struct wlr_data_source *source)
|
||||||
|
{
|
||||||
|
char **mime;
|
||||||
|
|
||||||
|
wl_array_for_each (mime, &source->mime_types)
|
||||||
|
{
|
||||||
|
GUnixPipe p;
|
||||||
|
|
||||||
|
if (!g_str_has_prefix (*mime, "text/") && !g_str_has_prefix (*mime, "image/"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!g_unix_pipe_open (&p, O_CLOEXEC | O_NONBLOCK, NULL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Write data to pipe */
|
||||||
|
wlr_data_source_send (source, *mime, g_unix_pipe_get (&p, G_UNIX_PIPE_END_WRITE));
|
||||||
|
|
||||||
|
/* Read data from pipe */
|
||||||
|
GInputStream *stream = g_unix_input_stream_new (g_unix_pipe_get (&p, G_UNIX_PIPE_END_READ), TRUE);
|
||||||
|
|
||||||
|
ClipboardData *data = clipboard_data_new (clipboard, *mime, -1);
|
||||||
|
g_input_stream_read_all_async (stream,
|
||||||
|
data->buffer,
|
||||||
|
sizeof(data->buffer),
|
||||||
|
G_PRIORITY_DEFAULT,
|
||||||
|
NULL,
|
||||||
|
on_clipboard_read_done,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -158,7 +158,7 @@
|
||||||
|
|
||||||
#include "casilda-config.h"
|
#include "casilda-config.h"
|
||||||
|
|
||||||
#define _POSIX_C_SOURCE 199309L /* clock_gettime */
|
#define _POSIX_C_SOURCE 200809L /* clock_gettime */
|
||||||
#define WLR_USE_UNSTABLE 1
|
#define WLR_USE_UNSTABLE 1
|
||||||
#define G_LOG_DOMAIN "Casilda"
|
#define G_LOG_DOMAIN "Casilda"
|
||||||
#define ENABLE_TEXTURE_DEBUG 0
|
#define ENABLE_TEXTURE_DEBUG 0
|
||||||
|
|
@ -242,6 +242,9 @@ typedef struct
|
||||||
/* Renderer context */
|
/* Renderer context */
|
||||||
GdkGLContext *gl_context;
|
GdkGLContext *gl_context;
|
||||||
|
|
||||||
|
GdkClipboard *clipboard;
|
||||||
|
gulong clipboard_source;
|
||||||
|
|
||||||
/* Wayland display */
|
/* Wayland display */
|
||||||
struct wl_display *wl_display;
|
struct wl_display *wl_display;
|
||||||
|
|
||||||
|
|
@ -2300,6 +2303,12 @@ on_casilda_compositor_frame_clock_update (G_GNUC_UNUSED GdkFrameClock *self,
|
||||||
wlr_output_send_frame (&priv->output);
|
wlr_output_send_frame (&priv->output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_casilda_compositor_clipboard_changed (G_GNUC_UNUSED GObject *obj, CasildaCompositorPrivate *priv)
|
||||||
|
{
|
||||||
|
casilda_clipboard_seat_set_selection (priv->clipboard, priv->seat);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
casilda_compositor_realize (GtkWidget *widget)
|
casilda_compositor_realize (GtkWidget *widget)
|
||||||
{
|
{
|
||||||
|
|
@ -2312,6 +2321,12 @@ casilda_compositor_realize (GtkWidget *widget)
|
||||||
g_signal_connect (priv->frame_clock, "update",
|
g_signal_connect (priv->frame_clock, "update",
|
||||||
G_CALLBACK (on_casilda_compositor_frame_clock_update),
|
G_CALLBACK (on_casilda_compositor_frame_clock_update),
|
||||||
priv);
|
priv);
|
||||||
|
|
||||||
|
priv->clipboard = gtk_widget_get_clipboard (widget);
|
||||||
|
priv->clipboard_source =
|
||||||
|
g_signal_connect (priv->clipboard, "changed",
|
||||||
|
G_CALLBACK (on_casilda_compositor_clipboard_changed),
|
||||||
|
priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -2327,6 +2342,14 @@ casilda_compositor_unrealize (GtkWidget *widget)
|
||||||
|
|
||||||
priv->frame_clock = NULL;
|
priv->frame_clock = NULL;
|
||||||
|
|
||||||
|
if (priv->clipboard && priv->clipboard_source)
|
||||||
|
{
|
||||||
|
g_signal_handler_disconnect (priv->clipboard, priv->clipboard_source);
|
||||||
|
priv->clipboard_source = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->clipboard = NULL;
|
||||||
|
|
||||||
GTK_WIDGET_CLASS (casilda_compositor_parent_class)->unrealize (widget);
|
GTK_WIDGET_CLASS (casilda_compositor_parent_class)->unrealize (widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2377,10 +2400,11 @@ seat_request_set_selection (struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
CasildaCompositorPrivate *priv = wl_container_of (listener, priv, request_set_selection);
|
CasildaCompositorPrivate *priv = wl_container_of (listener, priv, request_set_selection);
|
||||||
struct wlr_seat_request_set_selection_event *event = data;
|
struct wlr_seat_request_set_selection_event *event = data;
|
||||||
struct wlr_data_source *a;
|
|
||||||
|
|
||||||
wlr_seat_set_selection (priv->seat, event->source, event->serial);
|
wlr_seat_set_selection (priv->seat, event->source, event->serial);
|
||||||
/* TODO: integrate with Gtk clipboard */
|
|
||||||
|
/* Integrate with Gtk clipboard */
|
||||||
|
casilda_clipboard_set_from_data_source (priv->clipboard, event->source);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
#include <wlr/backend.h>
|
||||||
|
#include <wlr/types/wlr_seat.h>
|
||||||
|
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
void casilda_buffer_configure_shm (struct wl_display *wl_display);
|
void casilda_buffer_configure_shm (struct wl_display *wl_display);
|
||||||
|
|
@ -35,3 +37,9 @@ void casilda_buffer_configure_dmabuf (struct wl_display *wl_display);
|
||||||
|
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
GdkTexture *casilda_buffer_texture_from_wlr (struct wlr_buffer *buffer, pixman_region32_t *damage, GdkTexture *prev);
|
GdkTexture *casilda_buffer_texture_from_wlr (struct wlr_buffer *buffer, pixman_region32_t *damage, GdkTexture *prev);
|
||||||
|
|
||||||
|
G_GNUC_INTERNAL
|
||||||
|
void casilda_clipboard_seat_set_selection (GdkClipboard *clipboard, struct wlr_seat *seat);
|
||||||
|
|
||||||
|
G_GNUC_INTERNAL
|
||||||
|
void casilda_clipboard_set_from_data_source (GdkClipboard *clipboard, struct wlr_data_source *source);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ api_version = '1.0'
|
||||||
|
|
||||||
casilda_sources = [
|
casilda_sources = [
|
||||||
'casilda-buffer.c',
|
'casilda-buffer.c',
|
||||||
|
'casilda-clipboard.c',
|
||||||
'casilda-compositor.c',
|
'casilda-compositor.c',
|
||||||
'casilda-wayland-source.c',
|
'casilda-wayland-source.c',
|
||||||
]
|
]
|
||||||
|
|
@ -27,6 +28,7 @@ casilda_headers += configure_file(
|
||||||
|
|
||||||
casilda_deps = [
|
casilda_deps = [
|
||||||
gtk4_dep,
|
gtk4_dep,
|
||||||
|
gio_unix_dep,
|
||||||
libdrm_dep,
|
libdrm_dep,
|
||||||
wlroots_dep,
|
wlroots_dep,
|
||||||
xkbcommon,
|
xkbcommon,
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,14 @@ class MyApplication(Gtk.Application):
|
||||||
self.keyboard = self.window.get_display().get_default_seat().get_keyboard()
|
self.keyboard = self.window.get_display().get_default_seat().get_keyboard()
|
||||||
|
|
||||||
box = Gtk.Box (orientation=Gtk.Orientation.VERTICAL, spacing=12)
|
box = Gtk.Box (orientation=Gtk.Orientation.VERTICAL, spacing=12)
|
||||||
self.press_label = Gtk.Label(halign=Gtk.Align.START)
|
|
||||||
self.release_label = Gtk.Label(halign=Gtk.Align.START)
|
box.append(Gtk.Entry())
|
||||||
self.mod_label = Gtk.Label(halign=Gtk.Align.START)
|
box.append(Gtk.Label(label="Some test text you can select to test the clipboard", selectable=True))
|
||||||
self.click_label = Gtk.Label(halign=Gtk.Align.START)
|
|
||||||
|
self.press_label = Gtk.Label(halign=Gtk.Align.START, selectable=True)
|
||||||
|
self.release_label = Gtk.Label(halign=Gtk.Align.START, selectable=True)
|
||||||
|
self.mod_label = Gtk.Label(halign=Gtk.Align.START, selectable=True)
|
||||||
|
self.click_label = Gtk.Label(halign=Gtk.Align.START, selectable=True)
|
||||||
|
|
||||||
box.append(self.press_label)
|
box.append(self.press_label)
|
||||||
box.append(self.release_label)
|
box.append(self.release_label)
|
||||||
|
|
@ -43,15 +47,15 @@ class MyApplication(Gtk.Application):
|
||||||
|
|
||||||
def handle_key_pressed(self, controller, keyval, keycode, state):
|
def handle_key_pressed(self, controller, keyval, keycode, state):
|
||||||
self.press_label.set_text(f"EventControllerKey::key-pressed\n\t{keyval=} {keycode=}\n\t{state=}\n\t{self.keyboard.props.modifier_state=}")
|
self.press_label.set_text(f"EventControllerKey::key-pressed\n\t{keyval=} {keycode=}\n\t{state=}\n\t{self.keyboard.props.modifier_state=}")
|
||||||
return True
|
return False
|
||||||
|
|
||||||
def handle_key_released(self, controller, keyval, keycode, state):
|
def handle_key_released(self, controller, keyval, keycode, state):
|
||||||
self.release_label.set_text(f"EventControllerKey::key-released\n\t{keyval=} {keycode=}\n\t{state=}\n\t{self.keyboard.props.modifier_state=}")
|
self.release_label.set_text(f"EventControllerKey::key-released\n\t{keyval=} {keycode=}\n\t{state=}\n\t{self.keyboard.props.modifier_state=}")
|
||||||
return True
|
return False
|
||||||
|
|
||||||
def handle_modifiers(self, controller, state):
|
def handle_modifiers(self, controller, state):
|
||||||
self.mod_label.set_text(f"EventControllerKey::modifiers\n\t{state}\n\t{self.keyboard.props.modifier_state=}")
|
self.mod_label.set_text(f"EventControllerKey::modifiers\n\t{state}\n\t{self.keyboard.props.modifier_state=}")
|
||||||
return True
|
return False
|
||||||
|
|
||||||
def click_released(self, controller, n, x, y):
|
def click_released(self, controller, n, x, y):
|
||||||
self.click_label.set_text(f"GestureClick::released\n\t{n=} {x=} {y=}\n\t{self.keyboard.props.modifier_state=}")
|
self.click_label.set_text(f"GestureClick::released\n\t{n=} {x=} {y=}\n\t{self.keyboard.props.modifier_state=}")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue