mirror of https://github.com/fltk/fltk
Wayland: much lighter but partial implementation of the "GTK Shell" protocol
Only the middle-button click gesture is implemented which avoids interference with what libdecor does with right-click and double-click.
This commit is contained in:
parent
68594ec7fa
commit
18ccbb4a4f
|
@ -31,15 +31,10 @@
|
|||
# define HAVE_GTK 0
|
||||
#endif
|
||||
|
||||
#if HAVE_GTK
|
||||
# include "gtk-shell-client-protocol.h"
|
||||
#endif
|
||||
|
||||
#if USE_SYSTEM_LIBDECOR
|
||||
#include "../src/libdecor-plugin.h"
|
||||
#if HAVE_GTK
|
||||
#include <linux/input.h>
|
||||
#include "gtk-shell-protocol.c"
|
||||
#endif
|
||||
|
||||
enum zxdg_toplevel_decoration_v1_mode {
|
||||
|
@ -237,55 +232,6 @@ struct libdecor_frame_gtk {
|
|||
struct wl_list link;
|
||||
};
|
||||
|
||||
#if USE_SYSTEM_LIBDECOR
|
||||
struct libdecor_plugin_gtk {
|
||||
struct libdecor_plugin plugin;
|
||||
struct wl_callback *globals_callback;
|
||||
struct wl_callback *globals_callback_shm;
|
||||
struct libdecor *context;
|
||||
struct wl_registry *wl_registry;
|
||||
struct wl_subcompositor *wl_subcompositor;
|
||||
struct wl_compositor *wl_compositor;
|
||||
struct wl_shm *wl_shm;
|
||||
struct wl_callback *shm_callback;
|
||||
bool has_argb;
|
||||
struct wl_list visible_frame_list;
|
||||
struct wl_list seat_list;
|
||||
struct wl_list output_list;
|
||||
char *cursor_theme_name;
|
||||
int cursor_size;
|
||||
int double_click_time_ms;
|
||||
};
|
||||
|
||||
struct seat {
|
||||
struct libdecor_plugin_gtk *plugin_gtk;
|
||||
char *name;
|
||||
struct wl_seat *wl_seat;
|
||||
struct wl_pointer *wl_pointer;
|
||||
struct wl_touch *wl_touch;
|
||||
struct wl_surface *cursor_surface;
|
||||
struct wl_cursor *current_cursor;
|
||||
int cursor_scale;
|
||||
struct wl_list cursor_outputs;
|
||||
struct wl_cursor_theme *cursor_theme;
|
||||
struct wl_cursor *cursors[8]; // 8 replaces ARRAY_LENGTH(cursor_names)
|
||||
struct wl_cursor *cursor_left_ptr;
|
||||
struct wl_surface *pointer_focus;
|
||||
struct wl_surface *touch_focus;
|
||||
int pointer_x, pointer_y;
|
||||
uint32_t pointer_button_time_stamp;
|
||||
uint32_t touch_down_time_stamp;
|
||||
uint32_t serial;
|
||||
bool grabbed;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
static bool own_surface(struct wl_surface *surface)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif // USE_SYSTEM_LIBDECOR
|
||||
|
||||
#endif // USE_SYSTEM_LIBDECOR || !HAVE_GTK
|
||||
|
||||
|
||||
|
@ -391,187 +337,3 @@ unsigned char *fl_libdecor_titlebar_buffer(struct libdecor_frame *frame,
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* === Beginning of code to add support of GTK Shell to libdecor-gtk === */
|
||||
#if HAVE_GTK
|
||||
|
||||
static struct gtk_shell1 *gtk_shell = NULL;
|
||||
static uint32_t doubleclick_time = 250;
|
||||
|
||||
// libdecor's button member of wl_pointer_listener objects
|
||||
static void (*decor_pointer_button)(void*, struct wl_pointer *,
|
||||
uint32_t ,
|
||||
uint32_t ,
|
||||
uint32_t ,
|
||||
uint32_t);
|
||||
|
||||
// FLTK's replacement for button member of wl_pointer_listener objects
|
||||
static void fltk_pointer_button(void *data,
|
||||
struct wl_pointer *wl_pointer,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
uint32_t button,
|
||||
uint32_t state) {
|
||||
struct seat *seat = data;
|
||||
struct libdecor_frame_gtk *frame_gtk;
|
||||
if (!seat->pointer_focus || !own_surface(seat->pointer_focus))
|
||||
return;
|
||||
|
||||
frame_gtk = wl_surface_get_user_data(seat->pointer_focus);
|
||||
if (!frame_gtk)
|
||||
return;
|
||||
|
||||
if (button == BTN_MIDDLE && state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||
struct gtk_surface1 *gtk_surface = gtk_shell1_get_gtk_surface(gtk_shell,
|
||||
frame_gtk->headerbar.wl_surface);
|
||||
gtk_surface1_titlebar_gesture(gtk_surface, serial,
|
||||
seat->wl_seat, GTK_SURFACE1_GESTURE_MIDDLE_CLICK);
|
||||
gtk_surface1_release(gtk_surface);
|
||||
return;
|
||||
} else if (button == BTN_RIGHT && state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||
struct gtk_surface1 *gtk_surface = gtk_shell1_get_gtk_surface(gtk_shell,
|
||||
frame_gtk->headerbar.wl_surface);
|
||||
gtk_surface1_titlebar_gesture(gtk_surface, serial,
|
||||
seat->wl_seat, GTK_SURFACE1_GESTURE_RIGHT_CLICK);
|
||||
gtk_surface1_release(gtk_surface);
|
||||
return;
|
||||
} else if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||
if (time - seat->pointer_button_time_stamp < doubleclick_time) {
|
||||
seat->pointer_button_time_stamp = 0;
|
||||
struct gtk_surface1 *gtk_surface = gtk_shell1_get_gtk_surface(gtk_shell,
|
||||
frame_gtk->headerbar.wl_surface);
|
||||
gtk_surface1_titlebar_gesture(gtk_surface, serial,
|
||||
seat->wl_seat, GTK_SURFACE1_GESTURE_DOUBLE_CLICK);
|
||||
gtk_surface1_release(gtk_surface);
|
||||
return;
|
||||
}
|
||||
}
|
||||
decor_pointer_button(data, wl_pointer, serial, time, button, state);
|
||||
}
|
||||
|
||||
#if USE_SYSTEM_LIBDECOR
|
||||
static struct border_component_gtk *
|
||||
get_component_for_surface(struct libdecor_frame_gtk *frame_gtk,
|
||||
const struct wl_surface *surface)
|
||||
{
|
||||
if (frame_gtk->shadow.wl_surface == surface)
|
||||
return &frame_gtk->shadow;
|
||||
if (frame_gtk->headerbar.wl_surface == surface)
|
||||
return &frame_gtk->headerbar;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// libdecor's touch_down member of wl_touch_listener objects
|
||||
void (*decor_touch_down)(void *data, struct wl_touch *wl_touch, uint32_t serial,
|
||||
uint32_t time, struct wl_surface *surface, int32_t id,
|
||||
wl_fixed_t x, wl_fixed_t y);
|
||||
|
||||
|
||||
// FLTK's replacement for touch_down member of wl_touch_listener objects
|
||||
static void fltk_touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial,
|
||||
uint32_t time, struct wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y)
|
||||
{
|
||||
struct seat *seat = data;
|
||||
struct libdecor_frame_gtk *frame_gtk;
|
||||
if (!surface || !own_surface(surface)) return;
|
||||
frame_gtk = wl_surface_get_user_data(surface);
|
||||
if (!frame_gtk) return;
|
||||
seat->touch_focus = surface;
|
||||
frame_gtk->touch_active = get_component_for_surface(frame_gtk, surface);
|
||||
if (!frame_gtk->touch_active) return;
|
||||
|
||||
if (frame_gtk->touch_active->type == HEADER &&
|
||||
frame_gtk->hdr_focus.type < HEADER_MIN &&
|
||||
time - seat->touch_down_time_stamp <
|
||||
(uint32_t)frame_gtk->plugin_gtk->double_click_time_ms
|
||||
) {
|
||||
struct gtk_surface1 *gtk_surface = gtk_shell1_get_gtk_surface(
|
||||
gtk_shell, surface);
|
||||
gtk_surface1_titlebar_gesture(gtk_surface, serial, seat->wl_seat,
|
||||
GTK_SURFACE1_GESTURE_DOUBLE_CLICK);
|
||||
gtk_surface1_release(gtk_surface);
|
||||
} else {
|
||||
decor_touch_down(data, wl_touch, serial, time, surface, id, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct wl_object { // copied from wayland-private.h
|
||||
const struct wl_interface *interface;
|
||||
const void *implementation;
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
#endif // HAVE_GTK
|
||||
|
||||
|
||||
// replace libdecor's pointer_button by FLTK's
|
||||
void use_FLTK_pointer_button(struct libdecor_frame *frame) {
|
||||
#if HAVE_GTK
|
||||
static const char *my_plugin = NULL;
|
||||
if (!my_plugin) my_plugin = get_libdecor_plugin_description(frame);
|
||||
if (!my_plugin || strcmp(my_plugin, "GTK3 plugin")) return;
|
||||
static struct wl_pointer_listener *fltk_listener = NULL;
|
||||
if (!gtk_shell || fltk_listener) return;
|
||||
struct libdecor_frame_gtk *lfg = (struct libdecor_frame_gtk *)frame;
|
||||
if (wl_list_empty(&lfg->plugin_gtk->seat_list)) return;
|
||||
struct seat *seat;
|
||||
wl_list_for_each(seat, &lfg->plugin_gtk->seat_list, link) {
|
||||
break;
|
||||
}
|
||||
|
||||
struct wl_surface *surface = lfg->headerbar.wl_surface;
|
||||
if (surface && !own_surface(surface)) {
|
||||
// occurs if libdecor-gtk.so was dynamically loaded via LIBDECOR_PLUGIN_DIR
|
||||
gtk_shell = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
struct wl_object *object = (struct wl_object *)seat->wl_pointer;
|
||||
if (!object) return;
|
||||
struct wl_pointer_listener *decor_listener =
|
||||
(struct wl_pointer_listener*)object->implementation;
|
||||
fltk_listener =
|
||||
(struct wl_pointer_listener*)malloc(sizeof(struct wl_pointer_listener));
|
||||
// initialize FLTK's listener with libdecor's values
|
||||
*fltk_listener = *decor_listener;
|
||||
// memorize libdecor's button cb
|
||||
decor_pointer_button = decor_listener->button;
|
||||
// replace libdecor's button by FLTK's
|
||||
fltk_listener->button = fltk_pointer_button;
|
||||
// replace the pointer listener by a copy whose button member is FLTK's
|
||||
object->implementation = fltk_listener;
|
||||
|
||||
object = (struct wl_object *)seat->wl_touch;
|
||||
if (object) {
|
||||
struct wl_touch_listener *decor_touch_listener =
|
||||
(struct wl_touch_listener*)object->implementation;
|
||||
struct wl_touch_listener *fltk_touch_listener =
|
||||
(struct wl_touch_listener*)malloc(sizeof(struct wl_touch_listener));
|
||||
// initialize FLTK's touch listener with libdecor's values
|
||||
*fltk_touch_listener = *decor_touch_listener;
|
||||
// memorize libdecor's down cb
|
||||
decor_touch_down = decor_touch_listener->down;
|
||||
// replace libdecor's down by FLTK's
|
||||
fltk_touch_listener->down = fltk_touch_down;
|
||||
// replace the touch listener by a copy whose down member is FLTK's
|
||||
object->implementation = fltk_touch_listener;
|
||||
}
|
||||
|
||||
// get gnome's double_click_time_ms value
|
||||
doubleclick_time = lfg->plugin_gtk->double_click_time_ms;
|
||||
#endif // HAVE_GTK
|
||||
}
|
||||
|
||||
|
||||
void bind_to_gtk_shell(struct wl_registry *wl_registry, uint32_t id) {
|
||||
#if HAVE_GTK
|
||||
gtk_shell = (struct gtk_shell1*)wl_registry_bind(wl_registry, id,
|
||||
>k_shell1_interface, 5);
|
||||
#endif // HAVE_GTK
|
||||
}
|
||||
|
||||
/* === End of code to add support of GTK Shell to libdecor-gtk === */
|
||||
|
|
|
@ -709,17 +709,15 @@ if (UNIX AND OPTION_USE_WAYLAND)
|
|||
list (APPEND STATIC_FILES "xdg-decoration-protocol.c")
|
||||
list (APPEND SHARED_FILES "xdg-decoration-protocol.c")
|
||||
endif (NOT OPTION_USE_SYSTEM_LIBDECOR)
|
||||
if (GTK_FOUND AND (OPTION_USE_SYSTEM_LIBDECOR OR OPTION_ALLOW_GTK_PLUGIN))
|
||||
add_custom_command(
|
||||
add_custom_command(
|
||||
OUTPUT gtk-shell-protocol.c gtk-shell-client-protocol.h
|
||||
COMMAND wayland-scanner private-code ${CMAKE_CURRENT_SOURCE_DIR}/../libdecor/build/gtk-shell.xml gtk-shell-protocol.c
|
||||
COMMAND wayland-scanner client-header ${CMAKE_CURRENT_SOURCE_DIR}/../libdecor/build/gtk-shell.xml gtk-shell-client-protocol.h
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../libdecor/build/gtk-shell.xml
|
||||
VERBATIM
|
||||
)
|
||||
list (APPEND STATIC_FILES "gtk-shell-protocol.c")
|
||||
list (APPEND SHARED_FILES "gtk-shell-protocol.c")
|
||||
endif (GTK_FOUND AND (OPTION_USE_SYSTEM_LIBDECOR OR OPTION_ALLOW_GTK_PLUGIN))
|
||||
)
|
||||
list (APPEND STATIC_FILES "gtk-shell-protocol.c")
|
||||
list (APPEND SHARED_FILES "gtk-shell-protocol.c")
|
||||
add_custom_command(
|
||||
OUTPUT text-input-protocol.c text-input-client-protocol.h
|
||||
COMMAND wayland-scanner private-code ${PROTOCOLS}/unstable/text-input/text-input-unstable-v3.xml text-input-protocol.c
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbcommon-compose.h>
|
||||
#include "text-input-client-protocol.h"
|
||||
#include "gtk-shell-client-protocol.h"
|
||||
#include <assert.h>
|
||||
#include <sys/mman.h>
|
||||
#include <poll.h>
|
||||
|
@ -46,7 +47,6 @@
|
|||
#include <string.h> // for strerror()
|
||||
extern "C" {
|
||||
bool libdecor_get_cursor_settings(char **theme, int *size);
|
||||
void bind_to_gtk_shell(struct wl_registry *, uint32_t);
|
||||
}
|
||||
|
||||
|
||||
|
@ -87,6 +87,8 @@ struct pointer_output {
|
|||
|
||||
|
||||
static Fl_Int_Vector key_vector; // used by Fl_Wayland_Screen_Driver::event_key()
|
||||
static struct gtk_shell1 *gtk_shell = NULL;
|
||||
static struct wl_surface *gtk_shell_surface = NULL;
|
||||
|
||||
Fl_Wayland_Screen_Driver::compositor_name Fl_Wayland_Screen_Driver::compositor =
|
||||
Fl_Wayland_Screen_Driver::unspecified;
|
||||
|
@ -199,6 +201,7 @@ static Fl_Window *event_coords_from_surface(struct wl_surface *surface,
|
|||
static void pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
|
||||
struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
|
||||
Fl_Window *win = event_coords_from_surface(surface, surface_x, surface_y);
|
||||
if (!win && gtk_shell) gtk_shell_surface = surface;
|
||||
if (!win) return;
|
||||
// use custom cursor if present
|
||||
struct wl_cursor *cursor =
|
||||
|
@ -220,6 +223,7 @@ static void pointer_leave(void *data, struct wl_pointer *wl_pointer,
|
|||
struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data;
|
||||
if (seat->pointer_focus == surface) seat->pointer_focus = NULL;
|
||||
Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface);
|
||||
gtk_shell_surface = NULL;
|
||||
if (win) {
|
||||
Fl::belowmouse(0);
|
||||
set_event_xy(win);
|
||||
|
@ -257,6 +261,15 @@ static void pointer_button(void *data,
|
|||
{
|
||||
struct Fl_Wayland_Screen_Driver::seat *seat =
|
||||
(struct Fl_Wayland_Screen_Driver::seat*)data;
|
||||
if (gtk_shell_surface && state == WL_POINTER_BUTTON_STATE_PRESSED &&
|
||||
button == BTN_MIDDLE) {
|
||||
struct gtk_surface1 *gtk_surface = gtk_shell1_get_gtk_surface(gtk_shell,
|
||||
gtk_shell_surface);
|
||||
gtk_surface1_titlebar_gesture(gtk_surface, serial, seat->wl_seat,
|
||||
GTK_SURFACE1_GESTURE_MIDDLE_CLICK);
|
||||
gtk_surface1_release(gtk_surface);
|
||||
return;
|
||||
}
|
||||
seat->serial = serial;
|
||||
int event = 0;
|
||||
Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(seat->pointer_focus);
|
||||
|
@ -1148,7 +1161,8 @@ static void registry_handle_global(void *user_data, struct wl_registry *wl_regis
|
|||
Fl_Wayland_Screen_Driver::compositor = Fl_Wayland_Screen_Driver::MUTTER;
|
||||
//fprintf(stderr, "Running the Mutter compositor\n");
|
||||
if ( version >= 5) {
|
||||
bind_to_gtk_shell(wl_registry, id);
|
||||
gtk_shell = (struct gtk_shell1*)wl_registry_bind(wl_registry, id,
|
||||
>k_shell1_interface, 5);
|
||||
}
|
||||
} else if (strcmp(interface, "weston_desktop_shell") == 0) {
|
||||
Fl_Wayland_Screen_Driver::compositor = Fl_Wayland_Screen_Driver::WESTON;
|
||||
|
|
|
@ -44,7 +44,6 @@ struct cursor_image { // as in wayland-cursor.c of the Wayland project source co
|
|||
extern "C" {
|
||||
# include "../../../libdecor/src/libdecor-plugin.h"
|
||||
uchar *fl_libdecor_titlebar_buffer(struct libdecor_frame *frame, int *w, int *h, int *stride);
|
||||
void use_FLTK_pointer_button(struct libdecor_frame *);
|
||||
}
|
||||
|
||||
#define fl_max(a,b) ((a) > (b) ? (a) : (b))
|
||||
|
@ -854,7 +853,6 @@ static void handle_configure(struct libdecor_frame *frame,
|
|||
#ifdef LIBDECOR_MR131
|
||||
if (is_1st_run) use_FLTK_toplevel_configure_cb(frame);
|
||||
#endif
|
||||
use_FLTK_pointer_button(frame);
|
||||
struct wl_output *wl_output = NULL;
|
||||
if (window->fl_win->fullscreen_active()) {
|
||||
if (!(window->state & LIBDECOR_WINDOW_STATE_FULLSCREEN)) {
|
||||
|
|
Loading…
Reference in New Issue