2024-06-28 00:54:13 -07:00
diff --git a/protocol/gamescope-control.xml b/protocol/gamescope-control.xml
index 012c48c..7f5578b 100644
--- a/protocol/gamescope-control.xml
+++ b/protocol/gamescope-control.xml
@@ -99,5 +99,22 @@
<arg name="path" type="string" summary="Path to written screenshot"></arg>
</event>
+ <enum name="display_rotation_flag" bitfield="true" since="2">
+ <entry name="normal" value="1"/>
+ <entry name="left" value="2"/>
+ <entry name="right" value="3"/>
+ <entry name="upsidedown" value="4"/>
+ </enum>
+
+ <enum name="display_target_type" since="2">
+ <entry name="internal" value="1"/>
+ <entry name="external" value="2"/>
+ </enum>
+
+ <request name="rotate_display" since="2">
+ <arg name="orientation" type="uint" enum="display_rotation_flag" summary="Set the orientation of the display output."/>
+ <arg name="target_type" type="uint" enum="display_target_type" summary="Internal (1) or External (2) target type."/>
+ </request>
+
</interface>
</protocol>
diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp
index 97ef446..85e5126 100644
--- a/src/Backends/DRMBackend.cpp
+++ b/src/Backends/DRMBackend.cpp
@@ -56,6 +56,7 @@ static constexpr bool k_bUseCursorPlane = false;
extern int g_nPreferredOutputWidth;
extern int g_nPreferredOutputHeight;
+bool panelTypeChanged = false;
gamescope::ConVar<bool> cv_drm_single_plane_optimizations( "drm_single_plane_optimizations", true, "Whether or not to enable optimizations for single plane usage." );
@@ -67,7 +68,7 @@ gamescope::ConVar<bool> cv_drm_debug_disable_blend_tf( "drm_debug_disable_blend_
gamescope::ConVar<bool> cv_drm_debug_disable_ctm( "drm_debug_disable_ctm", false, "CTM chicken bit. (Forces CTM off, does not affect other logic)" );
gamescope::ConVar<bool> cv_drm_debug_disable_color_encoding( "drm_debug_disable_color_encoding", false, "YUV Color Encoding chicken bit. (Forces COLOR_ENCODING to DEFAULT, does not affect other logic)" );
gamescope::ConVar<bool> cv_drm_debug_disable_color_range( "drm_debug_disable_color_range", false, "YUV Color Range chicken bit. (Forces COLOR_RANGE to DEFAULT, does not affect other logic)" );
-gamescope::ConVar<bool> cv_drm_debug_disable_explicit_sync( "drm_debug_disable_explicit_sync", false, "Force disable explicit sync on the DRM backend." );
+gamescope::ConVar<bool> cv_drm_debug_disable_explicit_sync( "drm_debug_disable_explicit_sync", true, "Force disable explicit sync on the DRM backend." );
gamescope::ConVar<bool> cv_drm_debug_disable_in_fence_fd( "drm_debug_disable_in_fence_fd", false, "Force disable IN_FENCE_FD being set to avoid over-synchronization on the DRM backend." );
// HACK:
@@ -321,8 +322,19 @@ namespace gamescope
if ( m_pConnector->connector_type == DRM_MODE_CONNECTOR_eDP ||
m_pConnector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
m_pConnector->connector_type == DRM_MODE_CONNECTOR_DSI )
- return GAMESCOPE_SCREEN_TYPE_INTERNAL;
+ {
+ if ( g_bExternalForced )
+ {
+ panelTypeChanged = true;
+ return g_ForcedScreenType;
+ }
+ else
+ {
+ return GAMESCOPE_SCREEN_TYPE_INTERNAL;
+ }
+ }
+ panelTypeChanged = false;
return GAMESCOPE_SCREEN_TYPE_EXTERNAL;
}
@@ -536,6 +548,7 @@ bool g_bSupportsSyncObjs = false;
extern gamescope::GamescopeModeGeneration g_eGamescopeModeGeneration;
extern GamescopePanelOrientation g_DesiredInternalOrientation;
+extern GamescopePanelOrientation g_DesiredExternalOrientation;
extern bool g_bForceDisableColorMgmt;
@@ -2019,14 +2032,31 @@ namespace gamescope
void CDRMConnector::UpdateEffectiveOrientation( const drmModeModeInfo *pMode )
{
- if ( this->GetScreenType() == GAMESCOPE_SCREEN_TYPE_INTERNAL && g_DesiredInternalOrientation != GAMESCOPE_PANEL_ORIENTATION_AUTO )
- {
+
+ if ( this->GetScreenType() == GAMESCOPE_SCREEN_TYPE_EXTERNAL && panelTypeChanged )
+ drm_log.infof("Display is internal faked as external");
+ if ( this->GetScreenType() == GAMESCOPE_SCREEN_TYPE_INTERNAL && !panelTypeChanged )
+ drm_log.infof("Display is real internal");
+ if (panelTypeChanged){
+ drm_log.infof("Panel type was changed");
+ }
+
+ if (( this->GetScreenType() == GAMESCOPE_SCREEN_TYPE_INTERNAL && g_DesiredInternalOrientation != GAMESCOPE_PANEL_ORIENTATION_AUTO ) ||
+ ( this->GetScreenType() == GAMESCOPE_SCREEN_TYPE_EXTERNAL && g_DesiredInternalOrientation != GAMESCOPE_PANEL_ORIENTATION_AUTO
+ && panelTypeChanged)) {
+
+ drm_log.infof("We are rotating the orientation of the internal or faked external display");
m_ChosenOrientation = g_DesiredInternalOrientation;
}
+ else if (this->GetScreenType() == GAMESCOPE_SCREEN_TYPE_EXTERNAL && g_DesiredExternalOrientation != GAMESCOPE_PANEL_ORIENTATION_AUTO) {
+ drm_log.infof("We are rotating the orientation of an external display");
+ m_ChosenOrientation = g_DesiredExternalOrientation;
+ }
else
{
if ( this->GetProperties().panel_orientation )
{
+ drm_log.infof("We are using a kernel orientation quirk to rotate the display");
switch ( this->GetProperties().panel_orientation->GetCurrentValue() )
{
case DRM_MODE_PANEL_ORIENTATION_NORMAL:
@@ -2048,6 +2078,7 @@ namespace gamescope
if ( this->GetScreenType() == gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL && pMode )
{
+ drm_log.infof("We are using legacy code to rotate the display");
// Auto-detect portait mode for internal displays
m_ChosenOrientation = pMode->hdisplay < pMode->vdisplay
? GAMESCOPE_PANEL_ORIENTATION_270
@@ -2055,6 +2086,7 @@ namespace gamescope
}
else
{
+ drm_log.infof("No orientation quirks have been applied");
m_ChosenOrientation = GAMESCOPE_PANEL_ORIENTATION_0;
}
}
@@ -2120,6 +2152,10 @@ namespace gamescope
( m_Mutable.szMakePNP == "VLV"sv && m_Mutable.szModel == "Jupiter"sv ) ||
( m_Mutable.szMakePNP == "VLV"sv && m_Mutable.szModel == "Galileo"sv );
2024-07-02 15:32:25 -07:00
+ if ( g_customRefreshRates.size() > 0 && ( GetScreenType() == GAMESCOPE_SCREEN_TYPE_INTERNAL || g_bExternalForced ) ) {
+ m_Mutable.ValidDynamicRefreshRates = std::span(g_customRefreshRates);
+ return;
2024-06-28 00:54:13 -07:00
+ }
if ( bSteamDeckDisplay )
{
static constexpr uint32_t kPIDGalileoSDC = 0x3003;
@@ -2926,6 +2962,25 @@ bool drm_update_color_mgmt(struct drm_t *drm)
return true;
}
+void drm_set_orientation( struct drm_t *drm, bool isRotated)
+{
+ int width = g_nOutputWidth;
+ int height = g_nOutputHeight;
+ g_bRotated = isRotated;
+ if ( g_bRotated ) {
+ int tmp = width;
+ width = height;
+ height = tmp;
+ }
+
+ if (!drm->pConnector || !drm->pConnector->GetModeConnector())
+ return;
+
+ drmModeConnector *connector = drm->pConnector->GetModeConnector();
+ const drmModeModeInfo *mode = find_mode(connector, width, height, 0);
+ update_drm_effective_orientations(drm, mode);
+}
+
static void drm_unset_mode( struct drm_t *drm )
{
drm->pending.mode_id = 0;
diff --git a/src/backend.h b/src/backend.h
index 9c2db15..046eb10 100644
--- a/src/backend.h
+++ b/src/backend.h
@@ -17,6 +17,7 @@ struct wlr_buffer;
struct wlr_dmabuf_attributes;
struct FrameInfo_t;
+extern gamescope::GamescopeScreenType g_ForcedScreenType;
namespace gamescope
{
@@ -213,6 +214,8 @@ namespace gamescope
// Dumb helper we should remove to support multi display someday.
gamescope::GamescopeScreenType GetScreenType()
{
+ if (g_ForcedScreenType != GAMESCOPE_SCREEN_TYPE_AUTO)
+ return g_ForcedScreenType;
if ( GetCurrentConnector() )
return GetCurrentConnector()->GetScreenType();
diff --git a/src/gamescope_shared.h b/src/gamescope_shared.h
index f34174e..ed30d8c 100644
--- a/src/gamescope_shared.h
+++ b/src/gamescope_shared.h
@@ -22,6 +22,7 @@ namespace gamescope
{
GAMESCOPE_SCREEN_TYPE_INTERNAL,
GAMESCOPE_SCREEN_TYPE_EXTERNAL,
+ GAMESCOPE_SCREEN_TYPE_AUTO,
GAMESCOPE_SCREEN_TYPE_COUNT
};
2024-06-27 13:19:16 -07:00
diff --git a/src/main.cpp b/src/main.cpp
2024-06-28 00:54:13 -07:00
index 59dec4f..119e043 100644
2024-06-27 13:19:16 -07:00
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -107,6 +107,8 @@ const struct option *gamescope_options = (struct option[]){
// wlserver options
{ "xwayland-count", required_argument, nullptr, 0 },
+ { "touch-gestures", no_argument, nullptr, 0 },
+
// steamcompmgr options
{ "cursor", required_argument, nullptr, 0 },
2024-06-28 00:54:13 -07:00
@@ -125,7 +127,12 @@ const struct option *gamescope_options = (struct option[]){
{ "disable-xres", no_argument, nullptr, 'x' },
{ "fade-out-duration", required_argument, nullptr, 0 },
{ "force-orientation", required_argument, nullptr, 0 },
+ { "force-external-orientation", required_argument, nullptr, 0 },
+ { "force-panel-type", required_argument, nullptr, 0 },
{ "force-windows-fullscreen", no_argument, nullptr, 0 },
+ { "bypass-steam-resolution", no_argument, nullptr, 0 },
+ { "custom-refresh-rates", required_argument, nullptr, 0 },
+
{ "disable-color-management", no_argument, nullptr, 0 },
{ "sdr-gamut-wideness", required_argument, nullptr, 0 },
@@ -184,9 +191,13 @@ const char usage[] =
2024-06-27 13:19:16 -07:00
" -T, --stats-path write statistics to path\n"
" -C, --hide-cursor-delay hide cursor image after delay\n"
" -e, --steam enable Steam integration\n"
2024-06-28 00:54:13 -07:00
+ " --bypass-steam-resolution bypass Steam's default 720p/800p default resolution\n"
2024-06-27 13:19:16 -07:00
+ " --touch-gestures enable touch gestures for Steam menus\n"
" --xwayland-count create N xwayland servers\n"
" --prefer-vk-device prefer Vulkan device for compositing (ex: 1002:7300)\n"
" --force-orientation rotate the internal display (left, right, normal, upsidedown)\n"
2024-06-28 00:54:13 -07:00
+ " --force-external-orientation rotate the external display (left, right, normal, upsidedown)\n"
+ " --force-panel-type force gamescope to treat the display as either internal or external\n"
" --force-windows-fullscreen force windows inside of gamescope to be the size of the nested display (fullscreen)\n"
" --cursor-scale-height if specified, sets a base output height to linearly scale the cursor against.\n"
" --hdr-enabled enable HDR output (needs Gamescope WSI layer enabled for support from clients)\n"
@@ -199,6 +210,7 @@ const char usage[] =
" --hdr-itm-target-nits set the target luminace of the inverse tone mapping process.\n"
" Default: 1000 nits, Max: 10000 nits\n"
" --framerate-limit Set a simple framerate limit. Used as a divisor of the refresh rate, rounds down eg 60 / 59 -> 60fps, 60 / 25 -> 30fps. Default: 0, disabled.\n"
+ " --custom-refresh-rates Set custom refresh rates for the output. eg: 60,90,110-120\n"
" --mangoapp Launch with the mangoapp (mangohud) performance overlay enabled. You should use this instead of using mangohud on the game or gamescope.\n"
"\n"
"Nested mode options:\n"
@@ -282,6 +294,8 @@ bool g_bOutputHDREnabled = false;
bool g_bFullscreen = false;
bool g_bForceRelativeMouse = false;
+bool g_bExternalForced = false;
+
bool g_bGrabbed = false;
float g_mouseSensitivity = 1.0;
@@ -363,7 +377,37 @@ static GamescopePanelOrientation force_orientation(const char *str)
} else if (strcmp(str, "upsidedown") == 0) {
return GAMESCOPE_PANEL_ORIENTATION_180;
} else {
- fprintf( stderr, "gamescope: invalid value for --force-orientation\n" );
+ fprintf( stderr, "gamescope: invalid value for given for --force-orientation\n" );
+ exit(1);
+ }
+}
+
+GamescopePanelOrientation g_DesiredExternalOrientation = GAMESCOPE_PANEL_ORIENTATION_AUTO;
+static GamescopePanelOrientation force_external_orientation(const char *str)
+{
+ if (strcmp(str, "normal") == 0) {
+ return GAMESCOPE_PANEL_ORIENTATION_0;
+ } else if (strcmp(str, "right") == 0) {
+ return GAMESCOPE_PANEL_ORIENTATION_270;
+ } else if (strcmp(str, "left") == 0) {
+ return GAMESCOPE_PANEL_ORIENTATION_90;
+ } else if (strcmp(str, "upsidedown") == 0) {
+ return GAMESCOPE_PANEL_ORIENTATION_180;
+ } else {
+ fprintf( stderr, "gamescope: invalid value for --force-external-orientation\n" );
+ exit(1);
+ }
+}
+gamescope::GamescopeScreenType g_ForcedScreenType = gamescope::GAMESCOPE_SCREEN_TYPE_AUTO;
+static gamescope::GamescopeScreenType force_panel_type(const char *str)
+{
+ if (strcmp(str, "internal") == 0) {
+ return gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL;
+ } else if (strcmp(str, "external") == 0) {
+ g_bExternalForced = true;
+ return gamescope::GAMESCOPE_SCREEN_TYPE_EXTERNAL;
+ } else {
+ fprintf( stderr, "gamescope: invalid value for --force-panel-type\n" );
exit(1);
}
}
@@ -430,6 +474,33 @@ static enum gamescope::GamescopeBackend parse_backend_name(const char *str)
}
}
+std::vector<uint32_t> g_customRefreshRates;
+// eg: 60,60,90,110-120
+static std::vector<uint32_t> parse_custom_refresh_rates( const char *str )
+{
+ std::vector<uint32_t> rates;
+ char *token = strtok( strdup(str), ",");
+ while (token)
+ {
+ char *dash = strchr(token, '-');
+ if (dash)
+ {
+ uint32_t start = atoi(token);
+ uint32_t end = atoi(dash + 1);
+ for (uint32_t i = start; i <= end; i++)
+ {
+ rates.push_back(i);
+ }
+ }
+ else
+ {
+ rates.push_back(atoi(token));
+ }
+ token = strtok(nullptr, ",");
+ }
+ return rates;
+}
+
struct sigaction handle_signal_action = {};
extern std::mutex g_ChildPidMutex;
extern std::vector<pid_t> g_ChildPids;
@@ -766,6 +837,8 @@ int main(int argc, char **argv)
2024-06-27 13:19:16 -07:00
g_bDebugLayers = true;
} else if (strcmp(opt_name, "disable-color-management") == 0) {
g_bForceDisableColorMgmt = true;
+ } else if (strcmp(opt_name, "touch-gestures") == 0) {
+ cv_touch_gestures = true;
} else if (strcmp(opt_name, "xwayland-count") == 0) {
g_nXWaylandCount = atoi( optarg );
} else if (strcmp(opt_name, "composite-debug") == 0) {
2024-06-28 00:54:13 -07:00
@@ -779,6 +852,12 @@ int main(int argc, char **argv)
g_eGamescopeModeGeneration = parse_gamescope_mode_generation( optarg );
} else if (strcmp(opt_name, "force-orientation") == 0) {
g_DesiredInternalOrientation = force_orientation( optarg );
+ } else if (strcmp(opt_name, "force-external-orientation") == 0) {
+ g_DesiredExternalOrientation = force_external_orientation( optarg );
+ } else if (strcmp(opt_name, "force-panel-type") == 0) {
+ g_ForcedScreenType = force_panel_type( optarg );
+ } else if (strcmp(opt_name, "custom-refresh-rates") == 0) {
+ g_customRefreshRates = parse_custom_refresh_rates( optarg );
} else if (strcmp(opt_name, "sharpness") == 0 ||
strcmp(opt_name, "fsr-sharpness") == 0) {
g_upscaleFilterSharpness = atoi( optarg );
diff --git a/src/main.hpp b/src/main.hpp
index 4e4e9a7..c74f40b 100644
--- a/src/main.hpp
+++ b/src/main.hpp
@@ -3,6 +3,7 @@
#include <getopt.h>
#include <atomic>
+#include <vector>
extern const char *gamescope_optstring;
extern const struct option *gamescope_options;
@@ -28,6 +29,8 @@ extern bool g_bGrabbed;
extern float g_mouseSensitivity;
extern const char *g_sOutputName;
+extern bool g_bExternalForced;
+extern std::vector<uint32_t> g_customRefreshRates;
enum class GamescopeUpscaleFilter : uint32_t
{
diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp
index 096c8a1..92bf617 100644
--- a/src/steamcompmgr.cpp
+++ b/src/steamcompmgr.cpp
@@ -345,6 +345,8 @@ bool g_bForceHDR10OutputDebug = false;
gamescope::ConVar<bool> cv_hdr_enabled{ "hdr_enabled", false, "Whether or not HDR is enabled if it is available." };
bool g_bHDRItmEnable = false;
int g_nCurrentRefreshRate_CachedValue = 0;
+gamescope::ConVar<bool> cv_bypass_steam_resolution{ "bypass_steam_resolution", false, "Workaround the 720p/800p limits Steam uses for games" };
+
static void
update_color_mgmt()
@@ -3123,8 +3125,8 @@ static bool is_good_override_candidate( steamcompmgr_win_t *override, steamcompm
if ( !focus )
return false;
- return override != focus && override->GetGeometry().nX >= 0 && override->GetGeometry().nY >= 0;
-}
+ return override != focus && override->xwayland().a.x >= 0 && override->xwayland().a.y >= 0;
+}
static bool
pick_primary_focus_and_override(focus_t *out, Window focusControlWindow, const std::vector<steamcompmgr_win_t*>& vecPossibleFocusWindows, bool globalFocus, const std::vector<uint32_t>& ctxFocusControlAppIDs)
@@ -5371,6 +5373,13 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev)
size_t server_idx = size_t{ xwayland_mode_ctl[ 0 ] };
int width = xwayland_mode_ctl[ 1 ];
int height = xwayland_mode_ctl[ 2 ];
+
+ if ( g_nOutputWidth != 1280 && width == 1280 && cv_bypass_steam_resolution )
+ {
+ width = g_nOutputWidth;
+ height = g_nOutputHeight;
+ }
+
bool allowSuperRes = !!xwayland_mode_ctl[ 3 ];
if ( !allowSuperRes )
@@ -7268,6 +7277,8 @@ steamcompmgr_main(int argc, char **argv)
bForceWindowsFullscreen = true;
} else if (strcmp(opt_name, "hdr-enabled") == 0) {
cv_hdr_enabled = true;
+ } else if (strcmp(opt_name, "bypass-steam-resolution") == 0) {
+ cv_bypass_steam_resolution = true;
} else if (strcmp(opt_name, "hdr-debug-force-support") == 0) {
g_bForceHDRSupportDebug = true;
} else if (strcmp(opt_name, "hdr-debug-force-output") == 0) {
2024-06-27 13:19:16 -07:00
diff --git a/src/wlserver.cpp b/src/wlserver.cpp
2024-06-28 00:54:13 -07:00
index d9182aa..776e014 100644
2024-06-27 13:19:16 -07:00
--- a/src/wlserver.cpp
+++ b/src/wlserver.cpp
2024-06-28 00:54:13 -07:00
@@ -71,8 +71,13 @@
#include <set>
2024-06-27 13:19:16 -07:00
2024-06-28 00:54:13 -07:00
static LogScope wl_log("wlserver");
-
+bool pending_gesture_x = false;
+bool pending_gesture_y = false;
+bool pending_osk = false;
2024-06-27 13:19:16 -07:00
//#define GAMESCOPE_SWAPCHAIN_DEBUG
+gamescope::ConVar<bool> cv_touch_gestures( "enable_touch_gestures", false, "Enable/Disable the usage of touch gestures" );
2024-06-28 00:54:13 -07:00
+extern GamescopePanelOrientation g_DesiredInternalOrientation;
+extern GamescopePanelOrientation g_DesiredExternalOrientation;
2024-06-27 13:19:16 -07:00
struct wlserver_t wlserver = {
.touch_down_ids = {}
2024-06-28 00:54:13 -07:00
@@ -418,6 +423,39 @@ void wlserver_open_steam_menu( bool qam )
XTestFakeKeyEvent(server->get_xdisplay(), XKeysymToKeycode( server->get_xdisplay(), XK_Control_L ), False, CurrentTime);
}
+void wlserver_open_steam_osk(bool osk)
+{
+ gamescope_xwayland_server_t *server = wlserver_get_xwayland_server( 0 );
+ if (!server)
+ return;
+
+ uint32_t osk_open = osk;
+
+ if (osk_open)
+ {
+ const char *command = "xdg-open steam://open/keyboard?";
+ int result = system(command);
+ if (result == 0) {
+ printf("Command executed successfully.\n");
+ } else {
+ printf("Error executing command.\n");
+ }
+ pending_osk = false;
+ }
+ else
+ {
+ const char *command = "xdg-open steam://close/keyboard?";
+ int result = system(command);
+ if (result == 0) {
+ printf("Command executed successfully.\n");
+ } else {
+ printf("Error executing command.\n");
+ }
+ pending_osk = false;
+ }
+
+}
+
static void wlserver_handle_pointer_button(struct wl_listener *listener, void *data)
{
struct wlserver_pointer *pointer = wl_container_of( listener, pointer, button );
@@ -1095,6 +1133,56 @@ static void gamescope_control_take_screenshot( struct wl_client *client, struct
} );
}
+static void gamescope_control_rotate_display( struct wl_client *client, struct wl_resource *resource, uint32_t orientation, uint32_t target_type )
+{
+ bool isRotated = false;
+ if (target_type == GAMESCOPE_CONTROL_DISPLAY_TARGET_TYPE_INTERNAL )
+ {
+ switch (orientation) {
+ case GAMESCOPE_CONTROL_DISPLAY_ROTATION_FLAG_NORMAL:
+ g_DesiredInternalOrientation = GAMESCOPE_PANEL_ORIENTATION_0;
+ break;
+ case GAMESCOPE_CONTROL_DISPLAY_ROTATION_FLAG_LEFT:
+ g_DesiredInternalOrientation = GAMESCOPE_PANEL_ORIENTATION_90;
+ isRotated = true;
+ break;
+ case GAMESCOPE_CONTROL_DISPLAY_ROTATION_FLAG_RIGHT:
+ g_DesiredInternalOrientation = GAMESCOPE_PANEL_ORIENTATION_270;
+ isRotated = true;
+ break;
+ case GAMESCOPE_CONTROL_DISPLAY_ROTATION_FLAG_UPSIDEDOWN:
+ g_DesiredInternalOrientation = GAMESCOPE_PANEL_ORIENTATION_180;
+ break;
+ default:
+ wl_log.errorf("Invalid target orientation selected");
+ }
+ }
+ else if (target_type == GAMESCOPE_CONTROL_DISPLAY_TARGET_TYPE_EXTERNAL )
+ {
+ switch (orientation) {
+ case GAMESCOPE_CONTROL_DISPLAY_ROTATION_FLAG_NORMAL:
+ g_DesiredExternalOrientation = GAMESCOPE_PANEL_ORIENTATION_0;
+ break;
+ case GAMESCOPE_CONTROL_DISPLAY_ROTATION_FLAG_LEFT:
+ g_DesiredExternalOrientation = GAMESCOPE_PANEL_ORIENTATION_90;
+ isRotated = true;
+ break;
+ case GAMESCOPE_CONTROL_DISPLAY_ROTATION_FLAG_RIGHT:
+ g_DesiredExternalOrientation = GAMESCOPE_PANEL_ORIENTATION_270;
+ isRotated = true;
+ break;
+ case GAMESCOPE_CONTROL_DISPLAY_ROTATION_FLAG_UPSIDEDOWN:
+ g_DesiredExternalOrientation = GAMESCOPE_PANEL_ORIENTATION_180;
+ break;
+ default:
+ wl_log.errorf("Invalid target orientation selected");
+ }
+ }
+ drm_set_orientation(&g_DRM, isRotated);
+ GetBackend()->DirtyState( true, true );
+
+}
+
static void gamescope_control_handle_destroy( struct wl_client *client, struct wl_resource *resource )
{
wl_resource_destroy( resource );
@@ -1104,6 +1192,7 @@ static const struct gamescope_control_interface gamescope_control_impl = {
.destroy = gamescope_control_handle_destroy,
.set_app_target_refresh_cycle = gamescope_control_set_app_target_refresh_cycle,
.take_screenshot = gamescope_control_take_screenshot,
+ .rotate_display = gamescope_control_rotate_display,
};
static uint32_t get_conn_display_info_flags()
@@ -2469,36 +2558,104 @@ const std::shared_ptr<wlserver_vk_swapchain_feedback>& wlserver_surface_swapchai
/* Handle the orientation of the touch inputs */
static void apply_touchscreen_orientation(double *x, double *y )
{
- double tx = 0;
- double ty = 0;
+ double tx = 0;
+ double ty = 0;
- // Use internal screen always for orientation purposes.
- switch ( GetBackend()->GetConnector( gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL )->GetCurrentOrientation() )
- {
- default:
- case GAMESCOPE_PANEL_ORIENTATION_AUTO:
- case GAMESCOPE_PANEL_ORIENTATION_0:
- tx = *x;
- ty = *y;
- break;
- case GAMESCOPE_PANEL_ORIENTATION_90:
- tx = 1.0 - *y;
- ty = *x;
- break;
- case GAMESCOPE_PANEL_ORIENTATION_180:
- tx = 1.0 - *x;
- ty = 1.0 - *y;
- break;
- case GAMESCOPE_PANEL_ORIENTATION_270:
- tx = *y;
- ty = 1.0 - *x;
- break;
- }
+ // Use internal screen always for orientation purposes.
+ if ( g_ForcedScreenType != gamescope::GAMESCOPE_SCREEN_TYPE_AUTO )
+ {
+ if ( g_ForcedScreenType == gamescope::GAMESCOPE_SCREEN_TYPE_EXTERNAL )
+ {
+ if(panelTypeChanged)
+ {
+ switch (GetBackend()->GetConnector(gamescope::GAMESCOPE_SCREEN_TYPE_EXTERNAL)->GetCurrentOrientation())
+ {
+ default:
+ case GAMESCOPE_PANEL_ORIENTATION_AUTO:
+ case GAMESCOPE_PANEL_ORIENTATION_0:
+ tx = *x;
+ ty = *y;
+ break;
+ case GAMESCOPE_PANEL_ORIENTATION_90:
+ tx = 1.0 - *y;
+ ty = *x;
+ break;
+ case GAMESCOPE_PANEL_ORIENTATION_180:
+ tx = 1.0 - *x;
+ ty = 1.0 - *y;
+ break;
+ case GAMESCOPE_PANEL_ORIENTATION_270:
+ tx = *y;
+ ty = 1.0 - *x;
+ break;
+ }
+ }
+ }
+ else
+ {
+ switch (GetBackend()->GetConnector(gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL)->GetCurrentOrientation())
+ {
+ default:
+ case GAMESCOPE_PANEL_ORIENTATION_AUTO:
+ case GAMESCOPE_PANEL_ORIENTATION_0:
+ tx = *x;
+ ty = *y;
+ break;
+ case GAMESCOPE_PANEL_ORIENTATION_90:
+ tx = 1.0 - *y;
+ ty = *x;
+ break;
+ case GAMESCOPE_PANEL_ORIENTATION_180:
+ tx = 1.0 - *x;
+ ty = 1.0 - *y;
+ break;
+ case GAMESCOPE_PANEL_ORIENTATION_270:
+ tx = *y;
+ ty = 1.0 - *x;
+ break;
+ }
+ }
+
+ }
+ else if (g_ForcedScreenType == gamescope::GAMESCOPE_SCREEN_TYPE_AUTO)
+ {
+ switch (GetBackend()->GetConnector(gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL)->GetCurrentOrientation())
+ {
+ default:
+ case GAMESCOPE_PANEL_ORIENTATION_AUTO:
+ case GAMESCOPE_PANEL_ORIENTATION_0:
+ tx = *x;
+ ty = *y;
+ break;
+ case GAMESCOPE_PANEL_ORIENTATION_90:
+ tx = 1.0 - *y;
+ ty = *x;
+ break;
+ case GAMESCOPE_PANEL_ORIENTATION_180:
+ tx = 1.0 - *x;
+ ty = 1.0 - *y;
+ break;
+ case GAMESCOPE_PANEL_ORIENTATION_270:
+ tx = *y;
+ ty = 1.0 - *x;
+ break;
+ }
+ }
+
+ *x = tx;
+ *y = ty;
+}
- *x = tx;
- *y = ty;
+void wlserver_gesture_flush()
+{
+ pending_gesture_x = false;
+ pending_gesture_y = false;
}
+// Variables to track the direction of the touch motion
+uint32_t previous_tx = 0;
+uint32_t previous_ty = 0;
+
void wlserver_touchmotion( double x, double y, int touch_id, uint32_t time, bool bAlwaysWarpCursor )
{
assert( wlserver_is_lock_held() );
@@ -2534,6 +2691,59 @@ void wlserver_touchmotion( double x, double y, int touch_id, uint32_t time, bool
2024-06-27 13:19:16 -07:00
if ( bAlwaysWarpCursor )
wlserver_mousewarp( tx, ty, time, false );
+
2024-06-28 00:54:13 -07:00
+ if ( cv_touch_gestures )
+ {
+ uint32_t rounded_tx = static_cast<int>(std::round(tx));
+ uint32_t rounded_ty = static_cast<int>(std::round(ty));
+ uint32_t edge_range_x = static_cast<uint32_t>(g_nOutputWidth * 0.05);
+ uint32_t edge_range_y = static_cast<uint32_t>(g_nOutputWidth * 0.05);
+ uint32_t gesture_limits_x = edge_range_x * 2;
+ uint32_t gesture_limits_y = edge_range_y * 2;
+ uint32_t threshold_distance_x = gesture_limits_x;
+ uint32_t threshold_distance_y = gesture_limits_y;
2024-06-27 13:19:16 -07:00
+
2024-06-28 00:54:13 -07:00
+ // Left to Right and Right to Left
+ if (!pending_gesture_x && ((rounded_tx >= 1 && rounded_tx < edge_range_x) || (rounded_tx >= g_nOutputWidth - edge_range_x))) {
+ // Check if the distance moved is greater than the threshold
+ if (rounded_tx - previous_tx > threshold_distance_x) {
+ pending_gesture_x = true;
+ }
+ }
2024-06-27 13:19:16 -07:00
+
2024-06-28 00:54:13 -07:00
+ // Top to Bottom and Bottom to Top
+ if (!pending_gesture_y && ((rounded_ty >= 1 && rounded_ty < edge_range_y) || (rounded_ty >= g_nOutputHeight - edge_range_y))) {
+ // Check if the distance moved is greater than the threshold
+ if (rounded_ty - previous_ty > threshold_distance_y) {
+ pending_gesture_y = true;
+ }
2024-06-27 13:19:16 -07:00
+ }
+
2024-06-28 00:54:13 -07:00
+ //left
+ if (pending_gesture_x && previous_tx < rounded_tx && rounded_tx >= edge_range_x && rounded_tx < gesture_limits_x) {
2024-06-27 13:19:16 -07:00
+ wlserver_open_steam_menu(0);
2024-06-28 00:54:13 -07:00
+ wlserver_gesture_flush();
2024-06-27 13:19:16 -07:00
+ }
2024-06-28 00:54:13 -07:00
+ //right
+ if (pending_gesture_x && previous_tx > rounded_tx && rounded_tx <= g_nOutputWidth - edge_range_x && rounded_tx > g_nOutputWidth - gesture_limits_x) {
2024-06-27 13:19:16 -07:00
+ wlserver_open_steam_menu(1);
2024-06-28 00:54:13 -07:00
+ wlserver_gesture_flush();
2024-06-27 13:19:16 -07:00
+ }
+
2024-06-28 00:54:13 -07:00
+ // Top
+ if (pending_gesture_y && previous_ty < rounded_ty && rounded_ty >= edge_range_y && rounded_ty < gesture_limits_y) {
+ wlserver_gesture_flush();
+ // Top to Bottom function to add
+ }
+ // Bottom
+ if (pending_gesture_y && previous_ty > rounded_ty && !pending_osk && rounded_ty <= g_nOutputWidth - edge_range_y && rounded_ty > g_nOutputHeight - gesture_limits_y) {
+ wlserver_gesture_flush();
+ pending_osk = true;
2024-07-11 15:54:42 -07:00
+ wlserver_open_steam_osk(1);
2024-06-28 00:54:13 -07:00
+ }
+ previous_tx = rounded_tx;
+ previous_ty = rounded_ty;
+ }
2024-06-27 13:19:16 -07:00
}
else if ( eMode == gamescope::TouchClickModes::Disabled )
{
diff --git a/src/wlserver.hpp b/src/wlserver.hpp
2024-06-28 00:54:13 -07:00
index 0d8f3ac..07675fe 100644
2024-06-27 13:19:16 -07:00
--- a/src/wlserver.hpp
+++ b/src/wlserver.hpp
2024-06-28 00:54:13 -07:00
@@ -287,9 +287,12 @@ void wlserver_x11_surface_info_finish( struct wlserver_x11_surface_info *surf );
2024-06-27 13:19:16 -07:00
void wlserver_set_xwayland_server_mode( size_t idx, int w, int h, int refresh );
extern std::atomic<bool> g_bPendingTouchMovement;
+extern gamescope::ConVar<bool> cv_touch_gestures;
void wlserver_open_steam_menu( bool qam );
2024-06-28 00:54:13 -07:00
-
+extern void drm_set_orientation( struct drm_t *drm, bool isRotated);
+extern drm_t g_DRM;
+extern bool panelTypeChanged;
uint32_t wlserver_make_new_xwayland_server();
void wlserver_destroy_xwayland_server(gamescope_xwayland_server_t *server);
2024-06-27 13:19:16 -07:00