Skip to content

Commit

Permalink
remote: support the ConnectToEIS method added in version 2
Browse files Browse the repository at this point in the history
This is intended to replace the various NotifyFoo dbus methods and
instead connect the application with the implementation of the portal
directly via a shared socket.
  • Loading branch information
whot committed Nov 28, 2022
1 parent a47cdc1 commit 72ea745
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 2 deletions.
63 changes: 63 additions & 0 deletions libportal/remote.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,68 @@ typedef struct {
guint cancelled_id;
} CreateCall;

/**
* xdp_session_connect_to_eis
* @session: a [class@Session]
*
* Connect this XdpRemoteDesktopSession to an EIS implementation and return the fd.
* This fd can be passed into ei_setup_backend_fd(). See the libei
* documentation for details.
*
* This call must be issued before xdp_session_start(). If successful, all input
* event emulation must be handled via the EIS connection and calls to
* xdp_session_pointer_motion() etc. are silently ignored.
*
* Returns: the file descriptor to the EIS implementation or a negative errno
* on failure.
*/
int
xdp_session_connect_to_eis(XdpSession *session)
{
XdpPortal *portal = session->portal;
GVariantBuilder options;
g_autoptr(GVariant) ret = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GUnixFDList) fd_list = NULL;
int fd_out = -1;

g_return_val_if_fail (session->type == XDP_SESSION_REMOTE_DESKTOP, -EINVAL);
g_return_val_if_fail (xdp_session_get_session_state (session) == XDP_SESSION_INITIAL, -EBUSY);
g_return_val_if_fail (!session->uses_eis, -EALREADY);

if (portal->remote_desktop_interface_version < 2)
return -ENOTSUP;

g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT);

ret = g_dbus_connection_call_with_unix_fd_list_sync (portal->bus,
PORTAL_BUS_NAME,
PORTAL_OBJECT_PATH,
"org.freedesktop.portal.RemoteDesktop",
"ConnectToEIS",
g_variant_new ("(oa{sv})",
session->id,
&options),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&fd_list,
NULL,
&error);
if (!ret)
{
g_warning ("Failed to ConnectToEIS: %s", error->message);
return -ENODEV;
}

session->uses_eis = TRUE;

g_variant_get (ret, "(h)", &fd_out);

return g_unix_fd_list_get (fd_list, fd_out, NULL);
}

static void
create_call_free (CreateCall *call)
{
Expand Down Expand Up @@ -899,6 +961,7 @@ is_active_remotedesktop_session (XdpSession *session,
return XDP_IS_SESSION (session) &&
session->type == XDP_SESSION_REMOTE_DESKTOP &&
session->state == XDP_SESSION_ACTIVE &&
!session->uses_eis &&
(session->devices & required_device) != 0;
}

Expand Down
3 changes: 3 additions & 0 deletions libportal/remote.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ XdpDeviceType xdp_session_get_devices (XdpSession *session);
XDP_PUBLIC
GVariant * xdp_session_get_streams (XdpSession *session);

XDP_PUBLIC
int xdp_session_connect_to_eis (XdpSession *session);

XDP_PUBLIC
void xdp_session_pointer_motion (XdpSession *session,
double dx,
Expand Down
1 change: 1 addition & 0 deletions libportal/session-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct _XdpSession {

XdpPersistMode persist_mode;
char *restore_token;
gboolean uses_eis;

guint signal_id;
};
Expand Down
23 changes: 22 additions & 1 deletion tests/pyportaltest/templates/remotedesktop.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def load(mock, parameters):

params = MockParams.get(mock, MAIN_IFACE)
params.delay = 500
params.version = parameters.get("version", 1)
params.version = parameters.get("version", 2)
params.response = parameters.get("response", 0)
params.devices = parameters.get("devices", 0b111)
params.sessions: Dict[str, Session] = {}
Expand Down Expand Up @@ -245,3 +245,24 @@ def NotifyTouchUp(self, session_handle, options, slot):
logger.debug(f"NotifyTouchMotion: {session_handle} {options} {slot}")
except Exception as e:
logger.critical(e)


@dbus.service.method(
MAIN_IFACE,
in_signature="oa{sv}",
out_signature="h",
)
def ConnectToEIS(self, session_handle, options):
try:
logger.debug(f"ConnectToEIS: {session_handle} {options}")
import socket

sockets = socket.socketpair()
# Write some random data down so it'll break anything that actually
# expects the socket to be a real EIS socket
sockets[0].send(b"VANILLA")
fd = sockets[1]
logger.debug(f"ConnectToEIS with fd {fd.fileno()}")
return dbus.types.UnixFd(fd)
except Exception as e:
logger.critical(e)
43 changes: 42 additions & 1 deletion tests/pyportaltest/test_remotedesktop.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from . import PortalTest

import errno
import dbus
import gi
import logging
Expand Down Expand Up @@ -33,7 +34,7 @@ class SessionSetup(NamedTuple):

class TestRemoteDesktop(PortalTest):
def test_version(self):
self.assert_version_eq(1)
self.assert_version_eq(2)

def short_mainloop(self):
"""
Expand Down Expand Up @@ -414,6 +415,46 @@ def test_notify_touch(self):
session_handle, options, slot = args
assert slot == 10

def test_connect_to_eis_v1(self):
params = {"version": 1}
setup = self.create_session(params=params, start_session=False)
session = setup.session

err = session.connect_to_eis()
assert err == -errno.ENOTSUP

def test_connect_to_eis(self):
setup = self.create_session(start_session=False)
session = setup.session
handle = session.connect_to_eis()
assert handle

fd = os.fdopen(handle)
buf = fd.read()
assert buf == "VANILLA" # template sends this by default

method_calls = self.mock_interface.GetMethodCalls("ConnectToEIS")
assert len(method_calls) == 1
_, args = method_calls.pop(0)
session_handle, options = args
assert "handle_token" not in options # this is not a Request
assert list(options.keys()) == []

def test_connect_to_eis_fail_reconnect(self):
setup = self.create_session(start_session=False)
session = setup.session
handle = session.connect_to_eis()
assert handle

err = session.connect_to_eis()
assert err == -errno.EALREADY

def test_connect_to_eis_fail_connect_after_start(self):
setup = self.create_session(start_session=True)
session = setup.session
err = session.connect_to_eis()
assert err == -errno.EBUSY

def test_close_session(self):
"""
Ensure that closing our session explicitly closes the session on DBus
Expand Down

0 comments on commit 72ea745

Please sign in to comment.