我意识到Gtk没有相关的API,我需要根据指针约束协议 将鼠标光标锁定到特定窗口 但我不知道如何在我的 Gtk 代码中使用这个协议。
我想找到一种方法将其集成到我的 Gtk 项目中,我应该学习什么才能做到这一点?
下面的代码工作正常
#include <gtk/gtk.h>
#include <gdk/wayland/gdkwayland.h>
#include <stdio.h>
#include "pointer-constraints-unstable-v1.h"
#include "relative-pointer-unstable-v1.h"
struct zwp_pointer_constraints_v1 *pointer_constraints = NULL;
struct zwp_locked_pointer_v1 *locked_pointer = NULL;
struct wl_seat *seat = NULL;
// GdkWaylandWaylandDeviceget_wl_pointer
struct wl_pointer *pointer = NULL;
struct wl_compositor *compositor = NULL;
struct wl_registry *wl_registry = NULL;
// 下面两个从 gtk 拿, 剩下的就不用了
struct wl_display *wl_display = NULL;
struct wl_surface *wl_surface = NULL;
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager = NULL;
struct zwp_relative_pointer_v1 *relative_pointer = NULL;
static void relative_pointer_handle_relative_motion(void *data,
struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1,
uint32_t utime_hi,
uint32_t utime_lo,
wl_fixed_t dx,
wl_fixed_t dy,
wl_fixed_t dx_unaccel,
wl_fixed_t dy_unaccel)
{
double x = wl_fixed_to_double(dx);
double y = wl_fixed_to_double(dy);
printf("Relative motion: dx=%.2f, dy=%.2f\n", x, y);
}
static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
.relative_motion = relative_pointer_handle_relative_motion,
};
static void seat_handle_capabilities(void *data, struct wl_seat *seat,
enum wl_seat_capability caps)
{
if (caps & WL_SEAT_CAPABILITY_POINTER)
{
pointer = wl_seat_get_pointer(seat);
// 可以在这里为 pointer 添加监听器
// wl_pointer_add_listener(pointer, &pointer_listener, NULL);
}
}
static const struct wl_seat_listener seat_listener = {
.capabilities = seat_handle_capabilities,
};
static void registry_handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
{
if (strcmp(interface, wl_compositor_interface.name) == 0)
{
compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1);
}
else if (strcmp(interface, zwp_pointer_constraints_v1_interface.name) == 0)
{
pointer_constraints = wl_registry_bind(registry, name,
&zwp_pointer_constraints_v1_interface, 1);
}
else if (strcmp(interface, wl_seat_interface.name) == 0)
{
seat = wl_registry_bind(registry, name, &wl_seat_interface, 1);
wl_seat_add_listener(seat, &seat_listener, NULL);
}
else if (strcmp(interface, zwp_relative_pointer_manager_v1_interface.name) == 0)
{
relative_pointer_manager = wl_registry_bind(registry, name,
&zwp_relative_pointer_manager_v1_interface, 1);
}
// 处理其他全局对象...
}
void unlock_pointer()
{
if (locked_pointer)
{
zwp_locked_pointer_v1_destroy(locked_pointer);
locked_pointer = NULL;
}
if (relative_pointer)
{
zwp_relative_pointer_v1_destroy(relative_pointer);
relative_pointer = NULL;
}
printf("Pointer unlocked and relative pointer disabled\n");
}
void lock_pointer()
{
if (!pointer_constraints || !pointer || !wl_surface)
{
fprintf(stderr, "Pointer constraints, pointer, or surface not available\n");
return;
}
struct wl_region *region = wl_compositor_create_region(compositor);
wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX);
locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
pointer_constraints,
wl_surface,
pointer,
region,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
wl_region_destroy(region);
if (!locked_pointer)
{
fprintf(stderr, "Failed to lock pointer\n");
return;
}
if (relative_pointer_manager && pointer)
{
relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
relative_pointer_manager, pointer);
if (relative_pointer)
{
zwp_relative_pointer_v1_add_listener(relative_pointer, &relative_pointer_listener, NULL);
}
else
{
fprintf(stderr, "Failed to create relative pointer\n");
}
}
printf("Pointer locked and relative pointer enabled\n");
}
static void toggle_pointer_lock(GtkWidget *widget, gpointer data)
{
if (locked_pointer)
{
unlock_pointer();
}
else
{
lock_pointer();
}
}
static void activate(GtkApplication *app, gpointer user_data)
{
GtkWidget *window;
GtkWidget *button;
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "Wayland Info");
gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);
button = gtk_button_new_with_label("Toggle Pointer Lock");
g_signal_connect(button, "clicked", G_CALLBACK(toggle_pointer_lock), NULL);
gtk_window_set_child(GTK_WINDOW(window), button);
GdkDisplay *display = gtk_widget_get_display(window);
if (GDK_IS_WAYLAND_DISPLAY(display))
{
wl_display = gdk_wayland_display_get_wl_display(display);
wl_registry = wl_display_get_registry(wl_display);
printf("wl_display: %p\n", wl_display);
}
else
{
printf("Not a Wayland display\n");
}
// We need to realize the window to get the surface
gtk_widget_realize(window);
GdkSurface *surface = gtk_native_get_surface(GTK_NATIVE(window));
if (GDK_IS_WAYLAND_SURFACE(surface))
{
wl_surface = gdk_wayland_surface_get_wl_surface(surface);
printf("wl_surface: %p\n", wl_surface);
}
else
{
printf("Not a Wayland surface\n");
}
static const struct wl_registry_listener registry_listener = {
.global = registry_handle_global,
};
wl_registry_add_listener(wl_registry, ®istry_listener, NULL);
wl_display_roundtrip(wl_display);
gtk_widget_show(window);
}
int main(int argc, char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}