有Gtk4 wayland窗口指针约束的例子吗?

问题描述 投票:0回答:1

我意识到Gtk没有相关的API,我需要根据指针约束协议 将鼠标光标锁定到特定窗口 但我不知道如何在我的 Gtk 代码中使用这个协议。

我想找到一种方法将其集成到我的 Gtk 项目中,我应该学习什么才能做到这一点?

gnome wayland gtk4
1个回答
0
投票

下面的代码工作正常

#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, &registry_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;
}
© www.soinside.com 2019 - 2024. All rights reserved.