Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clubhouse: Request background permission #1218

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion eosclubhouse/clubhouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
from eosclubhouse.animation import Animation, AnimationImage, AnimationSystem, Animator, \
get_character_animation_dirs
from eosclubhouse import metrics
from eosclubhouse.portal import Portal

from eosclubhouse.widgets import FixedLayerGroup, ScalableImage, gtk_widget_add_custom_css_provider

Expand Down Expand Up @@ -2240,6 +2241,7 @@ def __init__(self, app):
self._gss = GameStateService()
self._user = UserAccount()
self._page_reset_timeout = 0
self._background_permission = None

self._scale = 1
self._ambient_sound_item = SoundItem('clubhouse/ambient')
Expand Down Expand Up @@ -2294,11 +2296,18 @@ def __init__(self, app):

self._user.connect('changed', lambda _user: self.update_user_info())
self.update_user_info()
self.connect('notify::has-toplevel-focus', self._request_background_permission)

@GObject.Property(type=float)
def scale(self):
return self._scale

def _request_background_permission(self, _win, _param):
if self._background_permission is None:
def set_bg_perm(value):
self._background_permission = value
Portal.request_background(callback=set_bg_perm)

def _user_event_box_button_press_event_cb(self, _button, event, achievements_view):
if not achievements_view.hover:
self.hide_achievements_view()
Expand Down Expand Up @@ -3082,7 +3091,6 @@ def __init__(self):
super().__init__(application_id=CLUBHOUSE_NAME,
inactivity_timeout=self._INACTIVITY_TIMEOUT,
resource_base_path='/com/hack_computer/Clubhouse')

self._installing_extension = False
self._use_inapp_notifications = False
self._quest_runner_handler = None
Expand Down
94 changes: 94 additions & 0 deletions eosclubhouse/portal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Copyright (C) 2020 Endless OS Foundation LLC.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#

import logging

from gi.repository import Gio, GLib


_logger = logging.getLogger(__name__)


class Portal:
_proxy = None
_response_signal_id = None

@classmethod
def _get_proxy(klass):
if klass._proxy is None:
klass._proxy = Gio.DBusProxy.new_for_bus_sync(
Gio.BusType.SESSION,
0,
None,
'org.freedesktop.portal.Desktop',
'/org/freedesktop/portal/desktop',
'org.freedesktop.portal.Background',
None
)
return klass._proxy

@classmethod
def request_background(klass, message='', callback=None):
handle_token = 'clubhouse_req_hack'
try:
klass._connect_response(handle_token, callback)
proxy = klass._get_proxy()
options = {
'handle_token': GLib.Variant('s', handle_token),
}
if message:
options['reason'] = GLib.Variant('s', message)
proxy.RequestBackground('(sa{sv})', '', options)
Copy link

@dylanmccall dylanmccall Nov 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is another error case here which might be worth handling by watching the returned Request object. If the user denies the request to run in the background, the portal will never ask again. The user needs to do flatpak permission-reset com.hack_computer.Clubhouse or poke around in GNOME Control Center to fix it. (Or there might be a way to reset your permissions inside a flatpak? I can't say I actually looked very hard when I did it).

Here's some code where I did that in GNOME Break Timer:

https://gitlab.gnome.org/GNOME/gnome-break-timer/-/blob/master/src/settings/MainWindow.vala#L278-311

https://gitlab.gnome.org/GNOME/gnome-break-timer/-/blob/master/src/settings/BreakManager.vala#L117-210

https://gitlab.gnome.org/GNOME/gnome-break-timer/-/blob/master/src/settings/MainWindow.vala#L278-311

For Clubhouse this might not be too much of a problem since it's just asking for the Background permission to remove pesky notifications, although it is rather unfortunate to have only one chance to do it right when we aren't handling the error. (It makes it really fiddly to test, for one thing).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this long and detailed description of the service, I'll take a second look to try to improve the integration. I've been doing some testing with a fedora 33 virtual machine and it looks like that just with the request, the inactivity dialog dissapears, but maybe that's just a implementation issue and this can fail in other distributions, so I'll try to implement the whole flow.

Copy link

@dylanmccall dylanmccall Nov 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect what might be happening there is it gets denied permission, rather than simply not granted. (Which feels like a bug in the portal, come to think of it. I reported it over here: flatpak/xdg-desktop-portal#551).

So then it is technically not allowed to run in the background, although I think what happens from there is undefined.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've detected that if the user allows, the app will run in background without any problem, and if the user declines, the app will be stopped when the window disappears, after a few seconds. But there's no notification, if the app request the background permission, the system do that automatically without asking again or notify to the user.

except GLib.Error as err:
_logger.warning('Error requesting background permission to portal: %s', err)

@classmethod
def _connect_response(klass, token, callback):
proxy = klass._get_proxy()
connection = proxy.get_connection()

sender = connection.get_unique_name()[1:].replace('.', '_')
handle = f'/org/freedesktop/portal/desktop/request/{sender}/{token}'

if klass._response_signal_id:
klass._disconnect_response()

def _response_received(conn, sender_name, object_path, interface_name,
signal_name, parameters, user_data):
if parameters:
_id, params = parameters.unpack()
if callback:
callback(params['background'])

klass._response_signal_id = Gio.DBusConnection.signal_subscribe(
connection,
'org.freedesktop.portal.Desktop',
'org.freedesktop.portal.Request',
'Response',
handle,
None,
Gio.DBusSignalFlags.NO_MATCH_RULE,
_response_received,
None,
)

@classmethod
def _disconnect_response(klass):
proxy = klass._get_proxy()
connection = proxy.get_connection()
Gio.DBusConnection.signal_unsubscribe(connection,
klass._response_signal_id)