mirror of
https://github.com/wxWidgets/wxWidgets.git
synced 2026-08-17 08:53:06 +08:00
Merge branch 'wayland-session-mgmt'
Add support for Wayland session management protocol and use it for wxPersistentTLW if available. See #26793. Closes #26324.
This commit is contained in:
+45
-26
@@ -471,37 +471,56 @@ if(wxUSE_GUI)
|
||||
set(wx_protocols_temp_dir ${wxOUTPUT_DIR}/wx/protocols)
|
||||
set(wx_protocols_output_dir ${wxSETUP_HEADER_PATH}/wx/protocols)
|
||||
|
||||
# Note that we need multiple execute_process()
|
||||
# invocations as single one would run commands
|
||||
# concurrently and not sequentially.
|
||||
execute_process(
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E make_directory ${wx_protocols_temp_dir}
|
||||
)
|
||||
execute_process(
|
||||
COMMAND
|
||||
${WAYLAND_SCANNER} client-header
|
||||
${wx_protocols_input_dir}/pointer-warp-v1.xml
|
||||
${wx_protocols_temp_dir}/pointer-warp-v1-client-protocol.h
|
||||
)
|
||||
execute_process(
|
||||
COMMAND
|
||||
${WAYLAND_SCANNER} private-code
|
||||
${wx_protocols_input_dir}/pointer-warp-v1.xml
|
||||
${wx_protocols_temp_dir}/pointer-warp-v1-client-protocol.c
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E make_directory ${wx_protocols_output_dir}
|
||||
)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${wx_protocols_temp_dir}/pointer-warp-v1-client-protocol.h
|
||||
${wx_protocols_temp_dir}/pointer-warp-v1-client-protocol.c
|
||||
${CMAKE_COMMAND} -E make_directory
|
||||
${wx_protocols_temp_dir}
|
||||
${wx_protocols_output_dir}
|
||||
)
|
||||
|
||||
# This function takes the protocol name and the directory
|
||||
# containing the corresponding XML file.
|
||||
function(wx_generate_wayland_protocol protocol_dir protocol)
|
||||
execute_process(
|
||||
COMMAND
|
||||
${WAYLAND_SCANNER} client-header
|
||||
${protocol_dir}/${protocol}.xml
|
||||
${wx_protocols_temp_dir}/${protocol}-client-protocol.h
|
||||
COMMAND
|
||||
${WAYLAND_SCANNER} private-code
|
||||
${protocol_dir}/${protocol}.xml
|
||||
${wx_protocols_temp_dir}/${protocol}-client-protocol.c
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${wx_protocols_temp_dir}/${protocol}-client-protocol.h
|
||||
${wx_protocols_temp_dir}/${protocol}-client-protocol.c
|
||||
${wx_protocols_output_dir}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
wx_generate_wayland_protocol(${wx_protocols_input_dir} pointer-warp-v1)
|
||||
|
||||
# Check if we have GTK new enough to allow using XDG
|
||||
# session management protocol: 3.24.53 is the earliest one
|
||||
# with gdk_wayland_window_get_xdg_toplevel() that we need.
|
||||
if(GTK3_VERSION VERSION_GREATER_EQUAL 3.24.53)
|
||||
# We also need wayland-protocols as this protocol
|
||||
# depends on xdg-shell one.
|
||||
pkg_check_modules(WAYLAND_PROTOCOLS wayland-protocols)
|
||||
if(WAYLAND_PROTOCOLS_FOUND)
|
||||
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
|
||||
|
||||
wx_generate_wayland_protocol(${wx_protocols_input_dir} xdg-session-management-v1)
|
||||
wx_generate_wayland_protocol(${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell xdg-shell)
|
||||
|
||||
set(wxHAVE_WAYLAND_SESSION_MANAGEMENT ON)
|
||||
else()
|
||||
message(WARNING "wayland-protocols not found, xdg-session-management protocol won't be used")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(wxHAVE_WAYLAND_CLIENT ON)
|
||||
list(APPEND wxTOOLKIT_INCLUDE_DIRS ${WAYLAND_CLIENT_INCLUDE_DIRS})
|
||||
list(APPEND wxTOOLKIT_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES})
|
||||
|
||||
@@ -630,6 +630,13 @@
|
||||
*/
|
||||
#cmakedefine wxHAVE_WAYLAND_CLIENT 1
|
||||
|
||||
/*
|
||||
Use Wayland session-management protocol.
|
||||
|
||||
This is defined if GTK is new enough to support it.
|
||||
*/
|
||||
#cmakedefine wxHAVE_WAYLAND_SESSION_MANAGEMENT 1
|
||||
|
||||
/*
|
||||
Use XTest extension to implement wxUIActionSimulator?
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ case $(uname -s) in
|
||||
fi
|
||||
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
dnf install -y ${WX_EXTRA_PACKAGES} gawk expat-devel findutils g++ git-core gspell-devel gstreamer1-plugins-base-devel gtk3-devel make libcurl-devel libjpeg-devel libnotify-devel libpng-devel libSM-devel libsecret-devel libtiff-devel SDL-devel webkit2gtk4.1-devel zlib-devel
|
||||
dnf install -y ${WX_EXTRA_PACKAGES} gawk expat-devel findutils g++ git-core gspell-devel gstreamer1-plugins-base-devel gtk3-devel make libcurl-devel libjpeg-devel libnotify-devel libpng-devel libSM-devel libsecret-devel libtiff-devel SDL-devel wayland-protocols-devel webkit2gtk4.1-devel zlib-devel
|
||||
fi
|
||||
;;
|
||||
|
||||
|
||||
@@ -556,6 +556,66 @@ as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
|
||||
# Sed expression to map a string onto a valid variable name.
|
||||
as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
|
||||
|
||||
as_awk_strverscmp='
|
||||
# Use only awk features that work with 7th edition Unix awk (1978).
|
||||
# My, what an old awk you have, Mr. Solaris!
|
||||
END {
|
||||
while (length(v1) && length(v2)) {
|
||||
# Set d1 to be the next thing to compare from v1, and likewise for d2.
|
||||
# Normally this is a single character, but if v1 and v2 contain digits,
|
||||
# compare them as integers and fractions as strverscmp does.
|
||||
if (v1 ~ /^[0-9]/ && v2 ~ /^[0-9]/) {
|
||||
# Split v1 and v2 into their leading digit string components d1 and d2,
|
||||
# and advance v1 and v2 past the leading digit strings.
|
||||
for (len1 = 1; substr(v1, len1 + 1) ~ /^[0-9]/; len1++) continue
|
||||
for (len2 = 1; substr(v2, len2 + 1) ~ /^[0-9]/; len2++) continue
|
||||
d1 = substr(v1, 1, len1); v1 = substr(v1, len1 + 1)
|
||||
d2 = substr(v2, 1, len2); v2 = substr(v2, len2 + 1)
|
||||
if (d1 ~ /^0/) {
|
||||
if (d2 ~ /^0/) {
|
||||
# Compare two fractions.
|
||||
while (d1 ~ /^0/ && d2 ~ /^0/) {
|
||||
d1 = substr(d1, 2); len1--
|
||||
d2 = substr(d2, 2); len2--
|
||||
}
|
||||
if (len1 != len2 && ! (len1 && len2 && substr(d1, 1, 1) == substr(d2, 1, 1))) {
|
||||
# The two components differ in length, and the common prefix
|
||||
# contains only leading zeros. Consider the longer to be less.
|
||||
d1 = -len1
|
||||
d2 = -len2
|
||||
} else {
|
||||
# Otherwise, compare as strings.
|
||||
d1 = "x" d1
|
||||
d2 = "x" d2
|
||||
}
|
||||
} else {
|
||||
# A fraction is less than an integer.
|
||||
exit 1
|
||||
}
|
||||
} else {
|
||||
if (d2 ~ /^0/) {
|
||||
# An integer is greater than a fraction.
|
||||
exit 2
|
||||
} else {
|
||||
# Compare two integers.
|
||||
d1 += 0
|
||||
d2 += 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# The normal case, without worrying about digits.
|
||||
d1 = substr(v1, 1, 1); v1 = substr(v1, 2)
|
||||
d2 = substr(v2, 1, 1); v2 = substr(v2, 2)
|
||||
}
|
||||
if (d1 < d2) exit 1
|
||||
if (d1 > d2) exit 2
|
||||
}
|
||||
# Beware Solaris /usr/xgp4/bin/awk (at least through Solaris 10),
|
||||
# which mishandles some comparisons of empty strings to integers.
|
||||
if (length(v2)) exit 1
|
||||
if (length(v1)) exit 2
|
||||
}
|
||||
'
|
||||
|
||||
test -n "$DJDIR" || exec 7<&0 </dev/null
|
||||
exec 6>&1
|
||||
@@ -28324,6 +28384,84 @@ $as_echo "$wx_cv_wayland_scanner" >&6; }
|
||||
fi
|
||||
|
||||
if test -n "$WAYLAND_SCANNER" ; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for support of the Wayland session management protocol" >&5
|
||||
$as_echo_n "checking for support of the Wayland session management protocol... " >&6; }
|
||||
if ${wx_cv_gtk_wayland_sm+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
|
||||
GTK_VERSION=`$PKG_CONFIG --modversion gtk+-3.0`
|
||||
as_arg_v1=$GTK_VERSION
|
||||
as_arg_v2=3.24.52
|
||||
awk "$as_awk_strverscmp" v1="$as_arg_v1" v2="$as_arg_v2" /dev/null
|
||||
case $? in #(
|
||||
1) :
|
||||
wx_cv_gtk_wayland_sm=no ;; #(
|
||||
0) :
|
||||
wx_cv_gtk_wayland_sm=maybe ;; #(
|
||||
2) :
|
||||
wx_cv_gtk_wayland_sm=yes
|
||||
;; #(
|
||||
*) :
|
||||
;;
|
||||
esac
|
||||
|
||||
if test "$wx_cv_gtk_wayland_sm" = "maybe"; then
|
||||
save_CFLAGS=$CFLAGS
|
||||
save_LIBS=$LIBS
|
||||
CFLAGS="$CFLAGS $TOOLKIT_INCLUDE"
|
||||
LIBS="$LIBS $GUI_TK_LIBRARY"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <gdk/gdkwayland.h>
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
gdk_wayland_window_get_xdg_toplevel(0)
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
wx_cv_gtk_wayland_sm=yes
|
||||
else
|
||||
wx_cv_gtk_wayland_sm=no
|
||||
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$save_LIBS
|
||||
CFLAGS=$save_CFLAGS
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $wx_cv_gtk_wayland_sm" >&5
|
||||
$as_echo "$wx_cv_gtk_wayland_sm" >&6; }
|
||||
|
||||
if test "$wx_cv_gtk_wayland_sm" = "yes"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for wayland-protocols data directory" >&5
|
||||
$as_echo_n "checking for wayland-protocols data directory... " >&6; }
|
||||
if ${wx_cv_wayland_protocols_dir+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
|
||||
wx_cv_wayland_protocols_dir=`$PKG_CONFIG --variable=pkgdatadir wayland-protocols`
|
||||
|
||||
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $wx_cv_wayland_protocols_dir" >&5
|
||||
$as_echo "$wx_cv_wayland_protocols_dir" >&6; }
|
||||
WAYLAND_PROTOCOLS_DIR=$wx_cv_wayland_protocols_dir
|
||||
|
||||
$as_echo "#define wxHAVE_WAYLAND_SESSION_MANAGEMENT 1" >>confdefs.h
|
||||
|
||||
else
|
||||
WAYLAND_SM_SUPPORT=':'
|
||||
fi
|
||||
|
||||
$as_echo "#define wxHAVE_WAYLAND_CLIENT 1" >>confdefs.h
|
||||
|
||||
ac_config_commands="$ac_config_commands wayland-protocols"
|
||||
@@ -45911,6 +46049,8 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
#
|
||||
|
||||
WAYLAND_SCANNER=$WAYLAND_SCANNER
|
||||
WAYLAND_SM_SUPPORT=$WAYLAND_SM_SUPPORT
|
||||
WAYLAND_PROTOCOLS_DIR=$WAYLAND_PROTOCOLS_DIR
|
||||
|
||||
|
||||
|
||||
@@ -46502,6 +46642,10 @@ $as_echo "$as_me: executing $ac_file commands" >&6;}
|
||||
mkdir -p lib/wx/include/${TOOLCHAIN_FULLNAME}/wx/protocols
|
||||
$WAYLAND_SCANNER client-header $srcdir/src/unix/protocols/pointer-warp-v1.xml lib/wx/include/${TOOLCHAIN_FULLNAME}/wx/protocols/pointer-warp-v1-client-protocol.h
|
||||
$WAYLAND_SCANNER private-code $srcdir/src/unix/protocols/pointer-warp-v1.xml lib/wx/include/${TOOLCHAIN_FULLNAME}/wx/protocols/pointer-warp-v1-client-protocol.c
|
||||
$WAYLAND_SM_SUPPORT $WAYLAND_SCANNER client-header $srcdir/src/unix/protocols/xdg-session-management-v1.xml lib/wx/include/${TOOLCHAIN_FULLNAME}/wx/protocols/xdg-session-management-v1-client-protocol.h
|
||||
$WAYLAND_SM_SUPPORT $WAYLAND_SCANNER private-code $srcdir/src/unix/protocols/xdg-session-management-v1.xml lib/wx/include/${TOOLCHAIN_FULLNAME}/wx/protocols/xdg-session-management-v1-client-protocol.c
|
||||
$WAYLAND_SM_SUPPORT $WAYLAND_SCANNER client-header $WAYLAND_PROTOCOLS_DIR/stable/xdg-shell/xdg-shell.xml lib/wx/include/${TOOLCHAIN_FULLNAME}/wx/protocols/xdg-shell-client-protocol.h
|
||||
$WAYLAND_SM_SUPPORT $WAYLAND_SCANNER private-code $WAYLAND_PROTOCOLS_DIR/stable/xdg-shell/xdg-shell.xml lib/wx/include/${TOOLCHAIN_FULLNAME}/wx/protocols/xdg-shell-client-protocol.c
|
||||
;;
|
||||
"rcdefs.h":C)
|
||||
mkdir -p $outdir &&
|
||||
@@ -46613,4 +46757,3 @@ else
|
||||
fi
|
||||
echo ""
|
||||
|
||||
|
||||
|
||||
@@ -3100,15 +3100,71 @@ installed, where VER is 2, 3 or 4.
|
||||
fi
|
||||
|
||||
if test -n "$WAYLAND_SCANNER" ; then
|
||||
dnl Check if we can use the session management protocol which
|
||||
dnl normally requires GTK >= 3.24.53 but allow using it with
|
||||
dnl the versions of 3.24.52 that already have the support
|
||||
dnl required for it, at least until 3.24.53 is released.
|
||||
AC_CACHE_CHECK([for support of the Wayland session management protocol],
|
||||
wx_cv_gtk_wayland_sm,
|
||||
[
|
||||
GTK_VERSION=`$PKG_CONFIG --modversion gtk+-3.0`
|
||||
AS_VERSION_COMPARE([$GTK_VERSION], [3.24.52],
|
||||
wx_cv_gtk_wayland_sm=no,
|
||||
wx_cv_gtk_wayland_sm=maybe,
|
||||
wx_cv_gtk_wayland_sm=yes
|
||||
)
|
||||
|
||||
if test "$wx_cv_gtk_wayland_sm" = "maybe"; then
|
||||
save_CFLAGS=$CFLAGS
|
||||
save_LIBS=$LIBS
|
||||
CFLAGS="$CFLAGS $TOOLKIT_INCLUDE"
|
||||
LIBS="$LIBS $GUI_TK_LIBRARY"
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <gdk/gdkwayland.h>],
|
||||
[
|
||||
gdk_wayland_window_get_xdg_toplevel(0)
|
||||
])],
|
||||
wx_cv_gtk_wayland_sm=yes,
|
||||
wx_cv_gtk_wayland_sm=no
|
||||
)
|
||||
LIBS=$save_LIBS
|
||||
CFLAGS=$save_CFLAGS
|
||||
fi
|
||||
]
|
||||
)
|
||||
|
||||
if test "$wx_cv_gtk_wayland_sm" = "yes"; then
|
||||
dnl We don't check for wayland-protocols being installed as
|
||||
dnl it's a dependency of libgtk-3-dev or similar, and so
|
||||
dnl should be available.
|
||||
AC_CACHE_CHECK([for wayland-protocols data directory],
|
||||
wx_cv_wayland_protocols_dir,
|
||||
[
|
||||
wx_cv_wayland_protocols_dir=`$PKG_CONFIG --variable=pkgdatadir wayland-protocols`
|
||||
]
|
||||
)
|
||||
WAYLAND_PROTOCOLS_DIR=$wx_cv_wayland_protocols_dir
|
||||
|
||||
AC_DEFINE(wxHAVE_WAYLAND_SESSION_MANAGEMENT)
|
||||
else
|
||||
dnl Don't bother running wayland-scanner for this protocol.
|
||||
WAYLAND_SM_SUPPORT=':'
|
||||
fi
|
||||
|
||||
AC_DEFINE(wxHAVE_WAYLAND_CLIENT)
|
||||
AC_CONFIG_COMMANDS([wayland-protocols],
|
||||
[
|
||||
mkdir -p lib/wx/include/${TOOLCHAIN_FULLNAME}/wx/protocols
|
||||
$WAYLAND_SCANNER client-header $srcdir/src/unix/protocols/pointer-warp-v1.xml lib/wx/include/${TOOLCHAIN_FULLNAME}/wx/protocols/pointer-warp-v1-client-protocol.h
|
||||
$WAYLAND_SCANNER private-code $srcdir/src/unix/protocols/pointer-warp-v1.xml lib/wx/include/${TOOLCHAIN_FULLNAME}/wx/protocols/pointer-warp-v1-client-protocol.c
|
||||
$WAYLAND_SM_SUPPORT $WAYLAND_SCANNER client-header $srcdir/src/unix/protocols/xdg-session-management-v1.xml lib/wx/include/${TOOLCHAIN_FULLNAME}/wx/protocols/xdg-session-management-v1-client-protocol.h
|
||||
$WAYLAND_SM_SUPPORT $WAYLAND_SCANNER private-code $srcdir/src/unix/protocols/xdg-session-management-v1.xml lib/wx/include/${TOOLCHAIN_FULLNAME}/wx/protocols/xdg-session-management-v1-client-protocol.c
|
||||
$WAYLAND_SM_SUPPORT $WAYLAND_SCANNER client-header $WAYLAND_PROTOCOLS_DIR/stable/xdg-shell/xdg-shell.xml lib/wx/include/${TOOLCHAIN_FULLNAME}/wx/protocols/xdg-shell-client-protocol.h
|
||||
$WAYLAND_SM_SUPPORT $WAYLAND_SCANNER private-code $WAYLAND_PROTOCOLS_DIR/stable/xdg-shell/xdg-shell.xml lib/wx/include/${TOOLCHAIN_FULLNAME}/wx/protocols/xdg-shell-client-protocol.c
|
||||
],
|
||||
[
|
||||
WAYLAND_SCANNER=$WAYLAND_SCANNER
|
||||
WAYLAND_SM_SUPPORT=$WAYLAND_SM_SUPPORT
|
||||
WAYLAND_PROTOCOLS_DIR=$WAYLAND_PROTOCOLS_DIR
|
||||
]
|
||||
)
|
||||
else
|
||||
|
||||
@@ -10,12 +10,19 @@
|
||||
#ifndef _WX_GTK_PRIVATE_TLWGEOM_H_
|
||||
#define _WX_GTK_PRIVATE_TLWGEOM_H_
|
||||
|
||||
#define wxPERSIST_TLW_XDG_SESSION_ID "xdg_session_id"
|
||||
|
||||
class wxTLWGeometry : public wxTLWGeometryGeneric
|
||||
{
|
||||
typedef wxTLWGeometryGeneric BaseType;
|
||||
public:
|
||||
virtual bool Save(Store& store) const override
|
||||
{
|
||||
if ( wxTopLevelWindow::HasWaylandXDGSessionManagement() )
|
||||
{
|
||||
return store.SaveString(wxPERSIST_TLW_XDG_SESSION_ID, m_xdgSessionId);
|
||||
}
|
||||
|
||||
if ( !wxTLWGeometryGeneric::Save(store) )
|
||||
return false;
|
||||
|
||||
@@ -35,6 +42,16 @@ public:
|
||||
|
||||
virtual bool Restore(const Store& store) override
|
||||
{
|
||||
if ( wxTopLevelWindow::HasWaylandXDGSessionManagement() )
|
||||
{
|
||||
store.RestoreString(wxPERSIST_TLW_XDG_SESSION_ID, &m_xdgSessionId);
|
||||
|
||||
// When using Wayland XDG session management, we need our ApplyTo()
|
||||
// to be called, even if we don't have any saved state yet, so
|
||||
// always return true, even if the session ID is empty.
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( !wxTLWGeometryGeneric::Restore(store) )
|
||||
return false;
|
||||
|
||||
@@ -48,6 +65,19 @@ public:
|
||||
|
||||
virtual bool GetFrom(const wxTopLevelWindow* tlw) override
|
||||
{
|
||||
// If we are using Wayland XDG session management protocol, we just
|
||||
// need to save the session ID.
|
||||
if ( wxTopLevelWindow::HasWaylandXDGSessionManagement() )
|
||||
{
|
||||
m_xdgSessionId = tlw->GetWaylandXDGSessionId();
|
||||
|
||||
// Note that it shouldn't be empty here: when XDG session
|
||||
// management protocol is supported, the compositor should have
|
||||
// assigned a session ID for the associated TLW.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( !wxTLWGeometryGeneric::GetFrom(tlw) )
|
||||
return false;
|
||||
|
||||
@@ -58,6 +88,28 @@ public:
|
||||
|
||||
virtual bool ApplyTo(wxTopLevelWindow* tlw) override
|
||||
{
|
||||
if ( wxTopLevelWindow::HasWaylandXDGSessionManagement() )
|
||||
{
|
||||
// As mentioned in Restore(), we need to call ApplyTo() even if we
|
||||
// don't have any saved state yet in order to register this window
|
||||
// with the session manager, so always do it, even if the session
|
||||
// ID is empty.
|
||||
tlw->SetWaylandXDGSessionId(m_xdgSessionId);
|
||||
|
||||
// However only return true if we did have a session ID to restore
|
||||
// and return false for the first run to give the application a
|
||||
// possibility to set the default size in this case.
|
||||
//
|
||||
// Note that returning true if we do have a session ID is
|
||||
// optimistic, we don't know if the geometry will be really
|
||||
// restored by the compositor (this will happen later, when the
|
||||
// window is shown), but we have to assume that it will be, as
|
||||
// always returning false from here would be definitely wrong as it
|
||||
// would cause the application to always overwrite the possibly
|
||||
// saved size with the default.
|
||||
return !m_xdgSessionId.empty();
|
||||
}
|
||||
|
||||
// Don't overwrite the current decoration size if we already have it.
|
||||
if ( !tlw->m_decorSize.left && !tlw->m_decorSize.right &&
|
||||
!tlw->m_decorSize.top && !tlw->m_decorSize.bottom )
|
||||
@@ -70,6 +122,8 @@ public:
|
||||
|
||||
private:
|
||||
wxTopLevelWindow::DecorSize m_decorSize;
|
||||
|
||||
wxString m_xdgSessionId;
|
||||
};
|
||||
|
||||
#endif // _WX_GTK_PRIVATE_TLWGEOM_H_
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
|
||||
#include "wx/protocols/pointer-warp-v1-client-protocol.h"
|
||||
|
||||
#ifdef wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
#include "wx/protocols/xdg-session-management-v1-client-protocol.h"
|
||||
#endif // wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
|
||||
namespace wxWayland
|
||||
{
|
||||
|
||||
@@ -51,6 +55,11 @@ wxDEFINE_WL_DELETER(wl_pointer, wl_pointer_release);
|
||||
wxDEFINE_WL_DELETER(wl_registry, wl_registry_destroy);
|
||||
wxDEFINE_WL_DELETER(wl_seat, wl_seat_release);
|
||||
wxDEFINE_WL_DELETER(wp_pointer_warp_v1, wp_pointer_warp_v1_destroy);
|
||||
#ifdef wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
wxDEFINE_WL_DELETER(xdg_session_manager_v1, xdg_session_manager_v1_destroy);
|
||||
wxDEFINE_WL_DELETER(xdg_session_v1, xdg_session_v1_destroy);
|
||||
wxDEFINE_WL_DELETER(xdg_toplevel_session_v1, xdg_toplevel_session_v1_destroy);
|
||||
#endif // wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
|
||||
template <typename T>
|
||||
using wl_unique_ptr = std::unique_ptr<T, wl_deleter<T>>;
|
||||
@@ -115,6 +124,11 @@ struct Globals
|
||||
|
||||
// Optional pointer to the global pointer warp protocol object.
|
||||
wl_unique_ptr<wp_pointer_warp_v1> pointer_warp;
|
||||
|
||||
#ifdef wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
// Optional pointer to the global session manager protocol object.
|
||||
wl_unique_ptr<xdg_session_manager_v1> session_manager;
|
||||
#endif // wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
};
|
||||
|
||||
extern Globals WLGlobals;
|
||||
|
||||
@@ -86,11 +86,28 @@ public:
|
||||
virtual void Refresh( bool eraseBackground = true,
|
||||
const wxRect *rect = (const wxRect *) nullptr ) override;
|
||||
|
||||
// GTK-specific accessor returning true if Wayland XDG session management
|
||||
// protocol is available.
|
||||
//
|
||||
// Returns false when not using Wayland at all.
|
||||
static bool HasWaylandXDGSessionManagement();
|
||||
|
||||
// Set the XDG session ID to use: calling this even with an empty string
|
||||
// registers this window as part of XDG toplevel session, meaning that its
|
||||
// geometry will be saved/restored by the compositor.
|
||||
bool SetWaylandXDGSessionId(const wxString& sessionId);
|
||||
|
||||
// Return the XDG session used by this object, if any.
|
||||
wxString GetWaylandXDGSessionId() const;
|
||||
|
||||
|
||||
// implementation from now on
|
||||
// --------------------------
|
||||
|
||||
// GTK callbacks
|
||||
virtual void GTKHandleRealized() override;
|
||||
virtual void GTKHandleUnrealized() override;
|
||||
|
||||
void GTKHandleMapped();
|
||||
|
||||
void GTKConfigureEvent(int x, int y);
|
||||
@@ -128,6 +145,10 @@ public:
|
||||
|
||||
void GTKDoAfterShow();
|
||||
|
||||
#ifdef wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
class wxXDGSessionData *m_xdgSessionData = nullptr;
|
||||
#endif // wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
|
||||
#ifdef __WXGTK3__
|
||||
void GTKUpdateClientSizeIfNecessary();
|
||||
|
||||
|
||||
@@ -67,11 +67,21 @@ private:
|
||||
return m_pers->SaveValue(name, value);
|
||||
}
|
||||
|
||||
virtual bool SaveString(const wxString& name, const wxString& value) override
|
||||
{
|
||||
return m_pers->SaveValue(name, value);
|
||||
}
|
||||
|
||||
virtual bool RestoreValue(const wxString& name, int* value) const override
|
||||
{
|
||||
return m_pers->RestoreValue(name, value);
|
||||
}
|
||||
|
||||
virtual bool RestoreString(const wxString& name, wxString* value) const override
|
||||
{
|
||||
return m_pers->RestoreValue(name, value);
|
||||
}
|
||||
|
||||
private:
|
||||
wxPersistentTLW* const m_pers;
|
||||
};
|
||||
|
||||
@@ -276,10 +276,30 @@ public:
|
||||
// will return false.
|
||||
virtual bool SaveValue(const wxString& name, int value) = 0;
|
||||
|
||||
// Same as above but for string values, not implemented by default
|
||||
// because this only needs to be implemented when using wxGTK with
|
||||
// Wayland XDG session management protocol and so can be ignored when
|
||||
// not targeting this platform.
|
||||
virtual bool SaveString(const wxString& name, const wxString& value)
|
||||
{
|
||||
wxUnusedVar(name);
|
||||
wxUnusedVar(value);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If restoring a value returns false, it just means that the value is
|
||||
// not present and RestoreToGeometry() still continues with restoring
|
||||
// the other values.
|
||||
virtual bool RestoreValue(const wxString& name, int* value) const = 0;
|
||||
|
||||
// Same as for but for string values, not implemented by default, see
|
||||
// comment for SaveString() above.
|
||||
virtual bool RestoreString(const wxString& name, wxString* value) const
|
||||
{
|
||||
wxUnusedVar(name);
|
||||
wxUnusedVar(value);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Save the current window geometry using the provided serializer and
|
||||
|
||||
@@ -436,6 +436,24 @@ public:
|
||||
*/
|
||||
virtual bool SaveValue(const wxString& name, int value) = 0;
|
||||
|
||||
/**
|
||||
Save a single field with the given string value.
|
||||
|
||||
This function is similar to SaveValue(), but is currently only used
|
||||
when using wxGTK with Wayland XDG session management protocol and
|
||||
so can be left unimplemented when not targeting this platform.
|
||||
|
||||
@param name uniquely identifies the field but is otherwise
|
||||
arbitrary.
|
||||
@param value value of the field, currently always non-empty.
|
||||
|
||||
@return @true if the field was saved or @false if saving it failed,
|
||||
resulting in wxTopLevelWindow::SaveGeometry() failure.
|
||||
|
||||
@since 3.3.4
|
||||
*/
|
||||
virtual bool SaveString(const wxString& name, const wxString& value);
|
||||
|
||||
/**
|
||||
Try to restore a single field.
|
||||
|
||||
@@ -452,6 +470,24 @@ public:
|
||||
found or an error occurred.
|
||||
*/
|
||||
virtual bool RestoreValue(const wxString& name, int* value) const = 0;
|
||||
|
||||
/**
|
||||
Try to restore a single string-valued field.
|
||||
|
||||
This function is similar to RestoreValue(), but is currently only
|
||||
used when using wxGTK with Wayland XDG session management protocol
|
||||
and so can be left unimplemented when not targeting this platform.
|
||||
|
||||
@param name uniquely identifies the field.
|
||||
@param value non-null pointer to the value to be filled by this
|
||||
function.
|
||||
|
||||
@return @true if the field was retrieved or @false if it wasn't
|
||||
found or an error occurred,
|
||||
|
||||
@since 3.3.4
|
||||
*/
|
||||
virtual bool RestoreString(const wxString& name, wxString* value) const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -629,6 +629,13 @@
|
||||
*/
|
||||
#undef wxHAVE_WAYLAND_CLIENT
|
||||
|
||||
/*
|
||||
Use Wayland session-management protocol.
|
||||
|
||||
This is defined if GTK is new enough to support it.
|
||||
*/
|
||||
#undef wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
|
||||
/*
|
||||
Use XTest extension to implement wxUIActionSimulator?
|
||||
|
||||
|
||||
@@ -49,6 +49,12 @@
|
||||
#include "wx/unix/private/x11ptr.h"
|
||||
#endif
|
||||
|
||||
#ifdef wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
#include "wx/gtk/private/wayland.h"
|
||||
|
||||
static constexpr const char* TRACE_XDGSM = "xdgsm";
|
||||
#endif // wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
|
||||
#define TRACE_TLWSIZE "tlwsize"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -383,6 +389,205 @@ void wxTopLevelWindowGTK::GTKConfigureEvent(int x, int y)
|
||||
// "realize" from m_widget
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// XDG session management support under Wayland
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifdef wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
|
||||
using wxWayland::wl_unique_ptr;
|
||||
|
||||
class wxXDGSessionData
|
||||
{
|
||||
public:
|
||||
wxXDGSessionData() = default;
|
||||
~wxXDGSessionData() = default;
|
||||
|
||||
wl_unique_ptr<xdg_session_v1> m_xdgSession;
|
||||
wl_unique_ptr<xdg_toplevel_session_v1> m_xdgToplevelSession;
|
||||
wxString m_sessionId;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxXDGSessionData);
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void
|
||||
xdgSessionCreated(void* data,
|
||||
xdg_session_v1* WXUNUSED(session),
|
||||
const char *id)
|
||||
{
|
||||
auto* const win = static_cast<wxTopLevelWindowGTK*>(data);
|
||||
|
||||
wxLogTrace(TRACE_XDGSM, "New XDG session \"%s\" created for %s",
|
||||
id, wxDumpWindow(win));
|
||||
|
||||
win->m_xdgSessionData->m_sessionId = wxString::FromUTF8(id);
|
||||
}
|
||||
|
||||
void xdgSessionRestored(void* data, xdg_session_v1* WXUNUSED(session))
|
||||
{
|
||||
auto* const win = static_cast<wxTopLevelWindowGTK*>(data);
|
||||
|
||||
wxLogTrace(TRACE_XDGSM, "XDG session \"%s\" restored for %s",
|
||||
win->m_xdgSessionData->m_sessionId, wxDumpWindow(win));
|
||||
}
|
||||
|
||||
void xdgSessionReplaced(void* data, xdg_session_v1* WXUNUSED(session))
|
||||
{
|
||||
auto* const win = static_cast<wxTopLevelWindowGTK*>(data);
|
||||
|
||||
// It's not clear what can we possibly do here, so don't do anything.
|
||||
wxLogTrace(TRACE_XDGSM, "XDG session \"%s\" replaced for %s",
|
||||
win->m_xdgSessionData->m_sessionId, wxDumpWindow(win));
|
||||
}
|
||||
|
||||
const xdg_session_v1_listener xdgSessionListener = {
|
||||
xdgSessionCreated,
|
||||
xdgSessionRestored,
|
||||
xdgSessionReplaced,
|
||||
};
|
||||
|
||||
void
|
||||
xdgToplevelSessionRestored(void* data, xdg_toplevel_session_v1* WXUNUSED(ts))
|
||||
{
|
||||
auto* const win = static_cast<wxTopLevelWindowGTK*>(data);
|
||||
|
||||
wxLogTrace(TRACE_XDGSM, "XDG toplevel session \"%s\" restored for %s",
|
||||
win->m_xdgSessionData->m_sessionId, wxDumpWindow(win));
|
||||
}
|
||||
|
||||
const xdg_toplevel_session_v1_listener xdgToplevelSessionListener = {
|
||||
xdgToplevelSessionRestored,
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
extern "C" {
|
||||
static gboolean wxgtk_tlw_xdg_realized(GdkWindow* window, wxTopLevelWindow* win)
|
||||
{
|
||||
wxLogTrace(TRACE_XDGSM, "xdg_toplevel_realized for %s", wxDumpWindow(win));
|
||||
|
||||
auto& data = win->m_xdgSessionData;
|
||||
wxCHECK_MSG( data, FALSE, "XDG session data should have been initialized" );
|
||||
|
||||
auto& xdgSession = data->m_xdgSession;
|
||||
|
||||
xdgSession.reset(xdg_session_manager_v1_get_session(
|
||||
wxWayland::WLGlobals.session_manager.get(),
|
||||
XDG_SESSION_MANAGER_V1_REASON_LAUNCH,
|
||||
data->m_sessionId.empty() ? nullptr : data->m_sessionId.utf8_str()
|
||||
));
|
||||
wxCHECK_MSG( xdgSession, FALSE, "Failed to get xdg_session" );
|
||||
|
||||
xdg_session_v1_add_listener(xdgSession.get(), &xdgSessionListener, win);
|
||||
|
||||
xdg_toplevel* const xdgToplevel = gdk_wayland_window_get_xdg_toplevel(window);
|
||||
if ( data->m_sessionId.empty() )
|
||||
{
|
||||
wxLogTrace(TRACE_XDGSM, "Adding %s to a new session",
|
||||
wxDumpWindow(win));
|
||||
|
||||
data->m_xdgToplevelSession.reset(xdg_session_v1_add_toplevel(
|
||||
xdgSession.get(),
|
||||
xdgToplevel,
|
||||
win->GetName().utf8_str()
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogTrace(TRACE_XDGSM, "Restoring session \"%s\" for %s",
|
||||
data->m_sessionId, wxDumpWindow(win));
|
||||
|
||||
data->m_xdgToplevelSession.reset(xdg_session_v1_restore_toplevel(
|
||||
data->m_xdgSession.get(),
|
||||
xdgToplevel,
|
||||
win->GetName().utf8_str()
|
||||
));
|
||||
}
|
||||
|
||||
xdg_toplevel_session_v1_add_listener(
|
||||
data->m_xdgToplevelSession.get(), &xdgToplevelSessionListener, win
|
||||
);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool wxTopLevelWindowGTK::HasWaylandXDGSessionManagement()
|
||||
{
|
||||
// Cache it just to avoid giving the trace messages more than once.
|
||||
static int s_cachedValue = -1;
|
||||
|
||||
if ( s_cachedValue == -1 )
|
||||
{
|
||||
s_cachedValue = 1;
|
||||
|
||||
if ( !g_signal_lookup("xdg-toplevel-realized", GDK_TYPE_WAYLAND_WINDOW) )
|
||||
{
|
||||
wxLogTrace(TRACE_XDGSM, "Runtime GTK version %d.%d.%d is too old.",
|
||||
gtk_get_major_version(),
|
||||
gtk_get_minor_version(),
|
||||
gtk_get_micro_version());
|
||||
|
||||
s_cachedValue = 0;
|
||||
}
|
||||
|
||||
if ( !wxWayland::WLGlobals.session_manager )
|
||||
{
|
||||
wxLogTrace(TRACE_XDGSM, "Compositor doesn't support the protocol.");
|
||||
|
||||
s_cachedValue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return s_cachedValue != 0;
|
||||
}
|
||||
|
||||
bool wxTopLevelWindowGTK::SetWaylandXDGSessionId(const wxString& sessionId)
|
||||
{
|
||||
wxCHECK_MSG( !m_xdgSessionData, false, "XDG session ID already set?" );
|
||||
|
||||
wxCHECK_MSG( !gtk_widget_get_realized(m_widget), false,
|
||||
"XDG session ID must be set before showing the window" );
|
||||
|
||||
wxCHECK_MSG( HasWaylandXDGSessionManagement(), false,
|
||||
"Shouldn't be called if not supported" );
|
||||
|
||||
m_xdgSessionData = new wxXDGSessionData();
|
||||
m_xdgSessionData->m_sessionId = sessionId;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
wxString wxTopLevelWindowGTK::GetWaylandXDGSessionId() const
|
||||
{
|
||||
return m_xdgSessionData ? m_xdgSessionData->m_sessionId : wxString{};
|
||||
}
|
||||
|
||||
#else // !wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
|
||||
/* static */
|
||||
bool wxTopLevelWindowGTK::HasWaylandXDGSessionManagement()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wxTopLevelWindowGTK::SetWaylandXDGSessionId(const wxString& sessionId)
|
||||
{
|
||||
wxUnusedVar(sessionId);
|
||||
return false;
|
||||
}
|
||||
|
||||
wxString wxTopLevelWindowGTK::GetWaylandXDGSessionId() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
#endif // wxHAVE_WAYLAND_SESSION_MANAGEMENT/!wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
|
||||
#if GTK_CHECK_VERSION(3,10,0)
|
||||
extern "C" {
|
||||
static void findTitlebar(GtkWidget* widget, void* data)
|
||||
@@ -410,6 +615,16 @@ void wxTopLevelWindowGTK::GTKHandleRealized()
|
||||
|
||||
GdkWindow* window = gtk_widget_get_window(m_widget);
|
||||
|
||||
#ifdef wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
// We effectively check if SetWaylandXDGSessionId() has been called, which
|
||||
// includes the check for the new enough GTK with support for this signal.
|
||||
if ( m_xdgSessionData )
|
||||
{
|
||||
g_signal_connect (window, "xdg-toplevel-realized",
|
||||
G_CALLBACK (wxgtk_tlw_xdg_realized), this);
|
||||
}
|
||||
#endif // wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
|
||||
#if GTK_CHECK_VERSION(3,10,0)
|
||||
if (wx_is_at_least_gtk3(10))
|
||||
{
|
||||
@@ -473,6 +688,19 @@ void wxTopLevelWindowGTK::GTKHandleRealized()
|
||||
#endif
|
||||
}
|
||||
|
||||
void wxTopLevelWindowGTK::GTKHandleUnrealized()
|
||||
{
|
||||
#ifdef wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
if ( m_xdgSessionData )
|
||||
{
|
||||
delete m_xdgSessionData;
|
||||
m_xdgSessionData = nullptr;
|
||||
}
|
||||
#endif // wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
|
||||
wxTopLevelWindowBase::GTKHandleUnrealized();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// "map_event" from m_widget
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -20,7 +20,14 @@
|
||||
// Code generated by wayland-scanner uses visibility attribute incorrectly for
|
||||
// C++, resulting in warnings, so disable them.
|
||||
wxGCC_WARNING_SUPPRESS(attributes)
|
||||
|
||||
#include "wx/protocols/pointer-warp-v1-client-protocol.c"
|
||||
|
||||
#ifdef wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
#include "wx/protocols/xdg-session-management-v1-client-protocol.c"
|
||||
#include "wx/protocols/xdg-shell-client-protocol.c"
|
||||
#endif // wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
|
||||
wxGCC_WARNING_RESTORE(attributes)
|
||||
|
||||
constexpr const char* TRACE_WAYLAND = "wayland";
|
||||
@@ -180,6 +187,15 @@ registry_handle_global(void* data,
|
||||
wl_registry_bind(registry, name, &wp_pointer_warp_v1_interface, 1)
|
||||
));
|
||||
}
|
||||
|
||||
#ifdef wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
if ( strcmp(interface, xdg_session_manager_v1_interface.name) == 0 )
|
||||
{
|
||||
WLGlobals.session_manager.reset(static_cast<xdg_session_manager_v1*>(
|
||||
wl_registry_bind(registry, name, &xdg_session_manager_v1_interface, 1)
|
||||
));
|
||||
}
|
||||
#endif // wxHAVE_WAYLAND_SESSION_MANAGEMENT
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -0,0 +1,318 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="xdg_session_management_v1">
|
||||
<copyright>
|
||||
Copyright 2018 Mike Blumenkrantz
|
||||
Copyright 2018 Samsung Electronics Co., Ltd
|
||||
Copyright 2018 Red Hat Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next
|
||||
paragraph) shall be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<description summary="Protocol for managing application sessions">
|
||||
This description provides a high-level overview of the interplay between
|
||||
the interfaces defined this protocol. For details, see the protocol
|
||||
specification.
|
||||
|
||||
The xdg_session_manager protocol declares interfaces necessary to
|
||||
allow clients to restore toplevel state from previous executions. The
|
||||
xdg_session_manager_v1.get_session request can be used to obtain a
|
||||
xdg_session_v1 resource representing the state of a set of toplevels.
|
||||
|
||||
Clients may obtain the session string to use in future calls through
|
||||
the xdg_session_v1.created event. Compositors will use this string
|
||||
as an identifiable token for future runs, possibly storing data about
|
||||
the related toplevels in persistent storage. Clients that wish to
|
||||
track sessions in multiple environments may use the $XDG_CURRENT_DESKTOP
|
||||
environment variable.
|
||||
|
||||
Toplevels are managed through the xdg_session_v1.add_toplevel and
|
||||
xdg_session_v1.remove_toplevel pair of requests. Clients will explicitly
|
||||
request a toplevel to be restored according to prior state through the
|
||||
xdg_session_v1.restore_toplevel request before the toplevel is mapped.
|
||||
|
||||
Compositors may store session information up to any arbitrary level, and
|
||||
apply any limits and policies to the amount of data stored and its lifetime.
|
||||
Clients must account for missing sessions and partial session restoration.
|
||||
|
||||
Warning! The protocol described in this file is currently in the testing
|
||||
phase. Backward compatible changes may be added together with the
|
||||
corresponding interface version bump. Backward incompatible changes can
|
||||
only be done by creating a new major version of the extension.
|
||||
</description>
|
||||
|
||||
<interface name="xdg_session_manager_v1" version="1">
|
||||
<description summary="manage sessions for applications">
|
||||
The xdg_session_manager_v1 interface defines base requests for creating and
|
||||
managing a session for an application. Sessions persist across application
|
||||
and compositor restarts unless explicitly destroyed. A session is created
|
||||
for the purpose of maintaining an application's xdg_toplevel surfaces
|
||||
across compositor or application restarts. The compositor should remember
|
||||
as many states as possible for surfaces in a given session, but there is
|
||||
no requirement for which states must be remembered.
|
||||
|
||||
Policies such as cache eviction are declared an implementation detail of
|
||||
the compositor. Clients should account for no longer existing sessions.
|
||||
</description>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="in_use" summary="a requested session is already in use"
|
||||
value="1"/>
|
||||
<entry name="invalid_session_id" summary="invalid session identifier"
|
||||
value="2"/>
|
||||
</enum>
|
||||
|
||||
<enum name="reason">
|
||||
<description summary="reason for getting a session">
|
||||
The reason may determine in what way a session restores the window
|
||||
management state of associated toplevels.
|
||||
|
||||
For example newly launched applications might be launched on the active
|
||||
workspace with restored size and position, while a recovered
|
||||
application might restore additional state such as active workspace and
|
||||
stacking order.
|
||||
</description>
|
||||
<entry name="launch" value="1">
|
||||
<description summary="an app is newly launched">
|
||||
A new app instance is launched, for example from an app launcher.
|
||||
</description>
|
||||
</entry>
|
||||
<entry name="recover" value="2">
|
||||
<description summary="an app recovered">
|
||||
A app instance is recovering from for example a compositor or app crash.
|
||||
</description>
|
||||
</entry>
|
||||
<entry name="session_restore" value="3">
|
||||
<description summary="an app restored">
|
||||
A app instance is restored, for example part of a restored session, or
|
||||
restored from having been temporarily terminated due to resource
|
||||
constraints.
|
||||
</description>
|
||||
</entry>
|
||||
</enum>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="Destroy this object">
|
||||
Destroy the manager object. The existing session objects will be
|
||||
unaffected.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="get_session">
|
||||
<description summary="create or restore a session">
|
||||
Create a session object corresponding to either an existing session
|
||||
identified by the given session identifier string or a new session.
|
||||
While the session object exists, the session is considered to be "in
|
||||
use".
|
||||
|
||||
If an identifier string represents a session that is currently actively
|
||||
in use by the the same client, an 'in_use' error is raised. If some
|
||||
other client is currently using the same session, the new session will
|
||||
replace managing the associated state.
|
||||
|
||||
NULL is passed to initiate a new session. If a session_id is passed
|
||||
which does not represent a valid session, the compositor treats it as if
|
||||
NULL had been passed.
|
||||
|
||||
The session id string must be UTF-8 encoded. It is also limited by the
|
||||
maximum length of wayland messages (around 4KB). The 'invalid_session_id'
|
||||
protocol error will be raised if an invalid string is provided.
|
||||
|
||||
A client is allowed to have any number of in use sessions at the same
|
||||
time.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="xdg_session_v1"/>
|
||||
<arg name="reason" type="uint" enum="reason"
|
||||
summary="reason for session"/>
|
||||
<arg name="session_id" type="string"
|
||||
summary="the session to restore"
|
||||
allow-null="true"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="xdg_session_v1" version="1">
|
||||
<description summary="A session for an application">
|
||||
A xdg_session_v1 object represents a session for an application. While the
|
||||
object exists, all surfaces which have been added to the session will
|
||||
have states stored by the compositor which can be reapplied at a later
|
||||
time. Two sessions cannot exist for the same identifier string.
|
||||
|
||||
States for surfaces added to a session are automatically updated by the
|
||||
compositor when they are changed.
|
||||
</description>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="name_in_use"
|
||||
summary="toplevel name is already in use"
|
||||
value="1"/>
|
||||
<entry name="already_mapped"
|
||||
summary="toplevel was already mapped when restored"
|
||||
value="2"/>
|
||||
<entry name="invalid_name"
|
||||
summary="provided toplevel name is invalid"
|
||||
value="3"/>
|
||||
</enum>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="Destroy the session">
|
||||
Destroy a session object, preserving the current state but not continuing
|
||||
to make further updates if state changes occur. This makes the associated
|
||||
xdg_toplevel_session_v1 objects inert.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="remove" type="destructor">
|
||||
<description summary="Remove the session">
|
||||
Remove the session, making it no longer available for restoration. A
|
||||
compositor should in response to this request remove the data related to
|
||||
this session from its storage.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="add_toplevel">
|
||||
<description summary="add a new surface to the session">
|
||||
Attempt to add a given surface to the session. The passed name is used
|
||||
to identify what window is being restored, and may be used to store
|
||||
window specific state within the session.
|
||||
|
||||
The name given to the toplevel must not correspond to any previously
|
||||
existing toplevel names in the session. If the name matches an already
|
||||
known toplevel name in the session, a 'name_in_use' protocol error will
|
||||
be raised.
|
||||
|
||||
This request will return a xdg_toplevel_session_v1 for later
|
||||
manipulation. As this resource is created from an empty initial state,
|
||||
compositors must not emit a xdg_toplevel_session_v1.restored event for
|
||||
resources created through this request.
|
||||
|
||||
The name string must be UTF-8 encoded. It is also limited by the maximum
|
||||
length of wayland messages (around 4KB). The 'invalid_name' protocol
|
||||
error will be raised if an invalid string is provided.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="xdg_toplevel_session_v1"/>
|
||||
<arg name="toplevel" type="object" interface="xdg_toplevel"/>
|
||||
<arg name="name" type="string" summary="name identifying the toplevel"/>
|
||||
</request>
|
||||
|
||||
<request name="restore_toplevel">
|
||||
<description summary="restore a surface state">
|
||||
Inform the compositor that the toplevel associated with the passed name
|
||||
should have its window management state restored.
|
||||
|
||||
If the toplevel name was previously granted to another xdg_toplevel,
|
||||
the 'name_in_use' protocol error will be raised.
|
||||
|
||||
This request must be called prior to the first commit on the associated
|
||||
wl_surface after creating the toplevel, otherwise an 'already_mapped'
|
||||
error is raised.
|
||||
|
||||
As part of the initial configure sequence, if the toplevel was
|
||||
successfully restored, a xdg_toplevel_session_v1.restored event is
|
||||
emitted. If the toplevel name was not known in the session, this request
|
||||
will be equivalent to the xdg_toplevel_session_v1.add_toplevel request,
|
||||
and no such event will be emitted. See the xdg_toplevel_session_v1.restored
|
||||
event for further details.
|
||||
|
||||
The name string must be UTF-8 encoded. It is also limited by the maximum
|
||||
length of wayland messages (around 4KB). The 'invalid_name' protocol
|
||||
error will be raised if an invalid string is provided.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="xdg_toplevel_session_v1"/>
|
||||
<arg name="toplevel" type="object" interface="xdg_toplevel"/>
|
||||
<arg name="name" type="string" summary="name identifying the toplevel"/>
|
||||
</request>
|
||||
|
||||
<request name="remove_toplevel">
|
||||
<description summary="remove a surface from the session">
|
||||
Remove a specified surface from the session and render any related
|
||||
xdg_toplevel_session_v1 object inert. The compositor should remove any
|
||||
data related to the toplevel in the corresponding session from its internal
|
||||
storage.
|
||||
|
||||
The window is specified by its name in the session. The name string
|
||||
must be encoded in UTF-8, and it is limited in size by the maximum
|
||||
length of wayland messages (around 4KB).
|
||||
</description>
|
||||
<arg name="name" type="string" summary="name identifying the toplevel"/>
|
||||
</request>
|
||||
|
||||
<event name="created">
|
||||
<description summary="newly-created session id">
|
||||
Emitted at most once some time after getting a new session object. It
|
||||
means that no previous state was restored, and a new session was created.
|
||||
The passed id can be persistently stored and used to restore previous
|
||||
sessions.
|
||||
</description>
|
||||
<arg name="session_id" type="string"/>
|
||||
</event>
|
||||
|
||||
<event name="restored">
|
||||
<description summary="the session has been restored">
|
||||
Emitted at most once some time after getting a new session object. It
|
||||
means that previous state was at least partially restored. The same id
|
||||
can again be used to restore previous sessions.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<event name="replaced">
|
||||
<description summary="the session has been replaced">
|
||||
Emitted at most once, if the session was taken over by some other
|
||||
client. When this happens, the session and all its toplevel session
|
||||
objects become inert, and should be destroyed.
|
||||
</description>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="xdg_toplevel_session_v1" version="1">
|
||||
<description summary="A session for an application">
|
||||
A xdg_toplevel_session_v1 resource acts as a handle for the given
|
||||
toplevel in the session. It allows for receiving events after a
|
||||
toplevel state was restored, and has the requests to manage them.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="Destroy the object">
|
||||
Destroy the object. This has no effect over window management of the
|
||||
associated toplevel.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="rename">
|
||||
<description summary="change the name of toplevel session">
|
||||
Renames the toplevel session. The new name can be used in subsequent requests
|
||||
to identify this session object. The state associated with this toplevel
|
||||
session will be preserved.
|
||||
|
||||
If the xdg_session_v1 already contains a toplevel with the specified name,
|
||||
the 'name_in_use' protocol error will be raised.
|
||||
</description>
|
||||
<arg name="name" type="string" summary="new name to identify the toplevel"/>
|
||||
</request>
|
||||
|
||||
<event name="restored">
|
||||
<description summary="a toplevel's session has been restored">
|
||||
The "restored" event is emitted prior to the first
|
||||
xdg_toplevel.configure for the toplevel. It will only be emitted after
|
||||
xdg_session_v1.restore_toplevel, and the initial empty surface state has
|
||||
been applied, and it indicates that the surface's session is being
|
||||
restored with this configure event.
|
||||
</description>
|
||||
</event>
|
||||
</interface>
|
||||
</protocol>
|
||||
Reference in New Issue
Block a user