mirror of
https://github.com/fltk/fltk.git
synced 2026-09-25 18:03:51 +08:00
Wayland: use "XDG activation" protocol to support a window activating another window.
Build and Test / build-linux (push) Canceled after 0s
Build and Test / build-wayland (push) Canceled after 0s
Build and Test / build-wayland-arm64 (push) Canceled after 0s
Build and Test / build-macos (push) Canceled after 0s
Build and Test / build-windows (push) Canceled after 0s
Build and Test / build-windows-arm (push) Canceled after 0s
Build and Test / build-linux (push) Canceled after 0s
Build and Test / build-wayland (push) Canceled after 0s
Build and Test / build-wayland-arm64 (push) Canceled after 0s
Build and Test / build-macos (push) Canceled after 0s
Build and Test / build-windows (push) Canceled after 0s
Build and Test / build-windows-arm (push) Canceled after 0s
See https://stackoverflow.com/questions/75861687/how-to-request-a-window-be-activated-with-the-wayland-protocol explaining the "XDG activation" protocol is necessary and able to programmatically activate a window. The effect of the new code is visible with FLTK test program windowfocus.
This commit is contained in:
@@ -318,6 +318,12 @@ if(UNIX)
|
||||
else()
|
||||
set(HAVE_XDG_DIALOG 0)
|
||||
endif()
|
||||
if(EXISTS ${PROTOCOLS}/staging/xdg-activation/xdg-activation-v1.xml)
|
||||
set(HAVE_XDG_ACTIVATION 1)
|
||||
message(STATUS "Found dev files for Wayland protocol 'XDG activation'")
|
||||
else()
|
||||
set(HAVE_XDG_ACTIVATION 0)
|
||||
endif()
|
||||
if(EXISTS ${PROTOCOLS}/staging/cursor-shape/cursor-shape-v1.xml AND
|
||||
EXISTS ${PROTOCOLS}/stable/tablet/tablet-v2.xml)
|
||||
set(HAVE_CURSOR_SHAPE 1)
|
||||
|
||||
@@ -356,3 +356,10 @@
|
||||
*/
|
||||
|
||||
#cmakedefine01 HAVE_CURSOR_SHAPE
|
||||
|
||||
|
||||
/*
|
||||
* Can we use the "XDG activation" Wayland protocol?
|
||||
*/
|
||||
|
||||
#cmakedefine01 HAVE_XDG_ACTIVATION
|
||||
|
||||
@@ -101,7 +101,8 @@ beginning with \c wl_, \c xkb_ or \c libdecor_ and belong to the \c libwayland-c
|
||||
\c libwayland-cursor.so, \c libxkbcommon.so and \c libdecor.so shared libraries.
|
||||
FLTK calls also several other functions which operate other used Wayland protocols.
|
||||
These have names beginning with \c xdg_, \c zwp_text_input_v3, \c zxdg_toplevel_decoration_,
|
||||
\c gtk_shell1_, \c gtk_surface1_, \c wp_cursor_shape_ and \c zwp_tablet_v2.
|
||||
\c gtk_shell1_, \c gtk_surface1_, \c wp_cursor_shape_, \c xdg_activation_ and
|
||||
\c zwp_tablet_v2.
|
||||
FLTK never writes itself to the socket; this is done inside the functions just mentioned.
|
||||
- Compositor to client: the callback function \c wld_socket_callback() runs when there are
|
||||
data to read in the socket; it calls \c libdecor_dispatch() which reads available data from
|
||||
@@ -161,6 +162,7 @@ wayland-scanner client-header $PROTOCOLS/stable/xdg-shell/xdg-shell.xml xdg-shel
|
||||
\endcode
|
||||
Similar operations are performed for FLTK to use protocols
|
||||
<a href=https://wayland.app/protocols/xdg-dialog-v1>XDG dialog windows</a>,
|
||||
<a href=https://wayland.app/protocols/xdg-activation-v1>XDG activation</a>,
|
||||
<a href=https://wayland.app/protocols/xdg-decoration-unstable-v1>XDG decoration</a>,
|
||||
<a href=https://wayland.app/protocols/cursor-shape-v1>Cursor shape</a>,
|
||||
<a href=https://wayland.app/protocols/text-input-unstable-v3>Text input</a>,
|
||||
@@ -332,6 +334,7 @@ Here is the list of the \c interface value for all protocols and system features
|
||||
wl_data_device | support of copy/paste/drag-n-drop
|
||||
wl_output | received once for each display
|
||||
xdg_wm_base | create mapped windows
|
||||
xdg_activation_v1 | programmatically activate a window
|
||||
xdg_wm_dialog_v1 | create dialogs related to other windows
|
||||
wp_cursor_shape_manager_v1 | set cursor images using enumerated cursors
|
||||
gtk_shell1 | indicates Mutter is in use + titlebar gestures
|
||||
|
||||
@@ -817,6 +817,19 @@ if(UNIX AND FLTK_USE_WAYLAND)
|
||||
list(APPEND STATIC_FILES "xdg-shell-protocol.c")
|
||||
list(APPEND SHARED_FILES "xdg-shell-protocol.c")
|
||||
|
||||
if(HAVE_XDG_ACTIVATION)
|
||||
set(INFILE ${PROTOCOLS}/staging/xdg-activation/xdg-activation-v1.xml)
|
||||
add_custom_command(
|
||||
OUTPUT xdg-activation-protocol.c xdg-activation-client-protocol.h
|
||||
COMMAND wayland-scanner private-code ${INFILE} xdg-activation-protocol.c
|
||||
COMMAND wayland-scanner client-header ${INFILE} xdg-activation-client-protocol.h
|
||||
DEPENDS ${INFILE}
|
||||
VERBATIM
|
||||
)
|
||||
list(APPEND STATIC_FILES "xdg-activation-protocol.c")
|
||||
list(APPEND SHARED_FILES "xdg-activation-protocol.c")
|
||||
endif()
|
||||
|
||||
if(NOT USE_SYSTEM_LIBDECOR)
|
||||
set(INFILE ${PROTOCOLS}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml)
|
||||
fl_check_required_file(STOP_REQUIRED ${INFILE})
|
||||
|
||||
@@ -110,6 +110,9 @@ public:
|
||||
#if HAVE_XDG_DIALOG
|
||||
struct xdg_wm_dialog_v1 *xdg_wm_dialog;
|
||||
#endif
|
||||
#if HAVE_XDG_ACTIVATION
|
||||
struct xdg_activation_v1 *xdg_activation;
|
||||
#endif
|
||||
#if HAVE_CURSOR_SHAPE
|
||||
struct wp_cursor_shape_manager_v1 *wp_cursor_shape_manager;
|
||||
struct wp_cursor_shape_device_v1 *wp_cursor_shape_device;
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
#if HAVE_XDG_DIALOG
|
||||
# include "xdg-dialog-client-protocol.h"
|
||||
#endif
|
||||
#if HAVE_XDG_ACTIVATION
|
||||
# include "xdg-activation-client-protocol.h"
|
||||
#endif
|
||||
#if HAVE_CURSOR_SHAPE
|
||||
# include "cursor-shape-client-protocol.h"
|
||||
# include "tablet-client-protocol.h"
|
||||
@@ -1393,6 +1396,11 @@ static void registry_handle_global(void *user_data, struct wl_registry *wl_regis
|
||||
scr_driver->xdg_wm_dialog = (struct xdg_wm_dialog_v1 *)
|
||||
wl_registry_bind(wl_registry, id, &xdg_wm_dialog_v1_interface, 1);
|
||||
#endif // HAVE_XDG_DIALOG
|
||||
#if HAVE_XDG_ACTIVATION
|
||||
} else if (strcmp(interface, xdg_activation_v1_interface.name) == 0) {
|
||||
scr_driver->xdg_activation = (struct xdg_activation_v1 *)
|
||||
wl_registry_bind(wl_registry, id, &xdg_activation_v1_interface, 1);
|
||||
#endif // HAVE_XDG_ACTIVATION
|
||||
#if HAVE_CURSOR_SHAPE
|
||||
} else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) {
|
||||
scr_driver->wp_cursor_shape_manager = (struct wp_cursor_shape_manager_v1 *)
|
||||
@@ -1460,6 +1468,9 @@ Fl_Wayland_Screen_Driver::Fl_Wayland_Screen_Driver() : Fl_Unix_Screen_Driver() {
|
||||
#if HAVE_XDG_DIALOG
|
||||
xdg_wm_dialog = NULL;
|
||||
#endif
|
||||
#if HAVE_XDG_ACTIVATION
|
||||
xdg_activation = NULL;
|
||||
#endif
|
||||
#if HAVE_CURSOR_SHAPE
|
||||
wp_cursor_shape_manager = NULL;
|
||||
wp_cursor_shape_device = NULL;
|
||||
@@ -1636,6 +1647,12 @@ void Fl_Wayland_Screen_Driver::close_display() {
|
||||
xdg_wm_dialog = NULL;
|
||||
}
|
||||
#endif // HAVE_XDG_DIALOG
|
||||
#if HAVE_XDG_ACTIVATION
|
||||
if (xdg_activation) {
|
||||
xdg_activation_v1_destroy(xdg_activation);
|
||||
xdg_activation = NULL;
|
||||
}
|
||||
#endif // HAVE_XDG_ACTIVATION
|
||||
#if HAVE_CURSOR_SHAPE
|
||||
if (wp_cursor_shape_device ) {
|
||||
wp_cursor_shape_device_v1_destroy(wp_cursor_shape_device);
|
||||
|
||||
@@ -64,6 +64,7 @@ private:
|
||||
struct gl_start_support *gl_start_support_; // for support of gl_start/gl_finish
|
||||
bool is_popup_window_;
|
||||
bool previous_border_; // records whether window before being turned fullscreen had a border
|
||||
void activate_(Fl_Window *);
|
||||
public:
|
||||
inline Fl_Cursor standard_cursor() { return standard_cursor_; }
|
||||
bool in_handle_configure; // distinguish OS and user window resize
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#include <wayland-cursor.h>
|
||||
#include "../../../libdecor/build/fl_libdecor.h"
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
#if HAVE_XDG_ACTIVATION
|
||||
# include "xdg-activation-client-protocol.h"
|
||||
#endif
|
||||
#include "gtk-shell-client-protocol.h"
|
||||
#if HAVE_XDG_DIALOG
|
||||
# include "xdg-dialog-client-protocol.h"
|
||||
@@ -164,15 +167,12 @@ void Fl_Wayland_Window_Driver::take_focus()
|
||||
struct wld_window *w = fl_wl_xid(pWindow);
|
||||
if (w) {
|
||||
Fl_Window *old_first = Fl::first_window();
|
||||
struct wld_window *first_xid = (old_first ? fl_wl_xid(old_first->top_window()) : NULL);
|
||||
if (first_xid && first_xid != w && xdg_toplevel()) {
|
||||
// this will move the target window to the front
|
||||
Fl_Wayland_Window_Driver *top_dr =
|
||||
Fl_Wayland_Window_Driver::driver(old_first->top_window());
|
||||
xdg_toplevel_set_parent(xdg_toplevel(), top_dr->xdg_toplevel());
|
||||
// this will remove the parent-child relationship
|
||||
xdg_toplevel_set_parent(xdg_toplevel(), NULL);
|
||||
wl_surface_commit(w->wl_surface);
|
||||
if (old_first) {
|
||||
if (old_first->parent()) old_first = old_first->top_window();
|
||||
if (old_first != pWindow && xdg_toplevel()) {
|
||||
// let the current active window activate this window
|
||||
Fl_Wayland_Window_Driver::driver(old_first)->activate_(pWindow);
|
||||
}
|
||||
}
|
||||
// this sets the first window
|
||||
fl_wl_find(w);
|
||||
@@ -2203,3 +2203,53 @@ void Fl_Wayland_Window_Driver::un_maximize() {
|
||||
if (xid->kind == DECORATED) libdecor_frame_unset_maximized(xid->frame);
|
||||
else Fl_Window_Driver::un_maximize();
|
||||
}
|
||||
|
||||
|
||||
#if HAVE_XDG_ACTIVATION
|
||||
|
||||
static void xdg_activation_done(void *data,
|
||||
struct xdg_activation_token_v1 *xdg_activation_token_v1,
|
||||
const char *token) {
|
||||
Fl_Wayland_Screen_Driver *screen_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
|
||||
xdg_activation_v1_activate(screen_driver->xdg_activation, token, (struct wl_surface*)data);
|
||||
xdg_activation_token_v1_destroy(xdg_activation_token_v1);
|
||||
}
|
||||
|
||||
|
||||
static struct xdg_activation_token_v1_listener xdg_activation_token_listener = {
|
||||
.done = xdg_activation_done
|
||||
};
|
||||
|
||||
#endif // HAVE_XDG_ACTIVATION
|
||||
|
||||
|
||||
/* This function lets one toplevel window, currently active, activate
|
||||
another toplevel window given in its target parameter.
|
||||
Wayland requires the "XDG activation" protocol for that.
|
||||
This function also implements a fallback method used in absence of this protocol
|
||||
which brings the target to front but doesn't activate it.
|
||||
*/
|
||||
void Fl_Wayland_Window_Driver::activate_(Fl_Window *target) {
|
||||
struct wl_surface *target_surface = fl_wl_xid(target)->wl_surface;
|
||||
#if HAVE_XDG_ACTIVATION
|
||||
Fl_Wayland_Screen_Driver *screen_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
|
||||
if (screen_driver->xdg_activation) {
|
||||
struct xdg_activation_token_v1 *token = xdg_activation_v1_get_activation_token(screen_driver->xdg_activation);
|
||||
const char *appid = pWindow->xclass() ? pWindow->xclass() : get_prog_name();
|
||||
xdg_activation_token_v1_set_app_id(token, appid);
|
||||
xdg_activation_token_v1_set_surface(token, fl_wl_xid(pWindow)->wl_surface);
|
||||
xdg_activation_token_v1_set_serial(token, screen_driver->seat->serial,
|
||||
screen_driver->seat->wl_seat);
|
||||
xdg_activation_token_v1_add_listener(token, &xdg_activation_token_listener, target_surface);
|
||||
xdg_activation_token_v1_commit(token);
|
||||
} else
|
||||
#endif // HAVE_XDG_ACTIVATION
|
||||
{ // Fallback in absence of support of the adequate Wayland protocol.
|
||||
// this will move the target window to the front
|
||||
Fl_Wayland_Window_Driver *top_dr = Fl_Wayland_Window_Driver::driver(target);
|
||||
xdg_toplevel_set_parent(top_dr->xdg_toplevel(), xdg_toplevel());
|
||||
// this will remove the parent-child relationship
|
||||
xdg_toplevel_set_parent(top_dr->xdg_toplevel(), NULL);
|
||||
wl_surface_commit(target_surface);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user