diff --git a/eosclubhouse/clubhouse.py b/eosclubhouse/clubhouse.py index 12c5938cf..37945f9e7 100644 --- a/eosclubhouse/clubhouse.py +++ b/eosclubhouse/clubhouse.py @@ -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 @@ -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') @@ -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() @@ -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 diff --git a/eosclubhouse/portal.py b/eosclubhouse/portal.py new file mode 100644 index 000000000..7439ccf52 --- /dev/null +++ b/eosclubhouse/portal.py @@ -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) + 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)