2022-01-31 20:37:25 +00:00
# include <xkbcommon/xkbcommon-keysyms.h>
2020-06-11 10:42:27 +00:00
# define _GNU_SOURCE 1
2020-01-02 07:23:39 +00:00
2019-11-21 05:16:53 +00:00
# include <assert.h>
# include <stdlib.h>
# include <unistd.h>
2019-12-31 01:50:22 +00:00
# include <pthread.h>
2021-09-01 16:25:24 +00:00
# include <string.h>
2022-01-08 15:32:54 +00:00
# include <poll.h>
2021-02-18 13:59:13 +00:00
2020-01-17 09:57:39 +00:00
# include <linux/input-event-codes.h>
2020-01-19 04:37:11 +00:00
# include <X11/extensions/XTest.h>
2020-01-17 09:57:39 +00:00
# include <xkbcommon/xkbcommon.h>
2019-11-21 05:16:53 +00:00
# include <wayland-server-core.h>
2020-06-11 10:42:27 +00:00
extern " C " {
# define static
# define class class_
2019-11-21 05:16:53 +00:00
# include <wlr/backend.h>
# include <wlr/backend/headless.h>
# include <wlr/backend/multi.h>
# include <wlr/backend/libinput.h>
2021-08-03 09:04:00 +00:00
# include <wlr/interfaces/wlr_input_device.h>
# include <wlr/interfaces/wlr_keyboard.h>
2019-11-21 05:16:53 +00:00
# include <wlr/render/wlr_renderer.h>
2020-12-16 10:47:32 +00:00
# include <wlr/types/wlr_keyboard.h>
# include <wlr/types/wlr_pointer.h>
# include <wlr/types/wlr_touch.h>
2020-06-11 10:42:27 +00:00
# include <wlr/xwayland.h>
2019-11-21 05:16:53 +00:00
# include <wlr/util/log.h>
2020-06-11 10:42:27 +00:00
# undef static
# undef class
}
2019-11-21 07:41:54 +00:00
2021-02-18 13:59:13 +00:00
# include "gamescope-xwayland-protocol.h"
2021-07-29 08:09:10 +00:00
# include "gamescope-pipewire-protocol.h"
2021-02-18 13:59:13 +00:00
2020-06-11 10:42:27 +00:00
# include "wlserver.hpp"
2020-01-17 09:57:39 +00:00
# include "drm.hpp"
2019-11-21 07:41:54 +00:00
# include "main.hpp"
2020-07-03 00:40:31 +00:00
# include "steamcompmgr.hpp"
2021-09-01 16:25:24 +00:00
# include "log.hpp"
2021-09-14 11:53:19 +00:00
# include "ime.hpp"
2022-01-06 09:02:21 +00:00
# include "xwayland_ctx.hpp"
2019-11-21 05:16:53 +00:00
2021-07-29 08:09:10 +00:00
# if HAVE_PIPEWIRE
# include "pipewire.hpp"
# endif
2020-01-14 02:45:53 +00:00
# include "gpuvis_trace_utils.h"
2021-09-01 16:25:24 +00:00
static LogScope wl_log ( " wlserver " ) ;
2021-08-03 09:33:12 +00:00
static struct wlserver_t wlserver = { } ;
2019-11-21 05:16:53 +00:00
2021-02-18 13:59:13 +00:00
struct wlserver_content_override {
struct wlr_surface * surface ;
uint32_t x11_window ;
struct wl_listener surface_destroy_listener ;
} ;
2021-10-04 22:00:29 +00:00
enum wlserver_touch_click_mode g_nDefaultTouchClickMode = WLSERVER_TOUCH_CLICK_LEFT ;
enum wlserver_touch_click_mode g_nTouchClickMode = g_nDefaultTouchClickMode ;
2020-04-02 02:13:58 +00:00
2021-04-01 21:58:33 +00:00
static struct wl_list pending_surfaces = { 0 } ;
static void wlserver_surface_set_wlr ( struct wlserver_surface * surf , struct wlr_surface * wlr_surf ) ;
2020-06-11 10:42:27 +00:00
extern const struct wlr_surface_role xwayland_surface_role ;
2020-01-23 05:50:01 +00:00
2022-01-07 04:49:21 +00:00
std : : vector < ResListEntry_t > gamescope_xwayland_server_t : : retrieve_commits ( )
{
std : : vector < ResListEntry_t > commits ;
{
std : : lock_guard < std : : mutex > lock ( wayland_commit_lock ) ;
commits = std : : move ( wayland_commit_queue ) ;
}
return commits ;
}
void gamescope_xwayland_server_t : : wayland_commit ( struct wlr_surface * surf , struct wlr_buffer * buf )
{
{
std : : lock_guard < std : : mutex > lock ( wayland_commit_lock ) ;
ResListEntry_t newEntry = {
. surf = surf ,
. buf = buf ,
} ;
wayland_commit_queue . push_back ( newEntry ) ;
}
nudge_steamcompmgr ( ) ;
}
2020-01-17 00:43:21 +00:00
void xwayland_surface_role_commit ( struct wlr_surface * wlr_surface ) {
2019-11-23 06:58:07 +00:00
assert ( wlr_surface - > role = = & xwayland_surface_role ) ;
2020-01-17 00:43:21 +00:00
2022-06-07 06:52:57 +00:00
uint32_t committed = wlr_surface - > current . committed ;
wlr_surface - > current . committed = 0 ;
if ( ! ( committed & WLR_SURFACE_STATE_BUFFER ) ) {
return ;
}
2021-06-08 17:40:22 +00:00
VulkanWlrTexture_t * tex = ( VulkanWlrTexture_t * ) wlr_surface_get_texture ( wlr_surface ) ;
if ( tex = = NULL )
2020-01-17 00:43:21 +00:00
{
return ;
}
2020-05-15 13:59:01 +00:00
2021-06-08 17:40:22 +00:00
struct wlr_buffer * buf = wlr_buffer_lock ( tex - > buf ) ;
2020-05-15 13:59:01 +00:00
2021-03-11 10:24:44 +00:00
gpuvis_trace_printf ( " xwayland_surface_role_commit wlr_surface %p " , wlr_surface ) ;
2020-05-15 12:51:41 +00:00
2022-01-07 04:49:21 +00:00
gamescope_xwayland_server_t * server = ( gamescope_xwayland_server_t * ) wlr_surface - > data ;
assert ( server ) ;
server - > wayland_commit ( wlr_surface , buf ) ;
2019-11-23 06:58:07 +00:00
}
static void xwayland_surface_role_precommit ( struct wlr_surface * wlr_surface ) {
assert ( wlr_surface - > role = = & xwayland_surface_role ) ;
}
const struct wlr_surface_role xwayland_surface_role = {
. name = " wlr_xwayland_surface " ,
. commit = xwayland_surface_role_commit ,
. precommit = xwayland_surface_role_precommit ,
} ;
2022-01-06 06:59:58 +00:00
void gamescope_xwayland_server_t : : on_xwayland_ready ( void * data )
2019-12-31 09:52:32 +00:00
{
2022-01-06 06:59:58 +00:00
xwayland_ready = true ;
2021-10-22 12:25:42 +00:00
2022-01-06 06:59:58 +00:00
if ( ! xwayland_server - > options . no_touch_pointer_emulation )
2021-10-22 12:25:42 +00:00
wl_log . infof ( " Xwayland doesn't support -noTouchPointerEmulation, touch events might get duplicated " ) ;
2022-01-06 07:18:22 +00:00
dpy = XOpenDisplay ( get_nested_display_name ( ) ) ;
2019-12-31 09:52:32 +00:00
}
2022-01-06 06:59:58 +00:00
void gamescope_xwayland_server_t : : xwayland_ready_callback ( struct wl_listener * listener , void * data )
{
gamescope_xwayland_server_t * server = wl_container_of ( listener , server , xwayland_ready_listener ) ;
server - > on_xwayland_ready ( data ) ;
}
2019-12-31 09:52:32 +00:00
2021-10-18 03:17:30 +00:00
static void bump_input_counter ( )
{
inputCounter + + ;
nudge_steamcompmgr ( ) ;
}
2020-01-17 09:57:39 +00:00
static void wlserver_handle_modifiers ( struct wl_listener * listener , void * data )
{
struct wlserver_keyboard * keyboard = wl_container_of ( listener , keyboard , modifiers ) ;
2021-09-13 21:14:15 +00:00
2020-01-17 09:57:39 +00:00
wlr_seat_set_keyboard ( wlserver . wlr . seat , keyboard - > device ) ;
wlr_seat_keyboard_notify_modifiers ( wlserver . wlr . seat , & keyboard - > device - > keyboard - > modifiers ) ;
2021-10-18 03:17:30 +00:00
bump_input_counter ( ) ;
2020-01-17 09:57:39 +00:00
}
static void wlserver_handle_key ( struct wl_listener * listener , void * data )
{
struct wlserver_keyboard * keyboard = wl_container_of ( listener , keyboard , key ) ;
2020-06-11 10:42:27 +00:00
struct wlr_event_keyboard_key * event = ( struct wlr_event_keyboard_key * ) data ;
2020-05-12 09:13:20 +00:00
xkb_keycode_t keycode = event - > keycode + 8 ;
xkb_keysym_t keysym = xkb_state_key_get_one_sym ( keyboard - > device - > keyboard - > xkb_state , keycode ) ;
2020-12-16 10:47:32 +00:00
if ( wlserver . wlr . session & & event - > state = = WL_KEYBOARD_KEY_STATE_PRESSED & & keysym > = XKB_KEY_XF86Switch_VT_1 & & keysym < = XKB_KEY_XF86Switch_VT_12 ) {
2020-05-12 09:13:20 +00:00
unsigned vt = keysym - XKB_KEY_XF86Switch_VT_1 + 1 ;
wlr_session_change_vt ( wlserver . wlr . session , vt ) ;
return ;
}
2022-01-31 20:37:25 +00:00
if ( ( event - > state = = WL_KEYBOARD_KEY_STATE_PRESSED | | event - > state = = WL_KEYBOARD_KEY_STATE_RELEASED ) & & ( keysym = = XKB_KEY_XF86AudioLowerVolume | | keysym = = XKB_KEY_XF86AudioRaiseVolume ) )
{
// Always send volume+/- to root server only, to avoid it reaching the game.
struct wlr_surface * old_kb_surf = wlserver . kb_focus_surface ;
struct wlr_surface * new_kb_surf = steamcompmgr_get_server_input_surface ( 0 ) ;
if ( new_kb_surf )
{
wlserver_keyboardfocus ( new_kb_surf ) ;
wlr_seat_set_keyboard ( wlserver . wlr . seat , keyboard - > device ) ;
wlr_seat_keyboard_notify_key ( wlserver . wlr . seat , event - > time_msec , event - > keycode , event - > state ) ;
wlserver_keyboardfocus ( old_kb_surf ) ;
return ;
}
}
2020-01-17 09:57:39 +00:00
wlr_seat_set_keyboard ( wlserver . wlr . seat , keyboard - > device ) ;
wlr_seat_keyboard_notify_key ( wlserver . wlr . seat , event - > time_msec , event - > keycode , event - > state ) ;
2021-10-18 03:17:30 +00:00
bump_input_counter ( ) ;
2020-01-17 09:57:39 +00:00
}
2020-04-01 20:42:09 +00:00
static void wlserver_movecursor ( int x , int y )
2020-01-19 04:37:11 +00:00
{
wlserver . mouse_surface_cursorx + = x ;
2021-09-13 21:14:15 +00:00
2020-01-19 04:37:11 +00:00
if ( wlserver . mouse_surface_cursorx > wlserver . mouse_focus_surface - > current . width - 1 )
{
wlserver . mouse_surface_cursorx = wlserver . mouse_focus_surface - > current . width - 1 ;
}
2021-09-13 21:14:15 +00:00
2020-01-19 04:37:11 +00:00
if ( wlserver . mouse_surface_cursorx < 0 )
{
wlserver . mouse_surface_cursorx = 0 ;
}
2021-09-13 21:14:15 +00:00
2020-01-19 04:37:11 +00:00
wlserver . mouse_surface_cursory + = y ;
2021-09-13 21:14:15 +00:00
2020-01-19 04:37:11 +00:00
if ( wlserver . mouse_surface_cursory > wlserver . mouse_focus_surface - > current . height - 1 )
{
wlserver . mouse_surface_cursory = wlserver . mouse_focus_surface - > current . height - 1 ;
}
2021-09-13 21:14:15 +00:00
2020-01-19 04:37:11 +00:00
if ( wlserver . mouse_surface_cursory < 0 )
{
wlserver . mouse_surface_cursory = 0 ;
}
}
2020-01-17 09:57:39 +00:00
static void wlserver_handle_pointer_motion ( struct wl_listener * listener , void * data )
{
2020-06-11 10:42:27 +00:00
struct wlr_event_pointer_motion * event = ( struct wlr_event_pointer_motion * ) data ;
2022-08-19 21:18:18 +00:00
// TODO: Pick the xwayland_server with active focus
auto server = steamcompmgr_get_focused_server ( ) ;
if ( server ! = NULL )
{
2022-08-19 21:28:38 +00:00
server - > ctx - > accum_x + = event - > unaccel_dx ;
server - > ctx - > accum_y + = event - > unaccel_dy ;
float dx , dy ;
server - > ctx - > accum_x = modf ( server - > ctx - > accum_x , & dx ) ;
server - > ctx - > accum_y = modf ( server - > ctx - > accum_y , & dy ) ;
2022-08-19 21:18:18 +00:00
XTestFakeRelativeMotionEvent ( server - > get_xdisplay ( ) , int ( dx ) , int ( dy ) , CurrentTime ) ;
XFlush ( server - > get_xdisplay ( ) ) ;
}
2020-01-17 09:57:39 +00:00
}
static void wlserver_handle_pointer_button ( struct wl_listener * listener , void * data )
{
struct wlserver_pointer * pointer = wl_container_of ( listener , pointer , button ) ;
2020-06-11 10:42:27 +00:00
struct wlr_event_pointer_button * event = ( struct wlr_event_pointer_button * ) data ;
2021-09-13 21:14:15 +00:00
2020-01-17 09:57:39 +00:00
wlr_seat_pointer_notify_button ( wlserver . wlr . seat , event - > time_msec , event - > button , event - > state ) ;
2021-09-13 19:29:17 +00:00
}
static void wlserver_handle_pointer_axis ( struct wl_listener * listener , void * data )
{
struct wlserver_pointer * pointer = wl_container_of ( listener , pointer , axis ) ;
struct wlr_event_pointer_axis * event = ( struct wlr_event_pointer_axis * ) data ;
wlr_seat_pointer_notify_axis ( wlserver . wlr . seat , event - > time_msec , event - > orientation , event - > delta , event - > delta_discrete , event - > source ) ;
}
static void wlserver_handle_pointer_frame ( struct wl_listener * listener , void * data )
{
2020-01-17 09:57:39 +00:00
wlr_seat_pointer_notify_frame ( wlserver . wlr . seat ) ;
2021-10-18 03:17:30 +00:00
bump_input_counter ( ) ;
2020-01-17 09:57:39 +00:00
}
2020-04-02 02:13:58 +00:00
static inline uint32_t steamcompmgr_button_to_wlserver_button ( int button )
{
switch ( button )
{
default :
2022-04-29 00:59:22 +00:00
case WLSERVER_TOUCH_CLICK_HOVER :
2020-04-02 02:13:58 +00:00
return 0 ;
2022-04-29 00:59:22 +00:00
case WLSERVER_TOUCH_CLICK_LEFT :
2020-04-02 02:13:58 +00:00
return BTN_LEFT ;
2022-04-29 00:59:22 +00:00
case WLSERVER_TOUCH_CLICK_RIGHT :
2020-04-02 02:13:58 +00:00
return BTN_RIGHT ;
2022-04-29 00:59:22 +00:00
case WLSERVER_TOUCH_CLICK_MIDDLE :
2020-04-02 02:13:58 +00:00
return BTN_MIDDLE ;
}
}
2022-02-10 02:19:08 +00:00
std : : atomic < bool > g_bPendingTouchMovement = { false } ;
2020-01-17 09:57:39 +00:00
static void wlserver_handle_touch_down ( struct wl_listener * listener , void * data )
{
struct wlserver_touch * touch = wl_container_of ( listener , touch , down ) ;
2020-06-11 10:42:27 +00:00
struct wlr_event_touch_down * event = ( struct wlr_event_touch_down * ) data ;
2021-09-13 21:14:15 +00:00
2022-06-17 23:42:22 +00:00
wlserver_touchdown ( event - > x , event - > y , event - > touch_id , event - > time_msec ) ;
2020-01-17 09:57:39 +00:00
}
static void wlserver_handle_touch_up ( struct wl_listener * listener , void * data )
{
2020-05-04 07:42:24 +00:00
struct wlserver_touch * touch = wl_container_of ( listener , touch , up ) ;
2020-06-11 10:42:27 +00:00
struct wlr_event_touch_up * event = ( struct wlr_event_touch_up * ) data ;
2020-05-04 07:42:24 +00:00
2022-06-17 23:42:22 +00:00
wlserver_touchup ( event - > touch_id , event - > time_msec ) ;
2020-01-17 09:57:39 +00:00
}
static void wlserver_handle_touch_motion ( struct wl_listener * listener , void * data )
{
struct wlserver_touch * touch = wl_container_of ( listener , touch , motion ) ;
2020-06-11 10:42:27 +00:00
struct wlr_event_touch_motion * event = ( struct wlr_event_touch_motion * ) data ;
2021-09-13 21:14:15 +00:00
2022-06-17 23:42:22 +00:00
wlserver_touchmotion ( event - > x , event - > y , event - > touch_id , event - > time_msec ) ;
2020-01-17 09:57:39 +00:00
}
static void wlserver_new_input ( struct wl_listener * listener , void * data )
{
2020-06-11 10:42:27 +00:00
struct wlr_input_device * device = ( struct wlr_input_device * ) data ;
2020-01-17 09:57:39 +00:00
switch ( device - > type )
{
case WLR_INPUT_DEVICE_KEYBOARD :
{
2020-06-11 10:42:27 +00:00
struct wlserver_keyboard * pKB = ( struct wlserver_keyboard * ) calloc ( 1 , sizeof ( struct wlserver_keyboard ) ) ;
2021-09-13 20:52:07 +00:00
2020-01-17 09:57:39 +00:00
pKB - > device = device ;
2021-09-13 21:14:15 +00:00
2020-01-17 09:57:39 +00:00
struct xkb_rule_names rules = { 0 } ;
struct xkb_context * context = xkb_context_new ( XKB_CONTEXT_NO_FLAGS ) ;
2021-09-13 20:52:07 +00:00
rules . rules = getenv ( " XKB_DEFAULT_RULES " ) ;
rules . model = getenv ( " XKB_DEFAULT_MODEL " ) ;
rules . layout = getenv ( " XKB_DEFAULT_LAYOUT " ) ;
rules . variant = getenv ( " XKB_DEFAULT_VARIANT " ) ;
rules . options = getenv ( " XKB_DEFAULT_OPTIONS " ) ;
struct xkb_keymap * keymap = xkb_keymap_new_from_names ( context , & rules ,
2020-01-17 09:57:39 +00:00
XKB_KEYMAP_COMPILE_NO_FLAGS ) ;
2021-09-13 20:52:07 +00:00
2020-01-17 09:57:39 +00:00
wlr_keyboard_set_keymap ( device - > keyboard , keymap ) ;
xkb_keymap_unref ( keymap ) ;
xkb_context_unref ( context ) ;
wlr_keyboard_set_repeat_info ( device - > keyboard , 25 , 600 ) ;
2021-09-13 21:14:15 +00:00
2021-09-23 08:40:18 +00:00
device - > keyboard - > data = pKB ;
2020-01-17 09:57:39 +00:00
pKB - > modifiers . notify = wlserver_handle_modifiers ;
wl_signal_add ( & device - > keyboard - > events . modifiers , & pKB - > modifiers ) ;
2021-09-13 21:14:15 +00:00
2020-01-17 09:57:39 +00:00
pKB - > key . notify = wlserver_handle_key ;
wl_signal_add ( & device - > keyboard - > events . key , & pKB - > key ) ;
}
break ;
case WLR_INPUT_DEVICE_POINTER :
{
2020-06-11 10:42:27 +00:00
struct wlserver_pointer * pointer = ( struct wlserver_pointer * ) calloc ( 1 , sizeof ( struct wlserver_pointer ) ) ;
2021-09-13 21:14:15 +00:00
2020-01-17 09:57:39 +00:00
pointer - > device = device ;
pointer - > motion . notify = wlserver_handle_pointer_motion ;
wl_signal_add ( & device - > pointer - > events . motion , & pointer - > motion ) ;
pointer - > button . notify = wlserver_handle_pointer_button ;
wl_signal_add ( & device - > pointer - > events . button , & pointer - > button ) ;
2021-09-13 19:29:17 +00:00
pointer - > axis . notify = wlserver_handle_pointer_axis ;
wl_signal_add ( & device - > pointer - > events . axis , & pointer - > axis ) ;
pointer - > frame . notify = wlserver_handle_pointer_frame ;
wl_signal_add ( & device - > pointer - > events . frame , & pointer - > frame ) ;
2020-01-17 09:57:39 +00:00
}
break ;
case WLR_INPUT_DEVICE_TOUCH :
{
2020-06-11 10:42:27 +00:00
struct wlserver_touch * touch = ( struct wlserver_touch * ) calloc ( 1 , sizeof ( struct wlserver_touch ) ) ;
2021-09-13 21:14:15 +00:00
2020-01-17 09:57:39 +00:00
touch - > device = device ;
2021-09-13 21:14:15 +00:00
2020-01-17 09:57:39 +00:00
touch - > down . notify = wlserver_handle_touch_down ;
wl_signal_add ( & device - > touch - > events . down , & touch - > down ) ;
touch - > up . notify = wlserver_handle_touch_up ;
wl_signal_add ( & device - > touch - > events . up , & touch - > up ) ;
touch - > motion . notify = wlserver_handle_touch_motion ;
wl_signal_add ( & device - > touch - > events . motion , & touch - > motion ) ;
}
break ;
default :
break ;
}
}
2021-09-14 11:53:19 +00:00
static struct wl_listener new_input_listener = { . notify = wlserver_new_input } ;
2020-01-17 09:57:39 +00:00
2021-04-01 21:58:33 +00:00
static void wlserver_new_surface ( struct wl_listener * l , void * data )
2020-07-03 01:45:00 +00:00
{
2021-04-01 21:58:33 +00:00
struct wlr_surface * wlr_surf = ( struct wlr_surface * ) data ;
uint32_t id = wl_resource_get_id ( wlr_surf - > resource ) ;
2020-07-03 01:45:00 +00:00
2021-04-01 21:58:33 +00:00
struct wlserver_surface * s , * tmp ;
wl_list_for_each_safe ( s , tmp , & pending_surfaces , pending_link )
{
2022-07-14 20:44:19 +00:00
if ( s - > wl_id = = id & & s - > wlr = = nullptr )
2021-04-01 21:58:33 +00:00
{
wlserver_surface_set_wlr ( s , wlr_surf ) ;
}
}
2020-07-03 01:45:00 +00:00
}
2021-09-14 11:53:19 +00:00
static struct wl_listener new_surface_listener = { . notify = wlserver_new_surface } ;
2021-04-01 21:58:33 +00:00
2022-01-08 15:32:54 +00:00
void gamescope_xwayland_server_t : : destroy_content_override ( struct wlserver_content_override * co )
2021-02-18 13:59:13 +00:00
{
wl_list_remove ( & co - > surface_destroy_listener . link ) ;
content_overrides . erase ( co - > x11_window ) ;
free ( co ) ;
}
static void content_override_handle_surface_destroy ( struct wl_listener * listener , void * data )
{
struct wlserver_content_override * co = wl_container_of ( listener , co , surface_destroy_listener ) ;
2022-01-08 15:32:54 +00:00
assert ( co - > surface ) ;
gamescope_xwayland_server_t * server = ( gamescope_xwayland_server_t * ) co - > surface - > data ;
2022-03-25 23:13:05 +00:00
if ( ! server )
{
wl_log . errorf ( " Unable to destroy content override for surface %p - was it launched on the wrong DISPLAY or did the surface never get wl_id? \n " , co - > surface ) ;
return ;
}
2022-01-08 15:32:54 +00:00
server - > destroy_content_override ( co ) ;
2021-02-18 13:59:13 +00:00
}
2022-01-08 15:32:54 +00:00
void gamescope_xwayland_server_t : : handle_override_window_content ( struct wl_client * client , struct wl_resource * resource , struct wl_resource * surface_resource , uint32_t x11_window )
2021-02-18 13:59:13 +00:00
{
struct wlr_surface * surface = wlr_surface_from_resource ( surface_resource ) ;
if ( content_overrides . count ( x11_window ) ) {
destroy_content_override ( content_overrides [ x11_window ] ) ;
}
struct wlserver_content_override * co = ( struct wlserver_content_override * ) calloc ( 1 , sizeof ( * co ) ) ;
co - > surface = surface ;
co - > x11_window = x11_window ;
co - > surface_destroy_listener . notify = content_override_handle_surface_destroy ;
wl_signal_add ( & surface - > events . destroy , & co - > surface_destroy_listener ) ;
content_overrides [ x11_window ] = co ;
}
2022-02-06 23:09:32 +00:00
struct wl_client * gamescope_xwayland_server_t : : get_client ( )
{
return xwayland_server - > client ;
}
2022-01-08 15:32:54 +00:00
static void gamescope_xwayland_handle_override_window_content ( struct wl_client * client , struct wl_resource * resource , struct wl_resource * surface_resource , uint32_t x11_window )
{
2022-02-04 00:49:26 +00:00
// This should ideally use the surface's xwayland, but we don't know it.
// We probably need to change our override_window_content protocol to add a
// xwayland socket name.
//
// Right now, the surface -> xwayland association comes from the
// handle_wl_id stuff from steamcompmgr.
// However, this surface has no associated X window, and won't recieve
// wl_id stuff as it's meant to replace another window's surface
// which we can't do without knowing the x11_window's xwayland server
// here for it to do that override logic in the first place.
//
// So... Just assume it comes from server 0 for now.
gamescope_xwayland_server_t * server = wlserver_get_xwayland_server ( 0 ) ;
assert ( server ) ;
2022-01-08 15:32:54 +00:00
server - > handle_override_window_content ( client , resource , surface_resource , x11_window ) ;
}
2021-02-18 13:59:13 +00:00
static void gamescope_xwayland_handle_destroy ( struct wl_client * client , struct wl_resource * resource )
{
wl_resource_destroy ( resource ) ;
}
static const struct gamescope_xwayland_interface gamescope_xwayland_impl = {
. destroy = gamescope_xwayland_handle_destroy ,
. override_window_content = gamescope_xwayland_handle_override_window_content ,
} ;
static void gamescope_xwayland_bind ( struct wl_client * client , void * data , uint32_t version , uint32_t id )
{
struct wl_resource * resource = wl_resource_create ( client , & gamescope_xwayland_interface , version , id ) ;
wl_resource_set_implementation ( resource , & gamescope_xwayland_impl , NULL , NULL ) ;
}
static void create_gamescope_xwayland ( void )
{
uint32_t version = 1 ;
2021-07-27 08:46:03 +00:00
wl_global_create ( wlserver . display , & gamescope_xwayland_interface , version , NULL , gamescope_xwayland_bind ) ;
2021-02-18 13:59:13 +00:00
}
2021-09-15 16:04:44 +00:00
# if HAVE_PIPEWIRE
2021-07-29 08:09:10 +00:00
static void gamescope_pipewire_handle_destroy ( struct wl_client * client , struct wl_resource * resource )
{
wl_resource_destroy ( resource ) ;
}
static const struct gamescope_pipewire_interface gamescope_pipewire_impl = {
. destroy = gamescope_pipewire_handle_destroy ,
} ;
static void gamescope_pipewire_bind ( struct wl_client * client , void * data , uint32_t version , uint32_t id )
{
struct wl_resource * resource = wl_resource_create ( client , & gamescope_pipewire_interface , version , id ) ;
wl_resource_set_implementation ( resource , & gamescope_pipewire_impl , NULL , NULL ) ;
gamescope_pipewire_send_stream_node ( resource , get_pipewire_stream_node_id ( ) ) ;
}
static void create_gamescope_pipewire ( void )
{
uint32_t version = 1 ;
wl_global_create ( wlserver . display , & gamescope_pipewire_interface , version , NULL , gamescope_pipewire_bind ) ;
}
2021-09-15 16:04:44 +00:00
# endif
2021-07-29 08:09:10 +00:00
2021-07-27 12:09:04 +00:00
static void handle_session_active ( struct wl_listener * listener , void * data )
{
2021-07-28 16:17:07 +00:00
if ( wlserver . wlr . session - > active ) {
g_DRM . out_of_date = true ;
g_DRM . needs_modeset = true ;
}
2021-07-27 12:09:04 +00:00
g_DRM . paused = ! wlserver . wlr . session - > active ;
2021-09-01 16:25:24 +00:00
wl_log . infof ( " Session %s " , g_DRM . paused ? " paused " : " resumed " ) ;
2021-07-27 12:09:04 +00:00
}
2021-09-01 16:31:45 +00:00
static void handle_wlr_log ( enum wlr_log_importance importance , const char * fmt , va_list args )
{
enum LogPriority prio ;
switch ( importance ) {
case WLR_ERROR :
prio = LOG_ERROR ;
break ;
case WLR_INFO :
prio = LOG_INFO ;
break ;
default :
prio = LOG_DEBUG ;
break ;
}
wl_log . vlogf ( prio , fmt , args ) ;
}
2022-05-05 10:13:39 +00:00
void wlserver_set_output_info ( const wlserver_output_info * info )
{
wlr_output_destroy_global ( wlserver . wlr . output ) ;
wlr_output_set_name ( wlserver . wlr . output , info - > name ) ;
wlr_output_set_description ( wlserver . wlr . output , info - > description ) ;
wlserver . wlr . output - > phys_width = info - > phys_width ;
wlserver . wlr . output - > phys_height = info - > phys_height ;
wlr_output_create_global ( wlserver . wlr . output ) ;
}
2021-09-14 14:59:46 +00:00
bool wlsession_init ( void ) {
2021-09-01 16:31:45 +00:00
wlr_log_init ( WLR_DEBUG , handle_wlr_log ) ;
2021-09-01 16:25:24 +00:00
2021-07-27 08:46:03 +00:00
wlserver . display = wl_display_create ( ) ;
2022-07-15 04:35:09 +00:00
wlserver . wlr . headless_backend = wlr_headless_backend_create ( wlserver . display ) ;
wlserver . wlr . output = wlr_headless_add_output ( wlserver . wlr . headless_backend , 1280 , 720 ) ;
strncpy ( wlserver . wlr . output - > make , " gamescope " , sizeof ( wlserver . wlr . output - > make ) ) ;
strncpy ( wlserver . wlr . output - > model , " gamescope " , sizeof ( wlserver . wlr . output - > model ) ) ;
const struct wlserver_output_info output_info = {
. name = " Virtual-1 " ,
. description = " Virtual gamescope output " ,
} ;
wlserver_set_output_info ( & output_info ) ;
2019-12-16 20:13:32 +00:00
2021-07-27 09:24:04 +00:00
if ( BIsNested ( ) )
2021-09-14 14:59:46 +00:00
return true ;
2020-07-23 11:52:07 +00:00
2021-07-27 09:24:04 +00:00
wlserver . wlr . session = wlr_session_create ( wlserver . display ) ;
if ( wlserver . wlr . session = = nullptr )
2021-07-22 13:08:34 +00:00
{
2021-09-01 16:25:24 +00:00
wl_log . errorf ( " Failed to create session " ) ;
2021-09-14 14:59:46 +00:00
return false ;
2021-07-27 09:24:04 +00:00
}
2021-07-27 12:09:04 +00:00
wlserver . session_active . notify = handle_session_active ;
wl_signal_add ( & wlserver . wlr . session - > events . active , & wlserver . session_active ) ;
2021-09-14 14:59:46 +00:00
return true ;
2021-07-27 09:24:04 +00:00
}
2021-07-28 15:58:07 +00:00
static void kms_device_handle_change ( struct wl_listener * listener , void * data )
{
g_DRM . out_of_date = true ;
2021-09-01 16:25:24 +00:00
wl_log . infof ( " Got change event for KMS device " ) ;
2021-09-02 21:52:16 +00:00
nudge_steamcompmgr ( ) ;
2021-07-28 15:58:07 +00:00
}
2021-07-27 09:24:04 +00:00
int wlsession_open_kms ( const char * device_name ) {
2021-07-28 15:58:07 +00:00
struct wlr_device * device = nullptr ;
2021-07-27 09:24:04 +00:00
if ( device_name ! = nullptr )
{
2021-07-28 15:58:07 +00:00
device = wlr_session_open_file ( wlserver . wlr . session , device_name ) ;
2021-07-27 09:24:04 +00:00
if ( device = = nullptr )
return - 1 ;
if ( ! drmIsKMS ( device - > fd ) )
2021-07-22 13:08:34 +00:00
{
2021-09-01 16:25:24 +00:00
wl_log . errorf ( " '%s' is not a KMS device " , device_name ) ;
2021-07-27 09:24:04 +00:00
wlr_session_close_file ( wlserver . wlr . session , device ) ;
return - 1 ;
2021-07-22 13:08:34 +00:00
}
}
2021-07-27 09:24:04 +00:00
else
{
ssize_t n = wlr_session_find_gpus ( wlserver . wlr . session , 1 , & device ) ;
if ( n < 0 )
{
2021-09-01 16:25:24 +00:00
wl_log . errorf ( " Failed to list GPUs " ) ;
2021-07-27 09:24:04 +00:00
return - 1 ;
}
if ( n = = 0 )
{
2021-09-01 16:25:24 +00:00
wl_log . errorf ( " No GPU detected " ) ;
2021-07-27 09:24:04 +00:00
return - 1 ;
}
}
2021-07-28 15:58:07 +00:00
struct wl_listener * listener = new wl_listener ( ) ;
listener - > notify = kms_device_handle_change ;
wl_signal_add ( & device - > events . change , listener ) ;
return device - > fd ;
2021-07-27 09:24:04 +00:00
}
2022-01-06 06:59:58 +00:00
gamescope_xwayland_server_t : : gamescope_xwayland_server_t ( wl_display * display )
{
struct wlr_xwayland_server_options xwayland_options = {
. lazy = false ,
. enable_wm = false ,
. no_touch_pointer_emulation = true ,
} ;
xwayland_server = wlr_xwayland_server_create ( display , & xwayland_options ) ;
wl_signal_add ( & xwayland_server - > events . ready , & xwayland_ready_listener ) ;
}
gamescope_xwayland_server_t : : ~ gamescope_xwayland_server_t ( )
{
wlr_xwayland_server_destroy ( xwayland_server ) ;
}
2021-09-14 15:03:52 +00:00
bool wlserver_init ( void ) {
2021-07-27 09:24:04 +00:00
assert ( wlserver . display ! = nullptr ) ;
2021-09-14 15:03:52 +00:00
bool bIsDRM = ! BIsNested ( ) ;
2021-07-27 09:24:04 +00:00
wl_list_init ( & pending_surfaces ) ;
2021-07-27 08:46:03 +00:00
wlserver . event_loop = wl_display_get_event_loop ( wlserver . display ) ;
2020-07-23 11:52:07 +00:00
2021-07-27 08:46:03 +00:00
wlserver . wlr . multi_backend = wlr_multi_backend_create ( wlserver . display ) ;
2022-05-05 10:13:39 +00:00
wlr_multi_backend_add ( wlserver . wlr . multi_backend , wlserver . wlr . headless_backend ) ;
2020-07-23 11:52:07 +00:00
2021-09-14 14:59:46 +00:00
assert ( wlserver . event_loop & & wlserver . wlr . multi_backend ) ;
2019-11-21 05:16:53 +00:00
2020-07-23 11:52:07 +00:00
wl_signal_add ( & wlserver . wlr . multi_backend - > events . new_input , & new_input_listener ) ;
2019-11-21 05:16:53 +00:00
if ( bIsDRM = = True )
{
2021-07-27 08:46:03 +00:00
wlserver . wlr . libinput_backend = wlr_libinput_backend_create ( wlserver . display , wlserver . wlr . session ) ;
2020-01-17 09:57:39 +00:00
if ( wlserver . wlr . libinput_backend = = NULL )
{
2021-09-14 14:59:46 +00:00
return false ;
2019-11-21 05:16:53 +00:00
}
2020-01-17 09:57:39 +00:00
wlr_multi_backend_add ( wlserver . wlr . multi_backend , wlserver . wlr . libinput_backend ) ;
2019-11-21 05:16:53 +00:00
}
2021-08-03 09:04:00 +00:00
2021-09-23 08:40:18 +00:00
// Create a stub wlr_keyboard only used to set the keymap
// We need to wait for the backend to be started before adding the device
struct wlr_keyboard * kbd = ( struct wlr_keyboard * ) calloc ( 1 , sizeof ( * kbd ) ) ;
wlr_keyboard_init ( kbd , nullptr ) ;
2021-08-03 09:04:00 +00:00
2021-09-23 08:40:18 +00:00
struct wlr_input_device * kbd_dev = ( struct wlr_input_device * ) calloc ( 1 , sizeof ( * kbd_dev ) ) ;
wlr_input_device_init ( kbd_dev , WLR_INPUT_DEVICE_KEYBOARD , nullptr , " virtual " , 0 , 0 ) ;
kbd_dev - > keyboard = kbd ;
2021-09-14 11:47:55 +00:00
2021-09-23 08:40:18 +00:00
wlserver . wlr . virtual_keyboard_device = kbd_dev ;
2020-07-23 11:52:07 +00:00
2021-08-02 16:00:38 +00:00
wlserver . wlr . renderer = vulkan_renderer_create ( ) ;
2019-11-21 05:16:53 +00:00
2021-07-27 08:46:03 +00:00
wlr_renderer_init_wl_display ( wlserver . wlr . renderer , wlserver . display ) ;
2019-11-21 05:16:53 +00:00
2021-07-27 08:46:03 +00:00
wlserver . wlr . compositor = wlr_compositor_create ( wlserver . display , wlserver . wlr . renderer ) ;
2021-04-01 21:58:33 +00:00
wl_signal_add ( & wlserver . wlr . compositor - > events . new_surface , & new_surface_listener ) ;
2021-02-18 13:59:13 +00:00
2021-09-14 11:53:19 +00:00
create_ime_manager ( & wlserver ) ;
2021-02-18 13:59:13 +00:00
create_gamescope_xwayland ( ) ;
2021-04-28 04:17:36 +00:00
2021-07-29 08:09:10 +00:00
# if HAVE_PIPEWIRE
create_gamescope_pipewire ( ) ;
# endif
2020-09-01 18:52:55 +00:00
int result = - 1 ;
int display_slot = 0 ;
while ( result ! = 0 & & display_slot < 128 )
{
2021-04-28 04:17:36 +00:00
sprintf ( wlserver . wl_display_name , " gamescope-%d " , display_slot ) ;
2021-07-27 08:46:03 +00:00
result = wl_display_add_socket ( wlserver . display , wlserver . wl_display_name ) ;
2020-09-01 18:52:55 +00:00
display_slot + + ;
}
if ( result ! = 0 )
2020-01-17 09:57:39 +00:00
{
2021-09-01 16:25:24 +00:00
wl_log . errorf_errno ( " Unable to open wayland socket " ) ;
2020-01-17 09:57:39 +00:00
wlr_backend_destroy ( wlserver . wlr . multi_backend ) ;
2021-09-14 14:59:46 +00:00
return false ;
2019-11-21 05:16:53 +00:00
}
2020-05-12 13:55:01 +00:00
2021-07-27 08:46:03 +00:00
wlserver . wlr . seat = wlr_seat_create ( wlserver . display , " seat0 " ) ;
2020-09-18 21:59:26 +00:00
wlr_seat_set_capabilities ( wlserver . wlr . seat , WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_KEYBOARD | WL_SEAT_CAPABILITY_TOUCH ) ;
2019-11-21 05:16:53 +00:00
2021-09-01 16:25:24 +00:00
wl_log . infof ( " Running compositor on wayland display '%s' " , wlserver . wl_display_name ) ;
2019-11-21 05:16:53 +00:00
2020-01-17 09:57:39 +00:00
if ( ! wlr_backend_start ( wlserver . wlr . multi_backend ) )
{
2021-09-01 16:25:24 +00:00
wl_log . errorf ( " Failed to start backend " ) ;
2020-01-17 09:57:39 +00:00
wlr_backend_destroy ( wlserver . wlr . multi_backend ) ;
2021-07-27 08:46:03 +00:00
wl_display_destroy ( wlserver . display ) ;
2021-09-14 14:59:46 +00:00
return false ;
2019-11-21 05:16:53 +00:00
}
2021-09-23 08:40:18 +00:00
wl_signal_emit ( & wlserver . wlr . multi_backend - > events . new_input , kbd_dev ) ;
2021-08-03 09:04:00 +00:00
2021-09-14 06:24:07 +00:00
int refresh = g_nNestedRefresh ;
if ( refresh = = 0 ) {
refresh = g_nOutputRefresh ;
}
2021-08-02 16:13:55 +00:00
wlr_output_enable ( wlserver . wlr . output , true ) ;
2021-09-14 06:24:07 +00:00
wlr_output_set_custom_mode ( wlserver . wlr . output , g_nNestedWidth , g_nNestedHeight , refresh * 1000 ) ;
2021-08-03 08:42:54 +00:00
if ( ! wlr_output_commit ( wlserver . wlr . output ) )
{
2021-09-01 16:25:24 +00:00
wl_log . errorf ( " Failed to commit noop output " ) ;
2021-09-14 14:59:46 +00:00
return false ;
2021-08-03 08:42:54 +00:00
}
2021-08-02 16:13:55 +00:00
2022-01-07 04:41:28 +00:00
for ( int i = 0 ; i < g_nXWaylandCount ; i + + )
{
auto server = std : : make_unique < gamescope_xwayland_server_t > ( wlserver . display ) ;
2021-08-02 16:13:55 +00:00
2022-01-07 04:41:28 +00:00
while ( ! server - > is_xwayland_ready ( ) ) {
wl_display_flush_clients ( wlserver . display ) ;
if ( wl_event_loop_dispatch ( wlserver . event_loop , - 1 ) < 0 ) {
wl_log . errorf ( " wl_event_loop_dispatch failed \n " ) ;
return false ;
}
2021-07-27 08:25:56 +00:00
}
2022-01-07 04:41:28 +00:00
wlserver . wlr . xwayland_servers . emplace_back ( std : : move ( server ) ) ;
}
2021-07-27 08:30:14 +00:00
2021-09-14 14:59:46 +00:00
return true ;
2019-11-21 05:16:53 +00:00
}
2019-12-31 01:50:22 +00:00
pthread_mutex_t waylock = PTHREAD_MUTEX_INITIALIZER ;
void wlserver_lock ( void )
{
pthread_mutex_lock ( & waylock ) ;
}
void wlserver_unlock ( void )
{
2021-07-27 08:46:03 +00:00
wl_display_flush_clients ( wlserver . display ) ;
2019-12-31 01:50:22 +00:00
pthread_mutex_unlock ( & waylock ) ;
}
2022-01-20 08:55:26 +00:00
extern std : : mutex g_SteamCompMgrXWaylandServerMutex ;
2021-09-10 09:01:54 +00:00
void wlserver_run ( void )
2019-11-21 05:16:53 +00:00
{
2021-07-25 18:42:16 +00:00
struct pollfd pollfd = {
2021-07-27 08:46:03 +00:00
. fd = wl_event_loop_get_fd ( wlserver . event_loop ) ,
2021-07-25 18:42:16 +00:00
. events = POLLIN ,
} ;
2021-08-10 10:05:49 +00:00
while ( g_bRun ) {
2021-07-25 18:42:16 +00:00
int ret = poll ( & pollfd , 1 , - 1 ) ;
if ( ret < 0 ) {
2020-01-16 01:48:20 +00:00
if ( errno = = EINTR )
continue ;
2021-09-01 16:25:24 +00:00
wl_log . errorf_errno ( " poll failed " ) ;
2021-07-25 18:42:16 +00:00
break ;
2019-12-31 01:50:22 +00:00
}
2020-01-16 01:48:20 +00:00
2021-07-25 18:42:16 +00:00
if ( pollfd . revents & ( POLLHUP | POLLERR ) ) {
2021-09-01 16:25:24 +00:00
wl_log . errorf ( " socket %s " , ( pollfd . revents & POLLERR ) ? " error " : " closed " ) ;
2021-07-25 18:42:16 +00:00
break ;
}
if ( pollfd . revents & POLLIN ) {
// We have wayland stuff to do, do it while locked
wlserver_lock ( ) ;
2021-07-27 08:46:03 +00:00
wl_display_flush_clients ( wlserver . display ) ;
int ret = wl_event_loop_dispatch ( wlserver . event_loop , 0 ) ;
2019-12-31 06:50:49 +00:00
if ( ret < 0 ) {
break ;
}
2021-07-25 18:42:16 +00:00
wlserver_unlock ( ) ;
}
2019-12-31 01:50:22 +00:00
}
2022-01-20 08:55:26 +00:00
// Released when steamcompmgr closes.
std : : unique_lock < std : : mutex > xwayland_server_guard ( g_SteamCompMgrXWaylandServerMutex ) ;
2019-11-21 05:16:53 +00:00
// We need to shutdown Xwayland before disconnecting all clients, otherwise
// wlroots will restart it automatically.
2022-01-06 06:59:58 +00:00
wlserver . wlr . xwayland_servers . clear ( ) ;
2021-07-27 08:46:03 +00:00
wl_display_destroy_clients ( wlserver . display ) ;
wl_display_destroy ( wlserver . display ) ;
2019-11-21 05:16:53 +00:00
}
2020-01-02 07:23:39 +00:00
2020-01-17 09:57:39 +00:00
void wlserver_keyboardfocus ( struct wlr_surface * surface )
{
struct wlr_keyboard * keyboard = wlr_seat_get_keyboard ( wlserver . wlr . seat ) ;
2021-09-14 11:44:35 +00:00
if ( keyboard = = nullptr )
wlr_seat_keyboard_notify_enter ( wlserver . wlr . seat , surface , nullptr , 0 , nullptr ) ;
else
2020-01-17 09:57:39 +00:00
wlr_seat_keyboard_notify_enter ( wlserver . wlr . seat , surface , keyboard - > keycodes , keyboard - > num_keycodes , & keyboard - > modifiers ) ;
2022-01-31 20:37:25 +00:00
wlserver . kb_focus_surface = surface ;
2020-01-17 09:57:39 +00:00
}
2020-01-18 23:10:14 +00:00
void wlserver_key ( uint32_t key , bool press , uint32_t time )
{
2021-09-14 11:47:55 +00:00
assert ( wlserver . wlr . virtual_keyboard_device ! = nullptr ) ;
wlr_seat_set_keyboard ( wlserver . wlr . seat , wlserver . wlr . virtual_keyboard_device ) ;
2020-01-18 23:10:14 +00:00
wlr_seat_keyboard_notify_key ( wlserver . wlr . seat , time , key , press ) ;
2021-10-18 03:17:30 +00:00
bump_input_counter ( ) ;
2020-01-18 23:10:14 +00:00
}
2021-09-13 06:39:34 +00:00
void wlserver_mousefocus ( struct wlr_surface * wlrsurface , int x /* = 0 */ , int y /* = 0 */ )
2020-01-02 07:23:39 +00:00
{
2020-01-17 09:57:39 +00:00
wlserver . mouse_focus_surface = wlrsurface ;
2021-09-13 06:39:34 +00:00
if ( x < wlrsurface - > current . width & & y < wlrsurface - > current . height )
{
wlserver . mouse_surface_cursorx = x ;
wlserver . mouse_surface_cursory = y ;
}
else
{
wlserver . mouse_surface_cursorx = wlrsurface - > current . width / 2.0 ;
wlserver . mouse_surface_cursory = wlrsurface - > current . height / 2.0 ;
}
2020-01-17 09:57:39 +00:00
wlr_seat_pointer_notify_enter ( wlserver . wlr . seat , wlrsurface , wlserver . mouse_surface_cursorx , wlserver . mouse_surface_cursory ) ;
2020-01-02 07:23:39 +00:00
}
2020-04-01 20:41:58 +00:00
void wlserver_mousemotion ( int x , int y , uint32_t time )
2020-01-02 07:23:39 +00:00
{
2022-01-06 07:18:22 +00:00
// TODO: Pick the xwayland_server with active focus
2022-01-07 03:53:03 +00:00
auto server = steamcompmgr_get_focused_server ( ) ;
2022-01-06 07:18:22 +00:00
if ( server ! = NULL )
2020-04-01 20:41:58 +00:00
{
2022-01-06 07:18:22 +00:00
XTestFakeRelativeMotionEvent ( server - > get_xdisplay ( ) , x , y , CurrentTime ) ;
XFlush ( server - > get_xdisplay ( ) ) ;
2020-01-19 04:37:11 +00:00
}
2020-01-02 07:23:39 +00:00
}
void wlserver_mousebutton ( int button , bool press , uint32_t time )
{
wlr_seat_pointer_notify_button ( wlserver . wlr . seat , time , button , press ? WLR_BUTTON_PRESSED : WLR_BUTTON_RELEASED ) ;
wlr_seat_pointer_notify_frame ( wlserver . wlr . seat ) ;
}
void wlserver_mousewheel ( int x , int y , uint32_t time )
{
if ( x ! = 0 )
{
wlr_seat_pointer_notify_axis ( wlserver . wlr . seat , time , WLR_AXIS_ORIENTATION_HORIZONTAL , x , x , WLR_AXIS_SOURCE_WHEEL ) ;
}
if ( y ! = 0 )
{
wlr_seat_pointer_notify_axis ( wlserver . wlr . seat , time , WLR_AXIS_ORIENTATION_VERTICAL , y , y , WLR_AXIS_SOURCE_WHEEL ) ;
}
wlr_seat_pointer_notify_frame ( wlserver . wlr . seat ) ;
}
2020-01-23 05:50:01 +00:00
void wlserver_send_frame_done ( struct wlr_surface * surf , const struct timespec * when )
{
wlr_surface_send_frame_done ( surf , when ) ;
}
2022-06-17 23:42:22 +00:00
void wlserver_touchmotion ( double x , double y , int touch_id , uint32_t time )
{
if ( wlserver . mouse_focus_surface ! = NULL )
{
double tx = g_bRotated ? y : x ;
double ty = g_bRotated ? 1.0 - x : y ;
tx * = g_nOutputWidth ;
ty * = g_nOutputHeight ;
tx + = focusedWindowOffsetX ;
ty + = focusedWindowOffsetY ;
tx * = focusedWindowScaleX ;
ty * = focusedWindowScaleY ;
wlserver . mouse_surface_cursorx = tx ;
wlserver . mouse_surface_cursory = ty ;
if ( g_nTouchClickMode = = WLSERVER_TOUCH_CLICK_PASSTHROUGH )
{
wlr_seat_touch_notify_motion ( wlserver . wlr . seat , time , touch_id , wlserver . mouse_surface_cursorx , wlserver . mouse_surface_cursory ) ;
}
else if ( g_nTouchClickMode = = WLSERVER_TOUCH_CLICK_DISABLED )
{
return ;
}
else
{
g_bPendingTouchMovement = true ;
wlr_seat_pointer_notify_motion ( wlserver . wlr . seat , time , wlserver . mouse_surface_cursorx , wlserver . mouse_surface_cursory ) ;
wlr_seat_pointer_notify_frame ( wlserver . wlr . seat ) ;
}
}
bump_input_counter ( ) ;
}
void wlserver_touchdown ( double x , double y , int touch_id , uint32_t time )
{
if ( wlserver . mouse_focus_surface ! = NULL )
{
double tx = g_bRotated ? y : x ;
double ty = g_bRotated ? 1.0 - x : y ;
tx * = g_nOutputWidth ;
ty * = g_nOutputHeight ;
tx + = focusedWindowOffsetX ;
ty + = focusedWindowOffsetY ;
tx * = focusedWindowScaleX ;
ty * = focusedWindowScaleY ;
wlserver . mouse_surface_cursorx = tx ;
wlserver . mouse_surface_cursory = ty ;
if ( g_nTouchClickMode = = WLSERVER_TOUCH_CLICK_PASSTHROUGH )
{
if ( touch_id > = 0 & & touch_id < WLSERVER_TOUCH_COUNT )
{
wlr_seat_touch_notify_down ( wlserver . wlr . seat , wlserver . mouse_focus_surface , time , touch_id ,
wlserver . mouse_surface_cursorx , wlserver . mouse_surface_cursory ) ;
wlserver . touch_down [ touch_id ] = true ;
}
}
else if ( g_nTouchClickMode = = WLSERVER_TOUCH_CLICK_DISABLED )
{
return ;
}
else
{
g_bPendingTouchMovement = true ;
wlr_seat_pointer_notify_motion ( wlserver . wlr . seat , time , wlserver . mouse_surface_cursorx , wlserver . mouse_surface_cursory ) ;
wlr_seat_pointer_notify_frame ( wlserver . wlr . seat ) ;
uint32_t button = steamcompmgr_button_to_wlserver_button ( g_nTouchClickMode ) ;
if ( button ! = 0 & & g_nTouchClickMode < WLSERVER_BUTTON_COUNT )
{
wlr_seat_pointer_notify_button ( wlserver . wlr . seat , time , button , WLR_BUTTON_PRESSED ) ;
wlr_seat_pointer_notify_frame ( wlserver . wlr . seat ) ;
wlserver . button_held [ g_nTouchClickMode ] = true ;
}
}
}
bump_input_counter ( ) ;
}
void wlserver_touchup ( int touch_id , uint32_t time )
{
if ( wlserver . mouse_focus_surface ! = NULL )
{
bool bReleasedAny = false ;
for ( int i = 0 ; i < WLSERVER_BUTTON_COUNT ; i + + )
{
if ( wlserver . button_held [ i ] = = true )
{
uint32_t button = steamcompmgr_button_to_wlserver_button ( i ) ;
if ( button ! = 0 )
{
wlr_seat_pointer_notify_button ( wlserver . wlr . seat , time , button , WLR_BUTTON_RELEASED ) ;
bReleasedAny = true ;
}
wlserver . button_held [ i ] = false ;
}
}
if ( bReleasedAny = = true )
{
wlr_seat_pointer_notify_frame ( wlserver . wlr . seat ) ;
}
if ( touch_id > = 0 & & touch_id < WLSERVER_TOUCH_COUNT & & wlserver . touch_down [ touch_id ] = = true )
{
wlr_seat_touch_notify_up ( wlserver . wlr . seat , time , touch_id ) ;
wlserver . touch_down [ touch_id ] = false ;
}
}
bump_input_counter ( ) ;
}
2022-01-06 06:59:58 +00:00
gamescope_xwayland_server_t * wlserver_get_xwayland_server ( size_t index )
2020-01-23 05:50:01 +00:00
{
2022-01-06 07:18:22 +00:00
if ( index > = wlserver . wlr . xwayland_servers . size ( ) )
return NULL ;
2022-01-06 06:59:58 +00:00
return wlserver . wlr . xwayland_servers [ index ] . get ( ) ;
2021-04-01 21:58:33 +00:00
}
2020-01-23 05:50:01 +00:00
2021-04-28 04:17:36 +00:00
const char * wlserver_get_wl_display_name ( void )
{
return wlserver . wl_display_name ;
}
2021-04-01 21:58:33 +00:00
static void handle_surface_destroy ( struct wl_listener * l , void * data )
{
struct wlserver_surface * surf = wl_container_of ( l , surf , destroy ) ;
wlserver_surface_finish ( surf ) ;
2022-07-14 21:35:19 +00:00
wlserver_surface_init ( surf , surf - > xwayland_server , surf - > x11_id ) ;
2021-04-01 21:58:33 +00:00
}
static void wlserver_surface_set_wlr ( struct wlserver_surface * surf , struct wlr_surface * wlr_surf )
{
2021-04-16 13:16:14 +00:00
assert ( surf - > wlr = = nullptr ) ;
2021-04-01 21:58:33 +00:00
wl_list_remove ( & surf - > pending_link ) ;
wl_list_init ( & surf - > pending_link ) ;
surf - > destroy . notify = handle_surface_destroy ;
wl_signal_add ( & wlr_surf - > events . destroy , & surf - > destroy ) ;
surf - > wlr = wlr_surf ;
2022-07-14 21:35:19 +00:00
wlr_surf - > data = surf - > xwayland_server ;
2021-04-01 21:58:33 +00:00
if ( ! wlr_surface_set_role ( wlr_surf , & xwayland_surface_role , NULL , NULL , 0 ) )
2020-01-23 05:50:01 +00:00
{
2021-09-01 16:25:24 +00:00
wl_log . errorf ( " Failed to set xwayland surface role " ) ;
2020-01-23 05:50:01 +00:00
}
2021-04-01 21:58:33 +00:00
}
2022-07-14 21:35:19 +00:00
void wlserver_surface_init ( struct wlserver_surface * surf , gamescope_xwayland_server_t * server , uint32_t x11_id )
2021-04-01 21:58:33 +00:00
{
2021-04-16 12:39:38 +00:00
surf - > wl_id = 0 ;
2021-02-18 13:59:13 +00:00
surf - > x11_id = x11_id ;
2021-04-01 21:58:33 +00:00
surf - > wlr = nullptr ;
2022-07-14 21:35:19 +00:00
surf - > xwayland_server = server ;
2021-04-01 21:58:33 +00:00
wl_list_init ( & surf - > pending_link ) ;
wl_list_init ( & surf - > destroy . link ) ;
}
2020-07-03 01:45:00 +00:00
2022-07-14 20:44:19 +00:00
void gamescope_xwayland_server_t : : set_wl_id ( struct wlserver_surface * surf , uint32_t id )
2021-04-01 21:58:33 +00:00
{
2021-05-01 01:45:00 +00:00
if ( surf - > wl_id ! = 0 )
{
2022-07-14 20:44:19 +00:00
wl_log . errorf ( " surf->wl_id already set, was %u, set %u " , surf - > wl_id , id ) ;
2021-05-20 15:40:20 +00:00
return ;
2021-05-01 01:45:00 +00:00
}
2020-07-03 01:45:00 +00:00
2021-04-16 12:39:38 +00:00
surf - > wl_id = id ;
2021-04-01 21:58:33 +00:00
surf - > wlr = nullptr ;
2022-07-14 21:35:19 +00:00
surf - > xwayland_server = this ;
2021-04-01 21:58:33 +00:00
wl_list_insert ( & pending_surfaces , & surf - > pending_link ) ;
wl_list_init ( & surf - > destroy . link ) ;
2021-02-18 13:59:13 +00:00
struct wlr_surface * wlr_surf = nullptr ;
if ( content_overrides . count ( surf - > x11_id ) )
{
wlr_surf = content_overrides [ surf - > x11_id ] - > surface ;
}
else
2021-04-01 21:58:33 +00:00
{
2022-01-06 06:59:58 +00:00
struct wl_resource * resource = wl_client_get_object ( xwayland_server - > client , id ) ;
2021-02-18 13:59:13 +00:00
if ( resource ! = nullptr )
wlr_surf = wlr_surface_from_resource ( resource ) ;
2021-04-01 21:58:33 +00:00
}
2021-02-18 13:59:13 +00:00
if ( wlr_surf ! = nullptr )
2022-01-07 04:49:21 +00:00
{
wlr_surf - > data = reinterpret_cast < void * > ( this ) ;
2021-02-18 13:59:13 +00:00
wlserver_surface_set_wlr ( surf , wlr_surf ) ;
2022-01-07 04:49:21 +00:00
}
2020-01-23 05:50:01 +00:00
}
2022-01-06 06:59:58 +00:00
bool gamescope_xwayland_server_t : : is_xwayland_ready ( ) const
{
return xwayland_ready ;
}
2022-01-06 07:18:22 +00:00
_XDisplay * gamescope_xwayland_server_t : : get_xdisplay ( )
{
return dpy ;
}
2022-01-06 06:59:58 +00:00
const char * gamescope_xwayland_server_t : : get_nested_display_name ( ) const
{
return xwayland_server - > display_name ;
}
2021-04-01 21:58:33 +00:00
void wlserver_surface_finish ( struct wlserver_surface * surf )
2020-01-23 05:50:01 +00:00
{
2021-05-05 23:37:51 +00:00
if ( surf - > wlr = = wlserver . mouse_focus_surface )
{
wlserver . mouse_focus_surface = nullptr ;
}
2022-01-31 20:37:25 +00:00
if ( surf - > wlr = = wlserver . kb_focus_surface )
{
wlserver . kb_focus_surface = nullptr ;
}
2021-04-16 12:39:38 +00:00
surf - > wl_id = 0 ;
2021-04-01 21:58:33 +00:00
surf - > wlr = nullptr ;
wl_list_remove ( & surf - > pending_link ) ;
wl_list_remove ( & surf - > destroy . link ) ;
2020-01-23 05:50:01 +00:00
}
2022-02-06 23:09:32 +00:00
void wlserver_set_xwayland_server_mode ( size_t idx , int w , int h , int refresh )
{
gamescope_xwayland_server_t * server = wlserver_get_xwayland_server ( idx ) ;
if ( ! server )
return ;
wl_client * client = server - > get_client ( ) ;
struct wl_resource * resource ;
wl_resource_for_each ( resource , & wlserver . wlr . output - > resources )
{
if ( wl_resource_get_client ( resource ) = = client )
{
wl_output_send_mode ( resource , WL_OUTPUT_MODE_CURRENT , w , h , refresh * 1000 ) ;
wl_output_send_done ( resource ) ;
wl_log . infof ( " Updating mode for xwayland server %zu %dx%d@%d - client %p - resource %p " , idx , w , h , refresh , client , resource ) ;
}
}
}