diff -Nru phosh-0.8.0/config.h.in phosh-0.13.1/config.h.in --- phosh-0.8.0/config.h.in 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/config.h.in 2021-08-31 09:15:52.000000000 +0000 @@ -11,3 +11,4 @@ #mesondefine LOCALEDIR +#mesondefine HAVE_RFKILL_EVENT_EXT diff -Nru phosh-0.8.0/data/00_sm.puri.Phosh.gschema.override phosh-0.13.1/data/00_sm.puri.Phosh.gschema.override --- phosh-0.8.0/data/00_sm.puri.Phosh.gschema.override 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/data/00_sm.puri.Phosh.gschema.override 2021-08-31 09:15:52.000000000 +0000 @@ -1,7 +1,7 @@ -[org.gnome.desktop.a11y.applications] +[org.gnome.desktop.a11y.applications:Phosh] screen-keyboard-enabled=true -[org.gnome.desktop.interface] +[org.gnome.desktop.interface:Phosh] clock-show-date=false clock-show-weekday=false diff -Nru phosh-0.8.0/data/camera-hardware-disabled-symbolic.svg phosh-0.13.1/data/camera-hardware-disabled-symbolic.svg --- phosh-0.8.0/data/camera-hardware-disabled-symbolic.svg 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/data/camera-hardware-disabled-symbolic.svg 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,6 @@ + + + + + + diff -Nru phosh-0.8.0/data/feedback-quiet-symbolic.svg phosh-0.13.1/data/feedback-quiet-symbolic.svg --- phosh-0.8.0/data/feedback-quiet-symbolic.svg 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/data/feedback-quiet-symbolic.svg 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,31 @@ + + + + + + + + + diff -Nru phosh-0.8.0/data/meson.build phosh-0.13.1/data/meson.build --- phosh-0.8.0/data/meson.build 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/data/meson.build 2021-08-31 09:15:52.000000000 +0000 @@ -1,6 +1,37 @@ +gsd_required_components = [ + 'org.gnome.SettingsDaemon.A11ySettings', + 'org.gnome.SettingsDaemon.Color', + 'org.gnome.SettingsDaemon.Datetime', + 'org.gnome.SettingsDaemon.Housekeeping', + 'org.gnome.SettingsDaemon.Keyboard', + 'org.gnome.SettingsDaemon.MediaKeys', + 'org.gnome.SettingsDaemon.Power', + 'org.gnome.SettingsDaemon.PrintNotifications', + 'org.gnome.SettingsDaemon.Rfkill', + 'org.gnome.SettingsDaemon.ScreensaverProxy', + 'org.gnome.SettingsDaemon.Sharing', + 'org.gnome.SettingsDaemon.Smartcard', + 'org.gnome.SettingsDaemon.Sound', + 'org.gnome.SettingsDaemon.UsbProtection', + 'org.gnome.SettingsDaemon.Wacom', + 'org.gnome.SettingsDaemon.Wwan', + 'org.gnome.SettingsDaemon.XSettings', +] + +desktop_required_components = gsd_required_components + [ + 'sm.puri.Phosh', + 'sm.puri.OSK0', +] + desktopconf = configuration_data() desktopconf.set('bindir', bindir) desktopconf.set('libexecdir', libexecdir) +desktopconf.set('required_components', ';'.join(desktop_required_components) + ';') +if get_option('systemd') + desktopconf.set('hidden_under_systemd', 'X-GNOME-HiddenUnderSystemd=true') +else + desktopconf.set('hidden_under_systemd', '') +endif desktop_files = [ 'sm.puri.Phosh.desktop', @@ -47,6 +78,14 @@ runconf.set('pkgdatadir', pkgdatadir) runconf.set('version', meson.project_version()) runconf.set('wlrootsdir', join_paths(libexecdir, 'wlroots')) +runconf.set('compositor', get_option('compositor')) + +if get_option('systemd') + runconf.set('session_manager', '--systemd') +else + runconf.set('session_manager', '--builtin') +endif + configure_file( input: 'phosh.in', output: 'phosh', @@ -59,7 +98,8 @@ #generate XML enum definitions for GSettings schema schema_enum_headers = files( - '../src/wwan/phosh-wwan-backend.h' + '../src/app-grid.h', + '../src/wwan/phosh-wwan-backend.h', ) generate_enums_schema = gnome.mkenums('sm.puri.phosh.enums.xml', sources: schema_enum_headers, @@ -97,6 +137,8 @@ install_dir: schemasdir ) +subdir('systemd') + install_data('phoc.ini', install_dir : pkgdatadir) install_data('wayland-sessions/phosh.desktop', install_dir : 'share/wayland-sessions') diff -Nru phosh-0.8.0/data/microphone-hardware-disabled-symbolic.svg phosh-0.13.1/data/microphone-hardware-disabled-symbolic.svg --- phosh-0.8.0/data/microphone-hardware-disabled-symbolic.svg 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/data/microphone-hardware-disabled-symbolic.svg 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,6 @@ + + + + + + diff -Nru phosh-0.8.0/data/phosh.in phosh-0.13.1/data/phosh.in --- phosh-0.8.0/data/phosh.in 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/data/phosh.in 2021-08-31 09:15:52.000000000 +0000 @@ -1,20 +1,8 @@ #!/bin/sh -COMPOSITOR="/usr/bin/phoc" +COMPOSITOR="@compositor@" PHOC_INI="@pkgdatadir@/phoc.ini" - -gnome_session_args() -{ - ARGS="--disable-acceleration-check --session=phosh" - - # Use builtin session handling until we can rely - # on a newer gnome-session everywhere - if gnome-session --help | grep -qs -e--builtin; then - ARGS="--builtin ${ARGS}" - fi - - echo "${ARGS}" -} +GNOME_SESSION=${GNOME_SESSION:-gnome-session} help() { @@ -60,4 +48,4 @@ # variables from /etc/profile.d (XDG_*) [ -n "$WLR_BACKENDS" ] || WLR_BACKENDS=drm,libinput export WLR_BACKENDS -exec "${COMPOSITOR}" -C "${PHOC_INI}" -E "bash -lc 'gnome-session $(gnome_session_args)'" +exec "${COMPOSITOR}" -C "${PHOC_INI}" -E "bash -lc '${GNOME_SESSION} --disable-acceleration-check --session=phosh @session_manager@'" diff -Nru phosh-0.8.0/data/phosh.service phosh-0.13.1/data/phosh.service --- phosh-0.8.0/data/phosh.service 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/data/phosh.service 2021-08-31 09:15:52.000000000 +0000 @@ -1,6 +1,6 @@ [Unit] Description=Phosh, a shell for mobile phones -Documentation=https://source.puri.sm/Librem5/phosh +Documentation=https://gitlab.gnome.org/World/Phosh/phosh # Make sure we are started after logins are permitted. After=systemd-user-sessions.service @@ -26,7 +26,7 @@ [Service] Environment=LANG=C.UTF-8 -Environment=XDG_CURRENT_DESKTOP=GNOME +Environment=XDG_CURRENT_DESKTOP=GNOME:Phosh Environment=XDG_SESSION_DESKTOP=phosh Environment=XDG_SESSION_TYPE=wayland ExecStart=/usr/bin/phosh @@ -34,7 +34,7 @@ User=1000 PAMName=login WorkingDirectory=~ -Restart=on-failure +Restart=always RestartSec=5s # A virtual terminal is needed. diff -Nru phosh-0.8.0/data/phosh.session.desktop.in.in phosh-0.13.1/data/phosh.session.desktop.in.in --- phosh-0.8.0/data/phosh.session.desktop.in.in 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/data/phosh.session.desktop.in.in 2021-08-31 09:15:52.000000000 +0000 @@ -1,4 +1,4 @@ [GNOME Session] # Translators: this is the session name, no need to translate it Name=Phosh -RequiredComponents=sm.puri.Phosh;org.gnome.SettingsDaemon.A11ySettings;org.gnome.SettingsDaemon.Color;org.gnome.SettingsDaemon.Datetime;org.gnome.SettingsDaemon.Housekeeping;org.gnome.SettingsDaemon.Keyboard;org.gnome.SettingsDaemon.Power;org.gnome.SettingsDaemon.PrintNotifications;org.gnome.SettingsDaemon.Rfkill;org.gnome.SettingsDaemon.ScreensaverProxy;org.gnome.SettingsDaemon.Sharing;org.gnome.SettingsDaemon.Smartcard;org.gnome.SettingsDaemon.Sound;sm.puri.OSK0; +RequiredComponents=@required_components@ diff -Nru phosh-0.8.0/data/sm.puri.Phosh.desktop.in.in phosh-0.13.1/data/sm.puri.Phosh.desktop.in.in --- phosh-0.8.0/data/sm.puri.Phosh.desktop.in.in 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/data/sm.puri.Phosh.desktop.in.in 2021-08-31 09:15:52.000000000 +0000 @@ -10,3 +10,4 @@ X-GNOME-Provides=panel;windowmanager; X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true +@hidden_under_systemd@ diff -Nru phosh-0.8.0/data/sm.puri.phosh.gschema.xml phosh-0.13.1/data/sm.puri.phosh.gschema.xml --- phosh-0.8.0/data/sm.puri.phosh.gschema.xml 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/data/sm.puri.phosh.gschema.xml 2021-08-31 09:15:52.000000000 +0000 @@ -2,7 +2,7 @@ - [ 'sm.puri.Calls.desktop', + [ 'org.gnome.Calls.desktop', 'sm.puri.Chatty.desktop', 'org.gnome.Epiphany.desktop', 'org.gnome.Contacts.desktop' @@ -13,6 +13,17 @@ displayed in the favorites panel along with running applications. + + ['adaptive'] + + How to filter apps in the overview. The default 'adaptive' shows only + adaptive apps in mobile mode and all apps in docked mode. 'off' turns + of all filtering. + + + Whether to filter out apps that aren't marked as adaptive in mobile mode. + + [] diff -Nru phosh-0.8.0/data/systemd/meson.build phosh-0.13.1/data/systemd/meson.build --- phosh-0.8.0/data/systemd/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/data/systemd/meson.build 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,37 @@ +if get_option('systemd') + +gsd_wants = '' +foreach component : gsd_required_components + gsd_wants += 'Wants=' + component + '.target\n' +endforeach + +session_dropins = [ + 'gnome-session@phosh.target.d', +] + +sessionconf = configuration_data() +sessionconf.set('gsd_wants', gsd_wants) + +foreach session_dropin : session_dropins + configure_file( + input: 'phosh.session.conf.in', + output: 'session.conf', + install_dir: join_paths(systemduserdir, session_dropin), + configuration: sessionconf, + install: true + ) +endforeach + +serviceconf = configuration_data() +serviceconf.set('libexecdir', libexecdir) +configure_file( + input: 'sm.puri.Phosh.service.in', + output: 'sm.puri.Phosh.service', + install_dir: systemduserdir, + configuration: serviceconf, + install: true +) + +install_data('sm.puri.Phosh.target', install_dir: systemduserdir) + +endif diff -Nru phosh-0.8.0/data/systemd/phosh.session.conf.in phosh-0.13.1/data/systemd/phosh.session.conf.in --- phosh-0.8.0/data/systemd/phosh.session.conf.in 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/data/systemd/phosh.session.conf.in 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,4 @@ +[Unit] +@gsd_wants@ + +Requires=sm.puri.Phosh.target diff -Nru phosh-0.8.0/data/systemd/sm.puri.Phosh.service.in phosh-0.13.1/data/systemd/sm.puri.Phosh.service.in --- phosh-0.8.0/data/systemd/sm.puri.Phosh.service.in 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/data/systemd/sm.puri.Phosh.service.in 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,27 @@ +# This is a systemd user unit intended to be started with gnome-session. + +[Unit] +Description=Phosh, a shell for mobile phones +Documentation=https://gitlab.gnome.org/World/Phosh/phosh + +After=gnome-session-manager.target + +Requisite=gnome-session-initialized.target +PartOf=gnome-session-initialized.target +Before=gnome-session-initialized.target + +StartLimitIntervalSec=15s +StartLimitBurst=3 + +OnFailure=gnome-session-shutdown.target +OnFailureJobMode=replace-irreversibly +CollectMode=inactive-or-failed +RefuseManualStart=on +RefuseManualStop=on + +[Service] +Type=notify +ExecStart=@libexecdir@/phosh +Restart=on-failure +RestartSec=0ms +Slice=session.slice diff -Nru phosh-0.8.0/data/systemd/sm.puri.Phosh.target phosh-0.13.1/data/systemd/sm.puri.Phosh.target --- phosh-0.8.0/data/systemd/sm.puri.Phosh.target 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/data/systemd/sm.puri.Phosh.target 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,10 @@ +[Unit] +Description=Phosh +DefaultDependencies=no + +Requisite=gnome-session-initialized.target +PartOf=gnome-session-initialized.target +Before=gnome-session-initialized.target + +Requires=sm.puri.Phosh.service +After=sm.puri.Phosh.service diff -Nru phosh-0.8.0/data/wayland-sessions/phosh.desktop phosh-0.13.1/data/wayland-sessions/phosh.desktop --- phosh-0.8.0/data/wayland-sessions/phosh.desktop 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/data/wayland-sessions/phosh.desktop 2021-08-31 09:15:52.000000000 +0000 @@ -3,4 +3,4 @@ Comment=Phone Shell Exec=phosh Type=Application -DesktopNames=GNOME +DesktopNames=GNOME:Phosh diff -Nru phosh-0.8.0/debian/changelog phosh-0.13.1/debian/changelog --- phosh-0.8.0/debian/changelog 2021-01-19 09:34:47.000000000 +0000 +++ phosh-0.13.1/debian/changelog 2021-08-31 12:52:10.000000000 +0000 @@ -1,3 +1,88 @@ +phosh (0.13.1-1) unstable; urgency=medium + + * New usptream version 0.13.1 + * Upload to unstable + * Add Breaks: on older GTK. With older GTK calls and phosh would block on + each other on startup. + + -- Guido Günther Tue, 31 Aug 2021 14:52:10 +0200 + +phosh (0.13.0-1) UNRELEASED; urgency=medium + + [ Guido Günther ] + * debian: Add breaks relationship on older calls. + This makes sure calls we don't try to run against a calls without + the DBus interface. + * d/control: Bump phoc recommends. + Recommend a version that allows us to bind all the interesting + keys. + * d/control: Bump breaks on gnome-calls. + Not strictly necessary but makes missing deps easier to detect. + + [ Arnaud Ferraris ] + * New upstream version 0.13.0 + * d/control: add build dependency on libgudev. + This is required by the new torch manager implementation. + * d/control: drop duplicate Homepage field + * d/control: drop Build-Depends on linux-libc-dev. + This is a downstream change, causing the arm64 build to fail on Debian + as our most recent kernel is 5.10.x. + * d/watch: update to reflect migration to GNOME infrastructure + + -- Arnaud Ferraris Tue, 10 Aug 2021 11:17:12 +0200 + +phosh (0.12.0-1) experimental; urgency=medium + + * New usptream version 0.12.0 + * d/control: Bump phoc version. + Recommend a version that has allows to bind all the needed keys. + * d/control: Add breaks on older calls. + We want a version that has the DBus interface + + -- Guido Günther Wed, 30 Jun 2021 11:52:38 +0200 + +phosh (0.11.0-1) experimental; urgency=medium + + * New upstream version 0.11.0 + * Use non-systemd mode for now. + Stick with gnome-session's builtin session management for the moment. + + -- Guido Günther Mon, 31 May 2021 10:59:33 +0200 + +phosh (0.10.2-1) experimental; urgency=medium + + * New upstream version 0.10.2 + + -- Guido Günther Thu, 29 Apr 2021 15:32:47 +0200 + +phosh (0.10.1-1) experimental; urgency=medium + + * New upstream version 0.10.1 + + -- Guido Günther Mon, 12 Apr 2021 11:17:01 +0200 + +phosh (0.10.0-1) experimental; urgency=medium + + * New upstream version 0.10.0 + + -- Guido Günther Wed, 31 Mar 2021 17:00:22 +0200 + +phosh (0.9.0-1) experimental; urgency=medium + + * New upstream version 0.9.0 + * d/control: Require libhandy >= 1.1.90 + * Clean d/phosh.service + * salsa-ci: Build against experimental. + We need that for newer libhandy + + -- Guido Günther Wed, 03 Mar 2021 09:53:01 +0100 + +phosh (0.8.1-1) experimental; urgency=medium + + * New upstream version 0.8.1 + + -- Guido Günther Fri, 12 Feb 2021 17:42:03 +0100 + phosh (0.8.0-1) unstable; urgency=medium * New upstream version 0.8.0 diff -Nru phosh-0.8.0/debian/clean phosh-0.13.1/debian/clean --- phosh-0.8.0/debian/clean 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/debian/clean 2021-08-31 12:52:10.000000000 +0000 @@ -0,0 +1 @@ +debian/phosh.service diff -Nru phosh-0.8.0/debian/control phosh-0.13.1/debian/control --- phosh-0.8.0/debian/control 2021-01-19 09:26:36.000000000 +0000 +++ phosh-0.13.1/debian/control 2021-08-31 12:52:10.000000000 +0000 @@ -6,6 +6,7 @@ Build-Depends: debhelper-compat (= 13), gtk-doc-tools , + libcallaudio-dev, libsecret-1-dev, libsystemd-dev, libfeedback-dev, @@ -14,7 +15,8 @@ libgnome-desktop-3-dev, libgtk-3-dev, libgtk-3-doc , - libhandy-1-dev (>= 1.0.2), + libgudev-1.0-dev, + libhandy-1-dev (>= 1.1.90), libnm-dev, libpam0g-dev, libpolkit-agent-1-dev, @@ -24,14 +26,18 @@ meson, pandoc , # to run the tests - at-spi2-core, - gnome-themes-extra-data, - phoc, - xvfb, - xauth, + at-spi2-core , + dbus-x11 , + gnome-settings-daemon-common , + gnome-shell-common , + gnome-themes-extra-data , + gsettings-desktop-schemas , + phoc , + xvfb , + xauth , Standards-Version: 4.5.0 +Homepage: https://gitlab.gnome.org/World/Phosh/phosh/ Rules-Requires-Root: no -Homepage: https://source.puri.sm/Librem5/phosh Vcs-Browser: https://salsa.debian.org/DebianOnMobile-team/phosh Vcs-Git: https://salsa.debian.org/DebianOnMobile-team/phosh.git @@ -43,7 +49,7 @@ fonts-lato, gnome-shell-common, gsettings-desktop-schemas, - phoc (>= 0.4.4), + phoc (>= 0.7.1), Recommends: feedbackd, gnome-session-bin, @@ -55,6 +61,9 @@ Provides: notification-daemon, polkit-1-auth-agent, +Breaks: + gnome-calls (<< 41~alpha), + libgtk-3-0 (<< 3.24.30), Description: Pure Wayland shell for mobile devices Phosh is a graphical shell for Wayland compositors speaking the layer-surface protocol and aimed at mobile devices like smart phones and tablets using touch diff -Nru phosh-0.8.0/debian/copyright phosh-0.13.1/debian/copyright --- phosh-0.8.0/debian/copyright 2020-12-19 11:55:52.000000000 +0000 +++ phosh-0.13.1/debian/copyright 2021-08-31 12:52:10.000000000 +0000 @@ -1,7 +1,7 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: phosh Upstream-Contact: Guido Günther -Source: https://source.puri.sm/Librem5/phosh +Source: https://gitlab.gnome.org/World/Phosh/phosh Files: * Copyright: 2000 Eazel, Inc. diff -Nru phosh-0.8.0/debian/rules phosh-0.13.1/debian/rules --- phosh-0.8.0/debian/rules 2021-01-19 09:30:46.000000000 +0000 +++ phosh-0.13.1/debian/rules 2021-08-31 12:52:10.000000000 +0000 @@ -2,7 +2,7 @@ export DEB_BUILD_MAINT_OPTIONS = hardening=+all -CONFIGURE_OPTS=-Dphoc_tests=disabled +CONFIGURE_OPTS=-Dphoc_tests=disabled -Dsystemd=false ifeq ($(filter nodoc,$(DEB_BUILD_PROFILES)),) CONFIGURE_OPTS+=-Dgtk_doc=true diff -Nru phosh-0.8.0/debian/salsa-ci.yml phosh-0.13.1/debian/salsa-ci.yml --- phosh-0.8.0/debian/salsa-ci.yml 2020-12-19 11:55:52.000000000 +0000 +++ phosh-0.13.1/debian/salsa-ci.yml 2021-08-31 12:52:10.000000000 +0000 @@ -5,3 +5,11 @@ include: - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml + +variables: + RELEASE: 'experimental' + # Since those pull from unstable + SALSA_CI_DISABLE_REPROTEST: 1 + SALSA_CI_DISABLE_PIUPARTS: 1 + SALSA_CI_DISABLE_AUTOPKGTEST: 1 + diff -Nru phosh-0.8.0/debian/watch phosh-0.13.1/debian/watch --- phosh-0.8.0/debian/watch 2020-12-19 11:55:52.000000000 +0000 +++ phosh-0.13.1/debian/watch 2021-08-31 12:52:10.000000000 +0000 @@ -1,3 +1,3 @@ version=4 opts=filenamemangle=s/.*\/archive\/(\d\S+)\/phosh.*\.tar\.gz/phosh-$1\.tar\.gz/g \ - https://source.puri.sm/Librem5/phosh/tags?sort=updated_desc .*/archive/v(\d\S+)/.*\.tar\.gz.* + https://gitlab.gnome.org/World/Phosh/phosh/-/tags?sort=updated_desc .*/archive/v(\d\S+)/.*\.tar\.gz.* diff -Nru phosh-0.8.0/.dir-locals.el phosh-0.13.1/.dir-locals.el --- phosh-0.8.0/.dir-locals.el 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/.dir-locals.el 2021-08-31 09:15:52.000000000 +0000 @@ -4,5 +4,12 @@ (indent-tabs-mode . nil) (c-basic-offset . 2) )) + (setq auto-mode-alist (cons '("\\.ui$" . nxml-mode) auto-mode-alist)) + (nxml-mode . ( + (indent-tabs-mode . nil) + )) + (css-mode . ( + (css-indent-offset . 2) + )) ) diff -Nru phosh-0.8.0/docs/patterns.md phosh-0.13.1/docs/patterns.md --- phosh-0.8.0/docs/patterns.md 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/docs/patterns.md 2021-08-31 09:15:52.000000000 +0000 @@ -16,12 +16,12 @@ Since it acts as a Wayland client it needs a compositor to function that provides the necessary protocols (most notably wlr-layer-shell). It's usually used with -[phoc](https://source.puri.sm/Librem5/phoc) (the PHOne Compositor). +[phoc](hhttps://gitlab.gnome.org/World/Phosh/phoc) (the PHOne Compositor). On the GNOME side it interfaces with the usual components (e.g. [gnome-settings-daemon](https://gitlab.gnome.org/GNOME/gnome-settings-daemon), [upower](https://gitlab.freedesktop.org/upower/upower), -[iio-sensor-proxy](https://source.puri.sm/Librem5/debs/iio-sensor-proxy)) +[iio-sensor-proxy](https://gitlab.freedesktop.org/hadess/iio-sensor-proxy/)) via DBus. For haptic feedback it uses [feedbackd](https://source.puri.sm/Librem5/feedbackd/). @@ -31,7 +31,7 @@ Although targeted at touch devices Phosh does not implement a on screen keyboard (OSK) but leaves this to -[squeekboard](https://source.puri.sm/Librem5/squeekboard). +[squeekboard](hhttps://gitlab.gnome.org/World/Phosh/squeekboard). The above combination of software is also often (a bit imprecisely) named Phosh. @@ -49,7 +49,7 @@ - wlr-layer-shell: Usually Wayland clients have little influence on where the compositor places them. This protocol gives Phosh enough room - to build the top bar via #PhoshPanel, the home bar #PhoshHome at + to build the top bar via #PhoshTopPanel, the home bar #PhoshHome at the bottom, system modal dialogs e.g. #PhoshSystemPrompt and lock screens via #PhoshLockscreen. - wlr-foreign-toplevel-management: This allows the management of diff -Nru phosh-0.8.0/docs/phosh-docs.xml phosh-0.13.1/docs/phosh-docs.xml --- phosh-0.8.0/docs/phosh-docs.xml 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/docs/phosh-docs.xml 2021-08-31 09:15:52.000000000 +0000 @@ -39,6 +39,7 @@ Widgets and Objects + @@ -49,20 +50,29 @@ + + + + + + + + + @@ -84,7 +94,7 @@ - + @@ -95,6 +105,7 @@ + @@ -103,9 +114,12 @@ + + + @@ -120,6 +134,7 @@ Utilities + @@ -133,6 +148,7 @@ Generated DBus Clients + diff -Nru phosh-0.8.0/docs/xml/meson.build phosh-0.13.1/docs/xml/meson.build --- phosh-0.8.0/docs/xml/meson.build 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/docs/xml/meson.build 2021-08-31 09:15:52.000000000 +0000 @@ -1,4 +1,4 @@ -url = 'https://source.puri.sm/Librem5/phosh' +url = 'https://gitlab.gnome.org/World/Phosh/phosh' ent_conf = configuration_data() ent_conf.set('PACKAGE', 'Phosh') diff -Nru phosh-0.8.0/gcovr.cfg phosh-0.13.1/gcovr.cfg --- phosh-0.8.0/gcovr.cfg 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/gcovr.cfg 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,5 @@ +exclude = src/dbus/ +exclude = src/libphosh-tool.a.p/ +exclude = src/libphosh.so.p/ +exclude = subprojects/ +exclude = tools/ diff -Nru phosh-0.8.0/.gitignore phosh-0.13.1/.gitignore --- phosh-0.8.0/.gitignore 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/.gitignore 2021-08-31 09:15:52.000000000 +0000 @@ -7,9 +7,13 @@ *~ \#*# .\#* +/subprojects/glib /subprojects/libhandy .vscode/ *.gcov +debian/phosh.service +debian/sm.puri.Phosh.service +debian/sm.puri.Phosh.target debian/files debian/*.substvars debian/*debhelper* diff -Nru phosh-0.8.0/.gitlab-ci/debian-cross.Dockerfile phosh-0.13.1/.gitlab-ci/debian-cross.Dockerfile --- phosh-0.8.0/.gitlab-ci/debian-cross.Dockerfile 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/.gitlab-ci/debian-cross.Dockerfile 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,14 @@ +FROM debian:bullseye-slim + +RUN export DEBIAN_FRONTEND=noninteractive \ + && dpkg --add-architecture i386 \ + && echo "deb [arch=i386] http://deb.debian.org/debian/ testing main" > /etc/apt/sources.list.d/i386.list \ + && echo "deb [arch=amd64 arch=i386] http://deb.debian.org/debian/ experimental main" >> /etc/apt/sources.list.d/exp.list \ + && apt-get -y update \ + && apt-get -y install --no-install-recommends eatmydata \ + && eatmydata apt-get -y -o APT::Immediate-Configure=false install libhandy-1-dev:i386/experimental libhandy-1-0:i386/experimental gir1.2-handy-1:i386/experimental libgladeui-common/experimental \ + && cd /home/user/app \ + && DEB_BUILD_PROFILES=nodoc,nocheck eatmydata apt-get -y --no-install-recommends -a i386 -o APT::Immediate-Configure=false build-dep . \ + && eatmydata apt-get -y install --no-install-recommends git wget crossbuild-essential-i386 \ + && eatmydata apt-get clean \ + && rm -rf /var/lib/apt/lists/* diff -Nru phosh-0.8.0/.gitlab-ci/debian.Dockerfile phosh-0.13.1/.gitlab-ci/debian.Dockerfile --- phosh-0.8.0/.gitlab-ci/debian.Dockerfile 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/.gitlab-ci/debian.Dockerfile 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,13 @@ +FROM debian:bullseye-slim + +RUN export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y update \ + && apt-get -y install --no-install-recommends wget ca-certificates gnupg eatmydata \ + && echo "deb http://deb.debian.org/debian/ experimental main" > /etc/apt/sources.list.d/exp.list \ + && eatmydata apt-get -y update \ + && eatmydata apt-get --no-install-recommends -y install libhandy-1-dev/experimental libhandy-1-0/experimental gir1.2-handy-1/experimental libgladeui-common/experimental \ + && cd /home/user/app \ + && eatmydata apt-get --no-install-recommends -y build-dep . \ + && eatmydata apt-get --no-install-recommends -y install build-essential git wget gcovr \ + && eatmydata apt-get clean \ + && eatmydata dpkg --force-depends --remove lcov diff -Nru phosh-0.8.0/.gitlab-ci/README.md phosh-0.13.1/.gitlab-ci/README.md --- phosh-0.8.0/.gitlab-ci/README.md 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/.gitlab-ci/README.md 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,12 @@ +### Checklist for Updating the Docker Images + + - [ ] Update the `${image}.Dockerfile` file with the dependencies + - [ ] Run `./run-docker.sh build --base ${image} --version ${number}` + - [ ] Run `./run-docker.sh push --base ${image} --version ${number}` + once the Docker image is built; you may need to log in by using + `docker login` or `podman login` like + podman login -u -p https://registry.gitlab.gnome.org/guidog/phosh + See https://docs.gitlab.com/ee/user/packages/container_registry/ + - [ ] Update the `image` keys in the `.gitlab-ci.yml` file with the new + image tag + - [ ] Open a merge request with your changes and let it run diff -Nru phosh-0.8.0/.gitlab-ci/run-docker.sh phosh-0.13.1/.gitlab-ci/run-docker.sh --- phosh-0.8.0/.gitlab-ci/run-docker.sh 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/.gitlab-ci/run-docker.sh 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,137 @@ +#!/bin/bash + +read_arg() { + # $1 = arg name + # $2 = arg value + # $3 = arg parameter + local rematch='^[^=]*=(.*)$' + if [[ $2 =~ $rematch ]]; then + read "$1" <<< "${BASH_REMATCH[1]}" + else + read "$1" <<< "$3" + # There is no way to shift our callers args, so + # return 1 to indicate they should do it instead. + return 1 + fi +} + +set -e + +build=0 +run=0 +push=0 +list=0 +print_help=0 +no_login=0 + +while (($# > 0)); do + case "${1%%=*}" in + build) build=1;; + run) run=1;; + push) push=1;; + list) list=1;; + help) print_help=1;; + --base|-b) read_arg base "$@" || shift;; + --version|-v) read_arg base_version "$@" || shift;; + --no-login) no_login=1;; + *) echo -e "\e[1;31mERROR\e[0m: Unknown option '$1'"; exit 1;; + esac + shift +done + +if [ $print_help == 1 ]; then + echo "$0 - Build and run Docker images" + echo "" + echo "Usage: $0 [options] [basename]" + echo "" + echo "Available commands" + echo "" + echo " build --base= - Build Docker image .Dockerfile" + echo " run --base= - Run Docker image " + echo " push --base= - Push Docker image to the registry" + echo " list - List available images" + echo " help - This help message" + echo "" + exit 0 +fi + +cd "$(dirname "$0")" + +if [ $list == 1 ]; then + echo "Available Docker images:" + for f in *.Dockerfile; do + filename=$( basename -- "$f" ) + basename="${filename%.*}" + + echo -e " \e[1;39m$basename\e[0m" + done + exit 0 +fi + +# All commands after this require --base to be set +if [ -z $base ]; then + echo "Usage: $0 " + exit 1 +fi + +if [ ! -f "$base.Dockerfile" ]; then + echo -e "\e[1;31mERROR\e[0m: Dockerfile for '$base' not found" + exit 1 +fi + +if [ -z $base_version ]; then + base_version="latest" +elif [ $base_version != "latest" ]; then + base_version="v$base_version" +fi + +if [ ! -x "$(command -v docker)" ] || [ docker --help |& grep -q podman ]; then + # Docker is actually implemented by podman, and its OCI output + # is incompatible with some of the dockerd instances on GitLab + # CI runners. + echo "Using: Podman" + format="--format docker" + CMD="podman" +else + echo "Using: Docker" + format="" + CMD="sudo docker" +fi + +REGISTRY="registry.gitlab.gnome.org" +REPO="world/phosh/phosh" +TAG="${REGISTRY}/${REPO}/${base}:${base_version}" + +if [ $build == 1 ]; then + echo -e "\e[1;32mBUILDING\e[0m: ${base} as ${TAG}" + ${CMD} build \ + ${format} \ + --volume "$(pwd)/..:/home/user/app" \ + --build-arg HOST_USER_ID="$UID" \ + --tag "${TAG}" \ + --file "${base}.Dockerfile" . + exit $? +fi + +if [ $push == 1 ]; then + echo -e "\e[1;32mPUSHING\e[0m: ${base} as ${TAG}" + + if [ $no_login == 0 ]; then + ${CMD} login ${REGISTRY} + fi + + ${CMD} push ${TAG} + exit $? +fi + +if [ $run == 1 ]; then + echo -e "\e[1;32mRUNNING\e[0m: ${base} as ${TAG}" + ${CMD} run \ + --rm \ + --volume "$(pwd)/..:/home/user/app" \ + --workdir "/home/user/app" \ + --tty \ + --interactive "${TAG}" \ + bash + exit $? +fi diff -Nru phosh-0.8.0/.gitlab-ci.yml phosh-0.13.1/.gitlab-ci.yml --- phosh-0.8.0/.gitlab-ci.yml 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/.gitlab-ci.yml 2021-08-31 09:15:52.000000000 +0000 @@ -5,28 +5,22 @@ - build - test+docs - package + - deploy variables: - DEPS: build-essential git wget lcov - WANT_BUILD_DEPS: "true" + DEBIAN_IMAGE: $CI_REGISTRY/world/phosh/phosh/debian:v0.0.20210803 + DEBIAN_CROSS_IMAGE: $CI_REGISTRY/world/phosh/phosh/debian-cross:v0.0.20210803 XVFB_RUN: xvfb-run -a -s -noreset COMMON_BUILD_OPTS: -Db_coverage=true --werror - ALPINE_EDGE_DEPS: alpine-sdk elogind-dev feedbackd-dev gcr-dev git glib-dev gnome-desktop-dev - gtk+3.0-dev libhandy1-dev gcr-dev libsecret-dev gcovr linux-pam-dev + ALPINE_EDGE_DEPS: alpine-sdk callaudiod-dev elogind-dev feedbackd-dev gcr-dev git glib-dev gnome-desktop-dev + gtk+3.0-dev libgudev-dev libhandy1-dev gcr-dev libsecret-dev gcovr linux-pam-dev meson musl-dev networkmanager-dev ninja polkit-elogind-dev pulseaudio-dev - upower-dev wayland-dev wayland-protocols - -.buster_vars: &buster_vars - variables: - CI_REPO: "deb http://ci.puri.sm/ scratch librem5" - DIST: buster - BUILD_OPTS: -Dphoc_tests=disabled -Dgtk_doc=false ${COMMON_BUILD_OPTS} + upower-dev wayland-dev wayland-protocols ttf-dejavu .bullseye_vars: &bullseye_vars variables: - CI_REPO: "deb http://ci.puri.sm/ bullseyeci main" DIST: bullseye - BUILD_OPTS: -Dphoc_tests=enabled -Dgtk_doc=true ${COMMON_BUILD_OPTS} + BUILD_OPTS: -Dphoc_tests=enabled -Dg_tests=true ${COMMON_BUILD_OPTS} .build_step: &build_step script: @@ -41,70 +35,9 @@ - ${XVFB_RUN} ninja -C _build test - ninja -C _build coverage -# For the smoke tests we also want debug packages, phoc, -# weston-info, gdb, valgrind, ... -.smoketest_vars: - variables: &smoketest_vars - CI_REPO: "deb http://ci.puri.sm/ scratch librem5" - DIST: buster - DEPS: phoc wget gnome-session-bin gdb weston valgrind - libhandy-1-0-dbgsym libgtk-3-0-dbgsym libglib2.0-0-dbgsym - dconf-gsettings-backend-dbgsym libfeedback-0.0-0-dbgsym - xvfb imagemagick - WANT_BUILD_DEPS: "false" - - -before_script: - - export DEBIAN_FRONTEND=noninteractive - - apt-get -y update - - apt-get -y install wget ca-certificates gnupg eatmydata - - echo "Using CI repo ${CI_REPO}" - - echo "$CI_REPO" > /etc/apt/sources.list.d/ci.list - - wget -O- https://ci.puri.sm/ci-repo.key | apt-key add - - - echo "deb http://debug.mirrors.debian.org/debian-debug/ ${DIST}-debug main" > /etc/apt/sources.list.d/debug.list - - eatmydata apt-get -y update - - '[ "$WANT_BUILD_DEPS" != "true" ] || eatmydata apt-get -y build-dep .' - - eatmydata apt-get -y install $DEPS - - ulimit -c unlimited - -.tags: &tags - tags: - - librem5 - -build:native-debian-buster: - <<: *tags - stage: build - image: debian:buster - <<: *buster_vars - <<: *build_step - artifacts: - paths: - - _build - except: - variables: - - $PKG_ONLY == "1" - -unit-test:native-debian-buster: - <<: *tags - stage: test+docs - image: debian:buster - needs: - - build:native-debian-buster - <<: *buster_vars - <<: *test_step - coverage: '/^\s+lines\.+:\s+([\d.]+\%)\s+/' - artifacts: - when: always - paths: - - _build - except: - variables: - - $PKG_ONLY == "1" - build:native-debian-bullseye: - <<: *tags stage: build - image: debian:bullseye + image: ${DEBIAN_IMAGE} <<: *bullseye_vars <<: *build_step artifacts: @@ -114,25 +47,16 @@ variables: - $PKG_ONLY == "1" +# Build for 32bit architecture to catch common errors build:cross-debian-bullseye:i386: - <<: *tags stage: build - image: debian:bullseye + image: "${DEBIAN_CROSS_IMAGE}" allow_failure: true - before_script: - - export DEBIAN_FRONTEND=noninteractive - - echo "deb [arch=i386] http://deb.debian.org/debian/ testing main" > /etc/apt/sources.list.d/i386.list - - apt-get -y update - - apt-get -y install eatmydata - - dpkg --add-architecture i386 - - eatmydata apt-get -y update - - eatmydata apt-get -y -a i386 -o APT::Immediate-Configure=false build-dep . - - eatmydata apt-get -y install $DEPS crossbuild-essential-i386 script: - git submodule update --recursive - - 'echo "Build opts: ${BUILD_OPTS}"' + - 'echo "Build opts: ${COMMON_BUILD_OPTS}"' - /usr/share/meson/debcrossgen --arch i386 -o cross-i386.txt - - meson ${BUILD_OPTS} . _build --cross-file cross-i386.txt + - meson ${COMMON_BUILD_OPTS} . _build --cross-file cross-i386.txt - ninja -C _build artifacts: paths: @@ -142,14 +66,13 @@ - $PKG_ONLY == "1" unit-test:native-debian-bullseye: - <<: *tags stage: test+docs - image: debian:bullseye + image: ${DEBIAN_IMAGE} needs: - build:native-debian-bullseye <<: *bullseye_vars <<: *test_step - coverage: '/^\s+lines\.+:\s+([\d.]+\%)\s+/' + coverage: '/^lines:\s+([\d.]+\%)\s+/' artifacts: when: always paths: @@ -159,13 +82,16 @@ - $PKG_ONLY == "1" build-gtkdoc: - <<: *tags - image: debian:bullseye stage: test+docs - needs: - - build:native-debian-bullseye - <<: *bullseye_vars + image: ${DEBIAN_IMAGE} + variables: + DIST: bullseye + BUILD_OPTS: -Dgtk_doc=true ${COMMON_BUILD_OPTS} script: + - git clean -dfx + - 'echo "Build opts: ${BUILD_OPTS}"' + - meson ${BUILD_OPTS} . _build + - ninja -C _build - tools/doc-check - mv _build/docs/html/ _reference/ artifacts: @@ -176,31 +102,26 @@ - $PKG_ONLY == "1" check-po: - <<: *tags stage: test+docs - image: debian:bullseye needs: - build:native-debian-bullseye + image: ${DEBIAN_IMAGE} before_script: - - apt-get -y update - - apt-get -y install intltool + - eatmydata apt-get -y -f install + - eatmydata apt-get -y update + - eatmydata apt-get -y install intltool gettext <<: *bullseye_vars script: - # barf on untranslated C files. Seems intltool - # can't be told to exit with non-zero exit status - # in this case - - cd po/ - - intltool-update -m 2>&1 | grep -qs '/.*\.c' && { intltool-update -m; exit 1; } || exit 0 + - tools/check-po except: variables: - $PKG_ONLY == "1" check-license-headers: - <<: *tags stage: test+docs - image: debian:bullseye needs: - build:native-debian-bullseye + image: ${DEBIAN_IMAGE} <<: *bullseye_vars script: # Checks .c and .h files begin with a license header as @@ -211,13 +132,12 @@ - $PKG_ONLY == "1" build:native-alpinelinux-edge: - <<: *tags stage: build image: alpine:edge allow_failure: true before_script: - echo "https://alpine.global.ssl.fastly.net/alpine/edge/testing" >> /etc/apk/repositories - - apk -q add $ALPINE_EDGE_DEPS + - apk add $ALPINE_EDGE_DEPS artifacts: paths: - _build @@ -230,7 +150,6 @@ - $PKG_ONLY == "1" unit-test:native-alpinelinux-edge: - <<: *tags stage: test+docs image: alpine:edge allow_failure: true @@ -238,7 +157,7 @@ - build:native-alpinelinux-edge before_script: - echo "https://alpine.global.ssl.fastly.net/alpine/edge/testing" >> /etc/apk/repositories - - apk -q add xvfb-run $ALPINE_EDGE_DEPS + - apk add xvfb-run $ALPINE_EDGE_DEPS script: - export LC_ALL=C.UTF-8 - ${XVFB_RUN} ninja -C _build test @@ -250,75 +169,23 @@ variables: - $PKG_ONLY == "1" -test:smoke:one-output: - <<: *tags - stage: test+docs - image: debian:buster - variables: *smoketest_vars - needs: - - build:native-debian-buster - script: - - export OUTDIR=output - - export G_DEBUG=fatal-criticals - - export WLR_X11_OUTPUTS=1 - - 'echo "SMOKE_PARAMS: $SMOKE_PARAMS"' - - tests/smoke $SMOKE_PARAMS - artifacts: - paths: - - output/*.log - - output/*.png - when: always - except: - variables: - - $PKG_ONLY == "1" +package:deb-pureos-byzantium:arm64: + variables: + L5_DOCKER_IMAGE: pureos/byzantium + DEB_BUILD_PROFILES: nodoc + extends: .l5-build-debian-package + tags: + - aarch64 -test:smoke:two-outputs: - <<: *tags - stage: test+docs - image: debian:buster - variables: *smoketest_vars +pages: + stage: deploy needs: - - build:native-debian-buster + - build-gtkdoc script: - - export OUTDIR=output - - export G_DEBUG=fatal-criticals - - export WLR_X11_OUTPUTS=2 - - 'echo "SMOKE_PARAMS: $SMOKE_PARAMS"' - - tests/smoke $SMOKE_PARAMS + - mv _reference/ public/ artifacts: paths: - - output/*.log - - output/*.png - when: always - except: - variables: - - $PKG_ONLY == "1" - -package:deb-debian-buster: - extends: .l5-build-debian-package - before_script: [] - -package:deb-debian-bullseye:arm64: - tags: - - librem5:arm64 - variables: - L5_DOCKER_IMAGE: debian:bullseye - L5_ADD_SCRATCH_CI: 'false' - before_script: [] - extends: .l5-build-debian-package - -package:deb-debian-buster:arm64: - tags: - - librem5:arm64 - before_script: [] - extends: .l5-build-debian-package + - public + only: + - main -package:deb-pureos-amber: - variables: - L5_DOCKER_IMAGE: pureos/amber - L5_ADD_SCRATCH_CI: 'false' - before_script: - - echo "deb https://repo.pureos.net/pureos amber-phone-staging main" > /etc/apt/sources.list.d/staging.list - - echo "deb https://repo.pureos.net/pureos amber-proposed-updates main" >> /etc/apt/sources.list.d/staging.list - extends: .l5-build-debian-package - allow_failure: true diff -Nru phosh-0.8.0/.gitmodules phosh-0.13.1/.gitmodules --- phosh-0.8.0/.gitmodules 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/.gitmodules 2021-08-31 09:15:52.000000000 +0000 @@ -1,3 +1,6 @@ [submodule "subprojects/gvc"] path = subprojects/gvc url = https://gitlab.gnome.org/GNOME/libgnome-volume-control.git +[submodule "subprojects/libcall-ui"] + path = subprojects/libcall-ui + url = https://gitlab.gnome.org/World/Phosh/libcall-ui.git diff -Nru phosh-0.8.0/HACKING.md phosh-0.13.1/HACKING.md --- phosh-0.8.0/HACKING.md 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/HACKING.md 2021-08-31 09:15:52.000000000 +0000 @@ -106,8 +106,8 @@ ``` - private methods and callbacks (these can also go at convenient places above `phosh_thing_constructed ()` - - `phosh_thing_set_properties ()` - - `phosh_thing_get_properties ()` + - `phosh_thing_set_property ()` + - `phosh_thing_get_property ()` - `phosh_thing_constructed ()` - `phosh_thing_dispose ()` - `phosh_thing_finalize ()` @@ -120,4 +120,33 @@ the header file and can thus be referenced from anywhere else in the source file. -[1]: https://source.puri.sm/Librem5/libhandy/blob/master/HACKING.md#coding-style +CSS Theming +=========== +For custom widget always set the css name using `gtk_widget_class_set_css_name ()`. +There's no need set an (additional) style class in the ui file. + +*Good*: + +```c +static void +phosh_lockscreen_class_init (PhoshLockscreenClass *klass) +{ + … + gtk_widget_class_set_css_name (widget_class, "phosh-lockscreen"); + … +} +``` + +*Bad*: + +```xml + +``` + +[1]: https://gitlab.gnome.org/GNOME/libhandy/blob/master/HACKING.md#coding-style diff -Nru phosh-0.8.0/meson.build phosh-0.13.1/meson.build --- phosh-0.8.0/meson.build 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/meson.build 2021-08-31 09:15:52.000000000 +0000 @@ -1,5 +1,5 @@ project('phosh', 'c', - version: '0.8.0', + version: '0.13.1', license: 'GPLv3+', meson_version: '>= 0.50.0', default_options: [ 'warning_level=1', 'buildtype=debugoptimized', 'c_std=gnu11' ], @@ -15,25 +15,16 @@ sessiondir = join_paths(datadir, 'gnome-session') pkgdatadir = join_paths(datadir, meson.project_name()) pkglibdir = join_paths(libdir, meson.project_name()) +systemddir = join_paths(prefix, 'lib/systemd') +systemduserdir = join_paths(systemddir, 'user') -config_h = configuration_data() -config_h.set_quoted('GETTEXT_PACKAGE', 'phosh') -config_h.set_quoted('LOCALEDIR', localedir) -config_h.set_quoted('PHOSH_VERSION', meson.project_version()) - -configure_file( - input: 'config.h.in', - output: 'config.h', - configuration: config_h, -) - -glib_ver = 'GLIB_VERSION_2_58' +glib_ver = 'GLIB_VERSION_2_62' add_project_arguments([ '-DHAVE_CONFIG_H', '-DGLIB_VERSION_MIN_REQUIRED=@0@'.format(glib_ver), + '-DGLIB_VERSION_MAX_REQUIRED=@0@'.format(glib_ver), '-DG_LOG_USE_STRUCTURED', - '-I' + meson.build_root(), ], language: 'c') root_inc = include_directories('.') @@ -103,14 +94,34 @@ gnome = import('gnome') i18n = import('i18n') +if get_option('g_tests') + glib_ver = '>= 2.69' +else + glib_ver = '>= 2.62' +endif + gcr_dep = dependency('gcr-3', version: '>= 3.7.5') -gio_dep = dependency('gio-2.0', version: '>=2.58') -gio_unix_dep = dependency('gio-unix-2.0', version: '>=2.58') -glib_dep = dependency('glib-2.0', version: '>=2.58') +glib_dep = dependency('glib-2.0', + version: glib_ver, + fallback: ['glib', 'libglib_dep'], + default_options: ['tests=false'] + ) +gio_dep = dependency('gio-2.0', + version: glib_ver, + fallback: ['glib', 'libgio_dep'], + default_options: ['tests=false'] + ) +gobject_dep = dependency('gobject-2.0', + version: glib_ver, + fallback: ['glib', 'libgobject_dep'], + default_options: ['tests=false'] + ) +gio_unix_dep = dependency('gio-unix-2.0', version: '>=2.62') gnome_desktop_dep = dependency('gnome-desktop-3.0', version: '>=3.26') -gobject_dep = dependency('gobject-2.0', version: '>=2.50.0') +gsettings_desktop_schemas_dep = dependency('gsettings-desktop-schemas') gtk_dep = dependency('gtk+-3.0', version: '>=3.22') gtk_wayland_dep = dependency('gtk+-wayland-3.0', version: '>=3.22') +gudev_dep = dependency('gudev-1.0') libfeedback_dep = dependency('libfeedback-0.0', fallback: ['libfeedback', 'libfeedback_dep'], default_options: ['introspection=disabled', 'daemon=false', 'gtk_doc=false'] @@ -127,10 +138,21 @@ ]) libgvc_dep = libgvc.get_variable('libgvc_dep') libhandy_dep = dependency('libhandy-1', - version: '>=1.0.0', + version: '>=1.1.90', fallback: ['libhandy', 'libhandy_dep'], default_options: ['introspection=disabled'] ) +libcall_ui = subproject('libcall-ui', + default_options: [ + 'package_name=' + meson.project_name(), + 'package_version=' + meson.project_version(), + 'pkgdatadir=' + pkgdatadir, + 'pkglibdir=' + pkglibdir, + 'examples=false', + 'gtk_doc=false', + 'tests=false', + ]) +libcall_ui_dep = libcall_ui.get_variable('libcall_ui_dep') libnm_dep = dependency('libnm', version: '>= 1.14') libpolkit_agent_dep = dependency('polkit-agent-1', version: '>= 0.105') # TODO: make optional for elogind? @@ -140,6 +162,26 @@ wayland_client_dep = dependency('wayland-client', version: '>=1.14') wayland_protos_dep = dependency('wayland-protocols', version: '>=1.12') + +code =''' +#include + +struct rfkill_event_ext e; +''' +have_rfkill_event_ext = cc.compiles(code, name : 'Have rfkill_event_ext') + +config_h = configuration_data() +config_h.set_quoted('GETTEXT_PACKAGE', 'phosh') +config_h.set_quoted('LOCALEDIR', localedir) +config_h.set_quoted('PHOSH_VERSION', meson.project_version()) +config_h.set('HAVE_RFKILL_EVENT_EXT', have_rfkill_event_ext) + +configure_file( + input: 'config.h.in', + output: 'config.h', + configuration: config_h, +) + meson.add_install_script( join_paths('build-aux', 'post_install.py'), datadir @@ -160,6 +202,8 @@ '', ' Tests: @0@'.format(get_option('tests')), ' Phoc Tests: @0@'.format(run_phoc_tests), + ' Compositor: @0@'.format(get_option('compositor')), + ' Systemd: @0@'.format(get_option('systemd')), 'Documentation: @0@'.format(get_option('gtk_doc')), '-----------', ] diff -Nru phosh-0.8.0/meson_options.txt phosh-0.13.1/meson_options.txt --- phosh-0.8.0/meson_options.txt 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/meson_options.txt 2021-08-31 09:15:52.000000000 +0000 @@ -8,4 +8,17 @@ option('gtk_doc', type: 'boolean', value: false, - description: 'Whether to generate the API reference for Handy') + description: 'Whether to generate the API reference for Phosh') + +option('systemd', + type: 'boolean', value: false, + description: 'Whether to generate systemd user units') + +option('compositor', + type: 'string', value: '/usr/bin/phoc', + description: 'Path to the Phoc compositor for use in the launcher script') + +# For some tests we need (unreleased) glib >= 2.69 +option('g_tests', + type: 'boolean', value: false, + description: 'Whether to build tests that require recent glib') diff -Nru phosh-0.8.0/NEWS phosh-0.13.1/NEWS --- phosh-0.8.0/NEWS 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/NEWS 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,76 @@ +phosh 0.13.1 +------------ +Released: August 2021 +* Cycle through all feedback profiles in quick setting + (Pablo Correa Gómez) +* Add button to close all notifications (Guido Günther) +* Improve support for mounting encrypted media (Guido Günther) +* Don't launch app twice when keyboard activated from search bar + (Guido Günther) +* Improve fractional scaling support (Guido Günther) +* Better media player styling (Guido Günther) +* UI translations: + Daniel Șerbănescu (ro) + Kristjan SCHMIDT (eo) + Marc Riera (ca) + Michael Oppliger (de) + Andika Triwidada (id) + +phosh 0.13.0 +------------ +Released: August 2021 +* torch: Use logind for torch brightness. This obsoletes any upower changes. + (Arnaud Ferraris) +* Support high contrast mode (David Hamner, Guido Günther) +* ci: Use prebuilt docker images in CI to speedup builds and save resources + (Guido Günther) +* lockscreen: Handle incoming phone calls (Guido Günther) +* backrounds: Handle fractional scaling (Guido Günther) +* notifications: Look at category for notification feedback +* lockscreen: Display notification summary and handle global + "show-in-lock-screen" toggle (Guido Günther) +* panel: Fix power menu close on tap (Mohammed Sadiq) +* quick settings: Cycle through all feedback settings instead of only + full / silent (Pablo Correa Gomez) +* Migrate to GNOME World (Andrea Veri, Guido Günther) +* UI translations: + Anders Jonsson (sv) + Efstathios Iosifidis (el) + Rafael Fontenelle (pt_BR) + Vittorio Monti (it) + Yuri Chornoivan (uk) + Мирослав Николић (sr) + +phosh 0.12.1 +------------ +Released: July 2021 +* Fix defaults for favorites +* Append 'Phosh' to XDG_CURRENT_DESKOP for the system unit too so overrides get + applied even when not using a display manager +* Bring search bar closer to designs again +* Simplify tests and test calls-manager. Fix leaks spotted by those. +* Don't claim accelerometer when rotation lock is on reducing iio-sensor-proxy + wakeups considerably +* i18n updates: uk, it, sv + +phosh 0.12.0 +------------ +Released: June 2021 +* Only enable proximity sensor on active calls, unblank screen on incoming + calls. This needs at least gnome-calls 0.3.4 and either one of + https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/3614 + https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2120 +* Implement most parts of org.Gtk.MountOperationHandler to handle + encrypted volume mounts in e.g. nautilus. +* Show adaptive apps in mobile mode and all apps in docked mode. This + can be toggled via the sm.puri.phosh.PhoshAppFilterModeFlags GSetting. + +phosh 0.11.0 +------------ +Released: May 2021 +* Wifi/WWAN/BT quick settings toggle on/off, long press opens Settings +* Initial support for gnome-session --systemd +* Torch brightness slider +* Allow to show battery percentage in top bar +* Fixes modal-dialog keyboard navigation +* Fixes crash with ja locale diff -Nru phosh-0.8.0/phosh.doap phosh-0.13.1/phosh.doap --- phosh-0.8.0/phosh.doap 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/phosh.doap 2021-08-31 09:15:52.000000000 +0000 @@ -10,7 +10,7 @@ A wayland shell PoC for for mobile phones Phosh aims to be a wayland shell for mobile phones. This is merely a PoC at the moment. - + C @@ -19,12 +19,14 @@ Guido Günther + guidog Zander Brown + zbrown diff -Nru phosh-0.8.0/po/ca.po phosh-0.13.1/po/ca.po --- phosh-0.8.0/po/ca.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/ca.po 2021-08-31 09:15:52.000000000 +0000 @@ -5,15 +5,17 @@ msgid "" msgstr "" "Project-Id-Version: phosh\n" -"Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/phosh/issues\n" -"POT-Creation-Date: 2020-07-18 15:28+0000\n" -"PO-Revision-Date: 2020-07-18 18:45+0200\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/phosh/issues\n" +"POT-Creation-Date: 2021-08-09 09:29+0000\n" +"PO-Revision-Date: 2021-08-09 12:40+0200\n" "Last-Translator: Marc Riera \n" "Language-Team: Catalan\n" "Language: ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.0\n" #. Translators: this is the session name, no need to translate it #: data/phosh.session.desktop.in.in:4 @@ -26,112 +28,302 @@ #: data/sm.puri.Phosh.desktop.in.in:5 msgid "Window management and application launching for mobile" -msgstr "Gestió de finestres i llançament d'aplicacions per a mòbils" +msgstr "Gestió de finestres i inici d'aplicacions per a mòbils" -#: src/app-grid-button.c:530 +#: src/app-grid-button.c:536 msgid "Application" msgstr "Aplicació" -#: src/bt-info.c:89 src/feedbackinfo.c:48 +#: src/bt-info.c:92 src/feedbackinfo.c:51 src/rotateinfo.c:103 msgid "On" msgstr "Activat" -#: src/bt-info.c:91 +#: src/bt-info.c:94 msgid "Bluetooth" msgstr "Bluetooth" +#: src/docked-info.c:81 +msgid "Docked" +msgstr "Acoblat" + +#: src/docked-info.c:81 src/docked-info.c:199 +msgid "Undocked" +msgstr "Desacoblat" + +#: src/end-session-dialog.c:162 +msgid "Log Out" +msgstr "Surt" + +#: src/end-session-dialog.c:165 +#, c-format +msgid "%s will be logged out automatically in %d second." +msgid_plural "%s will be logged out automatically in %d seconds." +msgstr[0] "Es tancarà la sessió de %s automàticament d'aquí a %d segon." +msgstr[1] "Es tancarà la sessió de %s automàticament d'aquí a %d segons." + +#: src/end-session-dialog.c:171 src/ui/top-panel.ui:37 +msgid "Power Off" +msgstr "Apaga" + +#: src/end-session-dialog.c:172 +#, c-format +msgid "The system will power off automatically in %d second." +msgid_plural "The system will power off automatically in %d seconds." +msgstr[0] "El sistema s'apagarà automàticament d'aquí a %d segon." +msgstr[1] "El sistema s'apagarà automàticament d'aquí a %d segons." + +#: src/end-session-dialog.c:178 src/ui/top-panel.ui:30 +msgid "Restart" +msgstr "Reinicia" + +#: src/end-session-dialog.c:179 +#, c-format +msgid "The system will restart automatically in %d second." +msgid_plural "The system will restart automatically in %d seconds." +msgstr[0] "El sistema es reiniciarà automàticament d'aquí a %d segon." +msgstr[1] "El sistema es reiniciarà automàticament d'aquí a %d segons." + +#: src/end-session-dialog.c:269 +msgid "Unknown application" +msgstr "Aplicació desconeguda" + #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details -#: src/feedbackinfo.c:41 +#: src/feedbackinfo.c:44 msgid "Quiet" msgstr "Silenciós" #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details -#: src/feedbackinfo.c:46 +#: src/feedbackinfo.c:49 msgid "Silent" msgstr "Desactivat" -#: src/lockscreen.c:84 src/ui/lockscreen.ui:234 +#: src/location-manager.c:268 +#, c-format +msgid "Allow '%s' to access your location information?" +msgstr "Voleu permetre que «%s» accedeixi a la informació de la ubicació?" + +#: src/location-manager.c:273 +msgid "Geolocation" +msgstr "Geolocalització" + +#: src/location-manager.c:274 +msgid "Yes" +msgstr "Sí" + +#: src/location-manager.c:274 +msgid "No" +msgstr "No" + +#: src/lockscreen.c:157 src/ui/lockscreen.ui:267 msgid "Enter Passcode" msgstr "Introduïu la contrasenya" -#: src/lockscreen.c:263 +#: src/lockscreen.c:340 msgid "Checking…" msgstr "S'està comprovant…" #. Translators: This is a time format for a date in #. long format -#: src/lockscreen.c:341 +#: src/lockscreen.c:418 msgid "%A, %B %-e" -msgstr "%A, %d %B" +msgstr "%A, %-e %B" -#: src/media-player.c:262 -msgid "Unknown title" +#. Translators: Used when the title of a song is unknown +#: src/media-player.c:279 src/ui/media-player.ui:107 +msgid "Unknown Title" msgstr "Títol desconegut" -#: src/media-player.c:270 -msgid "Unknown artist" +#. Translators: Used when the artist of a song is unknown +#: src/media-player.c:288 src/ui/media-player.ui:127 +msgid "Unknown Artist" msgstr "Artista desconegut" -#: src/monitor-manager.c:58 +#: src/monitor-manager.c:114 msgid "Built-in display" msgstr "Pantalla interna" +#: src/monitor-manager.c:132 +#, c-format +msgctxt "" +"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgid "%s %s" +msgstr "%s %s" + +#: src/monitor-manager.c:139 +#, c-format +msgctxt "" +"This is a monitor vendor name followed by product/model name where size in " +"inches could not be calculated, e.g. Dell U2414H" +msgid "%s %s" +msgstr "%s %s" + #. Translators: An unknown monitor type -#: src/monitor-manager.c:62 +#: src/monitor-manager.c:148 msgid "Unknown" msgstr "Desconegut" -#: src/network-auth-prompt.c:184 +#: src/network-auth-prompt.c:187 #, c-format msgid "Authentication type of wifi network “%s” not supported" msgstr "No s'admet el tipus d'autenticació de la xarxa sense fil «%s»" -#: src/network-auth-prompt.c:189 +#: src/network-auth-prompt.c:192 #, c-format msgid "Enter password for the wifi network “%s”" msgstr "Introduïu la contrasenya de la xarxa sense fil «%s»" -#: src/notifications/notification.c:365 src/notifications/notification.c:581 +#: src/notifications/mount-notification.c:122 +msgid "Open" +msgstr "Obre" + +#: src/notifications/notification.c:383 src/notifications/notification.c:639 msgid "Notification" msgstr "Notificació" -#: src/polkit-auth-agent.c:229 +#. Translators: Timestamp seconds suffix +#: src/notifications/timestamp-label.c:84 +msgctxt "timestamp-suffix-seconds" +msgid "s" +msgstr "s" + +#. Translators: Timestamp minute suffix +#: src/notifications/timestamp-label.c:86 +msgctxt "timestamp-suffix-minute" +msgid "m" +msgstr "min" + +#. Translators: Timestamp minutes suffix +#: src/notifications/timestamp-label.c:88 +msgctxt "timestamp-suffix-minutes" +msgid "m" +msgstr "min" + +#. Translators: Timestamp hour suffix +#: src/notifications/timestamp-label.c:90 +msgctxt "timestamp-suffix-hour" +msgid "h" +msgstr "h" + +#. Translators: Timestamp hours suffix +#: src/notifications/timestamp-label.c:92 +msgctxt "timestamp-suffix-hours" +msgid "h" +msgstr "h" + +#. Translators: Timestamp day suffix +#: src/notifications/timestamp-label.c:94 +msgctxt "timestamp-suffix-day" +msgid "d" +msgstr "dia" + +#. Translators: Timestamp days suffix +#: src/notifications/timestamp-label.c:96 +msgctxt "timestamp-suffix-days" +msgid "d" +msgstr "dies" + +#. Translators: Timestamp month suffix +#: src/notifications/timestamp-label.c:98 +msgctxt "timestamp-suffix-month" +msgid "mo" +msgstr "mes" + +#. Translators: Timestamp months suffix +#: src/notifications/timestamp-label.c:100 +msgctxt "timestamp-suffix-months" +msgid "mos" +msgstr "mesos" + +#. Translators: Timestamp year suffix +#: src/notifications/timestamp-label.c:102 +msgctxt "timestamp-suffix-year" +msgid "y" +msgstr "any" + +#. Translators: Timestamp years suffix +#: src/notifications/timestamp-label.c:104 +msgctxt "timestamp-suffix-years" +msgid "y" +msgstr "anys" + +#: src/notifications/timestamp-label.c:121 +msgid "now" +msgstr "ara" + +#. Translators: time difference "Over 5 years" +#: src/notifications/timestamp-label.c:189 +#, c-format +msgid "Over %dy" +msgstr "Més de %d anys" + +#. Translators: time difference "almost 5 years" +#: src/notifications/timestamp-label.c:193 +#, c-format +msgid "Almost %dy" +msgstr "Gairebé %d anys" + +#. Translators: a time difference like '<5m', if in doubt leave untranslated +#: src/notifications/timestamp-label.c:200 +#, c-format +msgid "%s%d%s" +msgstr "%s %d %s" + +#: src/polkit-auth-agent.c:228 msgid "Authentication dialog was dismissed by the user" msgstr "L'usuari ha descartat el diàleg d'autenticació" -#: src/polkit-auth-prompt.c:276 src/ui/network-auth-prompt.ui:128 -#: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 +#: src/polkit-auth-prompt.c:278 src/ui/gtk-mount-prompt.ui:21 +#: src/ui/network-auth-prompt.ui:83 src/ui/polkit-auth-prompt.ui:57 +#: src/ui/system-prompt.ui:33 msgid "Password:" msgstr "Contrasenya:" -#: src/polkit-auth-prompt.c:322 +#: src/polkit-auth-prompt.c:325 msgid "Sorry, that didn’t work. Please try again." msgstr "S'ha produït un error. Torneu-ho a provar." -#: src/polkit-auth-prompt.c:488 -msgid "Authenticate" -msgstr "Autenticació" - -#: src/rotateinfo.c:46 +#: src/rotateinfo.c:81 msgid "Portrait" msgstr "Vertical" -#: src/rotateinfo.c:49 +#: src/rotateinfo.c:84 msgid "Landscape" msgstr "Apaïsat" -#: src/system-prompt.c:371 +#. Translators: Automatic screen orientation is either on (enabled) or off (locked/disabled) +#. Translators: Automatic screen orientation is off (locked/disabled) +#: src/rotateinfo.c:103 src/rotateinfo.c:186 +msgid "Off" +msgstr "Desactivada" + +#: src/system-prompt.c:364 msgid "Passwords do not match." msgstr "Les contrasenyes no coincideixen." -#: src/system-prompt.c:378 +#: src/system-prompt.c:371 msgid "Password cannot be blank" msgstr "La contrasenya no pot estar en blanc" +#: src/torch-info.c:80 +msgid "Torch" +msgstr "Llanterna" + +#: src/ui/app-auth-prompt.ui:41 +msgid "Remember decision" +msgstr "Recorda la decisió" + +#: src/ui/app-auth-prompt.ui:54 src/ui/end-session-dialog.ui:54 +msgid "Cancel" +msgstr "Cancel·la" + +#: src/ui/app-auth-prompt.ui:63 src/ui/end-session-dialog.ui:63 +msgid "Ok" +msgstr "D'acord" + #: src/ui/app-grid-button.ui:49 msgid "App" msgstr "Aplicació" @@ -144,62 +336,85 @@ msgid "Add to _Favorites" msgstr "Afegeix als _preferits" -#: src/ui/app-grid.ui:21 +#: src/ui/app-grid.ui:22 msgid "Search apps…" msgstr "Cerca aplicacions…" -#: src/ui/lockscreen.ui:37 +#: src/ui/app-grid.ui:169 +msgid "Show only adaptive apps" +msgstr "Mostra només les aplicacions adaptatives" + +#: src/ui/end-session-dialog.ui:32 +msgid "Some applications are busy or have unsaved work" +msgstr "Algunes aplicacions estan ocupades o tenen feina sense desar" + +#: src/ui/gtk-mount-prompt.ui:95 +msgid "User:" +msgstr "Usuari:" + +#: src/ui/gtk-mount-prompt.ui:118 +msgid "Domain:" +msgstr "Domini:" + +#: src/ui/gtk-mount-prompt.ui:151 +msgid "Co_nnect" +msgstr "Co_nnecta" + +#: src/ui/lockscreen.ui:43 msgid "Slide up to unlock" msgstr "Llisqueu cap amunt per desbloquejar" -#: src/ui/lockscreen.ui:280 +#: src/ui/lockscreen.ui:313 msgid "Emergency" msgstr "Emergència" -#: src/ui/lockscreen.ui:296 +#: src/ui/lockscreen.ui:329 msgid "Unlock" -msgstr "Desbloca" +msgstr "Desbloqueja" -#: src/ui/media-player.ui:107 -msgid "Unknown Song" -msgstr "Cançó desconeguda" +#: src/ui/lockscreen.ui:369 +msgid "Back" +msgstr "Torna" -#: src/ui/media-player.ui:127 -msgid "Unknown Artist" -msgstr "Artista desconegut" +#: src/ui/network-auth-prompt.ui:6 src/ui/polkit-auth-prompt.ui:7 +msgid "Authentication required" +msgstr "Cal autenticació" -#: src/ui/network-auth-prompt.ui:90 +#: src/ui/network-auth-prompt.ui:41 msgid "_Cancel" msgstr "_Cancel·la" -#: src/ui/network-auth-prompt.ui:106 +#: src/ui/network-auth-prompt.ui:59 msgid "C_onnect" msgstr "C_onnecta" -#: src/ui/polkit-auth-prompt.ui:105 -msgid "User:" -msgstr "Usuari:" +#: src/ui/polkit-auth-prompt.ui:123 +msgid "Authenticate" +msgstr "Autenticació" -#: src/ui/system-prompt.ui:69 +#: src/ui/system-prompt.ui:63 msgid "Confirm:" msgstr "Confirmació:" -#: src/ui/top-panel.ui:15 +#: src/ui/top-panel.ui:16 msgid "Lock Screen" msgstr "Bloqueja la pantalla" -#: src/ui/top-panel.ui:22 +#: src/ui/top-panel.ui:23 msgid "Logout" msgstr "Surt" -#: src/ui/top-panel.ui:29 -msgid "Power Off" -msgstr "Apaga" - -#: src/wifiinfo.c:88 +#: src/wifiinfo.c:90 msgid "Wi-Fi" msgstr "Sense fil" -#: src/wwaninfo.c:167 +#. Translators: Refers to the cellular wireless network +#: src/wwaninfo.c:172 msgid "Cellular" msgstr "Mòbil" + +#~ msgid "Unknown artist" +#~ msgstr "Artista desconegut" + +#~ msgid "Unknown Song" +#~ msgstr "Cançó desconeguda" diff -Nru phosh-0.8.0/po/cs.po phosh-0.13.1/po/cs.po --- phosh-0.8.0/po/cs.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/cs.po 2021-08-31 09:15:52.000000000 +0000 @@ -1,21 +1,26 @@ -# Jaroslav Svoboda , 2018. #zanata # Daniel Rusek , 2019. #zanata -# Jaroslav Svoboda , 2019. #zanata +# Jaroslav Svoboda , 2019-2021. +# msgid "" msgstr "" "Project-Id-Version: phosh\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-03-14 13:18+0100\n" +"POT-Creation-Date: 2021-01-15 14:23+0100\n" +"PO-Revision-Date: 2021-03-03 21:13+0100\n" +"Last-Translator: Jaroslav Svoboda \n" +"Language-Team: Czech \n" +"Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2019-11-11 04:58+0000\n" -"Last-Translator: Daniel Rusek \n" -"Language-Team: Czech\n" -"Language: cs\n" -"X-Generator: Zanata 4.6.2\n" +"X-Generator: Gtranslator 3.38.0\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\n" +#. Translators: this is the session name, no need to translate it +#: data/phosh.session.desktop.in.in:4 +msgid "Phosh" +msgstr "Phosh" + #: data/sm.puri.Phosh.desktop.in.in:4 msgid "Phone Shell" msgstr "Shell telefonu" @@ -24,119 +29,251 @@ msgid "Window management and application launching for mobile" msgstr "Správa oken a spouštění aplikací pro mobilní zařízení" -#. Translators: this is the session name, no need to translate it -#: data/phosh.session.desktop.in.in:4 -msgid "Phosh" -msgstr "Phosh" - -#: src/app-grid-button.c:523 +#: src/app-grid-button.c:536 msgid "Application" msgstr "Aplikace" -#: src/feedbackinfo.c:38 +#: src/bt-info.c:92 src/feedbackinfo.c:51 +msgid "On" +msgstr "Zapnout" + +#: src/bt-info.c:94 +msgid "Bluetooth" +msgstr "Bluetooth" + +#: src/docked-info.c:81 +msgid "Docked" +msgstr "V doku" + +#: src/docked-info.c:195 +msgid "Undocked" +msgstr "Mobilní" + +#. Translators: quiet and silent are fbd profiles names: +#. see https://source.puri.sm/Librem5/feedbackd#profiles +#. for details +#: src/feedbackinfo.c:44 msgid "Quiet" -msgstr "" +msgstr "Ztlumeno" -#: src/feedbackinfo.c:40 +#. Translators: quiet and silent are fbd profiles names: +#. see https://source.puri.sm/Librem5/feedbackd#profiles +#. for details +#: src/feedbackinfo.c:49 msgid "Silent" -msgstr "" +msgstr "Potichu" -#: src/feedbackinfo.c:42 -msgid "On" -msgstr "" - -#: src/lockscreen.c:78 src/ui/lockscreen.ui:204 +#: src/lockscreen.c:86 src/ui/lockscreen.ui:234 msgid "Enter Passcode" -msgstr "Vložte heslo" +msgstr "Zadejte heslo" -#: src/lockscreen.c:257 +#: src/lockscreen.c:265 msgid "Checking…" -msgstr "Kontroluji…" +msgstr "Kontroluje se…" #. Translators: This is a time format for a date in #. long format -#: src/lockscreen.c:334 +#: src/lockscreen.c:343 msgid "%A, %B %-e" msgstr "%A, %B %-e" -#: src/monitor-manager.c:53 +#. Translators: Used when the title of a song is unknown +#: src/media-player.c:277 src/ui/media-player.ui:107 +msgid "Unknown Title" +msgstr "Neznámý název" + +#. Translators: Used when the artist of a song is unknown +#: src/media-player.c:286 src/ui/media-player.ui:127 +msgid "Unknown Artist" +msgstr "Neznámý umělec" + +#: src/monitor-manager.c:71 msgid "Built-in display" msgstr "Vestavěný displej" #. Translators: An unknown monitor type -#: src/monitor-manager.c:57 +#: src/monitor-manager.c:75 msgid "Unknown" -msgstr "Neznámý" +msgstr "Neznámé" + +#: src/network-auth-prompt.c:187 +#, c-format +msgid "Authentication type of wifi network “%s” not supported" +msgstr "Typ autentizace wifi sítě “%s” není podporován" -#: src/network-auth-prompt.c:184 +#: src/network-auth-prompt.c:192 #, c-format msgid "Enter password for the wifi network “%s”" -msgstr "" +msgstr "Vložte heslo wifi sítě \"%s”" + +#: src/notifications/mount-notification.c:137 +msgid "Open" +msgstr "Otevřít" + +#: src/notifications/notification.c:381 src/notifications/notification.c:637 +msgid "Notification" +msgstr "Upozornění" + +#. Translators: Timestamp seconds suffix +#: src/notifications/timestamp-label.c:84 +msgctxt "timestamp-suffix-seconds" +msgid "s" +msgstr "s" + +#. Translators: Timestamp minute suffix +#: src/notifications/timestamp-label.c:86 +msgctxt "timestamp-suffix-minute" +msgid "m" +msgstr "min" + +#. Translators: Timestamp minutes suffix +#: src/notifications/timestamp-label.c:88 +msgctxt "timestamp-suffix-minutes" +msgid "m" +msgstr "min" + +#. Translators: Timestamp hour suffix +#: src/notifications/timestamp-label.c:90 +msgctxt "timestamp-suffix-hour" +msgid "h" +msgstr "h" + +#. Translators: Timestamp hours suffix +#: src/notifications/timestamp-label.c:92 +msgctxt "timestamp-suffix-hours" +msgid "h" +msgstr "h" + +#. Translators: Timestamp day suffix +#: src/notifications/timestamp-label.c:94 +msgctxt "timestamp-suffix-day" +msgid "d" +msgstr "d" + +#. Translators: Timestamp days suffix +#: src/notifications/timestamp-label.c:96 +msgctxt "timestamp-suffix-days" +msgid "d" +msgstr "d" + +#. Translators: Timestamp month suffix +#: src/notifications/timestamp-label.c:98 +msgctxt "timestamp-suffix-month" +msgid "mo" +msgstr "měs" + +#. Translators: Timestamp months suffix +#: src/notifications/timestamp-label.c:100 +msgctxt "timestamp-suffix-months" +msgid "mos" +msgstr "měs" + +#. Translators: Timestamp year suffix +#: src/notifications/timestamp-label.c:102 +msgctxt "timestamp-suffix-year" +msgid "y" +msgstr "r" + +#. Translators: Timestamp years suffix +#: src/notifications/timestamp-label.c:104 +msgctxt "timestamp-suffix-years" +msgid "y" +msgstr "r" + +#: src/notifications/timestamp-label.c:121 +msgid "now" +msgstr "nyní" + +#. Translators: time difference "Over 5 years" +#: src/notifications/timestamp-label.c:189 +#, c-format +msgid "Over %dy" +msgstr "Více než %dy" + +#. Translators: time difference "almost 5 years" +#: src/notifications/timestamp-label.c:193 +#, c-format +msgid "Almost %dy" +msgstr "Téměř %dy" -#: src/polkit-auth-agent.c:229 +#. Translators: a time difference like '<5m', if in doubt leave untranslated +#: src/notifications/timestamp-label.c:200 +#, c-format +msgid "%s%d%s" +msgstr "%s%d%s" + +#: src/polkit-auth-agent.c:232 msgid "Authentication dialog was dismissed by the user" msgstr "Autentizační dialog byl zavřen uživatelem" -#: src/polkit-auth-prompt.c:276 src/ui/network-auth-prompt.ui:128 +#: src/polkit-auth-prompt.c:278 src/ui/network-auth-prompt.ui:130 #: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 msgid "Password:" msgstr "Heslo:" -#: src/polkit-auth-prompt.c:322 +#: src/polkit-auth-prompt.c:324 msgid "Sorry, that didn’t work. Please try again." msgstr "Promiňte, toto nefungovalo. Zkuste to prosím znovu." -#: src/polkit-auth-prompt.c:488 +#: src/polkit-auth-prompt.c:469 msgid "Authenticate" msgstr "Autentizovat" -#: src/system-prompt.c:371 +#: src/rotateinfo.c:65 +msgid "Portrait" +msgstr "Portrét" + +#: src/rotateinfo.c:68 +msgid "Landscape" +msgstr "Na šířku" + +#: src/system-prompt.c:373 msgid "Passwords do not match." msgstr "Hesla nesouhlasí." -#: src/system-prompt.c:378 +#: src/system-prompt.c:380 msgid "Password cannot be blank" msgstr "Heslo nemůže být prázdné" -#: src/wifiinfo.c:55 -msgid "Wi-Fi" -msgstr "" +#: src/torch-info.c:80 +msgid "Torch" +msgstr "Svítilna" -#: src/ui/app-grid-button.ui:48 +#: src/ui/app-grid-button.ui:49 msgid "App" msgstr "Aplikace" -#: src/ui/app-grid-button.ui:75 +#: src/ui/app-grid-button.ui:76 msgid "Remove from _Favorites" -msgstr "" +msgstr "Odstranit z _Oblíbených" -#: src/ui/app-grid-button.ui:80 +#: src/ui/app-grid-button.ui:81 msgid "Add to _Favorites" -msgstr "" +msgstr "Přidat do _Oblíbených" #: src/ui/app-grid.ui:21 msgid "Search apps…" msgstr "Hledat aplikace…" -#: src/ui/lockscreen.ui:36 +#: src/ui/lockscreen.ui:37 msgid "Slide up to unlock" msgstr "Táhnutím nahoru odemknete" -#: src/ui/lockscreen.ui:250 +#: src/ui/lockscreen.ui:280 msgid "Emergency" -msgstr "" +msgstr "Tísňové volání" -#: src/ui/lockscreen.ui:266 +#: src/ui/lockscreen.ui:296 msgid "Unlock" -msgstr "" +msgstr "Odemknout" -#: src/ui/network-auth-prompt.ui:90 +#: src/ui/network-auth-prompt.ui:89 msgid "_Cancel" -msgstr "" +msgstr "_Zrušit" -#: src/ui/network-auth-prompt.ui:106 +#: src/ui/network-auth-prompt.ui:105 msgid "C_onnect" -msgstr "" +msgstr "_Připojit" #: src/ui/polkit-auth-prompt.ui:105 msgid "User:" @@ -145,3 +282,31 @@ #: src/ui/system-prompt.ui:69 msgid "Confirm:" msgstr "Potvrdit:" + +#: src/ui/top-panel.ui:15 +msgid "Lock Screen" +msgstr "Zamknout obrazovku" + +#: src/ui/top-panel.ui:22 +msgid "Logout" +msgstr "Odhlásit" + +#: src/ui/top-panel.ui:29 +msgid "Restart" +msgstr "Restartovat" + +#: src/ui/top-panel.ui:36 +msgid "Power Off" +msgstr "Vypnout" + +#: src/wifiinfo.c:90 +msgid "Wi-Fi" +msgstr "Wi-Fi" + +#. Translators: Refers to the cellular wireless network +#: src/wwaninfo.c:170 +msgid "Cellular" +msgstr "Mobilní síť" + +#~ msgid "%d.%m.%y" +#~ msgstr "%d.%měs.%r" diff -Nru phosh-0.8.0/po/da.po phosh-0.13.1/po/da.po --- phosh-0.8.0/po/da.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/da.po 2021-08-31 09:15:52.000000000 +0000 @@ -2,15 +2,16 @@ # Copyright (C) 2020 phosh's COPYRIGHT HOLDER # This file is distributed under the same license as the phosh package. # Simon Jespersen , 2018-2019. #zanata -# scootergrisen, 2020. +# scootergrisen, 2020-2021. +# scootergrisen: oversættelsen mangler at blive testet msgid "" msgstr "" "Project-Id-Version: phosh\n" "Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/phosh/issues\n" -"POT-Creation-Date: 2020-08-14 15:29+0000\n" -"PO-Revision-Date: 2020-09-15 00:00+0200\n" +"POT-Creation-Date: 2021-04-01 03:31+0000\n" +"PO-Revision-Date: 2021-04-15 00:00+0200\n" "Last-Translator: scootergrisen\n" -"Language-Team: Danish \n" +"Language-Team: Danish\n" "Language: da\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -30,77 +31,159 @@ msgid "Window management and application launching for mobile" msgstr "Vindueshåndtering og programstarter til mobiltelefon" -#: src/app-grid-button.c:530 +#: src/app-grid-button.c:536 msgid "Application" msgstr "Program" -#: src/bt-info.c:89 src/feedbackinfo.c:48 +#: src/bt-info.c:92 src/feedbackinfo.c:51 src/rotateinfo.c:103 msgid "On" msgstr "Til" -#: src/bt-info.c:91 +#: src/bt-info.c:94 msgid "Bluetooth" msgstr "Bluetooth" +#: src/docked-info.c:81 +msgid "Docked" +msgstr "Forankeret" + +#: src/docked-info.c:81 src/docked-info.c:195 +msgid "Undocked" +msgstr "Ikke forankeret" + +#: src/end-session-dialog.c:162 +msgid "Log Out" +msgstr "Log ud" + +#: src/end-session-dialog.c:165 +#, c-format +msgid "%s will be logged out automatically in %d second." +msgid_plural "%s will be logged out automatically in %d seconds." +msgstr[0] "%s logges automatisk ud om %d sekund." +msgstr[1] "%s logges automatisk ud om %d sekunder." + +#: src/end-session-dialog.c:171 src/ui/top-panel.ui:37 +msgid "Power Off" +msgstr "Sluk" + +#: src/end-session-dialog.c:172 +#, c-format +msgid "The system will power off automatically in %d second." +msgid_plural "The system will power off automatically in %d seconds." +msgstr[0] "Systemet slukkes automatisk om %d sekund." +msgstr[1] "Systemet slukkes automatisk om %d sekunder." + +#: src/end-session-dialog.c:178 src/ui/top-panel.ui:30 +msgid "Restart" +msgstr "Genstart" + +#: src/end-session-dialog.c:179 +#, c-format +msgid "The system will restart automatically in %d second." +msgid_plural "The system will restart automatically in %d seconds." +msgstr[0] "Systemet genstartes automatisk om %d sekund." +msgstr[1] "Systemet genstartes automatisk om %d sekunder." + +#: src/end-session-dialog.c:270 +#| msgid "Application" +msgid "Unknown application" +msgstr "Ukendt program" + #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details -#: src/feedbackinfo.c:41 +#: src/feedbackinfo.c:44 msgid "Quiet" msgstr "Stille" #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details -#: src/feedbackinfo.c:46 +#: src/feedbackinfo.c:49 msgid "Silent" msgstr "Lydløs" -#: src/lockscreen.c:84 src/ui/lockscreen.ui:234 +#: src/location-manager.c:246 +#, c-format +msgid "Allow '%s' to access your location information?" +msgstr "Tillad at '%s' får adgang til din placeringsinformation?" + +#: src/location-manager.c:251 +#| msgid "Application" +msgid "Geolocation" +msgstr "Geoplacering" + +#: src/location-manager.c:252 +msgid "Yes" +msgstr "Ja" + +#: src/location-manager.c:252 +msgid "No" +msgstr "Nej" + +#: src/lockscreen.c:85 src/ui/lockscreen.ui:234 msgid "Enter Passcode" msgstr "Indtast adgangskode" -#: src/lockscreen.c:263 +#: src/lockscreen.c:264 msgid "Checking…" msgstr "Tjekker …" #. Translators: This is a time format for a date in #. long format -#: src/lockscreen.c:341 +#: src/lockscreen.c:342 msgid "%A, %B %-e" msgstr "%A %d. %B" #. Translators: Used when the title of a song is unknown -#: src/media-player.c:263 src/ui/media-player.ui:107 -#| msgid "Unknown title" +#: src/media-player.c:277 src/ui/media-player.ui:107 msgid "Unknown Title" msgstr "Ukendt titel" #. Translators: Used when the artist of a song is unknown -#: src/media-player.c:272 src/ui/media-player.ui:127 +#: src/media-player.c:286 src/ui/media-player.ui:127 msgid "Unknown Artist" msgstr "Ukendt kunstner" -#: src/monitor-manager.c:58 +#: src/monitor-manager.c:112 msgid "Built-in display" msgstr "Indbygget skærm" +#: src/monitor-manager.c:130 +#, c-format +msgctxt "" +"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgid "%s %s" +msgstr "%s %s" + +#: src/monitor-manager.c:137 +#, c-format +msgctxt "" +"This is a monitor vendor name followed by product/model name where size in " +"inches could not be calculated, e.g. Dell U2414H" +msgid "%s %sn" +msgstr "%s %sn" + #. Translators: An unknown monitor type -#: src/monitor-manager.c:62 +#: src/monitor-manager.c:146 msgid "Unknown" msgstr "Ukendt" -#: src/network-auth-prompt.c:184 +#: src/network-auth-prompt.c:187 #, c-format msgid "Authentication type of wifi network “%s” not supported" msgstr "Godkendelsestypen for wifi-netværket “%s” understøttes ikke" -#: src/network-auth-prompt.c:189 +#: src/network-auth-prompt.c:192 #, c-format msgid "Enter password for the wifi network “%s”" msgstr "Indtast adgangskode til wifi-netværket “%s”" -#: src/notifications/notification.c:382 src/notifications/notification.c:601 +#: src/notifications/mount-notification.c:137 +msgid "Open" +msgstr "Åbn" + +#: src/notifications/notification.c:381 src/notifications/notification.c:637 msgid "Notification" msgstr "Underretning" @@ -170,54 +253,87 @@ msgid "y" msgstr "å" -#. Translators: this is the date in (short) number only format -#: src/notifications/timestamp-label.c:107 -msgid "%d.%m.%y" -msgstr "%d.%m.%y" - -#. Translators: Timestamp prefix (e.g. Over 5h) -#: src/notifications/timestamp-label.c:198 -msgid "Over" -msgstr "Over" - -#. Translators: Timestamp prefix (e.g. Almost 5h) -#: src/notifications/timestamp-label.c:203 -msgid "Almost" -msgstr "Næsten" +#: src/notifications/timestamp-label.c:121 +#| msgid "Unknown" +msgid "now" +msgstr "nu" + +# scootergrisen: tjek at det er korrekt +#. Translators: time difference "Over 5 years" +#: src/notifications/timestamp-label.c:189 +#, c-format +#| msgid "Over" +msgid "Over %dy" +msgstr "Over %då" + +# scootergrisen: tjek at det er korrekt +#. Translators: time difference "almost 5 years" +#: src/notifications/timestamp-label.c:193 +#, c-format +#| msgid "Almost" +msgid "Almost %dy" +msgstr "Næsten %då" + +# scootergrisen: tjek at det er korrekt +#. Translators: a time difference like '<5m', if in doubt leave untranslated +#: src/notifications/timestamp-label.c:200 +#, c-format +msgid "%s%d%s" +msgstr "%s%d%s" -#: src/polkit-auth-agent.c:229 +#: src/polkit-auth-agent.c:225 msgid "Authentication dialog was dismissed by the user" msgstr "Godkendelsesdialogen blev lukket af brugeren" -#: src/polkit-auth-prompt.c:276 src/ui/network-auth-prompt.ui:128 -#: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 +#: src/polkit-auth-prompt.c:278 src/ui/network-auth-prompt.ui:85 +#: src/ui/polkit-auth-prompt.ui:57 src/ui/system-prompt.ui:33 msgid "Password:" msgstr "Adgangskode:" -#: src/polkit-auth-prompt.c:322 +#: src/polkit-auth-prompt.c:325 msgid "Sorry, that didn’t work. Please try again." msgstr "Beklager, det virkede ikke. Prøv venligst igen." -#: src/polkit-auth-prompt.c:488 -msgid "Authenticate" -msgstr "Godkend" - -#: src/rotateinfo.c:46 +#: src/rotateinfo.c:81 msgid "Portrait" msgstr "Portræt" -#: src/rotateinfo.c:49 +#: src/rotateinfo.c:84 msgid "Landscape" msgstr "Landskab" -#: src/system-prompt.c:371 +#. Translators: Automatic screen orientation is either on (enabled) or off (locked/disabled) +#. Translators: Automatic screen orientation is off (locked/disabled) +#: src/rotateinfo.c:103 src/rotateinfo.c:183 +msgid "Off" +msgstr "Fra" + +#: src/system-prompt.c:364 msgid "Passwords do not match." msgstr "Adgangskoderne er ikke ens." -#: src/system-prompt.c:378 +#: src/system-prompt.c:371 msgid "Password cannot be blank" msgstr "Adgangskoden må ikke være tom" +# scootergrisen: ved ikke hvad "Torch" er. Tjek at det er korrekt oversat +#: src/torch-info.c:80 +msgid "Torch" +msgstr "Lommelygte (Torch)" + +#: src/ui/app-auth-prompt.ui:41 +msgid "Remember decision" +msgstr "Husk beslutning" + +#: src/ui/app-auth-prompt.ui:55 src/ui/end-session-dialog.ui:50 +#| msgid "_Cancel" +msgid "Cancel" +msgstr "Annuller" + +#: src/ui/app-auth-prompt.ui:66 src/ui/end-session-dialog.ui:61 +msgid "Ok" +msgstr "OK" + #: src/ui/app-grid-button.ui:49 msgid "App" msgstr "Program" @@ -234,6 +350,10 @@ msgid "Search apps…" msgstr "Søger efter programmer …" +#: src/ui/end-session-dialog.ui:32 +msgid "Some applications are busy or have unsaved work" +msgstr "Nogle programmer er optagede eller har arbejde som ikke er blevet gemt" + #: src/ui/lockscreen.ui:37 msgid "Slide up to unlock" msgstr "Skub op for at låse op" @@ -246,43 +366,40 @@ msgid "Unlock" msgstr "Lås op" -#: src/ui/network-auth-prompt.ui:90 +#: src/ui/network-auth-prompt.ui:6 src/ui/polkit-auth-prompt.ui:7 +#| msgid "Authenticate" +msgid "Authentication required" +msgstr "Godkendelse kræves" + +#: src/ui/network-auth-prompt.ui:42 msgid "_Cancel" msgstr "_Annuller" -#: src/ui/network-auth-prompt.ui:106 +#: src/ui/network-auth-prompt.ui:61 msgid "C_onnect" msgstr "_Opret forbindelse" -#: src/ui/polkit-auth-prompt.ui:105 -msgid "User:" -msgstr "Bruger:" +#: src/ui/polkit-auth-prompt.ui:125 +msgid "Authenticate" +msgstr "Godkend" -#: src/ui/system-prompt.ui:69 +#: src/ui/system-prompt.ui:63 msgid "Confirm:" msgstr "Bekræft:" -#: src/ui/top-panel.ui:15 +#: src/ui/top-panel.ui:16 msgid "Lock Screen" msgstr "Lås skærm" -#: src/ui/top-panel.ui:22 +#: src/ui/top-panel.ui:23 msgid "Logout" msgstr "Log ud" -#: src/ui/top-panel.ui:29 -msgid "Restart" -msgstr "Genstart" - -#: src/ui/top-panel.ui:36 -msgid "Power Off" -msgstr "Sluk" - -#: src/wifiinfo.c:88 +#: src/wifiinfo.c:90 msgid "Wi-Fi" msgstr "Wi-Fi" #. Translators: Refers to the cellular wireless network -#: src/wwaninfo.c:168 +#: src/wwaninfo.c:172 msgid "Cellular" msgstr "Mobil" diff -Nru phosh-0.8.0/po/de.po phosh-0.13.1/po/de.po --- phosh-0.8.0/po/de.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/de.po 2021-08-31 09:15:52.000000000 +0000 @@ -1,6 +1,7 @@ # German translation for phosh # Copyright (C) 2018 THE phosh'S COPYRIGHT HOLDER # This file is distributed under the same license as the phosh package. +# # Guido Günther , 2018 # Daniel Brunkhorst , 2018. #zanata # Guido Günther , 2018. #zanata @@ -13,21 +14,24 @@ # Mike Ballmann , 2020. #zanata # heiko123abc , 2020. # Tim Sabsch , 2020. +# Michael Oppliger , 2021. +# Philipp Kiemle , 2021. +# # msgid "" msgstr "" "Project-Id-Version: phosh\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-06-25 08:32+0200\n" -"PO-Revision-Date: 2020-07-29 10:16+0200\n" -"Last-Translator: Tim Sabsch \n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/phosh/issues\n" +"POT-Creation-Date: 2021-08-11 13:39+0000\n" +"PO-Revision-Date: 2021-08-16 20:36+0200\n" +"Last-Translator: Philipp Kiemle \n" "Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 2.3.1\n" +"X-Generator: Poedit 2.4.2\n" #. Translators: this is the session name, no need to translate it #: data/phosh.session.desktop.in.in:4 @@ -42,177 +46,396 @@ msgid "Window management and application launching for mobile" msgstr "Fensterverwaltung und Starten von Apps für mobile Geräte" -#: src/app-grid-button.c:530 +#: src/app-grid-button.c:536 msgid "Application" msgstr "Anwendung" +#: src/bt-info.c:92 src/feedbackinfo.c:51 src/rotateinfo.c:103 +msgid "On" +msgstr "An" + +#: src/bt-info.c:94 +msgid "Bluetooth" +msgstr "Bluetooth" + +#: src/docked-info.c:81 +msgid "Docked" +msgstr "Angedockt" + +#: src/docked-info.c:81 src/docked-info.c:199 +msgid "Undocked" +msgstr "Abgedockt" + +#: src/end-session-dialog.c:162 +msgid "Log Out" +msgstr "Abmelden" + +#: src/end-session-dialog.c:165 +#, c-format +msgid "%s will be logged out automatically in %d second." +msgid_plural "%s will be logged out automatically in %d seconds." +msgstr[0] "%s wird automatisch in %d Sekunde abgemeldet." +msgstr[1] "%s wird automatisch in %d Sekunden abgemeldet." + +#: src/end-session-dialog.c:171 src/ui/top-panel.ui:37 +msgid "Power Off" +msgstr "Ausschalten" + +#: src/end-session-dialog.c:172 +#, c-format +msgid "The system will power off automatically in %d second." +msgid_plural "The system will power off automatically in %d seconds." +msgstr[0] "Das System wird in %d Sekunde ausgeschaltet." +msgstr[1] "Das System wird in %d Sekunden ausgeschaltet." + +#: src/end-session-dialog.c:178 src/ui/top-panel.ui:30 +msgid "Restart" +msgstr "Neustart" + +#: src/end-session-dialog.c:179 +#, c-format +msgid "The system will restart automatically in %d second." +msgid_plural "The system will restart automatically in %d seconds." +msgstr[0] "Das System wird in %d Sekunde neu gestartet." +msgstr[1] "Das System wird in %d Sekunden neu gestartet." + +#: src/end-session-dialog.c:269 +msgid "Unknown application" +msgstr "Unbekannte Anwendung" + #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details -#: src/feedbackinfo.c:41 +#: src/feedbackinfo.c:44 msgid "Quiet" msgstr "Leise" #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details -#: src/feedbackinfo.c:46 +#: src/feedbackinfo.c:49 msgid "Silent" msgstr "Lautlos" -#: src/feedbackinfo.c:42 -msgid "On" -msgstr "An" +#: src/location-manager.c:268 +#, c-format +msgid "Allow '%s' to access your location information?" +msgstr "Zulassen, dass »%s« Ihre Standortinformationen abruft?" + +#: src/location-manager.c:273 +msgid "Geolocation" +msgstr "Standort" + +#: src/location-manager.c:274 +msgid "Yes" +msgstr "Ja" + +#: src/location-manager.c:274 +msgid "No" +msgstr "Nein" -#: src/lockscreen.c:82 src/ui/lockscreen.ui:217 +#: src/lockscreen.c:157 src/ui/lockscreen.ui:267 msgid "Enter Passcode" msgstr "Zugangscode eingeben" -#: src/lockscreen.c:261 +#: src/lockscreen.c:340 msgid "Checking…" msgstr "Überprüfung läuft …" #. Translators: This is a time format for a date in #. long format -#: src/lockscreen.c:339 +#: src/lockscreen.c:418 msgid "%A, %B %-e" msgstr "%A %d. %B" -#: src/media-player.c:244 -msgid "Unknown title" +#. Translators: Used when the title of a song is unknown +#: src/media-player.c:279 src/ui/media-player.ui:107 +msgid "Unknown Title" msgstr "Unbekannter Titel" -#: src/media-player.c:252 -msgid "Unknown artist" +#. Translators: Used when the artist of a song is unknown +#: src/media-player.c:288 src/ui/media-player.ui:127 +msgid "Unknown Artist" msgstr "Unbekannter Künstler" -#: src/monitor-manager.c:58 +#: src/monitor-manager.c:114 msgid "Built-in display" msgstr "Eingebaute Anzeige" +#: src/monitor-manager.c:132 +#, c-format +msgctxt "" +"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgid "%s %s" +msgstr "%s %s" + +#: src/monitor-manager.c:139 +#, c-format +msgctxt "" +"This is a monitor vendor name followed by product/model name where size in " +"inches could not be calculated, e.g. Dell U2414H" +msgid "%s %s" +msgstr "%s %s" + #. Translators: An unknown monitor type -#: src/monitor-manager.c:62 +#: src/monitor-manager.c:148 msgid "Unknown" msgstr "Unbekannt" -#: src/network-auth-prompt.c:184 +#: src/network-auth-prompt.c:187 #, c-format msgid "Authentication type of wifi network “%s” not supported" -msgstr "Die Art der Legitimierung des WLAN-Netzwerks »%s« wird nicht unterstützt" +msgstr "" +"Die Art der Legitimierung des WLAN-Netzwerks »%s« wird nicht unterstützt" -#: src/network-auth-prompt.c:189 +#: src/network-auth-prompt.c:192 #, c-format msgid "Enter password for the wifi network “%s”" msgstr "Geben Sie das Passwort für das WLAN-Netzwerk »%s« ein" -#: src/notifications/notification.c:365 src/notifications/notification.c:581 +#: src/notifications/mount-notification.c:122 +msgid "Open" +msgstr "Öffnen" + +#: src/notifications/notification.c:383 src/notifications/notification.c:639 msgid "Notification" msgstr "Benachrichtigung" -#: src/polkit-auth-agent.c:229 +#. Translators: Timestamp seconds suffix +#: src/notifications/timestamp-label.c:84 +msgctxt "timestamp-suffix-seconds" +msgid "s" +msgstr "s" + +#. Translators: Timestamp minute suffix +#: src/notifications/timestamp-label.c:86 +msgctxt "timestamp-suffix-minute" +msgid "m" +msgstr "min" + +#. Translators: Timestamp minutes suffix +#: src/notifications/timestamp-label.c:88 +msgctxt "timestamp-suffix-minutes" +msgid "m" +msgstr "min" + +#. Translators: Timestamp hour suffix +#: src/notifications/timestamp-label.c:90 +msgctxt "timestamp-suffix-hour" +msgid "h" +msgstr "h" + +#. Translators: Timestamp hours suffix +#: src/notifications/timestamp-label.c:92 +msgctxt "timestamp-suffix-hours" +msgid "h" +msgstr "h" + +#. Translators: Timestamp day suffix +#: src/notifications/timestamp-label.c:94 +msgctxt "timestamp-suffix-day" +msgid "d" +msgstr "T" + +#. Translators: Timestamp days suffix +#: src/notifications/timestamp-label.c:96 +msgctxt "timestamp-suffix-days" +msgid "d" +msgstr "T" + +#. Translators: Timestamp month suffix +#: src/notifications/timestamp-label.c:98 +msgctxt "timestamp-suffix-month" +msgid "mo" +msgstr "Mon" + +#. Translators: Timestamp months suffix +#: src/notifications/timestamp-label.c:100 +msgctxt "timestamp-suffix-months" +msgid "mos" +msgstr "Mon" + +#. Translators: Timestamp year suffix +#: src/notifications/timestamp-label.c:102 +msgctxt "timestamp-suffix-year" +msgid "y" +msgstr "J" + +#. Translators: Timestamp years suffix +#: src/notifications/timestamp-label.c:104 +msgctxt "timestamp-suffix-years" +msgid "y" +msgstr "J" + +#: src/notifications/timestamp-label.c:121 +msgid "now" +msgstr "Jetzt" + +#. Translators: time difference "Over 5 years" +#: src/notifications/timestamp-label.c:189 +#, c-format +msgid "Over %dy" +msgstr "Über %d J" + +#. Translators: time difference "almost 5 years" +#: src/notifications/timestamp-label.c:193 +#, c-format +msgid "Almost %dy" +msgstr "Fast %d J" + +#. Translators: a time difference like '<5m', if in doubt leave untranslated +#: src/notifications/timestamp-label.c:200 +#, c-format +msgid "%s%d%s" +msgstr "%s%d%s" + +#: src/polkit-auth-agent.c:228 msgid "Authentication dialog was dismissed by the user" msgstr "Der Dialog zur Anmeldung wurde vom Benutzer geschlossen" -#: src/polkit-auth-prompt.c:276 src/ui/network-auth-prompt.ui:128 -#: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 +#: src/polkit-auth-prompt.c:278 src/ui/gtk-mount-prompt.ui:21 +#: src/ui/network-auth-prompt.ui:83 src/ui/polkit-auth-prompt.ui:57 +#: src/ui/system-prompt.ui:33 msgid "Password:" msgstr "Passwort:" -#: src/polkit-auth-prompt.c:322 +#: src/polkit-auth-prompt.c:325 msgid "Sorry, that didn’t work. Please try again." -msgstr "Entschuldigung, das hat nicht funktioniert. Bitte versuchen Sie es erneut." +msgstr "" +"Entschuldigung, das hat nicht funktioniert. Bitte versuchen Sie es erneut." -#: src/polkit-auth-prompt.c:488 -msgid "Authenticate" -msgstr "Legitimieren" +#: src/rotateinfo.c:81 +msgid "Portrait" +msgstr "Hochformat" + +#: src/rotateinfo.c:84 +msgid "Landscape" +msgstr "Querformat" + +#. Translators: Automatic screen orientation is either on (enabled) or off (locked/disabled) +#. Translators: Automatic screen orientation is off (locked/disabled) +#: src/rotateinfo.c:103 src/rotateinfo.c:186 +msgid "Off" +msgstr "Aus" -#: src/system-prompt.c:371 +#: src/system-prompt.c:364 msgid "Passwords do not match." msgstr "Die Passwörter stimmen nicht überein." -#: src/system-prompt.c:378 +#: src/system-prompt.c:371 msgid "Password cannot be blank" msgstr "Das Passwort darf nicht leer sein" -#: src/ui/app-grid-button.ui:48 +#: src/torch-info.c:80 +msgid "Torch" +msgstr "Taschenlampe" + +#: src/ui/app-auth-prompt.ui:41 +msgid "Remember decision" +msgstr "Entscheidung merken" + +#: src/ui/app-auth-prompt.ui:54 src/ui/end-session-dialog.ui:54 +msgid "Cancel" +msgstr "Abbrechen" + +#: src/ui/app-auth-prompt.ui:63 src/ui/end-session-dialog.ui:63 +msgid "Ok" +msgstr "OK" + +#: src/ui/app-grid-button.ui:49 msgid "App" msgstr "App" -#: src/ui/app-grid-button.ui:75 +#: src/ui/app-grid-button.ui:76 msgid "Remove from _Favorites" msgstr "Aus _Favoriten entfernen" -#: src/ui/app-grid-button.ui:80 +#: src/ui/app-grid-button.ui:81 msgid "Add to _Favorites" msgstr "Zu _Favoriten hinzufügen" -#: src/ui/app-grid.ui:21 +#: src/ui/app-grid.ui:22 msgid "Search apps…" msgstr "Apps suchen …" -#: src/ui/lockscreen.ui:37 +#: src/ui/app-grid.ui:169 +msgid "Show only adaptive apps" +msgstr "Nur adaptive Apps anzeigen" + +#: src/ui/end-session-dialog.ui:32 +msgid "Some applications are busy or have unsaved work" +msgstr "Einige Anwendungen sind beschäftigt oder haben ungesicherte Änderungen" + +#: src/ui/gtk-mount-prompt.ui:95 +msgid "User:" +msgstr "Benutzername:" + +#: src/ui/gtk-mount-prompt.ui:118 +msgid "Domain:" +msgstr "Domäne:" + +#: src/ui/gtk-mount-prompt.ui:151 +msgid "Co_nnect" +msgstr "_Verbinden" + +#: src/ui/lockscreen.ui:43 msgid "Slide up to unlock" msgstr "Nach oben wischen zum Entsperren" -#: src/ui/lockscreen.ui:263 +#: src/ui/lockscreen.ui:313 msgid "Emergency" msgstr "Notruf" -#: src/ui/lockscreen.ui:279 +#: src/ui/lockscreen.ui:329 msgid "Unlock" msgstr "Entsperren" -#: src/ui/media-player.ui:107 -msgid "Unknown Song" -msgstr "Unbekannter Titel" - -#: src/ui/media-player.ui:127 -msgid "Unknown Artist" -msgstr "Unbekannter Künstler" +#: src/ui/lockscreen.ui:369 +msgid "Back" +msgstr "Zurück" + +#: src/ui/network-auth-prompt.ui:6 src/ui/polkit-auth-prompt.ui:7 +msgid "Authentication required" +msgstr "Legitimierung erforderlich" -#: src/ui/network-auth-prompt.ui:90 +#: src/ui/network-auth-prompt.ui:41 msgid "_Cancel" msgstr "_Abbrechen" -#: src/ui/network-auth-prompt.ui:106 +#: src/ui/network-auth-prompt.ui:59 msgid "C_onnect" msgstr "_Verbinden" -#: src/ui/polkit-auth-prompt.ui:105 -msgid "User:" -msgstr "Benutzername:" +#: src/ui/polkit-auth-prompt.ui:123 +msgid "Authenticate" +msgstr "Legitimieren" -#: src/ui/system-prompt.ui:69 +#: src/ui/system-prompt.ui:63 msgid "Confirm:" msgstr "Bestätigen:" -#: src/ui/top-panel.ui:15 +#: src/ui/top-panel.ui:16 msgid "Lock Screen" msgstr "Bildschirm sperren" -#: src/ui/top-panel.ui:22 +#: src/ui/top-panel.ui:23 msgid "Logout" msgstr "Abmelden" -#: src/ui/top-panel.ui:29 -msgid "Power Off" -msgstr "Ausschalten" - -#: src/wifiinfo.c:55 +#: src/wifiinfo.c:90 msgid "Wi-Fi" msgstr "WLAN" -#~ msgid "Bluetooth" -#~ msgstr "Bluetooth" - -#~ msgid "Portrait" -#~ msgstr "Hochformat" +#. Translators: Refers to the cellular wireless network +#: src/wwaninfo.c:172 +msgid "Cellular" +msgstr "Mobilfunk" -#~ msgid "Landscape" -#~ msgstr "Querformat" +#~ msgid "Unknown artist" +#~ msgstr "Unbekannter Künstler" -#~ msgid "Cellular" -#~ msgstr "Mobilfunk" +#~ msgid "Unknown Song" +#~ msgstr "Unbekannter Titel" #~ msgid "Suspend" #~ msgstr "Bereitschaft" diff -Nru phosh-0.8.0/po/el.po phosh-0.13.1/po/el.po --- phosh-0.8.0/po/el.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/el.po 2021-08-31 09:15:52.000000000 +0000 @@ -5,17 +5,22 @@ msgid "" msgstr "" "Project-Id-Version: phosh\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-03-14 13:18+0100\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/phosh/issues\n" +"POT-Creation-Date: 2021-08-03 09:16+0000\n" +"PO-Revision-Date: 2021-08-04 02:02+0300\n" +"Last-Translator: Efstathios Iosifidis \n" +"Language-Team: Greek, Modern (1453-) \n" +"Language: el\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2020-04-14 12:26+0300\n" -"Last-Translator: Efstathios Iosifidis \n" -"Language-Team: Greek, Modern (1453-) \n" -"Language: el\n" -"X-Generator: Gtranslator 3.34.0\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"X-Generator: Poedit 2.3\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. Translators: this is the session name, no need to translate it +#: data/phosh.session.desktop.in.in:4 +msgid "Phosh" +msgstr "Phosh" #: data/sm.puri.Phosh.desktop.in.in:4 msgid "Phone Shell" @@ -25,124 +30,387 @@ msgid "Window management and application launching for mobile" msgstr "Διαχείριση παραθύρων και εκκίνησης εφαρμογών κινητού" -#. Translators: this is the session name, no need to translate it -#: data/phosh.session.desktop.in.in:4 -msgid "Phosh" -msgstr "Phosh" - -#: src/app-grid-button.c:523 +#: src/app-grid-button.c:536 msgid "Application" msgstr "Εφαρμογή" -#: src/feedbackinfo.c:38 +#: src/bt-info.c:92 src/feedbackinfo.c:51 src/rotateinfo.c:103 +msgid "On" +msgstr "Ενεργό" + +#: src/bt-info.c:94 +msgid "Bluetooth" +msgstr "Bluetooth" + +#: src/docked-info.c:81 +msgid "Docked" +msgstr "" + +#: src/docked-info.c:81 src/docked-info.c:199 +msgid "Undocked" +msgstr "" + +#: src/end-session-dialog.c:162 +msgid "Log Out" +msgstr "Αποσύνδεση" + +#: src/end-session-dialog.c:165 +#, c-format +msgid "%s will be logged out automatically in %d second." +msgid_plural "%s will be logged out automatically in %d seconds." +msgstr[0] "Ο %s θα αποσυνδεθεί αυτόματα σε %d δευτερόλεπτο." +msgstr[1] "Ο %s θα αποσυνδεθεί αυτόματα σε %d δευτερόλεπτα." + +#: src/end-session-dialog.c:171 src/ui/top-panel.ui:37 +msgid "Power Off" +msgstr "Διακοπή λειτουργίας" + +#: src/end-session-dialog.c:172 +#, c-format +msgid "The system will power off automatically in %d second." +msgid_plural "The system will power off automatically in %d seconds." +msgstr[0] "Το σύστημα θα απενεργοποιηθεί αυτόματα σε %d δευτερόλεπτο." +msgstr[1] "Το σύστημα θα απενεργοποιηθεί αυτόματα σε %d δευτερόλεπτα." + +#: src/end-session-dialog.c:178 src/ui/top-panel.ui:30 +msgid "Restart" +msgstr "Επανεκκίνηση" + +#: src/end-session-dialog.c:179 +#, c-format +msgid "The system will restart automatically in %d second." +msgid_plural "The system will restart automatically in %d seconds." +msgstr[0] "Το σύστημα θα επανεκκινήσει αυτόματα σε %d δευτερόλεπτο." +msgstr[1] "Το σύστημα θα επανεκκινήσει αυτόματα σε %d δευτερόλεπτα." + +#: src/end-session-dialog.c:269 +msgid "Unknown application" +msgstr "Άγνωστη εφαρμογή" + +#. Translators: quiet and silent are fbd profiles names: +#. see https://source.puri.sm/Librem5/feedbackd#profiles +#. for details +#: src/feedbackinfo.c:44 msgid "Quiet" msgstr "Σιωπηλό" -#: src/feedbackinfo.c:40 +#. Translators: quiet and silent are fbd profiles names: +#. see https://source.puri.sm/Librem5/feedbackd#profiles +#. for details +#: src/feedbackinfo.c:49 msgid "Silent" msgstr "Αθόρυβο" -#: src/feedbackinfo.c:42 -msgid "On" -msgstr "Ενεργό" +#: src/location-manager.c:268 +#, c-format +msgid "Allow '%s' to access your location information?" +msgstr "" +"Να επιτρέπεται στο «%s» να έχει πρόσβαση στις πληροφορίες τοποθεσίας σας;" + +#: src/location-manager.c:273 +msgid "Geolocation" +msgstr "Γεωεντοπισμός" -#: src/lockscreen.c:78 src/ui/lockscreen.ui:204 +#: src/location-manager.c:274 +msgid "Yes" +msgstr "Ναι" + +#: src/location-manager.c:274 +msgid "No" +msgstr "Όχι" + +#: src/lockscreen.c:152 src/ui/lockscreen.ui:239 msgid "Enter Passcode" msgstr "Εισάγετε συνθηματικό" -#: src/lockscreen.c:257 +#: src/lockscreen.c:335 msgid "Checking…" -msgstr "Γίνεται έλεγχος..." +msgstr "Γίνεται έλεγχος…" #. Translators: This is a time format for a date in #. long format -#: src/lockscreen.c:334 +#: src/lockscreen.c:413 msgid "%A, %B %-e" msgstr "%A, %B %-e" -#: src/monitor-manager.c:53 +#. Translators: Used when the title of a song is unknown +#: src/media-player.c:279 src/ui/media-player.ui:107 +msgid "Unknown Title" +msgstr "Άγνωστος τίτλος" + +#. Translators: Used when the artist of a song is unknown +#: src/media-player.c:288 src/ui/media-player.ui:127 +msgid "Unknown Artist" +msgstr "Άγνωστος καλλιτέχνης" + +#: src/monitor-manager.c:114 msgid "Built-in display" msgstr "Ενσωματομένη οθόνη" +#: src/monitor-manager.c:132 +#, c-format +msgctxt "" +"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgid "%s %s" +msgstr "%s %s" + +#: src/monitor-manager.c:139 +#, c-format +msgctxt "" +"This is a monitor vendor name followed by product/model name where size in " +"inches could not be calculated, e.g. Dell U2414H" +msgid "%s %s" +msgstr "%s %s" + #. Translators: An unknown monitor type -#: src/monitor-manager.c:57 +#: src/monitor-manager.c:148 msgid "Unknown" msgstr "Άγνωστος τύπος οθόνης" -#: src/network-auth-prompt.c:184 +#: src/network-auth-prompt.c:187 +#, c-format +msgid "Authentication type of wifi network “%s” not supported" +msgstr "Ο τύπος πιστοποίησης του ασύρματου δικτύου «%s» δεν υποστηρίζεται" + +#: src/network-auth-prompt.c:192 #, c-format msgid "Enter password for the wifi network “%s”" msgstr "Εισάγετε συνθηματικό για το ασύρματο δίκτυο «%s»" -#: src/polkit-auth-agent.c:229 +#: src/notifications/mount-notification.c:122 +msgid "Open" +msgstr "Άνοιγμα" + +#: src/notifications/notification.c:383 src/notifications/notification.c:639 +msgid "Notification" +msgstr "Ειδοποίηση" + +#. Translators: Timestamp seconds suffix +#: src/notifications/timestamp-label.c:84 +msgctxt "timestamp-suffix-seconds" +msgid "s" +msgstr "δ" + +#. Translators: Timestamp minute suffix +#: src/notifications/timestamp-label.c:86 +msgctxt "timestamp-suffix-minute" +msgid "m" +msgstr "λ" + +#. Translators: Timestamp minutes suffix +#: src/notifications/timestamp-label.c:88 +msgctxt "timestamp-suffix-minutes" +msgid "m" +msgstr "λ" + +#. Translators: Timestamp hour suffix +#: src/notifications/timestamp-label.c:90 +msgctxt "timestamp-suffix-hour" +msgid "h" +msgstr "ω" + +#. Translators: Timestamp hours suffix +#: src/notifications/timestamp-label.c:92 +msgctxt "timestamp-suffix-hours" +msgid "h" +msgstr "ω" + +#. Translators: Timestamp day suffix +#: src/notifications/timestamp-label.c:94 +msgctxt "timestamp-suffix-day" +msgid "d" +msgstr "ημ" + +#. Translators: Timestamp days suffix +#: src/notifications/timestamp-label.c:96 +msgctxt "timestamp-suffix-days" +msgid "d" +msgstr "ημ" + +#. Translators: Timestamp month suffix +#: src/notifications/timestamp-label.c:98 +msgctxt "timestamp-suffix-month" +msgid "mo" +msgstr "μην" + +#. Translators: Timestamp months suffix +#: src/notifications/timestamp-label.c:100 +msgctxt "timestamp-suffix-months" +msgid "mos" +msgstr "μην" + +#. Translators: Timestamp year suffix +#: src/notifications/timestamp-label.c:102 +msgctxt "timestamp-suffix-year" +msgid "y" +msgstr "ετος" + +#. Translators: Timestamp years suffix +#: src/notifications/timestamp-label.c:104 +msgctxt "timestamp-suffix-years" +msgid "y" +msgstr "έτη" + +#: src/notifications/timestamp-label.c:121 +msgid "now" +msgstr "τώρα" + +#. Translators: time difference "Over 5 years" +#: src/notifications/timestamp-label.c:189 +#, c-format +msgid "Over %dy" +msgstr "Πάνω από %dy" + +#. Translators: time difference "almost 5 years" +#: src/notifications/timestamp-label.c:193 +#, c-format +msgid "Almost %dy" +msgstr "Σχεδόν %dy" + +#. Translators: a time difference like '<5m', if in doubt leave untranslated +#: src/notifications/timestamp-label.c:200 +#, c-format +msgid "%s%d%s" +msgstr "%s%d%s" + +#: src/polkit-auth-agent.c:228 msgid "Authentication dialog was dismissed by the user" msgstr "Ο διάλογος πιστοποίησης απορρίφθηκε από τον χρήστη" -#: src/polkit-auth-prompt.c:276 src/ui/network-auth-prompt.ui:128 -#: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 +#: src/polkit-auth-prompt.c:278 src/ui/gtk-mount-prompt.ui:21 +#: src/ui/network-auth-prompt.ui:83 src/ui/polkit-auth-prompt.ui:57 +#: src/ui/system-prompt.ui:33 msgid "Password:" msgstr "Συνθηματικό:" -#: src/polkit-auth-prompt.c:322 +#: src/polkit-auth-prompt.c:325 msgid "Sorry, that didn’t work. Please try again." msgstr "Συγγνώμη, παρουσιάστηκε σφάλμα. Παρακαλούμε δοκιμάστε ξανά." -#: src/polkit-auth-prompt.c:488 -msgid "Authenticate" -msgstr "Πιστοποίηση" +#: src/rotateinfo.c:81 +msgid "Portrait" +msgstr "Κάθετα" + +#: src/rotateinfo.c:84 +msgid "Landscape" +msgstr "Οριζόντια" + +#. Translators: Automatic screen orientation is either on (enabled) or off (locked/disabled) +#. Translators: Automatic screen orientation is off (locked/disabled) +#: src/rotateinfo.c:103 src/rotateinfo.c:186 +msgid "Off" +msgstr "Ανενεργό" -#: src/system-prompt.c:371 +#: src/system-prompt.c:364 msgid "Passwords do not match." msgstr "Τα συνθηματικά δεν ταιριάζουν." -#: src/system-prompt.c:378 +#: src/system-prompt.c:371 msgid "Password cannot be blank" msgstr "Το συνθηματικό δεν μπορεί να είναι κενό" -#: src/wifiinfo.c:55 -msgid "Wi-Fi" -msgstr "Wi-Fi" +#: src/torch-info.c:80 +msgid "Torch" +msgstr "Φακός" + +#: src/ui/app-auth-prompt.ui:41 +msgid "Remember decision" +msgstr "Απομνημόνευση απόφασης" + +#: src/ui/app-auth-prompt.ui:54 src/ui/end-session-dialog.ui:54 +msgid "Cancel" +msgstr "Ακύρωση" + +#: src/ui/app-auth-prompt.ui:63 src/ui/end-session-dialog.ui:63 +msgid "Ok" +msgstr "ΟΚ" -#: src/ui/app-grid-button.ui:48 +#: src/ui/app-grid-button.ui:49 msgid "App" msgstr "Εφαρμογή" -#: src/ui/app-grid-button.ui:75 +#: src/ui/app-grid-button.ui:76 msgid "Remove from _Favorites" msgstr "Αφαίρεση από τα _αγαπημένα" -#: src/ui/app-grid-button.ui:80 +#: src/ui/app-grid-button.ui:81 msgid "Add to _Favorites" msgstr "Προσθήκη στα _αγαπημένα" -#: src/ui/app-grid.ui:21 +#: src/ui/app-grid.ui:22 msgid "Search apps…" -msgstr "Αναζήτηση εφαρμογών..." +msgstr "Αναζήτηση εφαρμογών…" + +#: src/ui/app-grid.ui:169 +msgid "Show only adaptive apps" +msgstr "Εμφάνιση μόνο προσαρμοσμένων εφαρμογών" -#: src/ui/lockscreen.ui:36 +#: src/ui/end-session-dialog.ui:32 +msgid "Some applications are busy or have unsaved work" +msgstr "" +"Ορισμένες εφαρμογές είναι απασχολημένες ή έχουν μη αποθηκευμένη εργασία" + +#: src/ui/gtk-mount-prompt.ui:95 +msgid "User:" +msgstr "Χρήστης:" + +#: src/ui/gtk-mount-prompt.ui:118 +msgid "Domain:" +msgstr "Τομέας:" + +#: src/ui/gtk-mount-prompt.ui:151 +msgid "Co_nnect" +msgstr "_Σύνδεση" + +#: src/ui/lockscreen.ui:43 msgid "Slide up to unlock" msgstr "Σύρετε προς τα πάνω για ξεκλείδωμα" -#: src/ui/lockscreen.ui:250 +#: src/ui/lockscreen.ui:285 msgid "Emergency" msgstr "Επείγον" -#: src/ui/lockscreen.ui:266 +#: src/ui/lockscreen.ui:301 msgid "Unlock" msgstr "Ξεκλείδωμα" -#: src/ui/network-auth-prompt.ui:90 +#: src/ui/lockscreen.ui:341 +msgid "Back" +msgstr "Πίσω" + +#: src/ui/network-auth-prompt.ui:6 src/ui/polkit-auth-prompt.ui:7 +msgid "Authentication required" +msgstr "Απαιτείται πιστοποίηση" + +#: src/ui/network-auth-prompt.ui:41 msgid "_Cancel" msgstr "_Ακύρωση" -#: src/ui/network-auth-prompt.ui:106 +#: src/ui/network-auth-prompt.ui:59 msgid "C_onnect" msgstr "_Σύνδεση" -#: src/ui/polkit-auth-prompt.ui:105 -msgid "User:" -msgstr "Χρήστης:" +#: src/ui/polkit-auth-prompt.ui:123 +msgid "Authenticate" +msgstr "Πιστοποίηση" -#: src/ui/system-prompt.ui:69 +#: src/ui/system-prompt.ui:63 msgid "Confirm:" msgstr "Επιβεβαίωση:" + +#: src/ui/top-panel.ui:16 +msgid "Lock Screen" +msgstr "Κλείδωμα οθόνης" + +#: src/ui/top-panel.ui:23 +msgid "Logout" +msgstr "Έξοδος" + +#: src/wifiinfo.c:90 +msgid "Wi-Fi" +msgstr "Wi-Fi" + +#. Translators: Refers to the cellular wireless network +#: src/wwaninfo.c:172 +msgid "Cellular" +msgstr "Κινητή τηλεφωνία" diff -Nru phosh-0.8.0/po/eo.po phosh-0.13.1/po/eo.po --- phosh-0.8.0/po/eo.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/eo.po 2021-08-31 09:15:52.000000000 +0000 @@ -1,146 +1,417 @@ -# Martin Chang , 2018. #zanata -# Martin Chang , 2019. #zanata +# Esperanto translation for phosh. +# Copyright (C) 2018 Free Software Foundation, Inc. +# This file is distributed under the same license as the phosh package +# Martin CHANG , 2018-2019. +# Kristjan SCHMIDT , 2021. +# Colin REEDER , 2021. +# msgid "" msgstr "" "Project-Id-Version: phosh\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-03-14 13:18+0100\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/phosh/issues\n" +"POT-Creation-Date: 2021-08-09 08:29+0000\n" +"PO-Revision-Date: 2021-08-11 08:20+0200\n" +"Last-Translator: Colin REEDER \n" +"Language-Team: Esperanto\n" +"Language: eo\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2019-12-04 04:34+0000\n" -"Last-Translator: Martin Chang \n" -"Language-Team: Esperanto\n" -"Language: eo\n" -"X-Generator: Zanata 4.6.2\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"X-Generator: Poedit 3.0\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. Translators: this is the session name, no need to translate it +#: data/phosh.session.desktop.in.in:4 +msgid "Phosh" +msgstr "Phosh" #: data/sm.puri.Phosh.desktop.in.in:4 msgid "Phone Shell" -msgstr "Fona ŝelo" +msgstr "Telefona Ŝelo" #: data/sm.puri.Phosh.desktop.in.in:5 msgid "Window management and application launching for mobile" -msgstr "Fenestroj administri kaj lanĉi aplikaĵoj por poŝtelefono" +msgstr "Administrado de fenestroj kaj lanĉado de aplikaĵoj por poŝtelefono" -#. Translators: this is the session name, no need to translate it -#: data/phosh.session.desktop.in.in:4 -msgid "Phosh" -msgstr "Phosh" - -#: src/app-grid-button.c:523 +#: src/app-grid-button.c:536 msgid "Application" msgstr "Aplikaĵo" -#: src/feedbackinfo.c:38 +#: src/bt-info.c:92 src/feedbackinfo.c:51 src/rotateinfo.c:103 +msgid "On" +msgstr "Ŝaltita" + +#: src/bt-info.c:94 +msgid "Bluetooth" +msgstr "Bludento" + +#: src/docked-info.c:81 +msgid "Docked" +msgstr "Dokita" + +#: src/docked-info.c:81 src/docked-info.c:199 +msgid "Undocked" +msgstr "Ne dokita" + +#: src/end-session-dialog.c:162 +msgid "Log Out" +msgstr "Elsaluti" + +#: src/end-session-dialog.c:165 +#, c-format +msgid "%s will be logged out automatically in %d second." +msgid_plural "%s will be logged out automatically in %d seconds." +msgstr[0] "%s estos elsalutita aŭtomate post %d sekundo." +msgstr[1] "%s estos elsalutita aŭtomate post %d sekundoj." + +#: src/end-session-dialog.c:171 src/ui/top-panel.ui:37 +msgid "Power Off" +msgstr "Malŝalti" + +#: src/end-session-dialog.c:172 +#, c-format +msgid "The system will power off automatically in %d second." +msgid_plural "The system will power off automatically in %d seconds." +msgstr[0] "La sistemo malŝaltos aŭtomate post %d sekundo." +msgstr[1] "La sistemo malŝaltos aŭtomate post %d sekundoj." + +#: src/end-session-dialog.c:178 src/ui/top-panel.ui:30 +msgid "Restart" +msgstr "Restartigi" + +#: src/end-session-dialog.c:179 +#, c-format +msgid "The system will restart automatically in %d second." +msgid_plural "The system will restart automatically in %d seconds." +msgstr[0] "La sistemo restartos aŭtomate post %d sekundo." +msgstr[1] "La sistemo restartos aŭtomate post %d sekundoj." + +#: src/end-session-dialog.c:269 +msgid "Unknown application" +msgstr "Nekonata aplikaĵo" + +#. Translators: quiet and silent are fbd profiles names: +#. see https://source.puri.sm/Librem5/feedbackd#profiles +#. for details +#: src/feedbackinfo.c:44 msgid "Quiet" -msgstr "" +msgstr "Mallaŭta" -#: src/feedbackinfo.c:40 +#. Translators: quiet and silent are fbd profiles names: +#. see https://source.puri.sm/Librem5/feedbackd#profiles +#. for details +#: src/feedbackinfo.c:49 msgid "Silent" -msgstr "" +msgstr "Silenta" -#: src/feedbackinfo.c:42 -msgid "On" -msgstr "" +#: src/location-manager.c:268 +#, c-format +msgid "Allow '%s' to access your location information?" +msgstr "Permesi '%s' atingi vian loko?" -#: src/lockscreen.c:78 src/ui/lockscreen.ui:204 +#: src/location-manager.c:273 +msgid "Geolocation" +msgstr "Geolokigo" + +#: src/location-manager.c:274 +msgid "Yes" +msgstr "Jes" + +#: src/location-manager.c:274 +msgid "No" +msgstr "Ne" + +#: src/lockscreen.c:157 src/ui/lockscreen.ui:267 msgid "Enter Passcode" msgstr "Enigu pasvorton" -#: src/lockscreen.c:257 +#: src/lockscreen.c:340 msgid "Checking…" msgstr "Kontroli…" #. Translators: This is a time format for a date in #. long format -#: src/lockscreen.c:334 +#: src/lockscreen.c:418 msgid "%A, %B %-e" msgstr "%A, %B %-e" -#: src/monitor-manager.c:53 +#. Translators: Used when the title of a song is unknown +#: src/media-player.c:279 src/ui/media-player.ui:107 +msgid "Unknown Title" +msgstr "Nekonata titolo" + +#. Translators: Used when the artist of a song is unknown +#: src/media-player.c:288 src/ui/media-player.ui:127 +msgid "Unknown Artist" +msgstr "Nekonata artisto" + +#: src/monitor-manager.c:114 msgid "Built-in display" msgstr "Integra vidigo" +#: src/monitor-manager.c:132 +#, c-format +msgctxt "" +"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgid "%s %s" +msgstr "%s %s" + +#: src/monitor-manager.c:139 +#, c-format +msgctxt "" +"This is a monitor vendor name followed by product/model name where size in " +"inches could not be calculated, e.g. Dell U2414H" +msgid "%s %s" +msgstr "%s %s" + #. Translators: An unknown monitor type -#: src/monitor-manager.c:57 +#: src/monitor-manager.c:148 msgid "Unknown" msgstr "Nekonate" -#: src/network-auth-prompt.c:184 +#: src/network-auth-prompt.c:187 +#, c-format +msgid "Authentication type of wifi network “%s” not supported" +msgstr "Tipo de aŭtentigo de vifio-reto \"%s\" ne estas subtenata" + +#: src/network-auth-prompt.c:192 #, c-format msgid "Enter password for the wifi network “%s”" +msgstr "Enigu pasvorton por la vifio-reto \"%s\"" + +#: src/notifications/mount-notification.c:122 +msgid "Open" +msgstr "Malfermi" + +#: src/notifications/notification.c:383 src/notifications/notification.c:639 +msgid "Notification" +msgstr "Sciigo" + +#. Translators: Timestamp seconds suffix +#: src/notifications/timestamp-label.c:84 +msgctxt "timestamp-suffix-seconds" +msgid "s" +msgstr "s" + +#. Translators: Timestamp minute suffix +#: src/notifications/timestamp-label.c:86 +msgctxt "timestamp-suffix-minute" +msgid "m" +msgstr "m" + +#. Translators: Timestamp minutes suffix +#: src/notifications/timestamp-label.c:88 +msgctxt "timestamp-suffix-minutes" +msgid "m" +msgstr "m" + +#. Translators: Timestamp hour suffix +#: src/notifications/timestamp-label.c:90 +msgctxt "timestamp-suffix-hour" +msgid "h" +msgstr "h" + +#. Translators: Timestamp hours suffix +#: src/notifications/timestamp-label.c:92 +msgctxt "timestamp-suffix-hours" +msgid "h" +msgstr "h" + +#. Translators: Timestamp day suffix +#: src/notifications/timestamp-label.c:94 +msgctxt "timestamp-suffix-day" +msgid "d" +msgstr "t" + +#. Translators: Timestamp days suffix +#: src/notifications/timestamp-label.c:96 +msgctxt "timestamp-suffix-days" +msgid "d" +msgstr "t" + +#. Translators: Timestamp month suffix +#: src/notifications/timestamp-label.c:98 +msgctxt "timestamp-suffix-month" +msgid "mo" +msgstr "mo" + +#. Translators: Timestamp months suffix +#: src/notifications/timestamp-label.c:100 +msgctxt "timestamp-suffix-months" +msgid "mos" +msgstr "mo" + +#. Translators: Timestamp year suffix +#: src/notifications/timestamp-label.c:102 +msgctxt "timestamp-suffix-year" +msgid "y" +msgstr "j" + +#. Translators: Timestamp years suffix +#: src/notifications/timestamp-label.c:104 +msgctxt "timestamp-suffix-years" +msgid "y" +msgstr "j" + +#: src/notifications/timestamp-label.c:121 +msgid "now" +msgstr "nuna" + +#. Translators: time difference "Over 5 years" +#: src/notifications/timestamp-label.c:189 +#, c-format +msgid "Over %dy" +msgstr "Pli ol %dj" + +#. Translators: time difference "almost 5 years" +#: src/notifications/timestamp-label.c:193 +#, c-format +msgid "Almost %dy" +msgstr "Preskaŭ %dj" + +#. Translators: a time difference like '<5m', if in doubt leave untranslated +#: src/notifications/timestamp-label.c:200 +#, c-format +msgid "%s%d%s" msgstr "" -#: src/polkit-auth-agent.c:229 +#: src/polkit-auth-agent.c:228 msgid "Authentication dialog was dismissed by the user" -msgstr "La aŭtentiga dialogo estis forigi laŭ la uzanto" +msgstr "La aŭtentiga dialogo estis forigita de la uzanto" -#: src/polkit-auth-prompt.c:276 src/ui/network-auth-prompt.ui:128 -#: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 +#: src/polkit-auth-prompt.c:278 src/ui/gtk-mount-prompt.ui:21 +#: src/ui/network-auth-prompt.ui:83 src/ui/polkit-auth-prompt.ui:57 +#: src/ui/system-prompt.ui:33 msgid "Password:" msgstr "Pasvorto:" -#: src/polkit-auth-prompt.c:322 +#: src/polkit-auth-prompt.c:325 msgid "Sorry, that didn’t work. Please try again." -msgstr "Pardonu, ĉi tio ne efikas. Bonvolu reprovi malfrue." +msgstr "Pardonu, ĉi tio ne sukcesas. Bonvolu reprovi." -#: src/polkit-auth-prompt.c:488 -msgid "Authenticate" -msgstr "Permesi" +#: src/rotateinfo.c:81 +msgid "Portrait" +msgstr "Vertikala" + +#: src/rotateinfo.c:84 +msgid "Landscape" +msgstr "Horizontala" + +#. Translators: Automatic screen orientation is either on (enabled) or off (locked/disabled) +#. Translators: Automatic screen orientation is off (locked/disabled) +#: src/rotateinfo.c:103 src/rotateinfo.c:186 +msgid "Off" +msgstr "Ne ŝaltita" -#: src/system-prompt.c:371 +#: src/system-prompt.c:364 msgid "Passwords do not match." -msgstr "Pasvortoj ne kongruas" +msgstr "Pasvortoj ne kongruas." -#: src/system-prompt.c:378 +#: src/system-prompt.c:371 msgid "Password cannot be blank" msgstr "Pasvorto devas ne malpleni" -#: src/wifiinfo.c:55 -msgid "Wi-Fi" -msgstr "" +#: src/torch-info.c:80 +msgid "Torch" +msgstr "Poŝlampo" + +#: src/ui/app-auth-prompt.ui:41 +msgid "Remember decision" +msgstr "Memori decidon" + +#: src/ui/app-auth-prompt.ui:54 src/ui/end-session-dialog.ui:54 +msgid "Cancel" +msgstr "Nuligi" + +#: src/ui/app-auth-prompt.ui:63 src/ui/end-session-dialog.ui:63 +msgid "Ok" +msgstr "Bone" -#: src/ui/app-grid-button.ui:48 +#: src/ui/app-grid-button.ui:49 msgid "App" msgstr "Aplikaĵo" -#: src/ui/app-grid-button.ui:75 +#: src/ui/app-grid-button.ui:76 msgid "Remove from _Favorites" -msgstr "" +msgstr "Forigi el _Legosignoj" -#: src/ui/app-grid-button.ui:80 +#: src/ui/app-grid-button.ui:81 msgid "Add to _Favorites" -msgstr "" +msgstr "Aldoni al _Legosignoj" -#: src/ui/app-grid.ui:21 +#: src/ui/app-grid.ui:22 msgid "Search apps…" -msgstr "Serĉi aplikaĵo…" +msgstr "Serĉi aplikaĵojn…" + +#: src/ui/app-grid.ui:169 +msgid "Show only adaptive apps" +msgstr "Montri nur adapta aplikaĵojn" + +#: src/ui/end-session-dialog.ui:32 +msgid "Some applications are busy or have unsaved work" +msgstr "Kelkaj aplikaĵoj estas okupita aŭ havas nekonservitajn ŝanĝojn" -#: src/ui/lockscreen.ui:36 +#: src/ui/gtk-mount-prompt.ui:95 +msgid "User:" +msgstr "Uzanto:" + +#: src/ui/gtk-mount-prompt.ui:118 +msgid "Domain:" +msgstr "Domajno:" + +#: src/ui/gtk-mount-prompt.ui:151 +msgid "Co_nnect" +msgstr "Ko_nekti" + +#: src/ui/lockscreen.ui:43 msgid "Slide up to unlock" msgstr "Ŝovi supre por malŝlosi" -#: src/ui/lockscreen.ui:250 +#: src/ui/lockscreen.ui:313 msgid "Emergency" -msgstr "" +msgstr "Krizo" -#: src/ui/lockscreen.ui:266 +#: src/ui/lockscreen.ui:329 msgid "Unlock" -msgstr "" +msgstr "Malŝlosi" + +#: src/ui/lockscreen.ui:369 +msgid "Back" +msgstr "Reen" -#: src/ui/network-auth-prompt.ui:90 +#: src/ui/network-auth-prompt.ui:6 src/ui/polkit-auth-prompt.ui:7 +msgid "Authentication required" +msgstr "Aŭtentigo estas deviga" + +#: src/ui/network-auth-prompt.ui:41 msgid "_Cancel" -msgstr "" +msgstr "_Nuligi" -#: src/ui/network-auth-prompt.ui:106 +#: src/ui/network-auth-prompt.ui:59 msgid "C_onnect" -msgstr "" +msgstr "K_onekti" -#: src/ui/polkit-auth-prompt.ui:105 -msgid "User:" -msgstr "Uzanto:" +#: src/ui/polkit-auth-prompt.ui:123 +msgid "Authenticate" +msgstr "Aŭtentigi" -#: src/ui/system-prompt.ui:69 +#: src/ui/system-prompt.ui:63 msgid "Confirm:" msgstr "Konfirmi:" + +#: src/ui/top-panel.ui:16 +msgid "Lock Screen" +msgstr "Ŝlosita Ekrano" + +#: src/ui/top-panel.ui:23 +msgid "Logout" +msgstr "Elsaluti" + +#: src/wifiinfo.c:90 +msgid "Wi-Fi" +msgstr "Vifio" + +#. Translators: Refers to the cellular wireless network +#: src/wwaninfo.c:172 +msgid "Cellular" +msgstr "Ĉela" diff -Nru phosh-0.8.0/po/ht.po phosh-0.13.1/po/ht.po --- phosh-0.8.0/po/ht.po 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/po/ht.po 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,326 @@ +# Phosh Creole Haitian translation +# Copyright (C) 2021 Purism +# This file is distributed under the same license as the Phosh package. +# Pierre Michel Augustin , 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/phosh/issues\n" +"POT-Creation-Date: 2021-02-07 15:30+0000\n" +"PO-Revision-Date: 2021-02-21 17:28-0500\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.0.6\n" +"Last-Translator: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Language: ht_HT\n" + +#. Translators: this is the session name, no need to translate it +#: data/phosh.session.desktop.in.in:4 +msgid "Phosh" +msgstr "Phosh" + +#: data/sm.puri.Phosh.desktop.in.in:4 +msgid "Phone Shell" +msgstr "Shell Telefòn" + +#: data/sm.puri.Phosh.desktop.in.in:5 +msgid "Window management and application launching for mobile" +msgstr "Jesyon fenèt ak lansman aplikasyon pou mobil" + +#: src/app-grid-button.c:536 +msgid "Application" +msgstr "Aplikasyon" + +#: src/bt-info.c:92 src/feedbackinfo.c:51 +msgid "On" +msgstr "Sou" + +#: src/bt-info.c:94 +msgid "Bluetooth" +msgstr "Bluetooth" + +#: src/docked-info.c:81 +msgid "Docked" +msgstr "Docked" + +#: src/docked-info.c:81 src/docked-info.c:195 +msgid "Undocked" +msgstr "Undocked" + +#. Translators: quiet and silent are fbd profiles names: +#. see https://source.puri.sm/Librem5/feedbackd#profiles +#. for details +#: src/feedbackinfo.c:44 +msgid "Quiet" +msgstr "Trankil" + +#. Translators: quiet and silent are fbd profiles names: +#. see https://source.puri.sm/Librem5/feedbackd#profiles +#. for details +#: src/feedbackinfo.c:49 +msgid "Silent" +msgstr "Silans" + +#: src/lockscreen.c:85 src/ui/lockscreen.ui:234 +msgid "Enter Passcode" +msgstr "Mete pas kod" + +#: src/lockscreen.c:264 +msgid "Checking…" +msgstr "Ap verifye…" + +#. Translators: This is a time format for a date in +#. long format +#: src/lockscreen.c:342 +msgid "%A, %B %-e" +msgstr "%A, %B %-e" + +#. Translators: Used when the title of a song is unknown +#: src/media-player.c:277 src/ui/media-player.ui:107 +msgid "Unknown Title" +msgstr "Tit enkoni" + +#. Translators: Used when the artist of a song is unknown +#: src/media-player.c:286 src/ui/media-player.ui:127 +msgid "Unknown Artist" +msgstr "Atis enkoni" + +#: src/monitor-manager.c:108 +msgid "Built-in display" +msgstr "Montre \"Built-in\"" + +#: src/monitor-manager.c:126 +#, c-format +msgctxt "" +"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgid "%s %s" +msgstr "%s %s" + +#: src/monitor-manager.c:133 +#, c-format +msgctxt "" +"This is a monitor vendor name followed by product/model name where size in" +"inches could not be calculated, e.g. Dell U2414H" +msgid "%s %sn" +msgstr "%s %sn" + +#. Translators: An unknown monitor type +#: src/monitor-manager.c:142 +msgid "Unknown" +msgstr "Enkoni" + +#: src/network-auth-prompt.c:187 +#, c-format +msgid "Authentication type of wifi network “%s” not supported" +msgstr "Otantifikasyon kalite rezo wifi “%s” pa sipòte" + +#: src/network-auth-prompt.c:192 +#, c-format +msgid "Enter password for the wifi network “%s”" +msgstr "Mete modpas pou rezo wifi “%s” la" + +#: src/notifications/mount-notification.c:137 +msgid "Open" +msgstr "Ouvri" + +#: src/notifications/notification.c:381 src/notifications/notification.c:637 +msgid "Notification" +msgstr "Notifikasyon" + +#. Translators: Timestamp seconds suffix +#: src/notifications/timestamp-label.c:84 +msgctxt "timestamp-suffix-seconds" +msgid "s" +msgstr "s" + +#. Translators: Timestamp minute suffix +#: src/notifications/timestamp-label.c:86 +msgctxt "timestamp-suffix-minute" +msgid "m" +msgstr "m" + +#. Translators: Timestamp minutes suffix +#: src/notifications/timestamp-label.c:88 +msgctxt "timestamp-suffix-minutes" +msgid "m" +msgstr "m" + +#. Translators: Timestamp hour suffix +#: src/notifications/timestamp-label.c:90 +msgctxt "timestamp-suffix-hour" +msgid "h" +msgstr "h" + +#. Translators: Timestamp hours suffix +#: src/notifications/timestamp-label.c:92 +msgctxt "timestamp-suffix-hours" +msgid "h" +msgstr "h" + +#. Translators: Timestamp day suffix +#: src/notifications/timestamp-label.c:94 +msgctxt "timestamp-suffix-day" +msgid "d" +msgstr "d" + +#. Translators: Timestamp days suffix +#: src/notifications/timestamp-label.c:96 +msgctxt "timestamp-suffix-days" +msgid "d" +msgstr "d" + +#. Translators: Timestamp month suffix +#: src/notifications/timestamp-label.c:98 +msgctxt "timestamp-suffix-month" +msgid "mo" +msgstr "mo" + +#. Translators: Timestamp months suffix +#: src/notifications/timestamp-label.c:100 +msgctxt "timestamp-suffix-months" +msgid "mos" +msgstr "mos" + +#. Translators: Timestamp year suffix +#: src/notifications/timestamp-label.c:102 +msgctxt "timestamp-suffix-year" +msgid "y" +msgstr "y" + +#. Translators: Timestamp years suffix +#: src/notifications/timestamp-label.c:104 +msgctxt "timestamp-suffix-years" +msgid "y" +msgstr "y" + +#: src/notifications/timestamp-label.c:121 +msgid "now" +msgstr "kounye a" + +#. Translators: time difference "Over 5 years" +#: src/notifications/timestamp-label.c:189 +#, c-format +msgid "Over %dy" +msgstr "Plis pase %dy" + +#. Translators: time difference "almost 5 years" +#: src/notifications/timestamp-label.c:193 +#, c-format +msgid "Almost %dy" +msgstr "Prèske %dy" + +#. Translators: a time difference like '<5m', if in doubt leave untranslated +#: src/notifications/timestamp-label.c:200 +#, c-format +msgid "%s%d%s" +msgstr "%s%d%s" + +#: src/polkit-auth-agent.c:225 +msgid "Authentication dialog was dismissed by the user" +msgstr "Dyalòg Otantifikasyon te ranvwaye pa itilizatè a" + +#: src/polkit-auth-prompt.c:278 src/ui/network-auth-prompt.ui:127 +#: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 +msgid "Password:" +msgstr "Mo de pas:" + +#: src/polkit-auth-prompt.c:325 +msgid "Sorry, that didn’t work. Please try again." +msgstr "Eskize, sa pa te mache. Souple eseye ankò." + +#: src/polkit-auth-prompt.c:470 +msgid "Authenticate" +msgstr "Otantifye" + +#: src/rotateinfo.c:65 +msgid "Portrait" +msgstr "Pòtrè" + +#: src/rotateinfo.c:68 +msgid "Landscape" +msgstr "Peyizaj" + +#: src/system-prompt.c:375 +msgid "Passwords do not match." +msgstr "Mo de pas pa matche ak." + +#: src/system-prompt.c:382 +msgid "Password cannot be blank" +msgstr "Mo de pas pa ka vid" + +#: src/torch-info.c:80 +msgid "Torch" +msgstr "Flach" + +#: src/ui/app-grid-button.ui:49 +msgid "App" +msgstr "Aplikasyon" + +#: src/ui/app-grid-button.ui:76 +msgid "Remove from _Favorites" +msgstr "Retire nan _sa_ou_renmen" + +#: src/ui/app-grid-button.ui:81 +msgid "Add to _Favorites" +msgstr "Ajoute nan _sa_ou_renmen" + +#: src/ui/app-grid.ui:21 +msgid "Search apps…" +msgstr "Chèche aplikasyon yo…" + +#: src/ui/lockscreen.ui:37 +msgid "Slide up to unlock" +msgstr "Monte pou debloke" + +#: src/ui/lockscreen.ui:280 +msgid "Emergency" +msgstr "Ijans" + +#: src/ui/lockscreen.ui:296 +msgid "Unlock" +msgstr "Debloke" + +#: src/ui/network-auth-prompt.ui:89 +msgid "_Cancel" +msgstr "_Anile" + +#: src/ui/network-auth-prompt.ui:105 +msgid "C_onnect" +msgstr "K_onekte" + +#: src/ui/polkit-auth-prompt.ui:105 +msgid "User:" +msgstr "Itilizatè:" + +#: src/ui/system-prompt.ui:69 +msgid "Confirm:" +msgstr "Konfime:" + +#: src/ui/top-panel.ui:15 +msgid "Lock Screen" +msgstr "Bloke ekran" + +#: src/ui/top-panel.ui:22 +msgid "Logout" +msgstr "Dekonekte" + +#: src/ui/top-panel.ui:29 +msgid "Restart" +msgstr "Redemare" + +#: src/ui/top-panel.ui:36 +msgid "Power Off" +msgstr "Fèmen" + +#: src/wifiinfo.c:90 +msgid "Wi-Fi" +msgstr "Wi-Fi" + +#. Translators: Refers to the cellular wireless network +#: src/wwaninfo.c:170 +msgid "Cellular" +msgstr "Selilè" diff -Nru phosh-0.8.0/po/hu.po phosh-0.13.1/po/hu.po --- phosh-0.8.0/po/hu.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/hu.po 2021-08-31 09:15:52.000000000 +0000 @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: phosh\n" "Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/phosh/issues\n" -"POT-Creation-Date: 2020-07-06 03:30+0000\n" +"POT-Creation-Date: 2021-01-16 03:33+0000\n" "PO-Revision-Date: 2020-07-08 12:55+0200\n" "Last-Translator: Meskó Balázs \n" "Language-Team: Hungarian\n" @@ -27,115 +27,244 @@ msgid "Window management and application launching for mobile" msgstr "Ablakkezelés és alkalmazásindítás mobilra" -#: src/app-grid-button.c:530 +#: src/app-grid-button.c:536 msgid "Application" msgstr "Alkalmazás" +#: src/bt-info.c:92 src/feedbackinfo.c:51 +msgid "On" +msgstr "Be" + +#: src/bt-info.c:94 +msgid "Bluetooth" +msgstr "" + +#: src/docked-info.c:81 +msgid "Docked" +msgstr "" + +#: src/docked-info.c:195 +msgid "Undocked" +msgstr "" + #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details -#: src/feedbackinfo.c:41 +#: src/feedbackinfo.c:44 msgid "Quiet" msgstr "Csendes" #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details -#: src/feedbackinfo.c:46 +#: src/feedbackinfo.c:49 msgid "Silent" msgstr "Néma" -#: src/feedbackinfo.c:48 -msgid "On" -msgstr "Be" - -#: src/lockscreen.c:82 src/ui/lockscreen.ui:217 +#: src/lockscreen.c:86 src/ui/lockscreen.ui:234 msgid "Enter Passcode" msgstr "Adja meg a jelkódot" -#: src/lockscreen.c:261 +#: src/lockscreen.c:265 msgid "Checking…" msgstr "Ellenőrzés…" #. Translators: This is a time format for a date in #. long format -#: src/lockscreen.c:339 +#: src/lockscreen.c:343 msgid "%A, %B %-e" msgstr "%B %-d. %A" -#: src/media-player.c:262 -msgid "Unknown title" +#. Translators: Used when the title of a song is unknown +#: src/media-player.c:277 src/ui/media-player.ui:107 +#, fuzzy +#| msgid "Unknown title" +msgid "Unknown Title" msgstr "Ismeretlen cím" -#: src/media-player.c:270 -msgid "Unknown artist" +#. Translators: Used when the artist of a song is unknown +#: src/media-player.c:286 src/ui/media-player.ui:127 +msgid "Unknown Artist" msgstr "Ismeretlen előadó" -#: src/monitor-manager.c:58 +#: src/monitor-manager.c:108 msgid "Built-in display" msgstr "Beépített kijelző" +#: src/monitor-manager.c:126 +#, c-format +msgctxt "" +"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgid "%s %s" +msgstr "" + +#: src/monitor-manager.c:133 +#, c-format +msgctxt "" +"This is a monitor vendor name followed by product/model name where size in " +"inches could not be calculated, e.g. Dell U2414H" +msgid "%s %sn" +msgstr "" + #. Translators: An unknown monitor type -#: src/monitor-manager.c:62 +#: src/monitor-manager.c:142 msgid "Unknown" msgstr "Ismeretlen" -#: src/network-auth-prompt.c:184 +#: src/network-auth-prompt.c:187 #, c-format msgid "Authentication type of wifi network “%s” not supported" msgstr "A(z) „%s” Wi-Fi-hálózat hitelesítési típusa nem támogatott" -#: src/network-auth-prompt.c:189 +#: src/network-auth-prompt.c:192 #, c-format msgid "Enter password for the wifi network “%s”" msgstr "Adja meg a(z) „%s” Wi-Fi-hálózat jelszavát" -#: src/notifications/notification.c:365 src/notifications/notification.c:581 +#: src/notifications/mount-notification.c:137 +msgid "Open" +msgstr "" + +#: src/notifications/notification.c:381 src/notifications/notification.c:637 msgid "Notification" msgstr "Értesítés" -#: src/polkit-auth-agent.c:229 +#. Translators: Timestamp seconds suffix +#: src/notifications/timestamp-label.c:84 +msgctxt "timestamp-suffix-seconds" +msgid "s" +msgstr "" + +#. Translators: Timestamp minute suffix +#: src/notifications/timestamp-label.c:86 +msgctxt "timestamp-suffix-minute" +msgid "m" +msgstr "" + +#. Translators: Timestamp minutes suffix +#: src/notifications/timestamp-label.c:88 +msgctxt "timestamp-suffix-minutes" +msgid "m" +msgstr "" + +#. Translators: Timestamp hour suffix +#: src/notifications/timestamp-label.c:90 +msgctxt "timestamp-suffix-hour" +msgid "h" +msgstr "" + +#. Translators: Timestamp hours suffix +#: src/notifications/timestamp-label.c:92 +msgctxt "timestamp-suffix-hours" +msgid "h" +msgstr "" + +#. Translators: Timestamp day suffix +#: src/notifications/timestamp-label.c:94 +msgctxt "timestamp-suffix-day" +msgid "d" +msgstr "" + +#. Translators: Timestamp days suffix +#: src/notifications/timestamp-label.c:96 +msgctxt "timestamp-suffix-days" +msgid "d" +msgstr "" + +#. Translators: Timestamp month suffix +#: src/notifications/timestamp-label.c:98 +msgctxt "timestamp-suffix-month" +msgid "mo" +msgstr "" + +#. Translators: Timestamp months suffix +#: src/notifications/timestamp-label.c:100 +msgctxt "timestamp-suffix-months" +msgid "mos" +msgstr "" + +#. Translators: Timestamp year suffix +#: src/notifications/timestamp-label.c:102 +msgctxt "timestamp-suffix-year" +msgid "y" +msgstr "" + +#. Translators: Timestamp years suffix +#: src/notifications/timestamp-label.c:104 +msgctxt "timestamp-suffix-years" +msgid "y" +msgstr "" + +#: src/notifications/timestamp-label.c:121 +#, fuzzy +#| msgid "Unknown" +msgid "now" +msgstr "Ismeretlen" + +#. Translators: time difference "Over 5 years" +#: src/notifications/timestamp-label.c:189 +#, c-format +msgid "Over %dy" +msgstr "" + +#. Translators: time difference "almost 5 years" +#: src/notifications/timestamp-label.c:193 +#, c-format +msgid "Almost %dy" +msgstr "" + +#. Translators: a time difference like '<5m', if in doubt leave untranslated +#: src/notifications/timestamp-label.c:200 +#, c-format +msgid "%s%d%s" +msgstr "" + +#: src/polkit-auth-agent.c:232 msgid "Authentication dialog was dismissed by the user" msgstr "A felhasználó bezárta a hitelesítési párbeszédet" -#: src/polkit-auth-prompt.c:276 src/ui/network-auth-prompt.ui:128 +#: src/polkit-auth-prompt.c:278 src/ui/network-auth-prompt.ui:130 #: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 msgid "Password:" msgstr "Jelszó:" -#: src/polkit-auth-prompt.c:322 +#: src/polkit-auth-prompt.c:325 msgid "Sorry, that didn’t work. Please try again." msgstr "Sajnáljuk, ez nem működött. Próbálja meg újra." -#: src/polkit-auth-prompt.c:488 +#: src/polkit-auth-prompt.c:470 msgid "Authenticate" msgstr "Hitelesítés" -#: src/rotateinfo.c:46 +#: src/rotateinfo.c:65 msgid "Portrait" msgstr "Álló" -#: src/rotateinfo.c:49 +#: src/rotateinfo.c:68 msgid "Landscape" msgstr "Fekvő" -#: src/system-prompt.c:371 +#: src/system-prompt.c:375 msgid "Passwords do not match." msgstr "A jelszavak nem egyeznek." -#: src/system-prompt.c:378 +#: src/system-prompt.c:382 msgid "Password cannot be blank" msgstr "A jelszavak nem lehetnek üresek" -#: src/ui/app-grid-button.ui:48 +#: src/torch-info.c:80 +msgid "Torch" +msgstr "" + +#: src/ui/app-grid-button.ui:49 msgid "App" msgstr "Alkalmazás" -#: src/ui/app-grid-button.ui:75 +#: src/ui/app-grid-button.ui:76 msgid "Remove from _Favorites" msgstr "Eltávolítás a _Kedvencek közül" -#: src/ui/app-grid-button.ui:80 +#: src/ui/app-grid-button.ui:81 msgid "Add to _Favorites" msgstr "Hozzáadás a _Kedvencekhez" @@ -147,27 +276,19 @@ msgid "Slide up to unlock" msgstr "Csúsztassa fel a feloldáshoz" -#: src/ui/lockscreen.ui:263 +#: src/ui/lockscreen.ui:280 msgid "Emergency" msgstr "Vészhelyzet" -#: src/ui/lockscreen.ui:279 +#: src/ui/lockscreen.ui:296 msgid "Unlock" msgstr "Feloldás" -#: src/ui/media-player.ui:107 -msgid "Unknown Song" -msgstr "Ismeretlen szám" - -#: src/ui/media-player.ui:127 -msgid "Unknown Artist" -msgstr "Ismeretlen előadó" - -#: src/ui/network-auth-prompt.ui:90 +#: src/ui/network-auth-prompt.ui:89 msgid "_Cancel" msgstr "_Mégse" -#: src/ui/network-auth-prompt.ui:106 +#: src/ui/network-auth-prompt.ui:105 msgid "C_onnect" msgstr "Kapcs_olódás" @@ -188,9 +309,24 @@ msgstr "Kilépés" #: src/ui/top-panel.ui:29 +msgid "Restart" +msgstr "" + +#: src/ui/top-panel.ui:36 msgid "Power Off" msgstr "Kikapcsolás" -#: src/wifiinfo.c:88 +#: src/wifiinfo.c:90 msgid "Wi-Fi" msgstr "Wi-Fi" + +#. Translators: Refers to the cellular wireless network +#: src/wwaninfo.c:170 +msgid "Cellular" +msgstr "" + +#~ msgid "Unknown artist" +#~ msgstr "Ismeretlen előadó" + +#~ msgid "Unknown Song" +#~ msgstr "Ismeretlen szám" diff -Nru phosh-0.8.0/po/id.po phosh-0.13.1/po/id.po --- phosh-0.8.0/po/id.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/id.po 2021-08-31 09:15:52.000000000 +0000 @@ -1,10 +1,14 @@ -# Andika Triwidada , 2020. #zanata +# Indonesian translation of phosh +# Copyright 2020 phosh's copyright holder +# This file is distributed under the same license as the phosh package. +# Andika Triwidada , 2020, 2021. #zanata +# msgid "" msgstr "" -"Project-Id-Version: phosh\n" -"Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/phosh/issues\n" -"POT-Creation-Date: 2020-12-12 15:33+0000\n" -"PO-Revision-Date: 2020-12-14 14:25+0700\n" +"Project-Id-Version: phosh main\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/phosh/issues\n" +"POT-Creation-Date: 2021-08-03 09:16+0000\n" +"PO-Revision-Date: 2021-08-28 09:22+0700\n" "Last-Translator: Andika Triwidada \n" "Language-Team: Indonesian\n" "Language: id\n" @@ -31,7 +35,7 @@ msgid "Application" msgstr "Aplikasi" -#: src/bt-info.c:92 src/feedbackinfo.c:51 +#: src/bt-info.c:92 src/feedbackinfo.c:51 src/rotateinfo.c:103 msgid "On" msgstr "Nyala" @@ -43,10 +47,47 @@ msgid "Docked" msgstr "Ditambatkan" -#: src/docked-info.c:195 +#: src/docked-info.c:81 src/docked-info.c:199 msgid "Undocked" msgstr "Lepas Tambat" +#: src/end-session-dialog.c:162 +msgid "Log Out" +msgstr "Keluar" + +#: src/end-session-dialog.c:165 +#, c-format +msgid "%s will be logged out automatically in %d second." +msgid_plural "%s will be logged out automatically in %d seconds." +msgstr[0] "%s akan dikeluarkan secara otomatis dalam %d detik." +msgstr[1] "%s akan dikeluarkan secara otomatis dalam %d detik." + +#: src/end-session-dialog.c:171 src/ui/top-panel.ui:37 +msgid "Power Off" +msgstr "Matikan Daya" + +#: src/end-session-dialog.c:172 +#, c-format +msgid "The system will power off automatically in %d second." +msgid_plural "The system will power off automatically in %d seconds." +msgstr[0] "Sistem akan dimatikan secara otomatis dalam %d detik." +msgstr[1] "Sistem akan dimatikan secara otomatis dalam %d detik." + +#: src/end-session-dialog.c:178 src/ui/top-panel.ui:30 +msgid "Restart" +msgstr "Mulai Ulang" + +#: src/end-session-dialog.c:179 +#, c-format +msgid "The system will restart automatically in %d second." +msgid_plural "The system will restart automatically in %d seconds." +msgstr[0] "Sistem akan dinyalakan ulang secara otomatis dalam %d detik." +msgstr[1] "Sistem akan dinyalakan ulang secara otomatis dalam %d detik." + +#: src/end-session-dialog.c:269 +msgid "Unknown application" +msgstr "Aplikasi tak dikenal" + #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details @@ -61,36 +102,68 @@ msgid "Silent" msgstr "Senyap" -#: src/lockscreen.c:86 src/ui/lockscreen.ui:234 +#: src/location-manager.c:268 +#, c-format +msgid "Allow '%s' to access your location information?" +msgstr "Izinkan '%s' mengakses informasi lokasi Anda?" + +#: src/location-manager.c:273 +msgid "Geolocation" +msgstr "Geolokasi" + +#: src/location-manager.c:274 +msgid "Yes" +msgstr "Ya" + +#: src/location-manager.c:274 +msgid "No" +msgstr "Tidak" + +#: src/lockscreen.c:152 src/ui/lockscreen.ui:239 msgid "Enter Passcode" msgstr "Masukkan Kode Sandi" -#: src/lockscreen.c:265 +#: src/lockscreen.c:335 msgid "Checking…" msgstr "Memeriksa…" #. Translators: This is a time format for a date in #. long format -#: src/lockscreen.c:343 +#: src/lockscreen.c:413 msgid "%A, %B %-e" msgstr "%A, %d %B" #. Translators: Used when the title of a song is unknown -#: src/media-player.c:277 src/ui/media-player.ui:107 +#: src/media-player.c:279 src/ui/media-player.ui:107 msgid "Unknown Title" msgstr "Judul Tidak Dikenal" #. Translators: Used when the artist of a song is unknown -#: src/media-player.c:286 src/ui/media-player.ui:127 +#: src/media-player.c:288 src/ui/media-player.ui:127 msgid "Unknown Artist" msgstr "Artis Tak Dikenal" -#: src/monitor-manager.c:71 +#: src/monitor-manager.c:114 msgid "Built-in display" msgstr "Tampilan bawaan" +#: src/monitor-manager.c:132 +#, c-format +msgctxt "" +"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgid "%s %s" +msgstr "%s %s" + +#: src/monitor-manager.c:139 +#, c-format +msgctxt "" +"This is a monitor vendor name followed by product/model name where size in " +"inches could not be calculated, e.g. Dell U2414H" +msgid "%s %s" +msgstr "%s %s" + #. Translators: An unknown monitor type -#: src/monitor-manager.c:75 +#: src/monitor-manager.c:148 msgid "Unknown" msgstr "Tak dikenal" @@ -104,129 +177,135 @@ msgid "Enter password for the wifi network “%s”" msgstr "Masukkan kata sandi untuk jaringan wifi %s" -#: src/notifications/mount-notification.c:137 +#: src/notifications/mount-notification.c:122 msgid "Open" msgstr "Buka" -#: src/notifications/notification.c:381 src/notifications/notification.c:637 +#: src/notifications/notification.c:383 src/notifications/notification.c:639 msgid "Notification" msgstr "Notifikasi" #. Translators: Timestamp seconds suffix -#: src/notifications/timestamp-label.c:83 +#: src/notifications/timestamp-label.c:84 msgctxt "timestamp-suffix-seconds" msgid "s" msgstr "d" #. Translators: Timestamp minute suffix -#: src/notifications/timestamp-label.c:85 +#: src/notifications/timestamp-label.c:86 msgctxt "timestamp-suffix-minute" msgid "m" msgstr "m" #. Translators: Timestamp minutes suffix -#: src/notifications/timestamp-label.c:87 +#: src/notifications/timestamp-label.c:88 msgctxt "timestamp-suffix-minutes" msgid "m" msgstr "m" #. Translators: Timestamp hour suffix -#: src/notifications/timestamp-label.c:89 +#: src/notifications/timestamp-label.c:90 msgctxt "timestamp-suffix-hour" msgid "h" msgstr "j" #. Translators: Timestamp hours suffix -#: src/notifications/timestamp-label.c:91 +#: src/notifications/timestamp-label.c:92 msgctxt "timestamp-suffix-hours" msgid "h" msgstr "j" #. Translators: Timestamp day suffix -#: src/notifications/timestamp-label.c:93 +#: src/notifications/timestamp-label.c:94 msgctxt "timestamp-suffix-day" msgid "d" msgstr "h" #. Translators: Timestamp days suffix -#: src/notifications/timestamp-label.c:95 +#: src/notifications/timestamp-label.c:96 msgctxt "timestamp-suffix-days" msgid "d" msgstr "h" #. Translators: Timestamp month suffix -#: src/notifications/timestamp-label.c:97 +#: src/notifications/timestamp-label.c:98 msgctxt "timestamp-suffix-month" msgid "mo" msgstr "b" #. Translators: Timestamp months suffix -#: src/notifications/timestamp-label.c:99 +#: src/notifications/timestamp-label.c:100 msgctxt "timestamp-suffix-months" msgid "mos" msgstr "b" #. Translators: Timestamp year suffix -#: src/notifications/timestamp-label.c:101 +#: src/notifications/timestamp-label.c:102 msgctxt "timestamp-suffix-year" msgid "y" msgstr "t" #. Translators: Timestamp years suffix -#: src/notifications/timestamp-label.c:103 +#: src/notifications/timestamp-label.c:104 msgctxt "timestamp-suffix-years" msgid "y" msgstr "t" -#. Translators: this is the date in (short) number only format -#: src/notifications/timestamp-label.c:106 -msgid "%d.%m.%y" -msgstr "%d.%m.%y" - -#. Translators: Timestamp prefix (e.g. Over 5h) -#: src/notifications/timestamp-label.c:197 -msgid "Over" -msgstr "Lewat" - -#. Translators: Timestamp prefix (e.g. Almost 5h) -#: src/notifications/timestamp-label.c:202 -msgid "Almost" -msgstr "Hampir" - -#: src/notifications/timestamp-label.c:210 +#: src/notifications/timestamp-label.c:121 msgid "now" msgstr "kini" -#: src/polkit-auth-agent.c:231 +#. Translators: time difference "Over 5 years" +#: src/notifications/timestamp-label.c:189 +#, c-format +msgid "Over %dy" +msgstr "Lebih %dt" + +#. Translators: time difference "almost 5 years" +#: src/notifications/timestamp-label.c:193 +#, c-format +msgid "Almost %dy" +msgstr "Hampir %dt" + +#. Translators: a time difference like '<5m', if in doubt leave untranslated +#: src/notifications/timestamp-label.c:200 +#, c-format +msgid "%s%d%s" +msgstr "%s%d%s" + +#: src/polkit-auth-agent.c:228 msgid "Authentication dialog was dismissed by the user" msgstr "Dialog autentikasi ditutup oleh pengguna" -#: src/polkit-auth-prompt.c:278 src/ui/network-auth-prompt.ui:128 -#: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 +#: src/polkit-auth-prompt.c:278 src/ui/gtk-mount-prompt.ui:21 +#: src/ui/network-auth-prompt.ui:83 src/ui/polkit-auth-prompt.ui:57 +#: src/ui/system-prompt.ui:33 msgid "Password:" msgstr "Kata sandi:" -#: src/polkit-auth-prompt.c:324 +#: src/polkit-auth-prompt.c:325 msgid "Sorry, that didn’t work. Please try again." msgstr "Maaf, itu tidak bekerja. Harap coba lagi." -#: src/polkit-auth-prompt.c:490 -msgid "Authenticate" -msgstr "Autentikasi" - -#: src/rotateinfo.c:65 +#: src/rotateinfo.c:81 msgid "Portrait" msgstr "Potret" -#: src/rotateinfo.c:68 +#: src/rotateinfo.c:84 msgid "Landscape" msgstr "Lanskap" -#: src/system-prompt.c:373 +#. Translators: Automatic screen orientation is either on (enabled) or off (locked/disabled) +#. Translators: Automatic screen orientation is off (locked/disabled) +#: src/rotateinfo.c:103 src/rotateinfo.c:186 +msgid "Off" +msgstr "Mati" + +#: src/system-prompt.c:364 msgid "Passwords do not match." msgstr "Kata sandi tidak cocok." -#: src/system-prompt.c:380 +#: src/system-prompt.c:371 msgid "Password cannot be blank" msgstr "Kata sandi tidak bisa kosong" @@ -234,6 +313,18 @@ msgid "Torch" msgstr "Obor" +#: src/ui/app-auth-prompt.ui:41 +msgid "Remember decision" +msgstr "Ingat keputusan" + +#: src/ui/app-auth-prompt.ui:54 src/ui/end-session-dialog.ui:54 +msgid "Cancel" +msgstr "Batal" + +#: src/ui/app-auth-prompt.ui:63 src/ui/end-session-dialog.ui:63 +msgid "Ok" +msgstr "Ok" + #: src/ui/app-grid-button.ui:49 msgid "App" msgstr "App" @@ -246,59 +337,79 @@ msgid "Add to _Favorites" msgstr "Tambah ke _Favorit" -#: src/ui/app-grid.ui:21 +#: src/ui/app-grid.ui:22 msgid "Search apps…" msgstr "Cari app…" -#: src/ui/lockscreen.ui:37 +#: src/ui/app-grid.ui:169 +msgid "Show only adaptive apps" +msgstr "Hanya tampilkan app yang adaptif" + +#: src/ui/end-session-dialog.ui:32 +msgid "Some applications are busy or have unsaved work" +msgstr "Beberapa aplikasi sibuk atau belum disimpan hasilnya" + +#: src/ui/gtk-mount-prompt.ui:95 +msgid "User:" +msgstr "Pengguna:" + +#: src/ui/gtk-mount-prompt.ui:118 +msgid "Domain:" +msgstr "Domain:" + +#: src/ui/gtk-mount-prompt.ui:151 +msgid "Co_nnect" +msgstr "S_ambung" + +#: src/ui/lockscreen.ui:43 msgid "Slide up to unlock" msgstr "Usap naik untuk membuka kunci" -#: src/ui/lockscreen.ui:280 +#: src/ui/lockscreen.ui:285 msgid "Emergency" msgstr "Darurat" -#: src/ui/lockscreen.ui:296 +#: src/ui/lockscreen.ui:301 msgid "Unlock" msgstr "Buka kunci" -#: src/ui/network-auth-prompt.ui:90 +#: src/ui/lockscreen.ui:341 +msgid "Back" +msgstr "Mundur" + +#: src/ui/network-auth-prompt.ui:6 src/ui/polkit-auth-prompt.ui:7 +msgid "Authentication required" +msgstr "Perlu autentikasi" + +#: src/ui/network-auth-prompt.ui:41 msgid "_Cancel" msgstr "_Batal" -#: src/ui/network-auth-prompt.ui:106 +#: src/ui/network-auth-prompt.ui:59 msgid "C_onnect" msgstr "S_ambung" -#: src/ui/polkit-auth-prompt.ui:105 -msgid "User:" -msgstr "Pengguna:" +#: src/ui/polkit-auth-prompt.ui:123 +msgid "Authenticate" +msgstr "Autentikasi" -#: src/ui/system-prompt.ui:69 +#: src/ui/system-prompt.ui:63 msgid "Confirm:" msgstr "Konfirmasi:" -#: src/ui/top-panel.ui:15 +#: src/ui/top-panel.ui:16 msgid "Lock Screen" msgstr "Kunci Layar" -#: src/ui/top-panel.ui:22 +#: src/ui/top-panel.ui:23 msgid "Logout" msgstr "Log Keluar" -#: src/ui/top-panel.ui:29 -msgid "Restart" -msgstr "Mulai Ulang" - -#: src/ui/top-panel.ui:36 -msgid "Power Off" -msgstr "Matikan Daya" - #: src/wifiinfo.c:90 msgid "Wi-Fi" msgstr "Wi-Fi" #. Translators: Refers to the cellular wireless network -#: src/wwaninfo.c:170 +#: src/wwaninfo.c:172 msgid "Cellular" msgstr "Seluler" diff -Nru phosh-0.8.0/po/it.po phosh-0.13.1/po/it.po --- phosh-0.8.0/po/it.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/it.po 2021-08-31 09:15:52.000000000 +0000 @@ -2,149 +2,411 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the phosh package. # Ant Pandolfo , 2018. -# antpanlinux , 2018. #zanata -# antpanlinux , 2019. #zanata +# antpanlinux , 2019. #zanata-2021. +# msgid "" msgstr "" "Project-Id-Version: phosh\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-03-14 13:18+0100\n" +"Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/phosh/issues\n" +"POT-Creation-Date: 2021-07-22 03:33+0000\n" +"PO-Revision-Date: 2021-07-10 15:47+0200\n" +"Last-Translator: antpanlinux \n" +"Language-Team: antpanlinux \n" +"Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2019-10-11 01:32+0000\n" -"Language-Team: antpanlinux \n" -"X-Generator: Zanata 4.6.2\n" -"Last-Translator: antpanlinux \n" +"X-Generator: Gtranslator 3.30.1\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Language: it\n" + +#. Translators: this is the session name, no need to translate it +#: data/phosh.session.desktop.in.in:4 +msgid "Phosh" +msgstr "Phosh" #: data/sm.puri.Phosh.desktop.in.in:4 msgid "Phone Shell" -msgstr "Shell" +msgstr "Shell del telefono" #: data/sm.puri.Phosh.desktop.in.in:5 msgid "Window management and application launching for mobile" -msgstr "Finestra gestore ed avviatore applicazioni per cellulare" +msgstr "Gestore di finestre e avviatore di applicazioni per cellulare" -#. Translators: this is the session name, no need to translate it -#: data/phosh.session.desktop.in.in:4 -msgid "Phosh" -msgstr "Phosh" - -#: src/app-grid-button.c:523 +#: src/app-grid-button.c:536 msgid "Application" msgstr "Applicazione" -#: src/feedbackinfo.c:38 +#: src/bt-info.c:92 src/feedbackinfo.c:51 src/rotateinfo.c:103 +msgid "On" +msgstr "Attivo" + +#: src/bt-info.c:94 +msgid "Bluetooth" +msgstr "Bluetooth" + +#: src/docked-info.c:81 +msgid "Docked" +msgstr "Agganciato" + +#: src/docked-info.c:81 src/docked-info.c:199 +msgid "Undocked" +msgstr "Sganciato" + +#: src/end-session-dialog.c:162 +msgid "Log Out" +msgstr "Termina sessione" + +#: src/end-session-dialog.c:165 +#, c-format +msgid "%s will be logged out automatically in %d second." +msgid_plural "%s will be logged out automatically in %d seconds." +msgstr[0] "%s verrà disconnesso automaticamente tra %d secondo." +msgstr[1] "%s verrà disconnesso automaticamente tra %d secondi." + +#: src/end-session-dialog.c:171 src/ui/top-panel.ui:37 +msgid "Power Off" +msgstr "Spegni" + +#: src/end-session-dialog.c:172 +#, c-format +msgid "The system will power off automatically in %d second." +msgid_plural "The system will power off automatically in %d seconds." +msgstr[0] "Il sistema si spegnerà automaticamente tra %d secondo." +msgstr[1] "Il sistema si spegnerà automaticamente tra %d secondi." + +#: src/end-session-dialog.c:178 src/ui/top-panel.ui:30 +msgid "Restart" +msgstr "Riavvia" + +#: src/end-session-dialog.c:179 +#, c-format +msgid "The system will restart automatically in %d second." +msgid_plural "The system will restart automatically in %d seconds." +msgstr[0] "Il sistema verrà riavviato automaticamente tra %d secondo." +msgstr[1] "Il sistema verrà riavviato automaticamente tra %d secondi." + +#: src/end-session-dialog.c:269 +msgid "Unknown application" +msgstr "Applicazione sconosciuta" + +#. Translators: quiet and silent are fbd profiles names: +#. see https://source.puri.sm/Librem5/feedbackd#profiles +#. for details +#: src/feedbackinfo.c:44 msgid "Quiet" -msgstr "" +msgstr "Muto" -#: src/feedbackinfo.c:40 +#. Translators: quiet and silent are fbd profiles names: +#. see https://source.puri.sm/Librem5/feedbackd#profiles +#. for details +#: src/feedbackinfo.c:49 msgid "Silent" -msgstr "" +msgstr "Silenzioso" -#: src/feedbackinfo.c:42 -msgid "On" -msgstr "" +#: src/location-manager.c:268 +#, c-format +msgid "Allow '%s' to access your location information?" +msgstr "Consenti a '%s' di conoscere la tua posizione?" + +#: src/location-manager.c:273 +msgid "Geolocation" +msgstr "Posizione" + +#: src/location-manager.c:274 +msgid "Yes" +msgstr "Sì" + +#: src/location-manager.c:274 +msgid "No" +msgstr "No" -#: src/lockscreen.c:78 src/ui/lockscreen.ui:204 +#: src/lockscreen.c:95 src/ui/lockscreen.ui:233 msgid "Enter Passcode" -msgstr "Inserisci codice" +msgstr "Inserire la password" -#: src/lockscreen.c:257 +#: src/lockscreen.c:278 msgid "Checking…" -msgstr "Sto controllando..." +msgstr "Sto controllando…" #. Translators: This is a time format for a date in #. long format -#: src/lockscreen.c:334 +#: src/lockscreen.c:356 msgid "%A, %B %-e" msgstr "%A, %B %-e" -#: src/monitor-manager.c:53 +#. Translators: Used when the title of a song is unknown +#: src/media-player.c:279 src/ui/media-player.ui:107 +msgid "Unknown Title" +msgstr "Titolo sconosciuto" + +#. Translators: Used when the artist of a song is unknown +#: src/media-player.c:288 src/ui/media-player.ui:127 +msgid "Unknown Artist" +msgstr "Artista sconosciuto" + +#: src/monitor-manager.c:114 msgid "Built-in display" msgstr "Schermo integrato" +#: src/monitor-manager.c:132 +#, c-format +msgctxt "" +"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgid "%s %s" +msgstr "%s %s" + +#: src/monitor-manager.c:139 +#, c-format +msgctxt "" +"This is a monitor vendor name followed by product/model name where size in " +"inches could not be calculated, e.g. Dell U2414H" +msgid "%s %s" +msgstr "%s %s" + #. Translators: An unknown monitor type -#: src/monitor-manager.c:57 +#: src/monitor-manager.c:148 msgid "Unknown" msgstr "Sconosciuto" -#: src/network-auth-prompt.c:184 +#: src/network-auth-prompt.c:187 +#, c-format +msgid "Authentication type of wifi network “%s” not supported" +msgstr "Tipo di autenticazione della rete Wi-Fi “%s” non supportato" + +#: src/network-auth-prompt.c:192 #, c-format msgid "Enter password for the wifi network “%s”" -msgstr "" +msgstr "Inserire la password per la rete Wi-Fi “%s”" + +#: src/notifications/mount-notification.c:122 +msgid "Open" +msgstr "Apri" + +#: src/notifications/notification.c:383 src/notifications/notification.c:639 +msgid "Notification" +msgstr "Notifica" + +#. Translators: Timestamp seconds suffix +#: src/notifications/timestamp-label.c:84 +msgctxt "timestamp-suffix-seconds" +msgid "s" +msgstr "s" + +#. Translators: Timestamp minute suffix +#: src/notifications/timestamp-label.c:86 +msgctxt "timestamp-suffix-minute" +msgid "m" +msgstr "m" + +#. Translators: Timestamp minutes suffix +#: src/notifications/timestamp-label.c:88 +msgctxt "timestamp-suffix-minutes" +msgid "m" +msgstr "m" + +#. Translators: Timestamp hour suffix +#: src/notifications/timestamp-label.c:90 +msgctxt "timestamp-suffix-hour" +msgid "h" +msgstr "o" + +#. Translators: Timestamp hours suffix +#: src/notifications/timestamp-label.c:92 +msgctxt "timestamp-suffix-hours" +msgid "h" +msgstr "o" + +#. Translators: Timestamp day suffix +#: src/notifications/timestamp-label.c:94 +msgctxt "timestamp-suffix-day" +msgid "d" +msgstr "g" + +#. Translators: Timestamp days suffix +#: src/notifications/timestamp-label.c:96 +msgctxt "timestamp-suffix-days" +msgid "d" +msgstr "g" + +#. Translators: Timestamp month suffix +#: src/notifications/timestamp-label.c:98 +msgctxt "timestamp-suffix-month" +msgid "mo" +msgstr "me" + +#. Translators: Timestamp months suffix +#: src/notifications/timestamp-label.c:100 +msgctxt "timestamp-suffix-months" +msgid "mos" +msgstr "mesi" + +#. Translators: Timestamp year suffix +#: src/notifications/timestamp-label.c:102 +msgctxt "timestamp-suffix-year" +msgid "y" +msgstr "a" + +#. Translators: Timestamp years suffix +#: src/notifications/timestamp-label.c:104 +msgctxt "timestamp-suffix-years" +msgid "y" +msgstr "a" + +#: src/notifications/timestamp-label.c:121 +msgid "now" +msgstr "adesso" + +#. Translators: time difference "Over 5 years" +#: src/notifications/timestamp-label.c:189 +#, c-format +msgid "Over %dy" +msgstr "Oltre %da" + +#. Translators: time difference "almost 5 years" +#: src/notifications/timestamp-label.c:193 +#, c-format +msgid "Almost %dy" +msgstr "Quasi %da" -#: src/polkit-auth-agent.c:229 +#. Translators: a time difference like '<5m', if in doubt leave untranslated +#: src/notifications/timestamp-label.c:200 +#, c-format +msgid "%s%d%s" +msgstr "%s%d%s" + +#: src/polkit-auth-agent.c:228 msgid "Authentication dialog was dismissed by the user" msgstr "La finestra di autenticazione è stata chiusa dall'utente" -#: src/polkit-auth-prompt.c:276 src/ui/network-auth-prompt.ui:128 -#: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 +#: src/polkit-auth-prompt.c:278 src/ui/gtk-mount-prompt.ui:21 +#: src/ui/network-auth-prompt.ui:83 src/ui/polkit-auth-prompt.ui:57 +#: src/ui/system-prompt.ui:33 msgid "Password:" msgstr "Password:" -#: src/polkit-auth-prompt.c:322 +#: src/polkit-auth-prompt.c:325 msgid "Sorry, that didn’t work. Please try again." -msgstr "Scusa non ha funzionato.Per favore riprova." +msgstr "Non ha funzionato. Per favore riprova." -#: src/polkit-auth-prompt.c:488 -msgid "Authenticate" -msgstr "Autenticato" +#: src/rotateinfo.c:81 +msgid "Portrait" +msgstr "Verticale" + +#: src/rotateinfo.c:84 +msgid "Landscape" +msgstr "Orizzontale" + +#. Translators: Automatic screen orientation is either on (enabled) or off (locked/disabled) +#. Translators: Automatic screen orientation is off (locked/disabled) +#: src/rotateinfo.c:103 src/rotateinfo.c:186 +msgid "Off" +msgstr "Inattivo" -#: src/system-prompt.c:371 +#: src/system-prompt.c:364 msgid "Passwords do not match." msgstr "Le password non corrispondono" -#: src/system-prompt.c:378 +#: src/system-prompt.c:371 msgid "Password cannot be blank" msgstr "La password non può essere vuota" -#: src/wifiinfo.c:55 -msgid "Wi-Fi" -msgstr "" +#: src/torch-info.c:80 +msgid "Torch" +msgstr "Torcia" + +#: src/ui/app-auth-prompt.ui:41 +msgid "Remember decision" +msgstr "Ricorda la decisione" + +#: src/ui/app-auth-prompt.ui:54 src/ui/end-session-dialog.ui:54 +msgid "Cancel" +msgstr "Annulla" + +#: src/ui/app-auth-prompt.ui:63 src/ui/end-session-dialog.ui:63 +msgid "Ok" +msgstr "Ok" -#: src/ui/app-grid-button.ui:48 +#: src/ui/app-grid-button.ui:49 msgid "App" msgstr "App" -#: src/ui/app-grid-button.ui:75 +#: src/ui/app-grid-button.ui:76 msgid "Remove from _Favorites" -msgstr "" +msgstr "Rimuovi dai _Preferiti" -#: src/ui/app-grid-button.ui:80 +#: src/ui/app-grid-button.ui:81 msgid "Add to _Favorites" -msgstr "" +msgstr "Aggiungi ai _Preferiti" -#: src/ui/app-grid.ui:21 +#: src/ui/app-grid.ui:22 msgid "Search apps…" -msgstr "Ricerca app..." +msgstr "Ricerca app…" -#: src/ui/lockscreen.ui:36 +#: src/ui/app-grid.ui:169 +msgid "Show only adaptive apps" +msgstr "Mostra solo le app adattive" + +#: src/ui/end-session-dialog.ui:32 +msgid "Some applications are busy or have unsaved work" +msgstr "Alcune applicazioni sono occupate o hanno del lavoro non salvato" + +#: src/ui/gtk-mount-prompt.ui:95 +msgid "User:" +msgstr "Utente:" + +#: src/ui/gtk-mount-prompt.ui:118 +msgid "Domain:" +msgstr "Dominio:" + +#: src/ui/gtk-mount-prompt.ui:151 +msgid "Co_nnect" +msgstr "Co_nnetti" + +#: src/ui/lockscreen.ui:37 msgid "Slide up to unlock" msgstr "Scorri verso l'alto per sbloccare" -#: src/ui/lockscreen.ui:250 +#: src/ui/lockscreen.ui:279 msgid "Emergency" -msgstr "" +msgstr "Emergenza" -#: src/ui/lockscreen.ui:266 +#: src/ui/lockscreen.ui:295 msgid "Unlock" -msgstr "" +msgstr "Sblocca" + +#: src/ui/network-auth-prompt.ui:6 src/ui/polkit-auth-prompt.ui:7 +msgid "Authentication required" +msgstr "Autenticazione richiesta" -#: src/ui/network-auth-prompt.ui:90 +#: src/ui/network-auth-prompt.ui:41 msgid "_Cancel" -msgstr "" +msgstr "_Annulla" -#: src/ui/network-auth-prompt.ui:106 +#: src/ui/network-auth-prompt.ui:59 msgid "C_onnect" -msgstr "" +msgstr "C_onnetti" -#: src/ui/polkit-auth-prompt.ui:105 -msgid "User:" -msgstr "Utente:" +#: src/ui/polkit-auth-prompt.ui:123 +msgid "Authenticate" +msgstr "Autenticazione" -#: src/ui/system-prompt.ui:69 +#: src/ui/system-prompt.ui:63 msgid "Confirm:" msgstr "Conferma:" + +#: src/ui/top-panel.ui:16 +msgid "Lock Screen" +msgstr "Blocca schermo" + +#: src/ui/top-panel.ui:23 +msgid "Logout" +msgstr "Esci" + +#: src/wifiinfo.c:90 +msgid "Wi-Fi" +msgstr "Wi-Fi" + +#. Translators: Refers to the cellular wireless network +#: src/wwaninfo.c:172 +msgid "Cellular" +msgstr "Cellulare" diff -Nru phosh-0.8.0/po/ja.po phosh-0.13.1/po/ja.po --- phosh-0.8.0/po/ja.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/ja.po 2021-08-31 09:15:52.000000000 +0000 @@ -41,9 +41,11 @@ msgid "Application" msgstr "アプリケーション" +#. Maintainers: while 普通 remains correct in context of normal, manner and silent manner modes, +#. it doesn't in the context of screen rotation. So I changed it to have it make kind of make sense for both. #: src/bt-info.c:92 src/feedbackinfo.c:51 msgid "On" -msgstr "普通" +msgstr "有効" #: src/bt-info.c:94 msgid "Bluetooth" @@ -57,6 +59,28 @@ msgid "Undocked" msgstr "ドック外" +#: src/end-session-dialog.c:162 +msgid "Log Out" +msgstr "ログアウト" + +#: src/end-session-dialog.c:165 +#, c-format +msgid "%s will be logged out automatically in %d second." +msgid_plural "%s will be logged out automatically in %d seconds." +msgstr[0] "%2$d秒後、%1$sさんは自動でログアウトされます。" + +#: src/end-session-dialog.c:172 +#, c-format +msgid "The system will power off automatically in %d second." +msgid_plural "The system will power off automatically in %d seconds." +msgstr[0] "%d秒後、この端末は自動でシャットダウンされます。" + +#: src/end-session-dialog.c:179 +#, c-format +msgid "The system will restart automatically in %d second." +msgid_plural "The system will restart automatically in %d seconds." +msgstr[0] "%d秒後、この端末は自動で再起動されます。" + #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details @@ -71,6 +95,25 @@ msgid "Silent" msgstr "サイレントマナー" +#: src/location-manager.c:266 +#, c-format +msgid "Allow '%s' to access your location information?" +msgstr "'%s'に位置情報へのアクセスを許可しますか?" + +#: src/location-manager.c:271 +msgid "Geolocation" +msgstr "位置情報" + +#: src/location-manager.c:252 +#: src/location-manager.c:272 +msgid "Yes" +msgstr "はい" + +#: src/location-manager.c:252 +#: src/location-manager.c:272 +msgid "No" +msgstr "いいえ" + #: src/lockscreen.c:86 src/ui/lockscreen.ui:234 msgid "Enter Passcode" msgstr "パスコードを入力" @@ -104,6 +147,11 @@ msgid "Unknown" msgstr "不明なディスプレー" +#: src/end-session-dialog.c:270 +#| msgid "Application" +msgid "Unknown application" +msgstr "不明なアプリ" + #: src/network-auth-prompt.c:187 #, c-format msgid "Authentication type of wifi network “%s” not supported" @@ -235,6 +283,12 @@ msgid "Landscape" msgstr "横方向" +#. Translators: Automatic screen orientation is either on (enabled) or off (locked/disabled) +#. Translators: Automatic screen orientation is off (locked/disabled) +#: src/rotateinfo.c:103 src/rotateinfo.c:183 +msgid "Off" +msgstr "無効" + #: src/system-prompt.c:373 msgid "Passwords do not match." msgstr "パスワードが一致しません。" @@ -247,6 +301,10 @@ msgid "Torch" msgstr "懐中電灯" +#: src/ui/app-auth-prompt.ui:41 +msgid "Remember decision" +msgstr "覚える" + #: src/ui/app-grid-button.ui:49 msgid "App" msgstr "アプリ" @@ -279,6 +337,19 @@ msgid "_Cancel" msgstr "キャンセル(_C)" +#: src/ui/end-session-dialog.ui:32 +msgid "Some applications are busy or have unsaved work" +msgstr "使用中または未保存したデータでございます。" + +#: src/ui/network-auth-prompt.ui:6 src/ui/polkit-auth-prompt.ui:7 +#| msgid "Authenticate" +msgid "Authentication required" +msgstr "認証必須" + +#: src/ui/app-auth-prompt.ui:66 src/ui/end-session-dialog.ui:61 +msgid "Ok" +msgstr "OK" + #: src/ui/network-auth-prompt.ui:105 msgid "C_onnect" msgstr "接続(_O)" @@ -315,3 +386,18 @@ #: src/wwaninfo.c:170 msgid "Cellular" msgstr "モバイル通信" + +#: src/monitor-manager.c:130 +#, c-format +msgctxt "" +"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgid "%s %s" +msgstr "%s %s" + +#: src/monitor-manager.c:137 +#, c-format +msgctxt "" +"This is a monitor vendor name followed by product/model name where size in " +"inches could not be calculated, e.g. Dell U2414H" +msgid "%s %sn" +msgstr "%s %sn" diff -Nru phosh-0.8.0/po/LINGUAS phosh-0.13.1/po/LINGUAS --- phosh-0.8.0/po/LINGUAS 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/LINGUAS 2021-08-31 09:15:52.000000000 +0000 @@ -16,6 +16,7 @@ fr fur he +ht hu id it diff -Nru phosh-0.8.0/po/nl.po phosh-0.13.1/po/nl.po --- phosh-0.8.0/po/nl.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/nl.po 2021-08-31 09:15:52.000000000 +0000 @@ -1,147 +1,397 @@ # Joachim Moernaut , 2018. #zanata # Joachim Moernaut , 2019. #zanata # Willem Sonke , 2019. #zanata +# jjdekroon , 2021. +# Nathan Follens , 2021. msgid "" msgstr "" "Project-Id-Version: phosh\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-03-14 13:18+0100\n" +"Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/phosh/issues\n" +"POT-Creation-Date: 2021-04-03 15:31+0000\n" +"PO-Revision-Date: 2021-04-03 19:25+0200\n" +"Last-Translator: Nathan Follens \n" +"Language-Team: Dutch\n" +"Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2019-10-02 09:46+0000\n" -"Last-Translator: Willem Sonke \n" -"Language-Team: Dutch\n" -"Language: nl\n" -"X-Generator: Zanata 4.6.2\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"X-Generator: Poedit 2.4.2\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. Translators: this is the session name, no need to translate it +#: data/phosh.session.desktop.in.in:4 +msgid "Phosh" +msgstr "Phosh" #: data/sm.puri.Phosh.desktop.in.in:4 msgid "Phone Shell" -msgstr "Phone Shell" +msgstr "Telefoonshell" #: data/sm.puri.Phosh.desktop.in.in:5 msgid "Window management and application launching for mobile" msgstr "Vensterbeheer en opstarten van mobiele toepassingen" -#. Translators: this is the session name, no need to translate it -#: data/phosh.session.desktop.in.in:4 -msgid "Phosh" -msgstr "Phosh" - -#: src/app-grid-button.c:523 +#: src/app-grid-button.c:536 msgid "Application" msgstr "Toepassing" -#: src/feedbackinfo.c:38 +#: src/bt-info.c:92 src/feedbackinfo.c:51 src/rotateinfo.c:103 +msgid "On" +msgstr "Aan" + +#: src/bt-info.c:94 +msgid "Bluetooth" +msgstr "Bluetooth" + +#: src/docked-info.c:81 +msgid "Docked" +msgstr "In dock" + +#: src/docked-info.c:81 src/docked-info.c:195 +msgid "Undocked" +msgstr "Uit dock" + +#: src/end-session-dialog.c:162 +msgid "Log Out" +msgstr "Uitloggen" + +#: src/end-session-dialog.c:165 +#, c-format +msgid "%s will be logged out automatically in %d second." +msgid_plural "%s will be logged out automatically in %d seconds." +msgstr[0] "%s wordt automatisch uitgelogd over %d seconde." +msgstr[1] "%s wordt automatisch uitgelogd over %d seconden." + +#: src/end-session-dialog.c:171 src/ui/top-panel.ui:37 +msgid "Power Off" +msgstr "Uitschakelen" + +#: src/end-session-dialog.c:172 +#, c-format +msgid "The system will power off automatically in %d second." +msgid_plural "The system will power off automatically in %d seconds." +msgstr[0] "Het systeem wordt automatisch uitgeschakeld over %d seconde." +msgstr[1] "Het systeem wordt automatisch uitgeschakeld over %d seconden." + +#: src/end-session-dialog.c:178 src/ui/top-panel.ui:30 +msgid "Restart" +msgstr "Herstarten" + +#: src/end-session-dialog.c:179 +#, c-format +msgid "The system will restart automatically in %d second." +msgid_plural "The system will restart automatically in %d seconds." +msgstr[0] "Het systeem zal automatisch herstarten over %d seconde." +msgstr[1] "Het systeem zal automatisch herstarten over %d seconden." + +#: src/end-session-dialog.c:270 +msgid "Unknown application" +msgstr "Onbekende applicatie" + +#. Translators: quiet and silent are fbd profiles names: +#. see https://source.puri.sm/Librem5/feedbackd#profiles +#. for details +#: src/feedbackinfo.c:44 msgid "Quiet" -msgstr "" +msgstr "Rustig" -#: src/feedbackinfo.c:40 +#. Translators: quiet and silent are fbd profiles names: +#. see https://source.puri.sm/Librem5/feedbackd#profiles +#. for details +#: src/feedbackinfo.c:49 msgid "Silent" -msgstr "" +msgstr "Stil" -#: src/feedbackinfo.c:42 -msgid "On" -msgstr "" +#: src/location-manager.c:246 +#, c-format +msgid "Allow '%s' to access your location information?" +msgstr "‘%s’ toegang geven tot uw locatiegegevens?" + +#: src/location-manager.c:251 +msgid "Geolocation" +msgstr "Geolocatie" + +#: src/location-manager.c:252 +msgid "Yes" +msgstr "Ja" + +#: src/location-manager.c:252 +msgid "No" +msgstr "Nee" -#: src/lockscreen.c:78 src/ui/lockscreen.ui:204 +#: src/lockscreen.c:85 src/ui/lockscreen.ui:234 msgid "Enter Passcode" -msgstr "Pin invoeren" +msgstr "Voer de pincode in" -#: src/lockscreen.c:257 +#: src/lockscreen.c:264 msgid "Checking…" -msgstr "" +msgstr "Bezig met controleren…" #. Translators: This is a time format for a date in #. long format -#: src/lockscreen.c:334 +#: src/lockscreen.c:342 msgid "%A, %B %-e" msgstr "%A %d %B" -#: src/monitor-manager.c:53 +#. Translators: Used when the title of a song is unknown +#: src/media-player.c:277 src/ui/media-player.ui:107 +msgid "Unknown Title" +msgstr "Onbekende titel" + +#. Translators: Used when the artist of a song is unknown +#: src/media-player.c:286 src/ui/media-player.ui:127 +msgid "Unknown Artist" +msgstr "Onbekende artiest" + +#: src/monitor-manager.c:112 msgid "Built-in display" -msgstr "Ingebouwd scherm" +msgstr "Ingebouwd beeldscherm" + +#: src/monitor-manager.c:130 +#, c-format +msgctxt "" +"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgid "%s %s" +msgstr "%s %s" + +#: src/monitor-manager.c:137 +#, c-format +msgctxt "" +"This is a monitor vendor name followed by product/model name where size in " +"inches could not be calculated, e.g. Dell U2414H" +msgid "%s %sn" +msgstr "%s %sn" #. Translators: An unknown monitor type -#: src/monitor-manager.c:57 +#: src/monitor-manager.c:146 msgid "Unknown" msgstr "Onbekend" -#: src/network-auth-prompt.c:184 +#: src/network-auth-prompt.c:187 +#, c-format +msgid "Authentication type of wifi network “%s” not supported" +msgstr "Authenticatietype van wifinetwerk ‘%s’ wordt niet ondersteund" + +#: src/network-auth-prompt.c:192 #, c-format msgid "Enter password for the wifi network “%s”" -msgstr "" +msgstr "Voer het wachtwoord in voor wifinetwerk ‘%s’" + +#: src/notifications/mount-notification.c:137 +msgid "Open" +msgstr "Openen" + +#: src/notifications/notification.c:381 src/notifications/notification.c:637 +msgid "Notification" +msgstr "Notificatie" + +#. Translators: Timestamp seconds suffix +#: src/notifications/timestamp-label.c:84 +msgctxt "timestamp-suffix-seconds" +msgid "s" +msgstr "s" + +#. Translators: Timestamp minute suffix +#: src/notifications/timestamp-label.c:86 +msgctxt "timestamp-suffix-minute" +msgid "m" +msgstr "m" + +#. Translators: Timestamp minutes suffix +#: src/notifications/timestamp-label.c:88 +msgctxt "timestamp-suffix-minutes" +msgid "m" +msgstr "m" + +#. Translators: Timestamp hour suffix +#: src/notifications/timestamp-label.c:90 +msgctxt "timestamp-suffix-hour" +msgid "h" +msgstr "u" + +#. Translators: Timestamp hours suffix +#: src/notifications/timestamp-label.c:92 +msgctxt "timestamp-suffix-hours" +msgid "h" +msgstr "u" + +#. Translators: Timestamp day suffix +#: src/notifications/timestamp-label.c:94 +msgctxt "timestamp-suffix-day" +msgid "d" +msgstr "d" + +#. Translators: Timestamp days suffix +#: src/notifications/timestamp-label.c:96 +msgctxt "timestamp-suffix-days" +msgid "d" +msgstr "d" + +#. Translators: Timestamp month suffix +#: src/notifications/timestamp-label.c:98 +msgctxt "timestamp-suffix-month" +msgid "mo" +msgstr "mnd" + +#. Translators: Timestamp months suffix +#: src/notifications/timestamp-label.c:100 +msgctxt "timestamp-suffix-months" +msgid "mos" +msgstr "mnd" + +#. Translators: Timestamp year suffix +#: src/notifications/timestamp-label.c:102 +msgctxt "timestamp-suffix-year" +msgid "y" +msgstr "j" + +#. Translators: Timestamp years suffix +#: src/notifications/timestamp-label.c:104 +msgctxt "timestamp-suffix-years" +msgid "y" +msgstr "j" + +#: src/notifications/timestamp-label.c:121 +msgid "now" +msgstr "nu" + +#. Translators: time difference "Over 5 years" +#: src/notifications/timestamp-label.c:189 +#, c-format +msgid "Over %dy" +msgstr "Meer dan %dj" + +#. Translators: time difference "almost 5 years" +#: src/notifications/timestamp-label.c:193 +#, c-format +msgid "Almost %dy" +msgstr "Bijna %dj" + +#. Translators: a time difference like '<5m', if in doubt leave untranslated +#: src/notifications/timestamp-label.c:200 +#, c-format +msgid "%s%d%s" +msgstr "%s%d%s" -#: src/polkit-auth-agent.c:229 +#: src/polkit-auth-agent.c:225 msgid "Authentication dialog was dismissed by the user" -msgstr "Aanmelddialoog geannuleerd door gebruiker" +msgstr "Authenticatievenster is door de gebruiker afgesloten" -#: src/polkit-auth-prompt.c:276 src/ui/network-auth-prompt.ui:128 -#: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 +#: src/polkit-auth-prompt.c:278 src/ui/network-auth-prompt.ui:85 +#: src/ui/polkit-auth-prompt.ui:57 src/ui/system-prompt.ui:33 msgid "Password:" msgstr "Wachtwoord:" -#: src/polkit-auth-prompt.c:322 +#: src/polkit-auth-prompt.c:325 msgid "Sorry, that didn’t work. Please try again." -msgstr "Aanmelden mislukt. Probeer het nogmaals." +msgstr "Helaas, dat werkte niet. Probeer het opnieuw." -#: src/polkit-auth-prompt.c:488 -msgid "Authenticate" -msgstr "Aanmelden" +#: src/rotateinfo.c:81 +msgid "Portrait" +msgstr "Staand" + +#: src/rotateinfo.c:84 +msgid "Landscape" +msgstr "Liggend" + +#. Translators: Automatic screen orientation is either on (enabled) or off (locked/disabled) +#. Translators: Automatic screen orientation is off (locked/disabled) +#: src/rotateinfo.c:103 src/rotateinfo.c:183 +msgid "Off" +msgstr "Uit" -#: src/system-prompt.c:371 +#: src/system-prompt.c:364 msgid "Passwords do not match." msgstr "Wachtwoorden komen niet overeen." -#: src/system-prompt.c:378 +#: src/system-prompt.c:371 msgid "Password cannot be blank" -msgstr "Wachtwoord mag niet leeg zijn." +msgstr "Wachtwoord mag niet leeg zijn" -#: src/wifiinfo.c:55 -msgid "Wi-Fi" -msgstr "" +#: src/torch-info.c:80 +msgid "Torch" +msgstr "Zaklamp" + +#: src/ui/app-auth-prompt.ui:41 +msgid "Remember decision" +msgstr "Keuze onthouden" + +#: src/ui/app-auth-prompt.ui:55 src/ui/end-session-dialog.ui:50 +msgid "Cancel" +msgstr "Annuleren" -#: src/ui/app-grid-button.ui:48 +#: src/ui/app-auth-prompt.ui:66 src/ui/end-session-dialog.ui:61 +msgid "Ok" +msgstr "Oké" + +#: src/ui/app-grid-button.ui:49 msgid "App" -msgstr "" +msgstr "App" -#: src/ui/app-grid-button.ui:75 +#: src/ui/app-grid-button.ui:76 msgid "Remove from _Favorites" -msgstr "" +msgstr "Verwijderen uit _favorieten" -#: src/ui/app-grid-button.ui:80 +#: src/ui/app-grid-button.ui:81 msgid "Add to _Favorites" -msgstr "" +msgstr "Toevoegen aan _favorieten" #: src/ui/app-grid.ui:21 msgid "Search apps…" -msgstr "" +msgstr "Apps zoeken…" -#: src/ui/lockscreen.ui:36 +#: src/ui/end-session-dialog.ui:32 +msgid "Some applications are busy or have unsaved work" +msgstr "Sommige applicaties zijn bezig of hebben niet-opgeslagen werk" + +#: src/ui/lockscreen.ui:37 msgid "Slide up to unlock" msgstr "Veeg omhoog om te ontgrendelen" -#: src/ui/lockscreen.ui:250 +#: src/ui/lockscreen.ui:280 msgid "Emergency" -msgstr "" +msgstr "Noodgeval" -#: src/ui/lockscreen.ui:266 +#: src/ui/lockscreen.ui:296 msgid "Unlock" -msgstr "" +msgstr "Ontgrendelen" + +#: src/ui/network-auth-prompt.ui:6 src/ui/polkit-auth-prompt.ui:7 +msgid "Authentication required" +msgstr "Verificatie vereist" -#: src/ui/network-auth-prompt.ui:90 +#: src/ui/network-auth-prompt.ui:42 msgid "_Cancel" -msgstr "" +msgstr "_Annuleren" -#: src/ui/network-auth-prompt.ui:106 +#: src/ui/network-auth-prompt.ui:61 msgid "C_onnect" -msgstr "" +msgstr "_Verbinden" -#: src/ui/polkit-auth-prompt.ui:105 -msgid "User:" -msgstr "Gebruikersnaam:" +#: src/ui/polkit-auth-prompt.ui:125 +msgid "Authenticate" +msgstr "Aanmelden" -#: src/ui/system-prompt.ui:69 +#: src/ui/system-prompt.ui:63 msgid "Confirm:" msgstr "Bevestigen:" + +#: src/ui/top-panel.ui:16 +msgid "Lock Screen" +msgstr "Vergrendelscherm" + +#: src/ui/top-panel.ui:23 +msgid "Logout" +msgstr "Afmelden" + +#: src/wifiinfo.c:90 +msgid "Wi-Fi" +msgstr "Wifi" + +#. Translators: Refers to the cellular wireless network +#: src/wwaninfo.c:172 +msgid "Cellular" +msgstr "Mobiel" + +#~ msgid "User:" +#~ msgstr "Gebruikersnaam:" diff -Nru phosh-0.8.0/po/POTFILES.in phosh-0.13.1/po/POTFILES.in --- phosh-0.8.0/po/POTFILES.in 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/POTFILES.in 2021-08-31 09:15:52.000000000 +0000 @@ -11,6 +11,7 @@ src/batteryinfo.c src/bt-info.c src/docked-info.c +src/end-session-dialog.c src/fader.c src/favorite-list-model.c src/feedbackinfo.c @@ -18,6 +19,7 @@ src/home.c src/idle-manager.c src/layersurface.c +src/location-manager.c src/lockscreen.c src/lockscreen-manager.c src/lockshield.c @@ -49,8 +51,11 @@ src/toplevel-manager.c src/torch-info.c src/ui/activity.ui +src/ui/app-auth-prompt.ui src/ui/app-grid-button.ui src/ui/app-grid.ui +src/ui/end-session-dialog.ui +src/ui/gtk-mount-prompt.ui src/ui/home.ui src/ui/lockscreen.ui src/ui/media-player.ui diff -Nru phosh-0.8.0/po/POTFILES.skip phosh-0.13.1/po/POTFILES.skip --- phosh-0.8.0/po/POTFILES.skip 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/POTFILES.skip 2021-08-31 09:15:52.000000000 +0000 @@ -1,4 +1,4 @@ src/gtk-list-models/gtkfilterlistmodel.c src/gtk-list-models/gtksortlistmodel.c src/settings/gvc-channel-bar.c -subprojects/gvc/gvc-mixer-control.c +subprojects/** diff -Nru phosh-0.8.0/po/pt_BR.po phosh-0.13.1/po/pt_BR.po --- phosh-0.8.0/po/pt_BR.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/pt_BR.po 2021-08-31 09:15:52.000000000 +0000 @@ -1,23 +1,23 @@ # Brazilian Portuguese translaiton to phosh. -# Copyright (C) 2020 THE phosh'S COPYRIGHT HOLDER +# Copyright (C) 2021 THE phosh'S COPYRIGHT HOLDER # This file is distributed under the same license as the phosh package. # Luís Fernando Stürmer da Rosa , 2018-2020. -# Rafael Fontenelle , 2020. +# Rafael Fontenelle , 2020-2021. # msgid "" msgstr "" "Project-Id-Version: phosh\n" -"Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/phosh/issues\n" -"POT-Creation-Date: 2020-08-01 15:29+0000\n" -"PO-Revision-Date: 2020-07-30 20:40-0300\n" -"Last-Translator: Luís Fernando Stürmer da Rosa \n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/phosh/issues\n" +"POT-Creation-Date: 2021-08-03 09:16+0000\n" +"PO-Revision-Date: 2021-08-06 08:40-0300\n" +"Last-Translator: Rafael Fontenelle \n" "Language-Team: Brazilian Portuguese \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.3.1\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Gtranslator 40.0\n" +"Plural-Forms: nplurals=2; plural=(n > 1)\n" #. Translators: this is the session name, no need to translate it #: data/phosh.session.desktop.in.in:4 @@ -32,155 +32,318 @@ msgid "Window management and application launching for mobile" msgstr "Gerenciador de janelas e lançador de aplicativos para telefone" -#: src/app-grid-button.c:530 +#: src/app-grid-button.c:536 msgid "Application" msgstr "Aplicativo" -#: src/bt-info.c:89 src/feedbackinfo.c:48 +#: src/bt-info.c:92 src/feedbackinfo.c:51 src/rotateinfo.c:103 msgid "On" msgstr "Ligado" -#: src/bt-info.c:91 +#: src/bt-info.c:94 msgid "Bluetooth" msgstr "Bluetooth" +#: src/docked-info.c:81 +msgid "Docked" +msgstr "Ancorado" + +#: src/docked-info.c:81 src/docked-info.c:199 +msgid "Undocked" +msgstr "Desancorado" + +#: src/end-session-dialog.c:162 +msgid "Log Out" +msgstr "Sair" + +#: src/end-session-dialog.c:165 +#, c-format +msgid "%s will be logged out automatically in %d second." +msgid_plural "%s will be logged out automatically in %d seconds." +msgstr[0] "%s será desconectado automaticamente em %d segundo." +msgstr[1] "%s será desconectado automaticamente em %d segundos." + +#: src/end-session-dialog.c:171 src/ui/top-panel.ui:37 +msgid "Power Off" +msgstr "Desligar" + +#: src/end-session-dialog.c:172 +#, c-format +msgid "The system will power off automatically in %d second." +msgid_plural "The system will power off automatically in %d seconds." +msgstr[0] "O sistema será desligado automaticamente em %d segundo." +msgstr[1] "O sistema será desligado automaticamente em %d segundos." + +#: src/end-session-dialog.c:178 src/ui/top-panel.ui:30 +msgid "Restart" +msgstr "Reiniciar" + +#: src/end-session-dialog.c:179 +#, c-format +msgid "The system will restart automatically in %d second." +msgid_plural "The system will restart automatically in %d seconds." +msgstr[0] "O sistema será reiniciado automaticamente em %d segundo." +msgstr[1] "O sistema será reiniciado automaticamente em %d segundos." + +#: src/end-session-dialog.c:269 +#| msgid "Application" +msgid "Unknown application" +msgstr "Aplicativo desconhecido" + #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details -#: src/feedbackinfo.c:41 +#: src/feedbackinfo.c:44 msgid "Quiet" msgstr "Quieto" #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details -#: src/feedbackinfo.c:46 +#: src/feedbackinfo.c:49 msgid "Silent" msgstr "Silêncio" -#: src/lockscreen.c:84 src/ui/lockscreen.ui:234 +#: src/location-manager.c:268 +#, c-format +msgid "Allow '%s' to access your location information?" +msgstr "Permitir que “%s” acesse informações da sua localização?" + +#: src/location-manager.c:273 +#| msgid "Application" +msgid "Geolocation" +msgstr "Localização geográfica" + +#: src/location-manager.c:274 +msgid "Yes" +msgstr "Sim" + +#: src/location-manager.c:274 +msgid "No" +msgstr "Não" + +#: src/lockscreen.c:152 src/ui/lockscreen.ui:239 msgid "Enter Passcode" msgstr "Insira a senha" -#: src/lockscreen.c:263 +#: src/lockscreen.c:335 msgid "Checking…" msgstr "Verificando…" #. Translators: This is a time format for a date in #. long format -#: src/lockscreen.c:341 +#: src/lockscreen.c:413 msgid "%A, %B %-e" msgstr "%A, %d de %B" -#: src/media-player.c:262 -msgid "Unknown title" +#. Translators: Used when the title of a song is unknown +#: src/media-player.c:279 src/ui/media-player.ui:107 +#| msgid "Unknown title" +msgid "Unknown Title" msgstr "Título desconhecido" -#: src/media-player.c:270 -msgid "Unknown artist" +#. Translators: Used when the artist of a song is unknown +#: src/media-player.c:288 src/ui/media-player.ui:127 +msgid "Unknown Artist" msgstr "Artista desconhecido" -#: src/monitor-manager.c:58 +#: src/monitor-manager.c:114 msgid "Built-in display" msgstr "Tela integrada" +#: src/monitor-manager.c:132 +#, c-format +msgctxt "" +"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgid "%s %s" +msgstr "%s %s" + +#: src/monitor-manager.c:139 +#, c-format +msgctxt "" +"This is a monitor vendor name followed by product/model name where size in " +"inches could not be calculated, e.g. Dell U2414H" +msgid "%s %s" +msgstr "%s %s" + #. Translators: An unknown monitor type -#: src/monitor-manager.c:62 +#: src/monitor-manager.c:148 msgid "Unknown" msgstr "Desconhecido" -#: src/network-auth-prompt.c:184 +#: src/network-auth-prompt.c:187 #, c-format msgid "Authentication type of wifi network “%s” not supported" msgstr "Tipo de autenticação da rede wifi “%s” sem suporte" -#: src/network-auth-prompt.c:189 +#: src/network-auth-prompt.c:192 #, c-format msgid "Enter password for the wifi network “%s”" msgstr "Insira a senha para a rede wifi “%s”" -#: src/notifications/notification.c:382 src/notifications/notification.c:601 +#: src/notifications/mount-notification.c:122 +msgid "Open" +msgstr "Abrir" + +#: src/notifications/notification.c:383 src/notifications/notification.c:639 msgid "Notification" msgstr "Notificação" -#: src/notifications/timestamp-label.c:83 +#. Translators: Timestamp seconds suffix +#: src/notifications/timestamp-label.c:84 +#| msgid "s" +msgctxt "timestamp-suffix-seconds" msgid "s" msgstr "s" -#: src/notifications/timestamp-label.c:84 -#: src/notifications/timestamp-label.c:85 +#. Translators: Timestamp minute suffix +#: src/notifications/timestamp-label.c:86 +#| msgid "m" +msgctxt "timestamp-suffix-minute" msgid "m" msgstr "m" -#: src/notifications/timestamp-label.c:86 -#: src/notifications/timestamp-label.c:87 +#. Translators: Timestamp minutes suffix +#: src/notifications/timestamp-label.c:88 +#| msgid "m" +msgctxt "timestamp-suffix-minutes" +msgid "m" +msgstr "m" + +#. Translators: Timestamp hour suffix +#: src/notifications/timestamp-label.c:90 +#| msgid "h" +msgctxt "timestamp-suffix-hour" msgid "h" msgstr "h" -#: src/notifications/timestamp-label.c:88 -#: src/notifications/timestamp-label.c:89 +#. Translators: Timestamp hours suffix +#: src/notifications/timestamp-label.c:92 +#| msgid "h" +msgctxt "timestamp-suffix-hours" +msgid "h" +msgstr "h" + +#. Translators: Timestamp day suffix +#: src/notifications/timestamp-label.c:94 +#| msgid "d" +msgctxt "timestamp-suffix-day" msgid "d" msgstr "d" -#: src/notifications/timestamp-label.c:90 +#. Translators: Timestamp days suffix +#: src/notifications/timestamp-label.c:96 +#| msgid "d" +msgctxt "timestamp-suffix-days" +msgid "d" +msgstr "d" + +#. Translators: Timestamp month suffix +#: src/notifications/timestamp-label.c:98 +#| msgid "mo" +msgctxt "timestamp-suffix-month" msgid "mo" msgstr "m" -#: src/notifications/timestamp-label.c:91 +#. Translators: Timestamp months suffix +#: src/notifications/timestamp-label.c:100 +#| msgid "mos" +msgctxt "timestamp-suffix-months" msgid "mos" -msgstr "ms" +msgstr "m" -#: src/notifications/timestamp-label.c:92 -#: src/notifications/timestamp-label.c:93 +#. Translators: Timestamp year suffix +#: src/notifications/timestamp-label.c:102 +#| msgid "y" +msgctxt "timestamp-suffix-year" msgid "y" msgstr "a" -#. Translators: this is the date in number only format -#: src/notifications/timestamp-label.c:96 -msgid "%d.%m.%y" -msgstr "%d.%m.%y" +#. Translators: Timestamp years suffix +#: src/notifications/timestamp-label.c:104 +#| msgid "y" +msgctxt "timestamp-suffix-years" +msgid "y" +msgstr "a" + +#: src/notifications/timestamp-label.c:121 +#| msgid "Unknown" +msgid "now" +msgstr "agora" + +#. Translators: time difference "Over 5 years" +#: src/notifications/timestamp-label.c:189 +#, c-format +#| msgid "Over" +msgid "Over %dy" +msgstr "Mais de %dy" + +#. Translators: time difference "almost 5 years" +#: src/notifications/timestamp-label.c:193 +#, c-format +#| msgid "Almost" +msgid "Almost %dy" +msgstr "Quase %dy" -#: src/notifications/timestamp-label.c:186 -msgid "Over" -msgstr "Mais de" - -#: src/notifications/timestamp-label.c:190 -msgid "Almost" -msgstr "Quase" +#. Translators: a time difference like '<5m', if in doubt leave untranslated +#: src/notifications/timestamp-label.c:200 +#, c-format +msgid "%s%d%s" +msgstr "%s%d%s" -#: src/polkit-auth-agent.c:229 +#: src/polkit-auth-agent.c:228 msgid "Authentication dialog was dismissed by the user" msgstr "Diálogo de autenticação dispensado pelo usuário" -#: src/polkit-auth-prompt.c:276 src/ui/network-auth-prompt.ui:128 -#: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 +#: src/polkit-auth-prompt.c:278 src/ui/gtk-mount-prompt.ui:21 +#: src/ui/network-auth-prompt.ui:83 src/ui/polkit-auth-prompt.ui:57 +#: src/ui/system-prompt.ui:33 msgid "Password:" msgstr "Senha:" -#: src/polkit-auth-prompt.c:322 +#: src/polkit-auth-prompt.c:325 msgid "Sorry, that didn’t work. Please try again." msgstr "Ops! Não deu! Tente novamente." -#: src/polkit-auth-prompt.c:488 -msgid "Authenticate" -msgstr "Autenticar" - -#: src/rotateinfo.c:46 +#: src/rotateinfo.c:81 msgid "Portrait" msgstr "Retrato" -#: src/rotateinfo.c:49 +#: src/rotateinfo.c:84 msgid "Landscape" msgstr "Paisagem" -#: src/system-prompt.c:371 +#. Translators: Automatic screen orientation is either on (enabled) or off (locked/disabled) +#. Translators: Automatic screen orientation is off (locked/disabled) +#: src/rotateinfo.c:103 src/rotateinfo.c:186 +msgid "Off" +msgstr "Desligada" + +#: src/system-prompt.c:364 msgid "Passwords do not match." msgstr "As senhas não conferem." -#: src/system-prompt.c:378 +#: src/system-prompt.c:371 msgid "Password cannot be blank" msgstr "A senha não pode ficar em branco" +#: src/torch-info.c:80 +msgid "Torch" +msgstr "Tocha" + +#: src/ui/app-auth-prompt.ui:41 +msgid "Remember decision" +msgstr "Lembrar da decisão" + +#: src/ui/app-auth-prompt.ui:54 src/ui/end-session-dialog.ui:54 +#| msgid "_Cancel" +msgid "Cancel" +msgstr "Cancelar" + +#: src/ui/app-auth-prompt.ui:63 src/ui/end-session-dialog.ui:63 +msgid "Ok" +msgstr "Ok" + #: src/ui/app-grid-button.ui:49 msgid "App" msgstr "Aplicativo" @@ -193,69 +356,93 @@ msgid "Add to _Favorites" msgstr "Adicionar aos _favoritos" -#: src/ui/app-grid.ui:21 +#: src/ui/app-grid.ui:22 msgid "Search apps…" msgstr "Procurar aplicativos…" -#: src/ui/lockscreen.ui:37 +#: src/ui/app-grid.ui:169 +msgid "Show only adaptive apps" +msgstr "Mostrar apenas aplicativos adaptativos" + +#: src/ui/end-session-dialog.ui:32 +msgid "Some applications are busy or have unsaved work" +msgstr "Alguns aplicativos estão ocupados ou possuem trabalhos não salvos" + +#: src/ui/gtk-mount-prompt.ui:95 +msgid "User:" +msgstr "Usuário:" + +#: src/ui/gtk-mount-prompt.ui:118 +msgid "Domain:" +msgstr "Domínio:" + +#: src/ui/gtk-mount-prompt.ui:151 +#| msgid "C_onnect" +msgid "Co_nnect" +msgstr "C_onectar" + +#: src/ui/lockscreen.ui:43 msgid "Slide up to unlock" msgstr "Deslize para desbloquear" -#: src/ui/lockscreen.ui:280 +#: src/ui/lockscreen.ui:285 msgid "Emergency" msgstr "Emergência" -#: src/ui/lockscreen.ui:296 +#: src/ui/lockscreen.ui:301 msgid "Unlock" msgstr "Desbloquear" -#: src/ui/media-player.ui:107 -msgid "Unknown Song" -msgstr "Música desconhecida" - -#: src/ui/media-player.ui:127 -msgid "Unknown Artist" -msgstr "Artista desconhecido" +#: src/ui/lockscreen.ui:341 +msgid "Back" +msgstr "Voltar" + +#: src/ui/network-auth-prompt.ui:6 src/ui/polkit-auth-prompt.ui:7 +#| msgid "Authenticate" +msgid "Authentication required" +msgstr "Autenticação necessária" -#: src/ui/network-auth-prompt.ui:90 +#: src/ui/network-auth-prompt.ui:41 msgid "_Cancel" msgstr "_Cancelar" -#: src/ui/network-auth-prompt.ui:106 +#: src/ui/network-auth-prompt.ui:59 msgid "C_onnect" msgstr "C_onectar" -#: src/ui/polkit-auth-prompt.ui:105 -msgid "User:" -msgstr "Usuário:" +#: src/ui/polkit-auth-prompt.ui:123 +msgid "Authenticate" +msgstr "Autenticar" -#: src/ui/system-prompt.ui:69 +#: src/ui/system-prompt.ui:63 msgid "Confirm:" msgstr "Confirmar:" -#: src/ui/top-panel.ui:15 +#: src/ui/top-panel.ui:16 msgid "Lock Screen" msgstr "Tela de bloqueio" -#: src/ui/top-panel.ui:22 +#: src/ui/top-panel.ui:23 msgid "Logout" msgstr "Encerrar sessão" -#: src/ui/top-panel.ui:29 -msgid "Restart" -msgstr "Reiniciar" - -#: src/ui/top-panel.ui:36 -msgid "Power Off" -msgstr "Desligar" - -#: src/wifiinfo.c:88 +#: src/wifiinfo.c:90 msgid "Wi-Fi" msgstr "Wi-Fi" -#: src/wwaninfo.c:167 +#. Translators: Refers to the cellular wireless network +#: src/wwaninfo.c:172 msgid "Cellular" msgstr "Celular" +#~ msgid "Unknown artist" +#~ msgstr "Artista desconhecido" + +#~ msgid "%d.%m.%y" +#~ msgstr "%d.%m.%y" + +#~ msgid "Unknown Song" +#~ msgstr "Música desconhecida" + #~ msgid "Suspend" #~ msgstr "Suspender" diff -Nru phosh-0.8.0/po/ro.po phosh-0.13.1/po/ro.po --- phosh-0.8.0/po/ro.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/ro.po 2021-08-31 09:15:52.000000000 +0000 @@ -1,23 +1,24 @@ # Romanian translation for phosh. # Copyright (C) 2020 phosh's COPYRIGHT HOLDER # This file is distributed under the same license as the phosh package. -# Florentina Mușat , 2020. +# Florentina Mușat , 2020-2021. # msgid "" msgstr "" "Project-Id-Version: phosh master\n" -"Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/phosh/issues\n" -"POT-Creation-Date: 2020-07-18 03:30+0000\n" -"PO-Revision-Date: 2020-07-18 16:59+0300\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/phosh/issues\n" +"POT-Creation-Date: 2021-08-03 09:16+0000\n" +"PO-Revision-Date: 2021-08-13 17:48+0200\n" "Last-Translator: Florentina Mușat \n" "Language-Team: Romanian \n" "Language: ro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " -"20)) ? 1 : 2);;\n" -"X-Generator: Poedit 2.3.1\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n==0 || (n!=1 && n%100>=1 && n" +"%100<=19) ? 1 : 2);\n" +"X-Generator: Gtranslator 3.30.1\n" +"X-Poedit-SourceCharset: UTF-8\n" #. Translators: this is the session name, no need to translate it #: data/phosh.session.desktop.in.in:4 @@ -30,183 +31,391 @@ #: data/sm.puri.Phosh.desktop.in.in:5 msgid "Window management and application launching for mobile" -msgstr "Administrare de fereastră și lansare de aplicație pentru mobil" +msgstr "Gestionarea ferestrei și pornirea aplicațiilor pentru mobil" -#: src/app-grid-button.c:530 +#: src/app-grid-button.c:536 msgid "Application" msgstr "Aplicație" -#: src/bt-info.c:89 src/feedbackinfo.c:48 +#: src/bt-info.c:92 src/feedbackinfo.c:51 src/rotateinfo.c:103 msgid "On" msgstr "Pornit" -#: src/bt-info.c:91 +#: src/bt-info.c:94 msgid "Bluetooth" msgstr "Bluetooth" +#: src/docked-info.c:81 +msgid "Docked" +msgstr "Cuplat" + +#: src/docked-info.c:81 src/docked-info.c:199 +msgid "Undocked" +msgstr "Decuplat" + +#: src/end-session-dialog.c:162 +msgid "Log Out" +msgstr "Deconectare" + +#: src/end-session-dialog.c:165 +#, c-format +msgid "%s will be logged out automatically in %d second." +msgid_plural "%s will be logged out automatically in %d seconds." +msgstr[0] "%s se va deconecta automat în %d secundă." +msgstr[1] "%s se va deconecta automat în %d secunde." +msgstr[2] "%s se va deconecta automat în %d de secunde." + +#: src/end-session-dialog.c:171 src/ui/top-panel.ui:37 +msgid "Power Off" +msgstr "Oprește" + +#: src/end-session-dialog.c:172 +#, c-format +msgid "The system will power off automatically in %d second." +msgid_plural "The system will power off automatically in %d seconds." +msgstr[0] "Sistemul se va opri automat în %d secundă." +msgstr[1] "Sistemul se va opri automat în %d secunde." +msgstr[2] "Sistemul se va opri automat în %d de secunde." + +#: src/end-session-dialog.c:178 src/ui/top-panel.ui:30 +msgid "Restart" +msgstr "Repornește" + +#: src/end-session-dialog.c:179 +#, c-format +msgid "The system will restart automatically in %d second." +msgid_plural "The system will restart automatically in %d seconds." +msgstr[0] "Sistemul va reporni automat în %d secundă." +msgstr[1] "Sistemul va reporni automat în %d secunde." +msgstr[2] "Sistemul va reporni automat în %d de secunde." + +#: src/end-session-dialog.c:269 +msgid "Unknown application" +msgstr "Aplicație necunoscută" + #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details -#: src/feedbackinfo.c:41 +#: src/feedbackinfo.c:44 msgid "Quiet" -msgstr "Încet" +msgstr "Liniștit" #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details -#: src/feedbackinfo.c:46 +#: src/feedbackinfo.c:49 msgid "Silent" msgstr "Silențios" -#: src/lockscreen.c:84 src/ui/lockscreen.ui:234 +#: src/location-manager.c:268 +#, c-format +msgid "Allow '%s' to access your location information?" +msgstr "„%s” poate accesa poziția ta geografică?" + +#: src/location-manager.c:273 +msgid "Geolocation" +msgstr "Poziția geografică" + +#: src/location-manager.c:274 +msgid "Yes" +msgstr "Da" + +#: src/location-manager.c:274 +msgid "No" +msgstr "Nu" + +#: src/lockscreen.c:152 src/ui/lockscreen.ui:239 msgid "Enter Passcode" -msgstr "Introduceți parola" +msgstr "Introdu codul de acces" -#: src/lockscreen.c:263 +#: src/lockscreen.c:335 msgid "Checking…" msgstr "Se verifică…" #. Translators: This is a time format for a date in #. long format -#: src/lockscreen.c:341 +#: src/lockscreen.c:413 msgid "%A, %B %-e" msgstr "%A, %B %-e" -#: src/media-player.c:262 -msgid "Unknown title" +#. Translators: Used when the title of a song is unknown +#: src/media-player.c:279 src/ui/media-player.ui:107 +msgid "Unknown Title" msgstr "Titlu necunoscut" -#: src/media-player.c:270 -msgid "Unknown artist" +#. Translators: Used when the artist of a song is unknown +#: src/media-player.c:288 src/ui/media-player.ui:127 +msgid "Unknown Artist" msgstr "Artist necunoscut" -#: src/monitor-manager.c:58 +#: src/monitor-manager.c:114 msgid "Built-in display" -msgstr "Afișaj integrat" +msgstr "Ecran integrat" + +#: src/monitor-manager.c:132 +#, c-format +msgctxt "" +"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgid "%s %s" +msgstr "%s %s" + +#: src/monitor-manager.c:139 +#, c-format +msgctxt "" +"This is a monitor vendor name followed by product/model name where size in " +"inches could not be calculated, e.g. Dell U2414H" +msgid "%s %s" +msgstr "%s %s" #. Translators: An unknown monitor type -#: src/monitor-manager.c:62 +#: src/monitor-manager.c:148 msgid "Unknown" msgstr "Necunoscut" -#: src/network-auth-prompt.c:184 +#: src/network-auth-prompt.c:187 #, c-format msgid "Authentication type of wifi network “%s” not supported" -msgstr "Tipul de autentificare de rețea de wifi „%s” nu este suportat" +msgstr "Tipul de autentificare pentru rețeaua Wi-Fi „%s” nu este acceptat" -#: src/network-auth-prompt.c:189 +#: src/network-auth-prompt.c:192 #, c-format msgid "Enter password for the wifi network “%s”" -msgstr "Introduceți parola pentru rețeaua de wifi „%s”" +msgstr "Introdu parola pentru rețeaua Wi-Fi „%s”" + +#: src/notifications/mount-notification.c:122 +msgid "Open" +msgstr "Deschide" -#: src/notifications/notification.c:365 src/notifications/notification.c:581 +#: src/notifications/notification.c:383 src/notifications/notification.c:639 msgid "Notification" msgstr "Notificare" -#: src/polkit-auth-agent.c:229 +#. Translators: Timestamp seconds suffix +#: src/notifications/timestamp-label.c:84 +msgctxt "timestamp-suffix-seconds" +msgid "s" +msgstr "s" + +#. Translators: Timestamp minute suffix +#: src/notifications/timestamp-label.c:86 +msgctxt "timestamp-suffix-minute" +msgid "m" +msgstr "m" + +#. Translators: Timestamp minutes suffix +#: src/notifications/timestamp-label.c:88 +msgctxt "timestamp-suffix-minutes" +msgid "m" +msgstr "m" + +#. Translators: Timestamp hour suffix +#: src/notifications/timestamp-label.c:90 +msgctxt "timestamp-suffix-hour" +msgid "h" +msgstr "o" + +#. Translators: Timestamp hours suffix +#: src/notifications/timestamp-label.c:92 +msgctxt "timestamp-suffix-hours" +msgid "h" +msgstr "o" + +#. Translators: Timestamp day suffix +#: src/notifications/timestamp-label.c:94 +msgctxt "timestamp-suffix-day" +msgid "d" +msgstr "z" + +#. Translators: Timestamp days suffix +#: src/notifications/timestamp-label.c:96 +msgctxt "timestamp-suffix-days" +msgid "d" +msgstr "z" + +#. Translators: Timestamp month suffix +#: src/notifications/timestamp-label.c:98 +msgctxt "timestamp-suffix-month" +msgid "mo" +msgstr "lu" + +#. Translators: Timestamp months suffix +#: src/notifications/timestamp-label.c:100 +msgctxt "timestamp-suffix-months" +msgid "mos" +msgstr "luni" + +#. Translators: Timestamp year suffix +#: src/notifications/timestamp-label.c:102 +msgctxt "timestamp-suffix-year" +msgid "y" +msgstr "a" + +#. Translators: Timestamp years suffix +#: src/notifications/timestamp-label.c:104 +msgctxt "timestamp-suffix-years" +msgid "y" +msgstr "a" + +#: src/notifications/timestamp-label.c:121 +msgid "now" +msgstr "acum" + +#. Translators: time difference "Over 5 years" +#: src/notifications/timestamp-label.c:189 +#, c-format +msgid "Over %dy" +msgstr "Peste %da" + +#. Translators: time difference "almost 5 years" +#: src/notifications/timestamp-label.c:193 +#, c-format +msgid "Almost %dy" +msgstr "Aproape %da" + +#. Translators: a time difference like '<5m', if in doubt leave untranslated +#: src/notifications/timestamp-label.c:200 +#, c-format +msgid "%s%d%s" +msgstr "%s%d%s" + +#: src/polkit-auth-agent.c:228 msgid "Authentication dialog was dismissed by the user" -msgstr "Fereastra de autentificare a fost închisă de către utilizator" +msgstr "Fereastra de autentificare a fost închisă de utilizator" -#: src/polkit-auth-prompt.c:276 src/ui/network-auth-prompt.ui:128 -#: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 +#: src/polkit-auth-prompt.c:278 src/ui/gtk-mount-prompt.ui:21 +#: src/ui/network-auth-prompt.ui:83 src/ui/polkit-auth-prompt.ui:57 +#: src/ui/system-prompt.ui:33 msgid "Password:" -msgstr "Parolă:" +msgstr "Parola:" -#: src/polkit-auth-prompt.c:322 +#: src/polkit-auth-prompt.c:325 msgid "Sorry, that didn’t work. Please try again." -msgstr "Nu a funcționat. Încercați din nou." - -#: src/polkit-auth-prompt.c:488 -msgid "Authenticate" -msgstr "Autentificare" +msgstr "Nu a funcționat. Încearcă din nou." -#: src/rotateinfo.c:46 +#: src/rotateinfo.c:81 msgid "Portrait" msgstr "Portret" -#: src/rotateinfo.c:49 +#: src/rotateinfo.c:84 msgid "Landscape" msgstr "Peisaj" -#: src/system-prompt.c:371 +#. Translators: Automatic screen orientation is either on (enabled) or off (locked/disabled) +#. Translators: Automatic screen orientation is off (locked/disabled) +#: src/rotateinfo.c:103 src/rotateinfo.c:186 +msgid "Off" +msgstr "Oprit" + +#: src/system-prompt.c:364 msgid "Passwords do not match." msgstr "Parolele nu se potrivesc." -#: src/system-prompt.c:378 +#: src/system-prompt.c:371 msgid "Password cannot be blank" msgstr "Parola nu poate fi goală" +#: src/torch-info.c:80 +msgid "Torch" +msgstr "Lanternă" + +#: src/ui/app-auth-prompt.ui:41 +msgid "Remember decision" +msgstr "Memorează decizia" + +#: src/ui/app-auth-prompt.ui:54 src/ui/end-session-dialog.ui:54 +msgid "Cancel" +msgstr "Anulează" + +#: src/ui/app-auth-prompt.ui:63 src/ui/end-session-dialog.ui:63 +msgid "Ok" +msgstr "De acord" + #: src/ui/app-grid-button.ui:49 msgid "App" msgstr "Aplicație" #: src/ui/app-grid-button.ui:76 msgid "Remove from _Favorites" -msgstr "Elimină din _favorite" +msgstr "Elimină din _Favorite" #: src/ui/app-grid-button.ui:81 msgid "Add to _Favorites" -msgstr "Adaugă la _favorite" +msgstr "Adaugă la _Favorite" -#: src/ui/app-grid.ui:21 +#: src/ui/app-grid.ui:22 msgid "Search apps…" msgstr "Caută aplicații…" -#: src/ui/lockscreen.ui:37 +#: src/ui/app-grid.ui:169 +msgid "Show only adaptive apps" +msgstr "Arată doar aplicații adaptabile" + +#: src/ui/end-session-dialog.ui:32 +msgid "Some applications are busy or have unsaved work" +msgstr "Unele aplicații sunt ocupate sau au lucrări nesalvate" + +#: src/ui/gtk-mount-prompt.ui:95 +msgid "User:" +msgstr "Utilizator:" + +#: src/ui/gtk-mount-prompt.ui:118 +msgid "Domain:" +msgstr "Domeniu:" + +#: src/ui/gtk-mount-prompt.ui:151 +#| msgid "C_onnect" +msgid "Co_nnect" +msgstr "Co_nectează" + +#: src/ui/lockscreen.ui:43 msgid "Slide up to unlock" -msgstr "Glisează în sus pentru a debloca" +msgstr "Trage în sus pentru a debloca" -#: src/ui/lockscreen.ui:280 +#: src/ui/lockscreen.ui:285 msgid "Emergency" msgstr "Urgență" -#: src/ui/lockscreen.ui:296 +#: src/ui/lockscreen.ui:301 msgid "Unlock" msgstr "Deblocare" -#: src/ui/media-player.ui:107 -msgid "Unknown Song" -msgstr "Cântec necunoscut" - -#: src/ui/media-player.ui:127 -msgid "Unknown Artist" -msgstr "Artist necunoscut" +#: src/ui/lockscreen.ui:341 +msgid "Back" +msgstr "Înapoi" + +#: src/ui/network-auth-prompt.ui:6 src/ui/polkit-auth-prompt.ui:7 +msgid "Authentication required" +msgstr "Autentificare necesară" -#: src/ui/network-auth-prompt.ui:90 +#: src/ui/network-auth-prompt.ui:41 msgid "_Cancel" msgstr "_Anulează" -#: src/ui/network-auth-prompt.ui:106 +#: src/ui/network-auth-prompt.ui:59 msgid "C_onnect" msgstr "C_onectează" -#: src/ui/polkit-auth-prompt.ui:105 -msgid "User:" -msgstr "Utilizator:" +#: src/ui/polkit-auth-prompt.ui:123 +msgid "Authenticate" +msgstr "Autentificare" -#: src/ui/system-prompt.ui:69 +#: src/ui/system-prompt.ui:63 msgid "Confirm:" msgstr "Confirmă:" -#: src/ui/top-panel.ui:15 +#: src/ui/top-panel.ui:16 msgid "Lock Screen" -msgstr "Ecran de blocare" +msgstr "Blochează ecranul" -#: src/ui/top-panel.ui:22 +#: src/ui/top-panel.ui:23 msgid "Logout" -msgstr "Deautentificare" +msgstr "Deconectare" -#: src/ui/top-panel.ui:29 -msgid "Power Off" -msgstr "Oprire" - -#: src/wifiinfo.c:88 +#: src/wifiinfo.c:90 msgid "Wi-Fi" msgstr "Wi-Fi" -#: src/wwaninfo.c:167 +#. Translators: Refers to the cellular wireless network +#: src/wwaninfo.c:172 msgid "Cellular" msgstr "Celular" - -#~ msgid "Suspend" -#~ msgstr "Suspendă" diff -Nru phosh-0.8.0/po/sr.po phosh-0.13.1/po/sr.po --- phosh-0.8.0/po/sr.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/sr.po 2021-08-31 09:15:52.000000000 +0000 @@ -1,33 +1,32 @@ # Serbian translation for phosh. -# Copyright (C) 2020 phosh's COPYRIGHT HOLDER +# Copyright ©2020 phosh's COPYRIGHT HOLDER # This file is distributed under the same license as the phosh package. # nikp123 , 2020. # Марко М. Костић , 2020. -# +# Мирослав Николић , 2021. msgid "" msgstr "" "Project-Id-Version: phosh master\n" -"Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/phosh/issues\n" -"POT-Creation-Date: 2020-10-29 15:33+0000\n" -"PO-Revision-Date: 2020-10-30 02:03+0100\n" -"Last-Translator: Марко М. Костић \n" -"Language-Team: Serbian \n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/phosh/issues\n" +"POT-Creation-Date: 2021-08-03 09:16+0000\n" +"PO-Revision-Date: 2021-08-08 07:02+0200\n" +"Last-Translator: Мирослав Николић \n" +"Language-Team: Serbian <(nothing)>\n" "Language: sr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=4; plural=n==1? 3 : n%10==1 && n%100!=11 ? 0 : n" -"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Poedit 2.4.1\n" +"Plural-Forms: nplurals=4; plural=n==1? 3 : n%10==1 && n%100!=11 ? 0 : " +"n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #. Translators: this is the session name, no need to translate it #: data/phosh.session.desktop.in.in:4 msgid "Phosh" -msgstr "Phosh" +msgstr "Теш" #: data/sm.puri.Phosh.desktop.in.in:4 msgid "Phone Shell" -msgstr "Мобилна шкољка" +msgstr "Телефонска шкољка" #: data/sm.puri.Phosh.desktop.in.in:5 msgid "Window management and application launching for mobile" @@ -37,7 +36,7 @@ msgid "Application" msgstr "Апликација" -#: src/bt-info.c:92 src/feedbackinfo.c:51 +#: src/bt-info.c:92 src/feedbackinfo.c:51 src/rotateinfo.c:103 msgid "On" msgstr "Укљ." @@ -49,10 +48,54 @@ msgid "Docked" msgstr "Усидрен" -#: src/docked-info.c:195 +#: src/docked-info.c:81 src/docked-info.c:199 msgid "Undocked" msgstr "Одсидрен" +#: src/end-session-dialog.c:162 +msgid "Log Out" +msgstr "Одјави ме" + +#: src/end-session-dialog.c:165 +#, c-format +msgid "%s will be logged out automatically in %d second." +msgid_plural "%s will be logged out automatically in %d seconds." +msgstr[0] "„%s“ ће бити одјављен за %d секунду." +msgstr[1] "„%s“ ће бити одјављен за %d секунде." +msgstr[2] "„%s“ ће бити одјављен за %d секунди." +msgstr[3] "„%s“ ће бити одјављен за једну секунду." + +#: src/end-session-dialog.c:171 src/ui/top-panel.ui:37 +msgid "Power Off" +msgstr "Искључивање" + +#: src/end-session-dialog.c:172 +#, c-format +msgid "The system will power off automatically in %d second." +msgid_plural "The system will power off automatically in %d seconds." +msgstr[0] "Рачунар ће се искључити за %d секунду." +msgstr[1] "Рачунар ће се искључити за %d секунде." +msgstr[2] "Рачунар ће се искључити за %d секунди." +msgstr[3] "Рачунар ће се искључити за једну секунду." + +#: src/end-session-dialog.c:178 src/ui/top-panel.ui:30 +msgid "Restart" +msgstr "Поново покрени" + +#: src/end-session-dialog.c:179 +#, c-format +msgid "The system will restart automatically in %d second." +msgid_plural "The system will restart automatically in %d seconds." +msgstr[0] "Систем ће се поново покренути за %d секунду." +msgstr[1] "Систем ће се поново покренути за %d секунде." +msgstr[2] "Систем ће се поново покренути за %d секунди." +msgstr[3] "Систем ће се поново покренути за једну секунду." + +#: src/end-session-dialog.c:269 +#| msgid "Application" +msgid "Unknown application" +msgstr "Непознат програм" + #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details @@ -67,164 +110,214 @@ msgid "Silent" msgstr "Утишано" -#: src/lockscreen.c:86 src/ui/lockscreen.ui:234 +#: src/location-manager.c:268 +#, c-format +msgid "Allow '%s' to access your location information?" +msgstr "Да дозволим да „%s“ приступи вашим подацима о месту?" + +#: src/location-manager.c:273 +#| msgid "Application" +msgid "Geolocation" +msgstr "Геолокација" + +#: src/location-manager.c:274 +msgid "Yes" +msgstr "Да" + +#: src/location-manager.c:274 +msgid "No" +msgstr "Не" + +#: src/lockscreen.c:152 src/ui/lockscreen.ui:239 msgid "Enter Passcode" msgstr "Унеси код" -#: src/lockscreen.c:265 +#: src/lockscreen.c:335 msgid "Checking…" msgstr "Проверавам…" #. Translators: This is a time format for a date in #. long format -#: src/lockscreen.c:343 +#: src/lockscreen.c:413 msgid "%A, %B %-e" msgstr "%A, %d. %B" #. Translators: Used when the title of a song is unknown -#: src/media-player.c:277 src/ui/media-player.ui:107 +#: src/media-player.c:279 src/ui/media-player.ui:107 msgid "Unknown Title" msgstr "Непознат наслов" #. Translators: Used when the artist of a song is unknown -#: src/media-player.c:286 src/ui/media-player.ui:127 +#: src/media-player.c:288 src/ui/media-player.ui:127 msgid "Unknown Artist" msgstr "Непознат извођач" -#: src/monitor-manager.c:71 +#: src/monitor-manager.c:114 msgid "Built-in display" msgstr "Уграђени екран" +#: src/monitor-manager.c:132 +#, c-format +msgctxt "" +"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgid "%s %s" +msgstr "%s %s" + +#: src/monitor-manager.c:139 +#, c-format +msgctxt "" +"This is a monitor vendor name followed by product/model name where size in " +"inches could not be calculated, e.g. Dell U2414H" +msgid "%s %s" +msgstr "%s %s" + #. Translators: An unknown monitor type -#: src/monitor-manager.c:75 +#: src/monitor-manager.c:148 msgid "Unknown" msgstr "Непознато" -#: src/network-auth-prompt.c:186 +#: src/network-auth-prompt.c:187 #, c-format msgid "Authentication type of wifi network “%s” not supported" msgstr "Тип пријављивања на бежичној мрежи „%s“ није подржан" -#: src/network-auth-prompt.c:191 +#: src/network-auth-prompt.c:192 #, c-format msgid "Enter password for the wifi network “%s”" msgstr "Унесите лозинку бежичне мреже „%s“" -#: src/notifications/notification.c:382 src/notifications/notification.c:601 +#: src/notifications/mount-notification.c:122 +msgid "Open" +msgstr "Отвори" + +#: src/notifications/notification.c:383 src/notifications/notification.c:639 msgid "Notification" msgstr "Обавештење" #. Translators: Timestamp seconds suffix -#: src/notifications/timestamp-label.c:83 +#: src/notifications/timestamp-label.c:84 msgctxt "timestamp-suffix-seconds" msgid "s" msgstr "с" #. Translators: Timestamp minute suffix -#: src/notifications/timestamp-label.c:85 +#: src/notifications/timestamp-label.c:86 msgctxt "timestamp-suffix-minute" msgid "m" msgstr "м" #. Translators: Timestamp minutes suffix -#: src/notifications/timestamp-label.c:87 +#: src/notifications/timestamp-label.c:88 msgctxt "timestamp-suffix-minutes" msgid "m" msgstr "м" #. Translators: Timestamp hour suffix -#: src/notifications/timestamp-label.c:89 +#: src/notifications/timestamp-label.c:90 msgctxt "timestamp-suffix-hour" msgid "h" msgstr "ч" #. Translators: Timestamp hours suffix -#: src/notifications/timestamp-label.c:91 +#: src/notifications/timestamp-label.c:92 msgctxt "timestamp-suffix-hours" msgid "h" msgstr "ч" #. Translators: Timestamp day suffix -#: src/notifications/timestamp-label.c:93 +#: src/notifications/timestamp-label.c:94 msgctxt "timestamp-suffix-day" msgid "d" msgstr "д" #. Translators: Timestamp days suffix -#: src/notifications/timestamp-label.c:95 +#: src/notifications/timestamp-label.c:96 msgctxt "timestamp-suffix-days" msgid "d" msgstr "д" #. Translators: Timestamp month suffix -#: src/notifications/timestamp-label.c:97 +#: src/notifications/timestamp-label.c:98 msgctxt "timestamp-suffix-month" msgid "mo" msgstr "мес." #. Translators: Timestamp months suffix -#: src/notifications/timestamp-label.c:99 +#: src/notifications/timestamp-label.c:100 msgctxt "timestamp-suffix-months" msgid "mos" msgstr "мес." #. Translators: Timestamp year suffix -#: src/notifications/timestamp-label.c:101 +#: src/notifications/timestamp-label.c:102 msgctxt "timestamp-suffix-year" msgid "y" msgstr "г" #. Translators: Timestamp years suffix -#: src/notifications/timestamp-label.c:103 +#: src/notifications/timestamp-label.c:104 msgctxt "timestamp-suffix-years" msgid "y" msgstr "г" -#. Translators: this is the date in (short) number only format -#: src/notifications/timestamp-label.c:106 -msgid "%d.%m.%y" -msgstr "%d.%m.%y" - -#. Translators: Timestamp prefix (e.g. Over 5h) -#: src/notifications/timestamp-label.c:197 -msgid "Over" -msgstr "Више од" - -#. Translators: Timestamp prefix (e.g. Almost 5h) -#: src/notifications/timestamp-label.c:202 -msgid "Almost" -msgstr "Скоро " +#: src/notifications/timestamp-label.c:121 +#| msgid "Unknown" +msgid "now" +msgstr "сада" + +#. Translators: time difference "Over 5 years" +#: src/notifications/timestamp-label.c:189 +#, c-format +#| msgid "Over" +msgid "Over %dy" +msgstr "Преко %dг" + +#. Translators: time difference "almost 5 years" +#: src/notifications/timestamp-label.c:193 +#, c-format +#| msgid "Almost" +msgid "Almost %dy" +msgstr "Скоро %dг" + +#. Translators: a time difference like '<5m', if in doubt leave untranslated +#: src/notifications/timestamp-label.c:200 +#, c-format +msgid "%s%d%s" +msgstr "%s%d%s" -#: src/polkit-auth-agent.c:231 +#: src/polkit-auth-agent.c:228 msgid "Authentication dialog was dismissed by the user" msgstr "Корисник је одбацио прозорче за потврђивање идентитета" -#: src/polkit-auth-prompt.c:278 src/ui/network-auth-prompt.ui:128 -#: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 +#: src/polkit-auth-prompt.c:278 src/ui/gtk-mount-prompt.ui:21 +#: src/ui/network-auth-prompt.ui:83 src/ui/polkit-auth-prompt.ui:57 +#: src/ui/system-prompt.ui:33 msgid "Password:" msgstr "Лозинка:" -#: src/polkit-auth-prompt.c:324 +#: src/polkit-auth-prompt.c:325 msgid "Sorry, that didn’t work. Please try again." msgstr "Нетачно. Покушајте поново." -#: src/polkit-auth-prompt.c:490 -msgid "Authenticate" -msgstr "Потврди идентитет" - -#: src/rotateinfo.c:65 +#: src/rotateinfo.c:81 msgid "Portrait" msgstr "Усправно" -#: src/rotateinfo.c:68 +#: src/rotateinfo.c:84 msgid "Landscape" msgstr "Положено" -#: src/system-prompt.c:373 +#. Translators: Automatic screen orientation is either on (enabled) or off (locked/disabled) +#. Translators: Automatic screen orientation is off (locked/disabled) +#: src/rotateinfo.c:103 src/rotateinfo.c:186 +msgid "Off" +msgstr "Искљ." + +#: src/system-prompt.c:364 msgid "Passwords do not match." msgstr "Лозинке се не подударају." -#: src/system-prompt.c:380 +#: src/system-prompt.c:371 msgid "Password cannot be blank" msgstr "Лозинка не може бити празна" @@ -232,6 +325,19 @@ msgid "Torch" msgstr "Бакља" +#: src/ui/app-auth-prompt.ui:41 +msgid "Remember decision" +msgstr "Упамти одлуку" + +#: src/ui/app-auth-prompt.ui:54 src/ui/end-session-dialog.ui:54 +#| msgid "_Cancel" +msgid "Cancel" +msgstr "Откажи" + +#: src/ui/app-auth-prompt.ui:63 src/ui/end-session-dialog.ui:63 +msgid "Ok" +msgstr "У реду" + #: src/ui/app-grid-button.ui:49 msgid "App" msgstr "Програм" @@ -244,62 +350,87 @@ msgid "Add to _Favorites" msgstr "Додај у о_миљено" -#: src/ui/app-grid.ui:21 +#: src/ui/app-grid.ui:22 msgid "Search apps…" msgstr "Претражи апликације…" -#: src/ui/lockscreen.ui:37 +#: src/ui/app-grid.ui:169 +msgid "Show only adaptive apps" +msgstr "Прикажи само прилагодљиве програме" + +#: src/ui/end-session-dialog.ui:32 +msgid "Some applications are busy or have unsaved work" +msgstr "Неки програми су заузети или имају несачувани рад" + +#: src/ui/gtk-mount-prompt.ui:95 +msgid "User:" +msgstr "Корисник:" + +#: src/ui/gtk-mount-prompt.ui:118 +msgid "Domain:" +msgstr "Домен:" + +#: src/ui/gtk-mount-prompt.ui:151 +#| msgid "C_onnect" +msgid "Co_nnect" +msgstr "П_овежи се" + +#: src/ui/lockscreen.ui:43 msgid "Slide up to unlock" msgstr "Превуци нагоре за откључавање" -#: src/ui/lockscreen.ui:280 +#: src/ui/lockscreen.ui:285 msgid "Emergency" msgstr "Хитни позив" -#: src/ui/lockscreen.ui:296 +#: src/ui/lockscreen.ui:301 msgid "Unlock" msgstr "Откључај" -#: src/ui/network-auth-prompt.ui:90 +#: src/ui/lockscreen.ui:341 +msgid "Back" +msgstr "Назад" + +#: src/ui/network-auth-prompt.ui:6 src/ui/polkit-auth-prompt.ui:7 +#| msgid "Authenticate" +msgid "Authentication required" +msgstr "Потребно је потврђивање идентитета" + +#: src/ui/network-auth-prompt.ui:41 msgid "_Cancel" msgstr "_Откажи" -#: src/ui/network-auth-prompt.ui:106 +#: src/ui/network-auth-prompt.ui:59 msgid "C_onnect" msgstr "П_овежи се" -#: src/ui/polkit-auth-prompt.ui:105 -msgid "User:" -msgstr "Корисник:" +#: src/ui/polkit-auth-prompt.ui:123 +msgid "Authenticate" +msgstr "Потврди идентитет" -#: src/ui/system-prompt.ui:69 +#: src/ui/system-prompt.ui:63 msgid "Confirm:" msgstr "Потврди:" -#: src/ui/top-panel.ui:15 +#: src/ui/top-panel.ui:16 msgid "Lock Screen" msgstr "Закључавање екрана" -#: src/ui/top-panel.ui:22 +#: src/ui/top-panel.ui:23 msgid "Logout" msgstr "Одјава" -#: src/ui/top-panel.ui:29 -msgid "Restart" -msgstr "Поново покрени" - -#: src/ui/top-panel.ui:36 -msgid "Power Off" -msgstr "Искључивање" - #: src/wifiinfo.c:90 msgid "Wi-Fi" msgstr "Бежична" #. Translators: Refers to the cellular wireless network -#: src/wwaninfo.c:170 +#: src/wwaninfo.c:172 msgid "Cellular" msgstr "Мобилна" +#~ msgid "%d.%m.%y" +#~ msgstr "%d.%m.%y" + #~ msgid "Suspend" #~ msgstr "Обустави" diff -Nru phosh-0.8.0/po/sv.po phosh-0.13.1/po/sv.po --- phosh-0.8.0/po/sv.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/sv.po 2021-08-31 09:15:52.000000000 +0000 @@ -1,13 +1,14 @@ # Ludwig Johnson , 2018. #zanata # Nami , 2019. #zanata -# Anders Jonsson , 2020. +# Anders Jonsson , 2020, 2021. +# Luna Jernberg , 2021. # msgid "" msgstr "" "Project-Id-Version: phosh\n" -"Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/phosh/issues\n" -"POT-Creation-Date: 2020-12-24 15:33+0000\n" -"PO-Revision-Date: 2020-12-25 00:01+0100\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/phosh/issues\n" +"POT-Creation-Date: 2021-08-03 09:16+0000\n" +"PO-Revision-Date: 2021-08-03 16:29+0200\n" "Last-Translator: Anders Jonsson \n" "Language-Team: Swedish \n" "Language: sv\n" @@ -34,7 +35,7 @@ msgid "Application" msgstr "Program" -#: src/bt-info.c:92 src/feedbackinfo.c:51 +#: src/bt-info.c:92 src/feedbackinfo.c:51 src/rotateinfo.c:103 msgid "On" msgstr "På" @@ -46,10 +47,47 @@ msgid "Docked" msgstr "Dockad" -#: src/docked-info.c:195 +#: src/docked-info.c:81 src/docked-info.c:199 msgid "Undocked" msgstr "Ej dockad" +#: src/end-session-dialog.c:162 +msgid "Log Out" +msgstr "Logga ut" + +#: src/end-session-dialog.c:165 +#, c-format +msgid "%s will be logged out automatically in %d second." +msgid_plural "%s will be logged out automatically in %d seconds." +msgstr[0] "%s kommer att loggas ut automatiskt om %d sekund." +msgstr[1] "%s kommer att loggas ut automatiskt om %d sekunder." + +#: src/end-session-dialog.c:171 src/ui/top-panel.ui:37 +msgid "Power Off" +msgstr "Stäng av" + +#: src/end-session-dialog.c:172 +#, c-format +msgid "The system will power off automatically in %d second." +msgid_plural "The system will power off automatically in %d seconds." +msgstr[0] "Systemet kommer att stängas av automatiskt om %d sekund." +msgstr[1] "Systemet kommer att stängas av automatiskt om %d sekunder." + +#: src/end-session-dialog.c:178 src/ui/top-panel.ui:30 +msgid "Restart" +msgstr "Starta om" + +#: src/end-session-dialog.c:179 +#, c-format +msgid "The system will restart automatically in %d second." +msgid_plural "The system will restart automatically in %d seconds." +msgstr[0] "Systemet kommer att startas om automatiskt om %d sekund." +msgstr[1] "Systemet kommer att startas om automatiskt om %d sekunder." + +#: src/end-session-dialog.c:269 +msgid "Unknown application" +msgstr "Okänt program" + # Inget ljud, möjligen vibration #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles @@ -65,36 +103,68 @@ msgid "Silent" msgstr "Tyst" -#: src/lockscreen.c:86 src/ui/lockscreen.ui:234 +#: src/location-manager.c:268 +#, c-format +msgid "Allow '%s' to access your location information?" +msgstr "Ge ”%s” tillgång till din platsinformation?" + +#: src/location-manager.c:273 +msgid "Geolocation" +msgstr "Platsbestämning" + +#: src/location-manager.c:274 +msgid "Yes" +msgstr "Ja" + +#: src/location-manager.c:274 +msgid "No" +msgstr "Nej" + +#: src/lockscreen.c:152 src/ui/lockscreen.ui:239 msgid "Enter Passcode" msgstr "Ange lösenord" -#: src/lockscreen.c:265 +#: src/lockscreen.c:335 msgid "Checking…" msgstr "Kontrollerar…" #. Translators: This is a time format for a date in #. long format -#: src/lockscreen.c:343 +#: src/lockscreen.c:413 msgid "%A, %B %-e" msgstr "%A, %-e %B" #. Translators: Used when the title of a song is unknown -#: src/media-player.c:277 src/ui/media-player.ui:107 +#: src/media-player.c:279 src/ui/media-player.ui:107 msgid "Unknown Title" msgstr "Okänd titel" #. Translators: Used when the artist of a song is unknown -#: src/media-player.c:286 src/ui/media-player.ui:127 +#: src/media-player.c:288 src/ui/media-player.ui:127 msgid "Unknown Artist" msgstr "Okänd artist" -#: src/monitor-manager.c:71 +#: src/monitor-manager.c:114 msgid "Built-in display" msgstr "Inbyggd skärm" +#: src/monitor-manager.c:132 +#, c-format +msgctxt "" +"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgid "%s %s" +msgstr "%s %s" + +#: src/monitor-manager.c:139 +#, c-format +msgctxt "" +"This is a monitor vendor name followed by product/model name where size in " +"inches could not be calculated, e.g. Dell U2414H" +msgid "%s %s" +msgstr "%s %s" + #. Translators: An unknown monitor type -#: src/monitor-manager.c:75 +#: src/monitor-manager.c:148 msgid "Unknown" msgstr "Okänd" @@ -108,129 +178,135 @@ msgid "Enter password for the wifi network “%s”" msgstr "Ange lösenord för wifi-nätverket ”%s”" -#: src/notifications/mount-notification.c:137 +#: src/notifications/mount-notification.c:122 msgid "Open" msgstr "Öppna" -#: src/notifications/notification.c:381 src/notifications/notification.c:637 +#: src/notifications/notification.c:383 src/notifications/notification.c:639 msgid "Notification" msgstr "Avisering" #. Translators: Timestamp seconds suffix -#: src/notifications/timestamp-label.c:83 +#: src/notifications/timestamp-label.c:84 msgctxt "timestamp-suffix-seconds" msgid "s" msgstr "s" #. Translators: Timestamp minute suffix -#: src/notifications/timestamp-label.c:85 +#: src/notifications/timestamp-label.c:86 msgctxt "timestamp-suffix-minute" msgid "m" msgstr "m" #. Translators: Timestamp minutes suffix -#: src/notifications/timestamp-label.c:87 +#: src/notifications/timestamp-label.c:88 msgctxt "timestamp-suffix-minutes" msgid "m" msgstr "m" #. Translators: Timestamp hour suffix -#: src/notifications/timestamp-label.c:89 +#: src/notifications/timestamp-label.c:90 msgctxt "timestamp-suffix-hour" msgid "h" msgstr "h" #. Translators: Timestamp hours suffix -#: src/notifications/timestamp-label.c:91 +#: src/notifications/timestamp-label.c:92 msgctxt "timestamp-suffix-hours" msgid "h" msgstr "h" #. Translators: Timestamp day suffix -#: src/notifications/timestamp-label.c:93 +#: src/notifications/timestamp-label.c:94 msgctxt "timestamp-suffix-day" msgid "d" msgstr "d" #. Translators: Timestamp days suffix -#: src/notifications/timestamp-label.c:95 +#: src/notifications/timestamp-label.c:96 msgctxt "timestamp-suffix-days" msgid "d" msgstr "d" #. Translators: Timestamp month suffix -#: src/notifications/timestamp-label.c:97 +#: src/notifications/timestamp-label.c:98 msgctxt "timestamp-suffix-month" msgid "mo" msgstr "mån" #. Translators: Timestamp months suffix -#: src/notifications/timestamp-label.c:99 +#: src/notifications/timestamp-label.c:100 msgctxt "timestamp-suffix-months" msgid "mos" msgstr "mån" #. Translators: Timestamp year suffix -#: src/notifications/timestamp-label.c:101 +#: src/notifications/timestamp-label.c:102 msgctxt "timestamp-suffix-year" msgid "y" msgstr "å" #. Translators: Timestamp years suffix -#: src/notifications/timestamp-label.c:103 +#: src/notifications/timestamp-label.c:104 msgctxt "timestamp-suffix-years" msgid "y" msgstr "å" -#. Translators: this is the date in (short) number only format -#: src/notifications/timestamp-label.c:106 -msgid "%d.%m.%y" -msgstr "%y.%m.%d" - -#. Translators: Timestamp prefix (e.g. Over 5h) -#: src/notifications/timestamp-label.c:197 -msgid "Over" -msgstr "Över" - -#. Translators: Timestamp prefix (e.g. Almost 5h) -#: src/notifications/timestamp-label.c:202 -msgid "Almost" -msgstr "Nästan" - -#: src/notifications/timestamp-label.c:210 +#: src/notifications/timestamp-label.c:121 msgid "now" msgstr "nu" -#: src/polkit-auth-agent.c:231 +#. Translators: time difference "Over 5 years" +#: src/notifications/timestamp-label.c:189 +#, c-format +msgid "Over %dy" +msgstr "Över %då" + +#. Translators: time difference "almost 5 years" +#: src/notifications/timestamp-label.c:193 +#, c-format +msgid "Almost %dy" +msgstr "Nästan %då" + +#. Translators: a time difference like '<5m', if in doubt leave untranslated +#: src/notifications/timestamp-label.c:200 +#, c-format +msgid "%s%d%s" +msgstr "%s%d%s" + +#: src/polkit-auth-agent.c:228 msgid "Authentication dialog was dismissed by the user" msgstr "Autentiseringsdialogen avvisades av användaren" -#: src/polkit-auth-prompt.c:278 src/ui/network-auth-prompt.ui:130 -#: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 +#: src/polkit-auth-prompt.c:278 src/ui/gtk-mount-prompt.ui:21 +#: src/ui/network-auth-prompt.ui:83 src/ui/polkit-auth-prompt.ui:57 +#: src/ui/system-prompt.ui:33 msgid "Password:" msgstr "Lösenord:" -#: src/polkit-auth-prompt.c:324 +#: src/polkit-auth-prompt.c:325 msgid "Sorry, that didn’t work. Please try again." msgstr "Tyvärr, det fungerade inte. Var god försök igen." -#: src/polkit-auth-prompt.c:468 -msgid "Authenticate" -msgstr "Godkänn" - -#: src/rotateinfo.c:65 +#: src/rotateinfo.c:81 msgid "Portrait" msgstr "Stående" -#: src/rotateinfo.c:68 +#: src/rotateinfo.c:84 msgid "Landscape" msgstr "Liggande" -#: src/system-prompt.c:373 +#. Translators: Automatic screen orientation is either on (enabled) or off (locked/disabled) +#. Translators: Automatic screen orientation is off (locked/disabled) +#: src/rotateinfo.c:103 src/rotateinfo.c:186 +msgid "Off" +msgstr "Av" + +#: src/system-prompt.c:364 msgid "Passwords do not match." msgstr "Lösenorden matchar inte." -#: src/system-prompt.c:380 +#: src/system-prompt.c:371 msgid "Password cannot be blank" msgstr "Lösenordet får inte vara tomt" @@ -238,6 +314,18 @@ msgid "Torch" msgstr "Ficklampa" +#: src/ui/app-auth-prompt.ui:41 +msgid "Remember decision" +msgstr "Kom ihåg beslut" + +#: src/ui/app-auth-prompt.ui:54 src/ui/end-session-dialog.ui:54 +msgid "Cancel" +msgstr "Avbryt" + +#: src/ui/app-auth-prompt.ui:63 src/ui/end-session-dialog.ui:63 +msgid "Ok" +msgstr "OK" + #: src/ui/app-grid-button.ui:49 msgid "App" msgstr "App" @@ -250,59 +338,79 @@ msgid "Add to _Favorites" msgstr "Lägg till i _favoriter" -#: src/ui/app-grid.ui:21 +#: src/ui/app-grid.ui:22 msgid "Search apps…" msgstr "Sök appar…" -#: src/ui/lockscreen.ui:37 +#: src/ui/app-grid.ui:169 +msgid "Show only adaptive apps" +msgstr "Visa endast adaptiva appar" + +#: src/ui/end-session-dialog.ui:32 +msgid "Some applications are busy or have unsaved work" +msgstr "Några program är upptagna eller innehåller icke sparat arbete" + +#: src/ui/gtk-mount-prompt.ui:95 +msgid "User:" +msgstr "Användare:" + +#: src/ui/gtk-mount-prompt.ui:118 +msgid "Domain:" +msgstr "Domän:" + +#: src/ui/gtk-mount-prompt.ui:151 +msgid "Co_nnect" +msgstr "A_nslut" + +#: src/ui/lockscreen.ui:43 msgid "Slide up to unlock" msgstr "Svep uppåt för att låsa upp" -#: src/ui/lockscreen.ui:280 +#: src/ui/lockscreen.ui:285 msgid "Emergency" msgstr "Nödläge" -#: src/ui/lockscreen.ui:296 +#: src/ui/lockscreen.ui:301 msgid "Unlock" msgstr "Lås upp" -#: src/ui/network-auth-prompt.ui:89 +#: src/ui/lockscreen.ui:341 +msgid "Back" +msgstr "Bakåt" + +#: src/ui/network-auth-prompt.ui:6 src/ui/polkit-auth-prompt.ui:7 +msgid "Authentication required" +msgstr "Autentisering krävs" + +#: src/ui/network-auth-prompt.ui:41 msgid "_Cancel" msgstr "A_vbryt" -#: src/ui/network-auth-prompt.ui:105 +#: src/ui/network-auth-prompt.ui:59 msgid "C_onnect" msgstr "A_nslut" -#: src/ui/polkit-auth-prompt.ui:105 -msgid "User:" -msgstr "Användare:" +#: src/ui/polkit-auth-prompt.ui:123 +msgid "Authenticate" +msgstr "Godkänn" -#: src/ui/system-prompt.ui:69 +#: src/ui/system-prompt.ui:63 msgid "Confirm:" msgstr "Bekräfta:" -#: src/ui/top-panel.ui:15 +#: src/ui/top-panel.ui:16 msgid "Lock Screen" msgstr "Lås skärm" -#: src/ui/top-panel.ui:22 +#: src/ui/top-panel.ui:23 msgid "Logout" msgstr "Logga ut" -#: src/ui/top-panel.ui:29 -msgid "Restart" -msgstr "Starta om" - -#: src/ui/top-panel.ui:36 -msgid "Power Off" -msgstr "Stäng av" - #: src/wifiinfo.c:90 msgid "Wi-Fi" msgstr "Wi-Fi" #. Translators: Refers to the cellular wireless network -#: src/wwaninfo.c:170 +#: src/wwaninfo.c:172 msgid "Cellular" msgstr "Mobilt nätverk" diff -Nru phosh-0.8.0/po/tr.po phosh-0.13.1/po/tr.po --- phosh-0.8.0/po/tr.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/tr.po 2021-08-31 09:15:52.000000000 +0000 @@ -1,12 +1,12 @@ # Turkish translation of phosh. -# Emin Tufan Çetin , 2019-2020. +# Emin Tufan Çetin , 2019, 2020, 2021. # msgid "" msgstr "" "Project-Id-Version: phosh\n" "Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/phosh/issues\n" -"POT-Creation-Date: 2020-08-14 15:29+0000\n" -"PO-Revision-Date: 2020-09-29 14:55+0300\n" +"POT-Creation-Date: 2021-04-01 03:31+0000\n" +"PO-Revision-Date: 2021-04-05 12:35+0300\n" "Last-Translator: Emin Tufan Çetin \n" "Language-Team: Turkish \n" "Language: tr\n" @@ -29,76 +29,154 @@ msgid "Window management and application launching for mobile" msgstr "Mobil için pencere yönetimi ve uygulama başlatımı" -#: src/app-grid-button.c:530 +#: src/app-grid-button.c:536 msgid "Application" msgstr "Uygulama" -#: src/bt-info.c:89 src/feedbackinfo.c:48 +#: src/bt-info.c:92 src/feedbackinfo.c:51 src/rotateinfo.c:103 msgid "On" msgstr "Açık" -#: src/bt-info.c:91 +#: src/bt-info.c:94 msgid "Bluetooth" msgstr "Bluetooth" +#: src/docked-info.c:81 +msgid "Docked" +msgstr "Yuvada" + +#: src/docked-info.c:81 src/docked-info.c:195 +msgid "Undocked" +msgstr "Yuvada Değil" + +#: src/end-session-dialog.c:162 +msgid "Log Out" +msgstr "Oturumu Kapat" + +#: src/end-session-dialog.c:165 +#, c-format +msgid "%s will be logged out automatically in %d second." +msgid_plural "%s will be logged out automatically in %d seconds." +msgstr[0] "%s oturumu %d saniye içinde kendiliğinden kapatılacak." + +#: src/end-session-dialog.c:171 src/ui/top-panel.ui:37 +msgid "Power Off" +msgstr "Gücü Kapat" + +#: src/end-session-dialog.c:172 +#, c-format +msgid "The system will power off automatically in %d second." +msgid_plural "The system will power off automatically in %d seconds." +msgstr[0] "Sistem %d saniye içinde kendiliğinden kapanacak." + +#: src/end-session-dialog.c:178 src/ui/top-panel.ui:30 +msgid "Restart" +msgstr "Yeniden Başlat" + +#: src/end-session-dialog.c:179 +#, c-format +msgid "The system will restart automatically in %d second." +msgid_plural "The system will restart automatically in %d seconds." +msgstr[0] "Sistem %d saniye içinde kendiliğinden yeniden başlayacak." + +#: src/end-session-dialog.c:270 +msgid "Unknown application" +msgstr "Bilinmeyen uygulama" + #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details -#: src/feedbackinfo.c:41 +#: src/feedbackinfo.c:44 msgid "Quiet" msgstr "Titreşim" #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details -#: src/feedbackinfo.c:46 +#: src/feedbackinfo.c:49 msgid "Silent" msgstr "Sessiz" -#: src/lockscreen.c:84 src/ui/lockscreen.ui:234 +#: src/location-manager.c:246 +#, c-format +msgid "Allow '%s' to access your location information?" +msgstr "'%s' konum bilginize erişebilsin mi?" + +#: src/location-manager.c:251 +msgid "Geolocation" +msgstr "Coğrafi Konum" + +#: src/location-manager.c:252 +msgid "Yes" +msgstr "Evet" + +#: src/location-manager.c:252 +msgid "No" +msgstr "Hayır" + +#: src/lockscreen.c:85 src/ui/lockscreen.ui:234 msgid "Enter Passcode" msgstr "Parolayı Gir" -#: src/lockscreen.c:263 +#: src/lockscreen.c:264 msgid "Checking…" msgstr "Denetleniyor…" #. Translators: This is a time format for a date in #. long format -#: src/lockscreen.c:341 +#: src/lockscreen.c:342 msgid "%A, %B %-e" msgstr "%A, %B %-e" #. Translators: Used when the title of a song is unknown -#: src/media-player.c:263 src/ui/media-player.ui:107 +#: src/media-player.c:277 src/ui/media-player.ui:107 msgid "Unknown Title" msgstr "Bilinmeyen Başlık" #. Translators: Used when the artist of a song is unknown -#: src/media-player.c:272 src/ui/media-player.ui:127 +#: src/media-player.c:286 src/ui/media-player.ui:127 msgid "Unknown Artist" msgstr "Bilinmeyen Sanatçı" -#: src/monitor-manager.c:58 +#: src/monitor-manager.c:112 msgid "Built-in display" msgstr "İç ekran" +#: src/monitor-manager.c:130 +#, c-format +msgctxt "" +"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgid "%s %s" +msgstr "%s %s" + +#: src/monitor-manager.c:137 +#, c-format +msgctxt "" +"This is a monitor vendor name followed by product/model name where size in " +"inches could not be calculated, e.g. Dell U2414H" +msgid "%s %sn" +msgstr "%s %sn" + #. Translators: An unknown monitor type -#: src/monitor-manager.c:62 +#: src/monitor-manager.c:146 msgid "Unknown" msgstr "Bilinmeyen" -#: src/network-auth-prompt.c:184 +#: src/network-auth-prompt.c:187 #, c-format msgid "Authentication type of wifi network “%s” not supported" msgstr "“%s” wifi ağının yetkilendirme türü desteklenmiyor" -#: src/network-auth-prompt.c:189 +#: src/network-auth-prompt.c:192 #, c-format msgid "Enter password for the wifi network “%s”" msgstr "“%s” wifi ağı için parola gir" -#: src/notifications/notification.c:382 src/notifications/notification.c:601 +#: src/notifications/mount-notification.c:137 +msgid "Open" +msgstr "Aç" + +#: src/notifications/notification.c:381 src/notifications/notification.c:637 msgid "Notification" msgstr "Bildirim" @@ -168,54 +246,79 @@ msgid "y" msgstr "y" -#. Translators: this is the date in (short) number only format -#: src/notifications/timestamp-label.c:107 -msgid "%d.%m.%y" -msgstr "%d.%m.%y" - -#. Translators: Timestamp prefix (e.g. Over 5h) -#: src/notifications/timestamp-label.c:198 -msgid "Over" -msgstr "Geçik" - -#. Translators: Timestamp prefix (e.g. Almost 5h) -#: src/notifications/timestamp-label.c:203 -msgid "Almost" -msgstr "Neredeyse" +#: src/notifications/timestamp-label.c:121 +msgid "now" +msgstr "şimdi" + +#. Translators: time difference "Over 5 years" +#: src/notifications/timestamp-label.c:189 +#, c-format +msgid "Over %dy" +msgstr "%d yılı aşkın" -#: src/polkit-auth-agent.c:229 +#. Translators: time difference "almost 5 years" +#: src/notifications/timestamp-label.c:193 +#, c-format +msgid "Almost %dy" +msgstr "Neredeyse %d yıl" + +#. Translators: a time difference like '<5m', if in doubt leave untranslated +#: src/notifications/timestamp-label.c:200 +#, c-format +msgid "%s%d%s" +msgstr "%s%d%s" + +#: src/polkit-auth-agent.c:225 msgid "Authentication dialog was dismissed by the user" msgstr "Kullanıcı, yetkilendirme kutusunu görmezden geldi" -#: src/polkit-auth-prompt.c:276 src/ui/network-auth-prompt.ui:128 -#: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 +#: src/polkit-auth-prompt.c:278 src/ui/network-auth-prompt.ui:85 +#: src/ui/polkit-auth-prompt.ui:57 src/ui/system-prompt.ui:33 msgid "Password:" msgstr "Parola:" -#: src/polkit-auth-prompt.c:322 +#: src/polkit-auth-prompt.c:325 msgid "Sorry, that didn’t work. Please try again." msgstr "Üzgünüz, işe yaramadı. Lütfen yeniden deneyin." -#: src/polkit-auth-prompt.c:488 -msgid "Authenticate" -msgstr "Yetkilendir" - -#: src/rotateinfo.c:46 +#: src/rotateinfo.c:81 msgid "Portrait" msgstr "Dikey" -#: src/rotateinfo.c:49 +#: src/rotateinfo.c:84 msgid "Landscape" msgstr "Yatay" -#: src/system-prompt.c:371 +#. Translators: Automatic screen orientation is either on (enabled) or off (locked/disabled) +#. Translators: Automatic screen orientation is off (locked/disabled) +#: src/rotateinfo.c:103 src/rotateinfo.c:183 +msgid "Off" +msgstr "Kapalı" + +#: src/system-prompt.c:364 msgid "Passwords do not match." msgstr "Parolalar eşleşmedi." -#: src/system-prompt.c:378 +#: src/system-prompt.c:371 msgid "Password cannot be blank" msgstr "Parola boş olamaz" +#: src/torch-info.c:80 +msgid "Torch" +msgstr "Fener" + +#: src/ui/app-auth-prompt.ui:41 +msgid "Remember decision" +msgstr "Kararı anımsa" + +#: src/ui/app-auth-prompt.ui:55 src/ui/end-session-dialog.ui:50 +msgid "Cancel" +msgstr "İptal" + +#: src/ui/app-auth-prompt.ui:66 src/ui/end-session-dialog.ui:61 +msgid "Ok" +msgstr "Tamam" + #: src/ui/app-grid-button.ui:49 msgid "App" msgstr "Uygulama" @@ -232,6 +335,10 @@ msgid "Search apps…" msgstr "Uygulama ara…" +#: src/ui/end-session-dialog.ui:32 +msgid "Some applications are busy or have unsaved work" +msgstr "Bazı uygulamalar meşgul ya da kaydedilmemiş verisi var" + #: src/ui/lockscreen.ui:37 msgid "Slide up to unlock" msgstr "Açmak için kaldır" @@ -244,52 +351,39 @@ msgid "Unlock" msgstr "Kilidi Aç" -#: src/ui/network-auth-prompt.ui:90 +#: src/ui/network-auth-prompt.ui:6 src/ui/polkit-auth-prompt.ui:7 +msgid "Authentication required" +msgstr "Yetkilendirme gerekli" + +#: src/ui/network-auth-prompt.ui:42 msgid "_Cancel" msgstr "_İptal" -#: src/ui/network-auth-prompt.ui:106 +#: src/ui/network-auth-prompt.ui:61 msgid "C_onnect" msgstr "_Bağlan" -#: src/ui/polkit-auth-prompt.ui:105 -msgid "User:" -msgstr "Kullanıcı:" +#: src/ui/polkit-auth-prompt.ui:125 +msgid "Authenticate" +msgstr "Yetkilendir" -#: src/ui/system-prompt.ui:69 +#: src/ui/system-prompt.ui:63 msgid "Confirm:" msgstr "Doğrula:" -#: src/ui/top-panel.ui:15 +#: src/ui/top-panel.ui:16 msgid "Lock Screen" msgstr "Ekranı Kilitle" -#: src/ui/top-panel.ui:22 +#: src/ui/top-panel.ui:23 msgid "Logout" msgstr "Oturumu Kapat" -#: src/ui/top-panel.ui:29 -msgid "Restart" -msgstr "Yeniden Başlat" - -#: src/ui/top-panel.ui:36 -msgid "Power Off" -msgstr "Gücü Kapat" - -#: src/wifiinfo.c:88 +#: src/wifiinfo.c:90 msgid "Wi-Fi" msgstr "Wi-Fi" #. Translators: Refers to the cellular wireless network -#: src/wwaninfo.c:168 +#: src/wwaninfo.c:172 msgid "Cellular" msgstr "Hücresel" - -#~ msgid "Unknown artist" -#~ msgstr "Bilinmeyen sanatçı" - -#~ msgid "Unknown Song" -#~ msgstr "Bilinmeyen Şarkı" - -#~ msgid "Suspend" -#~ msgstr "Askıya Al" diff -Nru phosh-0.8.0/po/uk.po phosh-0.13.1/po/uk.po --- phosh-0.8.0/po/uk.po 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/po/uk.po 2021-08-31 09:15:52.000000000 +0000 @@ -7,18 +7,17 @@ msgid "" msgstr "" "Project-Id-Version: phosh\n" -"Report-Msgid-Bugs-To: https://source.puri.sm/Librem5/phosh/issues\n" -"POT-Creation-Date: 2021-01-16 03:33+0000\n" -"PO-Revision-Date: 2021-01-16 09:10+0200\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/Phosh/phosh/issues\n" +"POT-Creation-Date: 2021-08-03 09:16+0000\n" +"PO-Revision-Date: 2021-08-03 16:28+0300\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Lokalize 20.11.70\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<" -"=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" +"X-Generator: Lokalize 20.12.0\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" #. Translators: this is the session name, no need to translate it #: data/phosh.session.desktop.in.in:4 @@ -37,9 +36,9 @@ msgid "Application" msgstr "Програма" -#: src/bt-info.c:92 src/feedbackinfo.c:51 +#: src/bt-info.c:92 src/feedbackinfo.c:51 src/rotateinfo.c:103 msgid "On" -msgstr "Увімкнено" +msgstr "❙" #: src/bt-info.c:94 msgid "Bluetooth" @@ -49,10 +48,50 @@ msgid "Docked" msgstr "Зафіксовано" -#: src/docked-info.c:195 +#: src/docked-info.c:81 src/docked-info.c:199 msgid "Undocked" msgstr "Від'єднано" +#: src/end-session-dialog.c:162 +msgid "Log Out" +msgstr "Вийти" + +#: src/end-session-dialog.c:165 +#, c-format +msgid "%s will be logged out automatically in %d second." +msgid_plural "%s will be logged out automatically in %d seconds." +msgstr[0] "Вихід з системи %s буде здійснено автоматично за %d секунду." +msgstr[1] "Вихід з системи %s буде здійснено автоматично за %d секунди." +msgstr[2] "Вихід з системи %s буде здійснено автоматично за %d секунд." + +#: src/end-session-dialog.c:171 src/ui/top-panel.ui:37 +msgid "Power Off" +msgstr "Вимкнути" + +#: src/end-session-dialog.c:172 +#, c-format +msgid "The system will power off automatically in %d second." +msgid_plural "The system will power off automatically in %d seconds." +msgstr[0] "Система автоматично вимкнеться за %d секунду." +msgstr[1] "Система автоматично вимкнеться за %d секунди." +msgstr[2] "Система автоматично вимкнеться за %d секунд." + +#: src/end-session-dialog.c:178 src/ui/top-panel.ui:30 +msgid "Restart" +msgstr "Перезапустити" + +#: src/end-session-dialog.c:179 +#, c-format +msgid "The system will restart automatically in %d second." +msgid_plural "The system will restart automatically in %d seconds." +msgstr[0] "Система автоматично перезапуститься за %d секунду." +msgstr[1] "Система автоматично перезапуститься за %d секунди." +msgstr[2] "Система автоматично перезапуститься за %d секунд." + +#: src/end-session-dialog.c:269 +msgid "Unknown application" +msgstr "Невідома програма" + #. Translators: quiet and silent are fbd profiles names: #. see https://source.puri.sm/Librem5/feedbackd#profiles #. for details @@ -67,51 +106,67 @@ msgid "Silent" msgstr "Беззвучно" -#: src/lockscreen.c:86 src/ui/lockscreen.ui:234 +#: src/location-manager.c:268 +#, c-format +msgid "Allow '%s' to access your location information?" +msgstr "Дозволити «%s» доступ до даних щодо вашого місця перебування?" + +#: src/location-manager.c:273 +msgid "Geolocation" +msgstr "Геопозиціювання" + +#: src/location-manager.c:274 +msgid "Yes" +msgstr "Так" + +#: src/location-manager.c:274 +msgid "No" +msgstr "Ні" + +#: src/lockscreen.c:152 src/ui/lockscreen.ui:239 msgid "Enter Passcode" msgstr "Уведіть пароль" -#: src/lockscreen.c:265 +#: src/lockscreen.c:335 msgid "Checking…" msgstr "Звіряю…" #. Translators: This is a time format for a date in #. long format -#: src/lockscreen.c:343 +#: src/lockscreen.c:413 msgid "%A, %B %-e" msgstr "%A, %-d %B" #. Translators: Used when the title of a song is unknown -#: src/media-player.c:277 src/ui/media-player.ui:107 +#: src/media-player.c:279 src/ui/media-player.ui:107 msgid "Unknown Title" msgstr "Невідома назва" #. Translators: Used when the artist of a song is unknown -#: src/media-player.c:286 src/ui/media-player.ui:127 +#: src/media-player.c:288 src/ui/media-player.ui:127 msgid "Unknown Artist" msgstr "Невідомий виконавець" -#: src/monitor-manager.c:108 +#: src/monitor-manager.c:114 msgid "Built-in display" msgstr "Вбудований дисплей" -#: src/monitor-manager.c:126 +#: src/monitor-manager.c:132 #, c-format -msgctxt "" -"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" +msgctxt "This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'" msgid "%s %s" msgstr "%s %s" -#: src/monitor-manager.c:133 +#: src/monitor-manager.c:139 #, c-format msgctxt "" "This is a monitor vendor name followed by product/model name where size in " "inches could not be calculated, e.g. Dell U2414H" -msgid "%s %sn" -msgstr "%s %sn" +msgid "%s %s" +msgstr "%s %s" #. Translators: An unknown monitor type -#: src/monitor-manager.c:142 +#: src/monitor-manager.c:148 msgid "Unknown" msgstr "Нетиповий" @@ -125,11 +180,11 @@ msgid "Enter password for the wifi network “%s”" msgstr "Введіть пароль до мережі wifi «%s»" -#: src/notifications/mount-notification.c:137 +#: src/notifications/mount-notification.c:122 msgid "Open" msgstr "Відкрити" -#: src/notifications/notification.c:381 src/notifications/notification.c:637 +#: src/notifications/notification.c:383 src/notifications/notification.c:639 msgid "Notification" msgstr "Сповіщення" @@ -206,14 +261,12 @@ #. Translators: time difference "Over 5 years" #: src/notifications/timestamp-label.c:189 #, c-format -#| msgid "Over" msgid "Over %dy" msgstr "Понад %dр." #. Translators: time difference "almost 5 years" #: src/notifications/timestamp-label.c:193 #, c-format -#| msgid "Almost" msgid "Almost %dy" msgstr "Майже %dр." @@ -223,12 +276,13 @@ msgid "%s%d%s" msgstr "%s%d%s" -#: src/polkit-auth-agent.c:232 +#: src/polkit-auth-agent.c:228 msgid "Authentication dialog was dismissed by the user" msgstr "Користувач перервав діалог автентифікації" -#: src/polkit-auth-prompt.c:278 src/ui/network-auth-prompt.ui:130 -#: src/ui/polkit-auth-prompt.ui:41 src/ui/system-prompt.ui:39 +#: src/polkit-auth-prompt.c:278 src/ui/gtk-mount-prompt.ui:21 +#: src/ui/network-auth-prompt.ui:83 src/ui/polkit-auth-prompt.ui:57 +#: src/ui/system-prompt.ui:33 msgid "Password:" msgstr "Пароль:" @@ -236,23 +290,25 @@ msgid "Sorry, that didn’t work. Please try again." msgstr "На жаль, це не спрацювало. Будь ласка, спробуйте ще." -#: src/polkit-auth-prompt.c:470 -msgid "Authenticate" -msgstr "Автентифікуватися" - -#: src/rotateinfo.c:65 +#: src/rotateinfo.c:81 msgid "Portrait" msgstr "Книжкова" -#: src/rotateinfo.c:68 +#: src/rotateinfo.c:84 msgid "Landscape" msgstr "Альбомна" -#: src/system-prompt.c:375 +#. Translators: Automatic screen orientation is either on (enabled) or off (locked/disabled) +#. Translators: Automatic screen orientation is off (locked/disabled) +#: src/rotateinfo.c:103 src/rotateinfo.c:186 +msgid "Off" +msgstr "○" + +#: src/system-prompt.c:364 msgid "Passwords do not match." msgstr "Паролі не збігаються." -#: src/system-prompt.c:382 +#: src/system-prompt.c:371 msgid "Password cannot be blank" msgstr "Пароль не може бути порожнім" @@ -260,6 +316,18 @@ msgid "Torch" msgstr "Факел" +#: src/ui/app-auth-prompt.ui:41 +msgid "Remember decision" +msgstr "Запам'ятати вибір" + +#: src/ui/app-auth-prompt.ui:54 src/ui/end-session-dialog.ui:54 +msgid "Cancel" +msgstr "Скасувати" + +#: src/ui/app-auth-prompt.ui:63 src/ui/end-session-dialog.ui:63 +msgid "Ok" +msgstr "Гаразд" + #: src/ui/app-grid-button.ui:49 msgid "App" msgstr "Програма" @@ -272,59 +340,80 @@ msgid "Add to _Favorites" msgstr "Додати до _вибраних" -#: src/ui/app-grid.ui:21 +#: src/ui/app-grid.ui:22 msgid "Search apps…" msgstr "Шукати серед програм…" -#: src/ui/lockscreen.ui:37 +#: src/ui/app-grid.ui:169 +msgid "Show only adaptive apps" +msgstr "Показувати лише адаптивні програми" + +#: src/ui/end-session-dialog.ui:32 +msgid "Some applications are busy or have unsaved work" +msgstr "Деякі програми зайняті або мають незбережені дані" + +#: src/ui/gtk-mount-prompt.ui:95 +msgid "User:" +msgstr "Користувач:" + +#: src/ui/gtk-mount-prompt.ui:118 +msgid "Domain:" +msgstr "Домен:" + +#: src/ui/gtk-mount-prompt.ui:151 +msgid "Co_nnect" +msgstr "З'єд_натися" + +#: src/ui/lockscreen.ui:43 msgid "Slide up to unlock" msgstr "Протягніть угору, щоб розблокувати" -#: src/ui/lockscreen.ui:280 +#: src/ui/lockscreen.ui:285 msgid "Emergency" msgstr "Екстрений виклик" -#: src/ui/lockscreen.ui:296 +#: src/ui/lockscreen.ui:301 msgid "Unlock" msgstr "Розблокувати" -#: src/ui/network-auth-prompt.ui:89 +#: src/ui/lockscreen.ui:341 +msgid "Back" +msgstr "" +"Назад" + +#: src/ui/network-auth-prompt.ui:6 src/ui/polkit-auth-prompt.ui:7 +msgid "Authentication required" +msgstr "Слід пройти розпізнавання" + +#: src/ui/network-auth-prompt.ui:41 msgid "_Cancel" msgstr "_Скасувати" -#: src/ui/network-auth-prompt.ui:105 +#: src/ui/network-auth-prompt.ui:59 msgid "C_onnect" msgstr "З'_єднатися" -#: src/ui/polkit-auth-prompt.ui:105 -msgid "User:" -msgstr "Користувач:" +#: src/ui/polkit-auth-prompt.ui:123 +msgid "Authenticate" +msgstr "Автентифікуватися" -#: src/ui/system-prompt.ui:69 +#: src/ui/system-prompt.ui:63 msgid "Confirm:" msgstr "Підтвердіть:" -#: src/ui/top-panel.ui:15 +#: src/ui/top-panel.ui:16 msgid "Lock Screen" msgstr "Заблокувати екран" -#: src/ui/top-panel.ui:22 +#: src/ui/top-panel.ui:23 msgid "Logout" msgstr "Вийти" -#: src/ui/top-panel.ui:29 -msgid "Restart" -msgstr "Перезапустити" - -#: src/ui/top-panel.ui:36 -msgid "Power Off" -msgstr "Вимкнути" - #: src/wifiinfo.c:90 msgid "Wi-Fi" msgstr "Wi-Fi" #. Translators: Refers to the cellular wireless network -#: src/wwaninfo.c:170 +#: src/wwaninfo.c:172 msgid "Cellular" msgstr "Стільниковий" diff -Nru phosh-0.8.0/protocol/meson.build phosh-0.13.1/protocol/meson.build --- phosh-0.8.0/protocol/meson.build 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/protocol/meson.build 2021-08-31 09:15:52.000000000 +0000 @@ -13,13 +13,14 @@ '/'.join([wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml']), 'gamma-control.xml', 'idle.xml', - 'wlr-screencopy-unstable-v1.xml', 'phosh-private.xml', + 'virtual-keyboard-unstable-v1.xml', 'wlr-foreign-toplevel-management-unstable-v1.xml', 'wlr-input-inhibitor-unstable-v1.xml', 'wlr-layer-shell-unstable-v1.xml', 'wlr-output-management-unstable-v1.xml', 'wlr-output-power-management-unstable-v1.xml', + 'wlr-screencopy-unstable-v1.xml', ] wl_proto_sources = [] foreach proto: wl_protos diff -Nru phosh-0.8.0/protocol/virtual-keyboard-unstable-v1.xml phosh-0.13.1/protocol/virtual-keyboard-unstable-v1.xml --- phosh-0.8.0/protocol/virtual-keyboard-unstable-v1.xml 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/protocol/virtual-keyboard-unstable-v1.xml 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,113 @@ + + + + Copyright © 2008-2011 Kristian Høgsberg + Copyright © 2010-2013 Intel Corporation + Copyright © 2012-2013 Collabora, Ltd. + Copyright © 2018 Purism SPC + + 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. + + + + + The virtual keyboard provides an application with requests which emulate + the behaviour of a physical keyboard. + + This interface can be used by clients on its own to provide raw input + events, or it can accompany the input method protocol. + + + + + Provide a file descriptor to the compositor which can be + memory-mapped to provide a keyboard mapping description. + + Format carries a value from the keymap_format enumeration. + + + + + + + + + + + + + A key was pressed or released. + The time argument is a timestamp with millisecond granularity, with an + undefined base. All requests regarding a single object must share the + same clock. + + Keymap must be set before issuing this request. + + State carries a value from the key_state enumeration. + + + + + + + + + Notifies the compositor that the modifier and/or group state has + changed, and it should update state. + + The client should use wl_keyboard.modifiers event to synchronize its + internal state with seat state. + + Keymap must be set before issuing this request. + + + + + + + + + + + + + + + A virtual keyboard manager allows an application to provide keyboard + input events as if they came from a physical keyboard. + + + + + + + + + Creates a new virtual keyboard associated to a seat. + + If the compositor enables a keyboard to perform arbitrary actions, it + should present an error when an untrusted client requests a new + keyboard. + + + + + + diff -Nru phosh-0.8.0/README.md phosh-0.13.1/README.md --- phosh-0.8.0/README.md 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/README.md 2021-08-31 09:15:52.000000000 +0000 @@ -1,5 +1,4 @@ # Phosh -[![Code coverage](https://source.puri.sm/Librem5/phosh/badges/master/coverage.svg)](https://source.puri.sm/Librem5/phosh/commits/master) a pure wayland shell for mobile devices like Purism's Librem 5. @@ -10,7 +9,7 @@ ## Getting the source ```sh - git clone https://source.puri.sm/Librem5/phosh + git clone https://gitlab.gnome.org/World/Phosh/phosh cd phosh ``` @@ -27,7 +26,7 @@ For an explicit list of dependencies check the `Build-Depends` entry in the [debian/control][] file. -If your distro doesn't ship [libhandy](https://source.puri.sm/Librem5/libhandy) +If your distro doesn't ship [libhandy](https://gitlab.gnome.org/GNOME/libhandy) you need to build that from source. More details are in the [gitlab-ci.yml][] file. @@ -103,13 +102,17 @@ . # Getting in Touch -* Issue tracker: https://source.puri.sm/Librem5/phosh +* Issue tracker: https://gitlab.gnome.org/World/Phosh/phosh/issues * Mailing list: https://lists.community.puri.sm/listinfo/librem-5-dev * Matrix: https://im.puri.sm/#/room/#phosh:talk.puri.sm * XMPP: phosh@conference.sigxcpu.org For details see the [developer documentation](https://developer.puri.sm/Contact.html). -[gitlab-ci.yml]: https://source.puri.sm/Librem5/phosh/blob/master/.gitlab-ci.yml -[debian/control]: https://source.puri.sm/Librem5/phosh/blob/master/debian/control -[phoc]: https://source.puri.sm/Librem5/phoc +### Development Documentation + +API documentation is at https://world.pages.gitlab.gnome.org/Phosh/phosh + +[gitlab-ci.yml]: https://gitlab.gnome.org/World/Phosh/phosh/blob/master/.gitlab-ci.yml +[debian/control]: https://gitlab.gnome.org/World/Phosh/phosh/blob/master/debian/control +[phoc]: https://gitlab.gnome.org/World/Phosh/phoc diff -Nru phosh-0.8.0/src/app-auth-prompt.c phosh-0.13.1/src/app-auth-prompt.c --- phosh-0.8.0/src/app-auth-prompt.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/app-auth-prompt.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-app-auth-prompt" + +#include "config.h" + +#include "app-auth-prompt.h" + +#include + +/** + * SECTION:app-auth-prompt + * @short_description: A system modal prompt to authorize applications + * @Title: PhoshAppAuthPrompt + * + * The #PhoshAppAuthPrompt is used to authorize applications. It's used + * by the #PhoshLocationManager and will later on be used for org.freedesktop.impl.Access. + */ + +enum { + CLOSED, + N_SIGNALS +}; +static guint signals[N_SIGNALS] = { 0 }; + + +enum { + PROP_0, + + PROP_ICON, + PROP_SUBTITLE, + PROP_BODY, + PROP_DENY_LABEL, + PROP_GRANT_LABEL, + PROP_OFFER_REMEMBER, + PROP_LAST_PROP, +}; +static GParamSpec *props[PROP_LAST_PROP]; + + +typedef struct _PhoshAppAuthPrompt { + PhoshSystemModalDialog parent; + + GIcon *icon; + char *subtitle; + char *body; + char *deny_label; + char *grant_label; + gboolean offer_remember; + + GtkWidget *icon_app; + GtkWidget *lbl_subtitle; + GtkWidget *lbl_body; + GtkWidget *btn_grant; + GtkWidget *btn_deny; + GtkWidget *checkbtn_remember; + + gboolean grant_access; + gboolean remember; +} PhoshAppAuthPrompt; + + +G_DEFINE_TYPE (PhoshAppAuthPrompt, phosh_app_auth_prompt, PHOSH_TYPE_SYSTEM_MODAL_DIALOG) + + +static void +phosh_app_auth_prompt_set_property (GObject *obj, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshAppAuthPrompt *self = PHOSH_APP_AUTH_PROMPT (obj); + + switch (prop_id) { + case PROP_ICON: + self->icon = g_value_dup_object (value); + break; + case PROP_SUBTITLE: + self->subtitle = g_value_dup_string (value); + break; + case PROP_BODY: + self->body = g_value_dup_string (value); + break; + case PROP_GRANT_LABEL: + self->grant_label = g_value_dup_string (value); + break; + case PROP_DENY_LABEL: + self->deny_label = g_value_dup_string (value); + break; + case PROP_OFFER_REMEMBER: + self->offer_remember = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + + +static void +phosh_app_auth_prompt_get_property (GObject *obj, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshAppAuthPrompt *self = PHOSH_APP_AUTH_PROMPT (obj); + + switch (prop_id) { + case PROP_ICON: + g_value_set_object (value, self->icon); + break; + case PROP_SUBTITLE: + g_value_set_string (value, self->subtitle); + break; + case PROP_BODY: + g_value_set_string (value, self->body); + break; + case PROP_GRANT_LABEL: + g_value_set_string (value, self->grant_label); + break; + case PROP_DENY_LABEL: + g_value_set_string (value, self->deny_label); + break; + case PROP_OFFER_REMEMBER: + g_value_set_boolean (value, self->offer_remember); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + + +static void +on_btn_grant_clicked (PhoshAppAuthPrompt *self, GtkButton *btn) +{ + self->grant_access = TRUE; + self->remember = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->checkbtn_remember)); + + g_signal_emit (self, signals[CLOSED], 0); + gtk_widget_destroy (GTK_WIDGET (self)); +} + + +static void +on_dialog_canceled (PhoshAppAuthPrompt *self) +{ + g_return_if_fail (PHOSH_IS_APP_AUTH_PROMPT (self)); + self->remember = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->checkbtn_remember)); + + g_signal_emit (self, signals[CLOSED], 0); + gtk_widget_destroy (GTK_WIDGET (self)); +} + + + +static void +phosh_app_auth_prompt_finalize (GObject *obj) +{ + PhoshAppAuthPrompt *self = PHOSH_APP_AUTH_PROMPT (obj); + + g_clear_object (&self->icon); + g_clear_pointer (&self->subtitle, g_free); + g_clear_pointer (&self->body, g_free); + g_clear_pointer (&self->grant_label, g_free); + g_clear_pointer (&self->deny_label, g_free); + + G_OBJECT_CLASS (phosh_app_auth_prompt_parent_class)->finalize (obj); +} + + +static void +phosh_app_auth_prompt_constructed (GObject *object) +{ + PhoshAppAuthPrompt *self = PHOSH_APP_AUTH_PROMPT (object); + + G_OBJECT_CLASS (phosh_app_auth_prompt_parent_class)->constructed (object); + + g_object_bind_property (self, "subtitle", self->lbl_subtitle, "label", G_BINDING_DEFAULT); + g_object_bind_property (self, "body", self->lbl_body, "label", G_BINDING_DEFAULT); + g_object_bind_property (self, "grant-label", self->btn_grant, "label", G_BINDING_DEFAULT); + g_object_bind_property (self, "deny-label", self->btn_deny, "label", G_BINDING_DEFAULT); + g_object_bind_property (self, "icon", self->icon_app, "gicon", G_BINDING_DEFAULT); + g_object_bind_property (self, "offer-remember", self->checkbtn_remember, "visible", G_BINDING_DEFAULT); + + gtk_widget_grab_default (self->btn_grant); +} + + +static void +phosh_app_auth_prompt_class_init (PhoshAppAuthPromptClass *klass) +{ + GObjectClass *object_class = (GObjectClass *)klass; + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->get_property = phosh_app_auth_prompt_get_property; + object_class->set_property = phosh_app_auth_prompt_set_property; + object_class->constructed = phosh_app_auth_prompt_constructed; + object_class->finalize = phosh_app_auth_prompt_finalize; + + props[PROP_ICON] = + g_param_spec_object ( + "icon", + "Icon", + "The auth dialog icon", + G_TYPE_ICON, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + props[PROP_SUBTITLE] = + g_param_spec_string ( + "subtitle", + "Subtitle", + "The auth dialog subtitle", + "", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + props[PROP_BODY] = + g_param_spec_string ( + "body", + "Body", + "The auth dialog body", + "", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + props[PROP_GRANT_LABEL] = + g_param_spec_string ( + "grant-label", + "Grant label", + "The auth dialog's grant access button label", + "", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + props[PROP_DENY_LABEL] = + g_param_spec_string ( + "deny-label", + "Deny label", + "The auth dialog's deny access button label", + "", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + props[PROP_OFFER_REMEMBER] = + g_param_spec_boolean ( + "offer-remember", + "Offer Remember", + "Whether to offer to remember the auth decision result", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); + + signals[CLOSED] = g_signal_new ("closed", + G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, + NULL, G_TYPE_NONE, 0); + + gtk_widget_class_set_template_from_resource (widget_class, + "/sm/puri/phosh/ui/app-auth-prompt.ui"); + gtk_widget_class_bind_template_child (widget_class, PhoshAppAuthPrompt, icon_app); + gtk_widget_class_bind_template_child (widget_class, PhoshAppAuthPrompt, lbl_subtitle); + gtk_widget_class_bind_template_child (widget_class, PhoshAppAuthPrompt, lbl_body); + gtk_widget_class_bind_template_child (widget_class, PhoshAppAuthPrompt, btn_grant); + gtk_widget_class_bind_template_child (widget_class, PhoshAppAuthPrompt, btn_deny); + gtk_widget_class_bind_template_child (widget_class, PhoshAppAuthPrompt, checkbtn_remember); + gtk_widget_class_bind_template_callback (widget_class, on_btn_grant_clicked); + gtk_widget_class_bind_template_callback (widget_class, on_dialog_canceled); +} + + +static void +phosh_app_auth_prompt_init (PhoshAppAuthPrompt *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} + + +GtkWidget * +phosh_app_auth_prompt_new (GIcon *icon, + const char *title, + const char *subtitle, + const char *body, + const char *grant_label, + const char *deny_label, + gboolean offer_remember) +{ + return g_object_new (PHOSH_TYPE_APP_AUTH_PROMPT, + "icon", icon, + "title", title, + "subtitle", subtitle, + "body", body, + "grant-label", grant_label, + "deny-label", deny_label, + "offer-remember", offer_remember, + NULL); +} + +gboolean +phosh_app_auth_prompt_get_grant_access (GtkWidget *self) +{ + g_return_val_if_fail (PHOSH_IS_APP_AUTH_PROMPT (self), FALSE); + + return PHOSH_APP_AUTH_PROMPT (self)->grant_access; +} diff -Nru phosh-0.8.0/src/app-auth-prompt.h phosh-0.13.1/src/app-auth-prompt.h --- phosh-0.8.0/src/app-auth-prompt.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/app-auth-prompt.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include +#include "system-modal-dialog.h" + +G_BEGIN_DECLS + +#define PHOSH_TYPE_APP_AUTH_PROMPT (phosh_app_auth_prompt_get_type ()) + +G_DECLARE_FINAL_TYPE (PhoshAppAuthPrompt, phosh_app_auth_prompt, PHOSH, APP_AUTH_PROMPT, PhoshSystemModalDialog) + +GtkWidget *phosh_app_auth_prompt_new (GIcon *icon, + const char *title, + const char *subtitle, + const char *body, + const char *grant_label, + const char *deny_label, + gboolean offer_remember); +gboolean phosh_app_auth_prompt_get_grant_access (GtkWidget *self); +gboolean phosh_app_auth_prompt_get_remember (GtkWidget *self); + +G_END_DECLS diff -Nru phosh-0.8.0/src/app-grid-button.c phosh-0.13.1/src/app-grid-button.c --- phosh-0.8.0/src/app-grid-button.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/app-grid-button.c 2021-08-31 09:15:52.000000000 +0000 @@ -121,8 +121,8 @@ g_clear_object (&priv->actions); g_clear_object (&priv->action_map); - phosh_clear_handler (&priv->favorite_changed_watcher, - phosh_favorite_list_model_get_default ()); + g_clear_signal_handler (&priv->favorite_changed_watcher, + phosh_favorite_list_model_get_default ()); G_OBJECT_CLASS (phosh_app_grid_button_parent_class)->finalize (object); } @@ -468,7 +468,7 @@ list = phosh_favorite_list_model_get_default (); - phosh_clear_handler (&priv->favorite_changed_watcher, list); + g_clear_signal_handler (&priv->favorite_changed_watcher, list); if (info) { priv->info = g_object_ref (info); diff -Nru phosh-0.8.0/src/app-grid.c phosh-0.13.1/src/app-grid.c --- phosh-0.8.0/src/app-grid.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/app-grid.c 2021-08-31 09:15:52.000000000 +0000 @@ -8,15 +8,32 @@ #define ACTIVE_SEARCH_CLASS "search-active" +#define _GNU_SOURCE +#include + #include "feedback-manager.h" #include "app-grid.h" #include "app-grid-button.h" #include "app-list-model.h" #include "favorite-list-model.h" +#include "shell.h" #include "gtk-list-models/gtksortlistmodel.h" #include "gtk-list-models/gtkfilterlistmodel.h" +enum { + PROP_0, + PROP_FILTER_ADAPTIVE, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + +enum { + APP_LAUNCHED, + N_SIGNALS +}; +static guint signals[N_SIGNALS] = { 0 }; + typedef struct _PhoshAppGridPrivate PhoshAppGridPrivate; struct _PhoshAppGridPrivate { GtkFilterListModel *model; @@ -26,17 +43,56 @@ GtkWidget *favs; GtkWidget *favs_revealer; GtkWidget *scrolled_window; + GtkWidget *menu_button; char *search_string; + gboolean filter_adaptive; + GSettings *settings; + GStrv force_adaptive; + GSimpleActionGroup *actions; + PhoshAppFilterModeFlags filter_mode; }; G_DEFINE_TYPE_WITH_PRIVATE (PhoshAppGrid, phosh_app_grid, GTK_TYPE_BOX) -enum { - APP_LAUNCHED, - N_SIGNALS -}; -static guint signals[N_SIGNALS] = { 0 }; +static void +phosh_app_grid_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshAppGrid *self = PHOSH_APP_GRID (object); + + switch (property_id) { + case PROP_FILTER_ADAPTIVE: + phosh_app_grid_set_filter_adaptive (self, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_app_grid_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshAppGrid *self = PHOSH_APP_GRID (object); + PhoshAppGridPrivate *priv = phosh_app_grid_get_instance_private (self); + + switch (property_id) { + case PROP_FILTER_ADAPTIVE: + g_value_set_boolean (value, priv->filter_adaptive); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + static void app_launched_cb (GtkWidget *widget, @@ -63,6 +119,64 @@ } + +static void +on_filter_setting_changed (PhoshAppGrid *self, + GParamSpec *pspec, + gpointer *unused) +{ + PhoshAppGridPrivate *priv; + gboolean show; + + g_return_if_fail (PHOSH_IS_APP_GRID (self)); + + priv = phosh_app_grid_get_instance_private (self); + + g_strfreev (priv->force_adaptive); + priv->force_adaptive = g_settings_get_strv (priv->settings, + "force-adaptive"); + priv->filter_mode = g_settings_get_flags (priv->settings, + "app-filter-mode"); + + show = !!(priv->filter_mode & PHOSH_APP_FILTER_MODE_FLAGS_ADAPTIVE); + gtk_widget_set_visible (priv->menu_button, show); + + gtk_filter_list_model_refilter (priv->model); +} + + +static gboolean +filter_adaptive (PhoshAppGrid *self, GDesktopAppInfo *info) +{ + PhoshAppGridPrivate *priv = phosh_app_grid_get_instance_private (self); + g_autofree char *mobile = NULL; + const char *id; + + if (!(priv->filter_mode & PHOSH_APP_FILTER_MODE_FLAGS_ADAPTIVE)) + return TRUE; + + if (!priv->filter_adaptive) + return TRUE; + + mobile = g_desktop_app_info_get_string (G_DESKTOP_APP_INFO (info), + "X-Purism-FormFactor"); + if (mobile && strcasestr (mobile, "mobile;")) + return TRUE; + + g_free (mobile); + mobile = g_desktop_app_info_get_string (G_DESKTOP_APP_INFO (info), + "X-KDE-FormFactor"); + if (mobile && strcasestr (mobile, "handset;")) + return TRUE; + + id = g_app_info_get_id (G_APP_INFO (info)); + if (id && g_strv_contains ((const char * const*)priv->force_adaptive, id)) + return TRUE; + + return FALSE; +} + + static const char *(*app_attr[]) (GAppInfo *info) = { g_app_info_get_display_name, g_app_info_get_name, @@ -91,6 +205,11 @@ search = priv->search_string; + if (G_IS_DESKTOP_APP_INFO (info)) { + if (!filter_adaptive (self, G_DESKTOP_APP_INFO (info))) + return FALSE; + } + /* filter out favorites when not searching */ if (search == NULL || strlen (search) == 0) { if (phosh_favorite_list_model_app_is_favorite (NULL, info)) @@ -198,6 +317,7 @@ PhoshAppGridPrivate *priv = phosh_app_grid_get_instance_private (self); GtkSortListModel *sorted; PhoshFavoriteListModel *favorites; + g_autoptr (GAction) action = NULL; gtk_widget_init_template (GTK_WIDGET (self)); @@ -220,20 +340,50 @@ search_apps, self, NULL); + g_object_unref (sorted); gtk_flow_box_bind_model (GTK_FLOW_BOX (priv->apps), G_LIST_MODEL (priv->model), create_launcher, self, NULL); + + priv->settings = g_settings_new ("sm.puri.phosh"); + g_object_connect (priv->settings, + "swapped-signal::changed::force-adaptive", + G_CALLBACK (on_filter_setting_changed), self, + "swapped-signal::changed::app-filter-mode", + G_CALLBACK (on_filter_setting_changed), self, + NULL); + on_filter_setting_changed (self, NULL, NULL); + + priv->actions = g_simple_action_group_new (); + gtk_widget_insert_action_group (GTK_WIDGET (self), "app-grid", + G_ACTION_GROUP (priv->actions)); + action = (GAction*) g_property_action_new ("filter-adaptive", self, "filter-adaptive"); + g_action_map_add_action (G_ACTION_MAP (priv->actions), action); } static void -phosh_app_grid_finalize (GObject *object) +phosh_app_grid_dispose (GObject *object) { PhoshAppGrid *self = PHOSH_APP_GRID (object); PhoshAppGridPrivate *priv = phosh_app_grid_get_instance_private (self); + g_clear_object (&priv->actions); g_clear_object (&priv->model); + g_clear_object (&priv->settings); + + G_OBJECT_CLASS (phosh_app_grid_parent_class)->dispose (object); +} + + +static void +phosh_app_grid_finalize (GObject *object) +{ + PhoshAppGrid *self = PHOSH_APP_GRID (object); + PhoshAppGridPrivate *priv = phosh_app_grid_get_instance_private (self); + g_clear_pointer (&priv->search_string, g_free); + g_strfreev (priv->force_adaptive); G_OBJECT_CLASS (phosh_app_grid_parent_class)->finalize (object); } @@ -372,10 +522,28 @@ GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + object_class->dispose = phosh_app_grid_dispose; object_class->finalize = phosh_app_grid_finalize; + object_class->set_property = phosh_app_grid_set_property; + object_class->get_property = phosh_app_grid_get_property; + widget_class->key_press_event = phosh_app_grid_key_press_event; + /** + * PhoshAppGrid:filter-adaptive: + * + * Whether only adaptive apps should be shown + */ + props[PROP_FILTER_ADAPTIVE] = + g_param_spec_boolean ("filter-adaptive", + "", + "", + FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); + gtk_widget_class_set_template_from_resource (widget_class, "/sm/puri/phosh/ui/app-grid.ui"); gtk_widget_class_bind_template_child_private (widget_class, PhoshAppGrid, search); @@ -383,6 +551,7 @@ gtk_widget_class_bind_template_child_private (widget_class, PhoshAppGrid, favs); gtk_widget_class_bind_template_child_private (widget_class, PhoshAppGrid, favs_revealer); gtk_widget_class_bind_template_child_private (widget_class, PhoshAppGrid, scrolled_window); + gtk_widget_class_bind_template_child_private (widget_class, PhoshAppGrid, menu_button); gtk_widget_class_bind_template_callback (widget_class, search_changed); gtk_widget_class_bind_template_callback (widget_class, search_preedit_changed); @@ -434,3 +603,40 @@ priv = phosh_app_grid_get_instance_private (self); gtk_widget_grab_focus (priv->search); } + + +gboolean +phosh_app_grid_handle_search (PhoshAppGrid *self, GdkEvent *event) +{ + PhoshAppGridPrivate *priv; + gboolean ret; + + g_return_val_if_fail (PHOSH_IS_APP_GRID (self), GDK_EVENT_PROPAGATE); + priv = phosh_app_grid_get_instance_private (self); + ret = gtk_search_entry_handle_event (GTK_SEARCH_ENTRY (priv->search), event); + if (ret == GDK_EVENT_STOP) + gtk_entry_grab_focus_without_selecting (GTK_ENTRY (priv->search)); + + return ret; +} + + +void +phosh_app_grid_set_filter_adaptive (PhoshAppGrid *self, gboolean enable) +{ + PhoshAppGridPrivate *priv; + + g_debug ("Filter-adaptive: %d", enable); + + g_return_if_fail (PHOSH_IS_APP_GRID (self)); + priv = phosh_app_grid_get_instance_private (self); + + if (priv->filter_adaptive == enable) + return; + + priv->filter_adaptive = enable; + + gtk_filter_list_model_refilter (priv->model); + + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_FILTER_ADAPTIVE]); +} diff -Nru phosh-0.8.0/src/app-grid.h phosh-0.13.1/src/app-grid.h --- phosh-0.8.0/src/app-grid.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/app-grid.h 2021-08-31 09:15:52.000000000 +0000 @@ -13,6 +13,19 @@ G_BEGIN_DECLS +/** + * PhoshAppFilterModeFlags: + * @PHOSH_APP_FILTER_MODE_FLAGS_NONE: No filtering + * @PHOSH_APP_FILTER_MODE_FLAGS_ADAPTIVE: Only show apps in mobile mode that adapt + * to smalls screen sizes. + * + * Controls what kind of app filtering is done. +*/ +typedef enum { + PHOSH_APP_FILTER_MODE_FLAGS_NONE = 0, + PHOSH_APP_FILTER_MODE_FLAGS_ADAPTIVE = (1 << 0), +} PhoshAppFilterModeFlags; + #define PHOSH_TYPE_APP_GRID phosh_app_grid_get_type() G_DECLARE_DERIVABLE_TYPE (PhoshAppGrid, phosh_app_grid, PHOSH, APP_GRID, GtkBox) @@ -24,5 +37,8 @@ GtkWidget *phosh_app_grid_new (void); void phosh_app_grid_reset (PhoshAppGrid *self); void phosh_app_grid_focus_search (PhoshAppGrid *self); +gboolean phosh_app_grid_handle_search (PhoshAppGrid *self, GdkEvent *event); +void phosh_app_grid_set_filter_adaptive (PhoshAppGrid *self, gboolean enable); + G_END_DECLS diff -Nru phosh-0.8.0/src/app-list-model.c phosh-0.13.1/src/app-list-model.c --- phosh-0.8.0/src/app-list-model.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/app-list-model.c 2021-08-31 09:15:52.000000000 +0000 @@ -169,7 +169,7 @@ g_source_remove (priv->debounce); } priv->debounce = g_timeout_add (500, items_changed, data); - g_source_set_name_by_id (priv->debounce, "debounce app changes"); + g_source_set_name_by_id (priv->debounce, "[phosh] debounce app changes"); } diff -Nru phosh-0.8.0/src/background.c phosh-0.13.1/src/background.c --- phosh-0.8.0/src/background.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/background.c 2021-08-31 09:15:52.000000000 +0000 @@ -15,7 +15,8 @@ #include "background.h" #include "shell.h" -#include "panel.h" +#include "top-panel.h" +#include "util.h" #define GNOME_DESKTOP_USE_UNSTABLE_API #include @@ -68,7 +69,7 @@ GdkRGBA color; gboolean primary; - guint scale; + float scale; GdkPixbuf *pixbuf; GSettings *settings; gboolean configured; @@ -95,7 +96,7 @@ phosh_background_set_primary (self, g_value_get_boolean (value)); break; case PROP_SCALE: - phosh_background_set_scale (self, g_value_get_uint (value)); + phosh_background_set_scale (self, g_value_get_float (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -117,7 +118,7 @@ g_value_set_boolean (value, self->primary); break; case PROP_SCALE: - g_value_set_uint (value, self->scale); + g_value_set_float (value, self->scale); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -270,7 +271,7 @@ else g_object_get (self, "configured-width", &width, "configured-height", &height, NULL); - g_debug ("Scaling %p to %dx%d, scale %d", self, width, height, self->scale); + g_debug ("Scaling %p to %dx%d, scale %f", self, width, height, self->scale); self->pixbuf = image_background (pixbuf, width * self->scale, height * self->scale, style, &self->color); /* force background redraw */ gtk_widget_queue_draw (GTK_WIDGET (self)); @@ -303,18 +304,13 @@ image = gdk_pixbuf_new_from_stream_finish (res, &err); if (!image) { - if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - /* Do nothing we expect a new load to be triggered */ - g_debug ("Load of %s canceled", self->uri); - } else { - g_warning ("Failed to load background %s: %s", self->uri, err->message); - } - if (!self->pixbuf) + /* Do nothing on cancel since we expect a new load to be triggered */ + if (!phosh_async_error_warn (err, "Failed to load background")) background_fallback (self); g_object_unref (self); return; } - g_debug ("loaded %s", self->uri); + g_debug ("Loaded %s", self->uri); background_update (self, image, self->style); g_object_unref (self); } @@ -361,7 +357,7 @@ g_return_if_fail (PHOSH_IS_BACKGROUND (self)); if (!g_task_propagate_boolean (G_TASK (res), &err)) { - g_warning ("Failed to load %s: %s", self->uri, err->message); + phosh_async_error_warn (err, "%s", self->uri); goto out; } @@ -398,6 +394,7 @@ g_warning ("Couldn't get filename for %s: %s", self->uri, err->message); return FALSE; } + g_clear_object (&self->slideshow); self->slideshow = gnome_bg_slide_show_new (filename); self->cancel = g_cancellable_new (); @@ -534,6 +531,9 @@ { PhoshBackground *self = PHOSH_BACKGROUND (object); + g_cancellable_cancel (self->cancel); + g_clear_object (&self->cancel); + g_clear_object (&self->slideshow); G_OBJECT_CLASS (phosh_background_parent_class)->dispose (object); @@ -585,16 +585,16 @@ G_PARAM_EXPLICIT_NOTIFY | G_PARAM_CONSTRUCT); props[PROP_SCALE] = - g_param_spec_uint ("scale", - "Scale", - "The output scale", - 1, - G_MAXUINT, - 1, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS | - G_PARAM_EXPLICIT_NOTIFY | - G_PARAM_CONSTRUCT); + g_param_spec_float ("scale", + "Scale", + "The output scale", + 1.0, + G_MAXFLOAT, + 1.0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_CONSTRUCT); g_object_class_install_properties (object_class, PROP_LAST_PROP, props); } @@ -610,7 +610,7 @@ GtkWidget * phosh_background_new (gpointer layer_shell, gpointer wl_output, - guint scale, + float scale, gboolean primary) { return g_object_new (PHOSH_TYPE_BACKGROUND, @@ -644,9 +644,9 @@ void -phosh_background_set_scale (PhoshBackground *self, guint scale) +phosh_background_set_scale (PhoshBackground *self, float scale) { - if (self->scale == scale) + if ((int)(self->scale * 1000) == (int)(scale * 1000)) return; self->scale = scale; diff -Nru phosh-0.8.0/src/background.h phosh-0.13.1/src/background.h --- phosh-0.8.0/src/background.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/background.h 2021-08-31 09:15:52.000000000 +0000 @@ -18,7 +18,7 @@ GtkWidget *phosh_background_new (gpointer layer_shell, gpointer wl_output, - guint scale, + float scale, gboolean primary); void phosh_background_set_primary (PhoshBackground *self, gboolean primary); -void phosh_background_set_scale (PhoshBackground *self, guint scale); +void phosh_background_set_scale (PhoshBackground *self, float scale); diff -Nru phosh-0.8.0/src/background-manager.c phosh-0.13.1/src/background-manager.c --- phosh-0.8.0/src/background-manager.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/background-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -44,7 +44,7 @@ background = g_object_ref_sink(PHOSH_BACKGROUND (phosh_background_new ( phosh_wayland_get_zwlr_layer_shell_v1(wl), monitor->wl_output, - MAX(1, monitor->scale), + MAX(1.0, phosh_monitor_get_fractional_scale (monitor)), monitor == self->primary_monitor))); g_hash_table_insert (self->backgrounds, g_object_ref (monitor), @@ -71,14 +71,16 @@ PhoshMonitor *monitor) { PhoshBackground *background; + float scale; g_return_if_fail (PHOSH_IS_MONITOR (monitor)); - g_debug ("Monitor %p (%s) configured", monitor, monitor->name); + scale = phosh_monitor_get_fractional_scale (monitor); + g_debug ("Monitor %p (%s) configured, scale %f", monitor, monitor->name, scale); background = g_hash_table_lookup (self->backgrounds, monitor); g_return_if_fail (background); - phosh_background_set_scale (background, monitor->scale); + phosh_background_set_scale (background, scale); gtk_widget_show (GTK_WIDGET (background)); } @@ -204,3 +206,18 @@ { return g_object_new (PHOSH_TYPE_BACKGROUND_MANAGER, NULL); } + + +/** + * phosh_background_manager_get_backgrounds: + * @self: The #PhoshBackgroundManager + * + * Returns: (transfer container) (element-type PhoshBackground): The current backgrounds + */ +GList * +phosh_background_manager_get_backgrounds (PhoshBackgroundManager *self) +{ + g_return_val_if_fail (PHOSH_IS_BACKGROUND_MANAGER (self), NULL); + + return g_hash_table_get_values (self->backgrounds); +} diff -Nru phosh-0.8.0/src/background-manager.h phosh-0.13.1/src/background-manager.h --- phosh-0.8.0/src/background-manager.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/background-manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -16,4 +16,5 @@ BACKGROUND_MANAGER, GObject) -PhoshBackgroundManager *phosh_background_manager_new (void); +PhoshBackgroundManager *phosh_background_manager_new (void); +GList *phosh_background_manager_get_backgrounds (PhoshBackgroundManager *self); diff -Nru phosh-0.8.0/src/batteryinfo.c phosh-0.13.1/src/batteryinfo.c --- phosh-0.8.0/src/batteryinfo.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/batteryinfo.c 2021-08-31 09:15:52.000000000 +0000 @@ -14,6 +14,7 @@ #include "batteryinfo.h" #include "upower.h" +#include "util.h" /** * SECTION:batteryinfo @@ -21,10 +22,19 @@ * @Title: PhoshBatteryInfo */ +enum { + PROP_0, + PROP_SHOW_DETAIL, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + + typedef struct _PhoshBatteryInfo { - PhoshStatusIcon parent; - UpClient *upower; - UpDevice *device; + PhoshStatusIcon parent; + UpClient *upower; + UpDevice *device; + gboolean show_detail; } PhoshBatteryInfo; @@ -32,14 +42,51 @@ static void +phosh_battery_info_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshBatteryInfo *self = PHOSH_BATTERY_INFO (object); + + switch (property_id) { + case PROP_SHOW_DETAIL: + phosh_battery_info_set_show_detail (self, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_battery_info_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshBatteryInfo *self = PHOSH_BATTERY_INFO (object); + + switch (property_id) { + case PROP_SHOW_DETAIL: + g_value_set_boolean (value, self->show_detail); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void setup_display_device (PhoshBatteryInfo *self) { - GError *err = NULL; + g_autoptr (GError) err = NULL; self->upower = up_client_new_full (NULL, &err); if (self->upower == NULL) { - g_warning ("Failed to connect to upowerd: %s", err->message); - g_clear_error (&err); + phosh_dbus_service_error_warn (err, "Failed to connect to upowerd"); return; } @@ -57,7 +104,8 @@ const GValue *from_value, GValue *to_value, gpointer user_data) { - g_value_set_string(to_value, g_strdup_printf ("%d%%", (int)(g_value_get_double(from_value) + 0.5))); + g_value_take_string (to_value, + g_strdup_printf ("%d%%", (int) (g_value_get_double (from_value) + 0.5))); return TRUE; } @@ -81,6 +129,11 @@ NULL, NULL, NULL); + g_object_bind_property (self, + "info", + phosh_status_icon_get_extra_widget (PHOSH_STATUS_ICON (self)), + "label", + G_BINDING_SYNC_CREATE); } } @@ -90,11 +143,8 @@ { PhoshBatteryInfo *self = PHOSH_BATTERY_INFO (object); - if (self->device) - g_clear_object (&self->device); - - if (self->upower) - g_clear_object (&self->upower); + g_clear_object (&self->device); + g_clear_object (&self->upower); G_OBJECT_CLASS (phosh_battery_info_parent_class)->dispose (object); } @@ -104,15 +154,38 @@ phosh_battery_info_class_init (PhoshBatteryInfoClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->constructed = phosh_battery_info_constructed; object_class->dispose = phosh_battery_info_dispose; + object_class->get_property = phosh_battery_info_get_property; + object_class->set_property = phosh_battery_info_set_property; + + gtk_widget_class_set_css_name (widget_class, "phosh-battery-info"); + + props[PROP_SHOW_DETAIL] = + g_param_spec_boolean ( + "show-detail", + "", + "", + FALSE, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); } static void phosh_battery_info_init (PhoshBatteryInfo *self) { + GtkWidget *percentage = gtk_label_new (NULL); + phosh_status_icon_set_extra_widget (PHOSH_STATUS_ICON (self), percentage); + + g_object_bind_property (self, + "show-detail", + percentage, + "visible", + G_BINDING_SYNC_CREATE); } @@ -121,3 +194,25 @@ { return g_object_new (PHOSH_TYPE_BATTERY_INFO, NULL); } + + +void +phosh_battery_info_set_show_detail (PhoshBatteryInfo *self, gboolean show) +{ + g_return_if_fail (PHOSH_IS_BATTERY_INFO (self)); + + if (self->show_detail == show) + return; + + self->show_detail = !!show; + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SHOW_DETAIL]); +} + + +gboolean +phosh_battery_info_get_show_detail (PhoshBatteryInfo *self) +{ + g_return_val_if_fail (PHOSH_IS_BATTERY_INFO (self), FALSE); + + return self->show_detail; +} diff -Nru phosh-0.8.0/src/batteryinfo.h phosh-0.13.1/src/batteryinfo.h --- phosh-0.8.0/src/batteryinfo.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/batteryinfo.h 2021-08-31 09:15:52.000000000 +0000 @@ -17,5 +17,7 @@ G_DECLARE_FINAL_TYPE (PhoshBatteryInfo, phosh_battery_info, PHOSH, BATTERY_INFO, PhoshStatusIcon) GtkWidget * phosh_battery_info_new (void); +void phosh_battery_info_set_show_detail (PhoshBatteryInfo *self, gboolean show); +gboolean phosh_battery_info_get_show_detail (PhoshBatteryInfo *self); G_END_DECLS diff -Nru phosh-0.8.0/src/bt-info.c phosh-0.13.1/src/bt-info.c --- phosh-0.8.0/src/bt-info.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/bt-info.c 2021-08-31 09:15:52.000000000 +0000 @@ -130,13 +130,14 @@ } -static gboolean -on_idle (PhoshBtInfo *self) +static void +phosh_bt_info_idle_init (PhoshStatusIcon *icon) { + PhoshBtInfo *self = PHOSH_BT_INFO (icon); + update_icon (self, NULL, self->bt); update_info (self); on_bt_enabled (self, NULL, self->bt); - return G_SOURCE_REMOVE; } @@ -177,8 +178,6 @@ "notify::present", G_CALLBACK (on_bt_present), self); - - g_idle_add ((GSourceFunc) on_idle, self); } @@ -200,11 +199,17 @@ phosh_bt_info_class_init (PhoshBtInfoClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + PhoshStatusIconClass *status_icon_class = PHOSH_STATUS_ICON_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->constructed = phosh_bt_info_constructed; object_class->dispose = phosh_bt_info_dispose; object_class->get_property = phosh_bt_info_get_property; + status_icon_class->idle_init = phosh_bt_info_idle_init; + + gtk_widget_class_set_css_name (widget_class, "phosh-bt-info"); + props[PROP_ENABLED] = g_param_spec_boolean ("enabled", "enabled", diff -Nru phosh-0.8.0/src/bt-manager.c phosh-0.13.1/src/bt-manager.c --- phosh-0.8.0/src/bt-manager.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/bt-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -13,6 +13,7 @@ #include "bt-manager.h" #include "shell.h" #include "dbus/gsd-rfkill-dbus.h" +#include "util.h" #define BUS_NAME "org.gnome.SettingsDaemon.Rfkill" #define OBJECT_PATH "/org/gnome/SettingsDaemon/Rfkill" @@ -39,7 +40,7 @@ static GParamSpec *props[PROP_LAST_PROP]; struct _PhoshBtManager { - GObject parent; + PhoshManager manager; /* Whether bt radio is on */ gboolean enabled; @@ -49,7 +50,7 @@ PhoshRfkillDBusRfkill *proxy; }; -G_DEFINE_TYPE (PhoshBtManager, phosh_bt_manager, G_TYPE_OBJECT); +G_DEFINE_TYPE (PhoshBtManager, phosh_bt_manager, PHOSH_TYPE_MANAGER); static void @@ -134,42 +135,6 @@ static void -phosh_bt_manager_class_init (PhoshBtManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->get_property = phosh_bt_manager_get_property; - - props[PROP_ICON_NAME] = - g_param_spec_string ("icon-name", - "icon name", - "The bt icon name", - "bluetooth-disabled-symbolic", - G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY); - - props[PROP_ENABLED] = - g_param_spec_boolean ("enabled", - "enabled", - "Whether bluetooth hardware is enabled", - FALSE, - G_PARAM_READABLE | - G_PARAM_EXPLICIT_NOTIFY | - G_PARAM_STATIC_STRINGS); - - props[PROP_PRESENT] = - g_param_spec_boolean ("present", - "Present", - "Whether bluettoh hardware is present", - FALSE, - G_PARAM_READABLE | - G_PARAM_EXPLICIT_NOTIFY | - G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties (object_class, PROP_LAST_PROP, props); -} - - -static void on_proxy_new_for_bus_finish (GObject *source_object, GAsyncResult *res, PhoshBtManager *self) @@ -181,7 +146,7 @@ self->proxy = phosh_rfkill_dbus_rfkill_proxy_new_for_bus_finish (res, &err); if (!self->proxy) { - g_warning ("Failed to get gsd rfkill proxy: %s", err->message); + phosh_dbus_service_error_warn (err, "Failed to get gsd rfkill proxy"); goto out; } @@ -202,9 +167,11 @@ } -static gboolean -on_idle (PhoshBtManager *self) +static void +phosh_bt_manager_idle_init (PhoshManager *manager) { + PhoshBtManager *self = PHOSH_BT_MANAGER (manager); + phosh_rfkill_dbus_rfkill_proxy_new_for_bus (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, BUS_NAME, @@ -212,7 +179,58 @@ NULL, (GAsyncReadyCallback) on_proxy_new_for_bus_finish, g_object_ref (self)); - return G_SOURCE_REMOVE; +} + + +static void +phosh_bt_manager_dispose (GObject *object) +{ + PhoshBtManager *self = PHOSH_BT_MANAGER (object); + + g_clear_object (&self->proxy); + + G_OBJECT_CLASS (phosh_bt_manager_parent_class)->dispose (object); +} + + +static void +phosh_bt_manager_class_init (PhoshBtManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PhoshManagerClass *manager_class = PHOSH_MANAGER_CLASS (klass); + + object_class->dispose = phosh_bt_manager_dispose; + + object_class->get_property = phosh_bt_manager_get_property; + + manager_class->idle_init = phosh_bt_manager_idle_init; + + props[PROP_ICON_NAME] = + g_param_spec_string ("icon-name", + "icon name", + "The bt icon name", + "bluetooth-disabled-symbolic", + G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY); + + props[PROP_ENABLED] = + g_param_spec_boolean ("enabled", + "enabled", + "Whether bluetooth hardware is enabled", + FALSE, + G_PARAM_READABLE | + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_STATIC_STRINGS); + + props[PROP_PRESENT] = + g_param_spec_boolean ("present", + "Present", + "Whether bluettoh hardware is present", + FALSE, + G_PARAM_READABLE | + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); } @@ -220,8 +238,6 @@ phosh_bt_manager_init (PhoshBtManager *self) { self->icon_name = "bluetooth-disabled-symbolic"; - /* Perform DBus setup when idle */ - g_idle_add ((GSourceFunc)on_idle, self); } @@ -250,6 +266,24 @@ } +void +phosh_bt_manager_set_enabled (PhoshBtManager *self, gboolean enabled) +{ + g_return_if_fail (PHOSH_IS_BT_MANAGER (self)); + + if (!self->present) + return; + + if (enabled == self->enabled) + return; + + g_return_if_fail (self->proxy); + + self->enabled = enabled; + phosh_rfkill_dbus_rfkill_set_bluetooth_airplane_mode (self->proxy, !enabled); +} + + gboolean phosh_bt_manager_get_present (PhoshBtManager *self) { diff -Nru phosh-0.8.0/src/bt-manager.h phosh-0.13.1/src/bt-manager.h --- phosh-0.8.0/src/bt-manager.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/bt-manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -6,17 +6,20 @@ #pragma once +#include + #include G_BEGIN_DECLS #define PHOSH_TYPE_BT_MANAGER (phosh_bt_manager_get_type ()) -G_DECLARE_FINAL_TYPE (PhoshBtManager, phosh_bt_manager, PHOSH, BT_MANAGER, GObject) +G_DECLARE_FINAL_TYPE (PhoshBtManager, phosh_bt_manager, PHOSH, BT_MANAGER, PhoshManager) PhoshBtManager *phosh_bt_manager_new (void); const char *phosh_bt_manager_get_icon_name (PhoshBtManager *self); gboolean phosh_bt_manager_get_enabled (PhoshBtManager *self); +void phosh_bt_manager_set_enabled (PhoshBtManager *self, gboolean enabled); gboolean phosh_bt_manager_get_present (PhoshBtManager *self); G_END_DECLS diff -Nru phosh-0.8.0/src/call.c phosh-0.13.1/src/call.c --- phosh-0.8.0/src/call.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/call.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,347 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-call" + +#include "call.h" +#include "util.h" + +#include + + +enum { + PROP_0, + PROP_DBUS_PROXY, + PROP_DISPLAY_NAME, + PROP_ID, + PROP_STATE, + PROP_ENCRYPTED, + PROP_CAN_DTMF, + PROP_LAST_PROP = PROP_DISPLAY_NAME, +}; +static GParamSpec *props[PROP_LAST_PROP]; + + +typedef struct _PhoshCall { + GObject parent; + + PhoshCallsDBusCallsCall *proxy; /* DBus proxy to a single call on for gnome-calls' DBus service */ + GCancellable *cancel; + + gboolean can_dtmf; +} PhoshCall; + + +static void phosh_call_cui_call_interface_init (CuiCallInterface *iface); +G_DEFINE_TYPE_WITH_CODE (PhoshCall, phosh_call, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (CUI_TYPE_CALL, + phosh_call_cui_call_interface_init)) + + +static const char * +phosh_call_get_id (CuiCall *call) +{ + PhoshCall *self; + + g_return_val_if_fail (PHOSH_IS_CALL (call), NULL); + self = PHOSH_CALL (call); + + return phosh_calls_dbus_calls_call_get_id (self->proxy); +} + + +static const char * +phosh_call_get_display_name (CuiCall *call) +{ + PhoshCall *self; + + g_return_val_if_fail (PHOSH_IS_CALL (call), NULL); + self = PHOSH_CALL (call); + + return phosh_calls_dbus_calls_call_get_display_name (self->proxy); +} + + +static CuiCallState +phosh_call_get_state (CuiCall *call) +{ + PhoshCall *self; + + g_return_val_if_fail (PHOSH_IS_CALL (call), CUI_CALL_STATE_UNKNOWN); + self = PHOSH_CALL (call); + + return phosh_calls_dbus_calls_call_get_state (self->proxy); +} + + +static gboolean +phosh_call_get_encrypted (CuiCall *call) +{ + PhoshCall *self; + + g_return_val_if_fail (PHOSH_IS_CALL (call), CUI_CALL_STATE_UNKNOWN); + self = PHOSH_CALL (call); + + return phosh_calls_dbus_calls_call_get_encrypted (self->proxy); +} + + +static gboolean +phosh_call_get_can_dtmf (CuiCall *call) +{ + PhoshCall *self; + + g_return_val_if_fail (PHOSH_IS_CALL (call), CUI_CALL_STATE_UNKNOWN); + self = PHOSH_CALL (call); + + return self->can_dtmf; +} + + +static void +on_prop_changed (PhoshCall *self, GParamSpec *pspec) +{ + const char *name = g_param_spec_get_name (pspec); + + /* Just forward any property changes, we fetch them from the DBus proxy anyway */ + if (g_strcmp0 (name, "state") == 0 || + g_strcmp0 (name, "encrypted") == 0 || + g_strcmp0 (name, "id") == 0 || + g_strcmp0 (name, "display-name") == 0) { + g_object_notify (G_OBJECT (self), name); + } +} + + +static void +phosh_call_set_dbus_proxy (PhoshCall *self, PhoshCallsDBusCallsCall *proxy) +{ + self->proxy = g_object_ref (proxy); + + g_object_connect (self->proxy, + "swapped-signal::notify::state", G_CALLBACK (on_prop_changed), self, + "swapped-signal::notify::encrypted", G_CALLBACK (on_prop_changed), self, + "swapped-signal::notify::id", G_CALLBACK (on_prop_changed), self, + "swapped-signal::notify::display-name", G_CALLBACK (on_prop_changed), self, + NULL); + + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DBUS_PROXY]); +} + + +static void +phosh_call_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshCall *self = PHOSH_CALL (object); + + switch (property_id) { + case PROP_DBUS_PROXY: + /* construct only */ + phosh_call_set_dbus_proxy (self, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_call_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshCall *self = PHOSH_CALL (object); + CuiCall *iface = CUI_CALL (object); + + switch (property_id) { + case PROP_DBUS_PROXY: + g_value_set_object (value, self->proxy); + break; + case PROP_ID: + g_value_set_string (value, phosh_call_get_id (iface)); + break; + case PROP_DISPLAY_NAME: + g_value_set_string (value, phosh_call_get_display_name (iface)); + break; + case PROP_STATE: + g_value_set_enum (value, phosh_call_get_state (iface)); + break; + case PROP_ENCRYPTED: + g_value_set_boolean (value, phosh_call_get_encrypted (iface)); + break; + case PROP_CAN_DTMF: + g_value_set_boolean (value, phosh_call_get_can_dtmf (iface)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_call_dispose (GObject *object) +{ + PhoshCall *self = PHOSH_CALL (object); + + g_cancellable_cancel (self->cancel); + g_clear_object (&self->cancel); + g_signal_handlers_disconnect_by_data (self->proxy, self); + g_clear_object (&self->proxy); + + G_OBJECT_CLASS (phosh_call_parent_class)->dispose (object); +} + + +static void +phosh_call_class_init (PhoshCallClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = phosh_call_dispose; + object_class->set_property = phosh_call_set_property; + object_class->get_property = phosh_call_get_property; + + /** + * PhoshCall:dbus-proxy: + * + * The DBus proxy object to a call on gnome-calls DBus interface + */ + props[PROP_DBUS_PROXY] = g_param_spec_object ("dbus-proxy", + "", + "", + PHOSH_CALLS_DBUS_TYPE_CALLS_CALL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); + + g_object_class_override_property (object_class, + PROP_DISPLAY_NAME, + "id"); + + g_object_class_override_property (object_class, + PROP_ID, + "display-name"); + + g_object_class_override_property (object_class, + PROP_STATE, + "state"); + + g_object_class_override_property (object_class, + PROP_ENCRYPTED, + "encrypted"); + + g_object_class_override_property (object_class, + PROP_CAN_DTMF, + "can-dtmf"); +} + + +static void +on_call_accept_finish (PhoshCallsDBusCallsCall *proxy, + GAsyncResult *res, + gpointer unused) +{ + g_autoptr (GError) err = NULL; + + g_return_if_fail (PHOSH_CALLS_DBUS_IS_CALLS_CALL_PROXY (proxy)); + + if (!phosh_calls_dbus_calls_call_call_accept_finish (proxy, res, &err)) + phosh_async_error_warn (err, "Failed to accept call %p", proxy); +} + + +static void +phosh_call_accept (CuiCall *call) +{ + PhoshCall *self; + + g_return_if_fail (PHOSH_IS_CALL (call)); + self = PHOSH_CALL (call); + + phosh_calls_dbus_calls_call_call_accept (self->proxy, + self->cancel, + (GAsyncReadyCallback) on_call_accept_finish, + NULL); +} + +static void +on_call_hangup_finish (PhoshCallsDBusCallsCall *proxy, + GAsyncResult *res, + gpointer unused) +{ + g_autoptr (GError) err = NULL; + + g_return_if_fail (PHOSH_CALLS_DBUS_IS_CALLS_CALL_PROXY (proxy)); + + if (!phosh_calls_dbus_calls_call_call_hangup_finish (proxy, res, &err)) + phosh_async_error_warn (err, "Failed to hangup call %p", proxy); +} + + +static void +phosh_call_hang_up (CuiCall *call) +{ + PhoshCall *self; + + g_return_if_fail (PHOSH_IS_CALL (call)); + self = PHOSH_CALL (call); + + phosh_calls_dbus_calls_call_call_hangup (self->proxy, + self->cancel, + (GAsyncReadyCallback) on_call_hangup_finish, + NULL); +} + + +static void +phosh_call_send_dtmf (CuiCall *call, const char *dtmf) +{ + g_return_if_fail (PHOSH_IS_CALL (call)); + + /* TBD */ +} + + +static void +phosh_call_cui_call_interface_init (CuiCallInterface *iface) +{ + iface->get_id = phosh_call_get_id; + iface->get_display_name = phosh_call_get_display_name; + iface->get_state = phosh_call_get_state; + iface->get_encrypted = phosh_call_get_encrypted; + iface->get_can_dtmf = phosh_call_get_can_dtmf; + + iface->accept = phosh_call_accept; + iface->hang_up = phosh_call_hang_up; + iface->send_dtmf = phosh_call_send_dtmf; +} + + +static void +phosh_call_init (PhoshCall *self) +{ + self->cancel = g_cancellable_new (); + + /* TODO: once DBus handles it */ + self->can_dtmf = FALSE; +} + + +PhoshCall * +phosh_call_new (PhoshCallsDBusCallsCall *proxy) +{ + return g_object_new (PHOSH_TYPE_CALL, + "dbus-proxy", proxy, + NULL); +} diff -Nru phosh-0.8.0/src/call.h phosh-0.13.1/src/call.h --- phosh-0.8.0/src/call.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/call.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +#pragma once + +#include "calls-dbus.h" + +#include +#include + +G_BEGIN_DECLS + +#define PHOSH_TYPE_CALL (phosh_call_get_type()) + +G_DECLARE_FINAL_TYPE (PhoshCall, phosh_call, PHOSH, CALL, GObject) + +PhoshCall * phosh_call_new (PhoshCallsDBusCallsCall *proxy); + +G_END_DECLS diff -Nru phosh-0.8.0/src/calls-manager.c phosh-0.13.1/src/calls-manager.c --- phosh-0.8.0/src/calls-manager.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/calls-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,453 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-calls-manager" + +#include "config.h" + +#include "call.h" +#include "calls-manager.h" +#include "shell.h" +#include "util.h" +#include "dbus/calls-dbus.h" + +#define BUS_NAME "org.gnome.Calls" +#define OBJECT_PATH "/org/gnome/Calls" +#define OBJECT_PATHS_CALLS_PREFIX OBJECT_PATH "/Call/" + +/** + * SECTION:calls-manager + * @short_description: Track ongoing phone calls + * @Title: PhoshCallsManager + * + * #PhoshCallsManager tracks on going calls on the org.gnome.Calls DBus + * interface and allows interaction with them by wrapping the + * #PhoshCallsDBusCallsCall proxies in #PhoshCall so all DBus and + * ObjectManager related logic stays local within #PhoshCallsManager. + */ + +enum { + PROP_0, + PROP_PRESENT, + PROP_ACTIVE_CALL, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + + +enum { + CALL_INBOUND, + CALL_REMOVED, + N_SIGNALS +}; +static guint signals[N_SIGNALS] = { 0 }; + + +struct _PhoshCallsManager { + PhoshManager parent; + + gboolean present; + gboolean incoming; + char *active_call; + + PhoshCallsDBusObjectManagerClient *om_client; + GCancellable *cancel; + GHashTable *calls; +}; +G_DEFINE_TYPE (PhoshCallsManager, phosh_calls_manager, PHOSH_TYPE_MANAGER); + + +static gboolean +is_active (PhoshCallState state) +{ + gboolean ret = FALSE; + + if (state == PHOSH_CALL_STATE_ACTIVE || + state == PHOSH_CALL_STATE_ALERTING || + state == PHOSH_CALL_STATE_DIALING) + ret = TRUE; + + return ret; +} + + +static void +on_call_state_changed (PhoshCallsManager *self, + GParamSpec *pspec, + PhoshCallsDBusCallsCall *proxy) +{ + const char *path; + PhoshCallState state; + PhoshCall *call; + + g_return_if_fail (PHOSH_IS_CALLS_MANAGER (self)); + g_return_if_fail (PHOSH_CALLS_DBUS_IS_CALLS_CALL (proxy)); + + call = g_object_get_data (G_OBJECT (proxy), "call"); + g_return_if_fail (call); + + path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (proxy)); + state = phosh_calls_dbus_calls_call_get_state (proxy); + + g_debug ("Call %s, state %d", path, state); + if (g_strcmp0 (path, self->active_call) == 0) { + /* current active call became inactive> */ + if (!is_active (state)) { + g_debug ("No active call, was %s", path); + g_clear_pointer (&self->active_call, g_free); + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ACTIVE_CALL]); + /* TODO: pick new active call from list once calls supports multiple active calls */ + } + return; + } + + if (!is_active (state)) + return; + + /* New active call */ + g_free (self->active_call); + self->active_call = g_strdup (path); + g_debug ("New active call %s", path); + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ACTIVE_CALL]); +} + + +static void +on_call_proxy_new_for_bus_finish (GObject *source_object, + GAsyncResult *res, + gpointer *data) +{ + const char *path; + gboolean inbound; + PhoshCallsManager *self; + g_autoptr (PhoshCallsDBusCallsCall) proxy = NULL; + g_autoptr (PhoshCall) call = NULL; + g_autoptr (GError) err = NULL; + + proxy = phosh_calls_dbus_calls_call_proxy_new_for_bus_finish (res, &err); + if (!proxy) { + phosh_async_error_warn (err, "Failed to get call proxy"); + return; + } + + self = PHOSH_CALLS_MANAGER (data); + path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (proxy)); + + /* Wrap DBus proxy in PhoshCall */ + call = phosh_call_new (proxy); + g_object_set_data (G_OBJECT (proxy), "call", call); + + if (g_hash_table_contains (self->calls, path)) + g_critical ("Already got a call with path %s", path); + else + g_hash_table_insert (self->calls, g_strdup (path), g_steal_pointer (&call)); + + + g_signal_connect_swapped (proxy, + "notify::state", + G_CALLBACK (on_call_state_changed), + self); + on_call_state_changed (self, NULL, proxy); + + inbound = phosh_calls_dbus_calls_call_get_inbound (proxy); + g_debug ("Added call %s, inbound: %d", path, inbound); + + if (inbound) + g_signal_emit (self, signals[CALL_INBOUND], 0, path); +} + + +static void +on_call_obj_added (PhoshCallsManager *self, + GDBusObject *object) +{ + const char *path; + + g_return_if_fail (PHOSH_IS_CALLS_MANAGER (self)); + + path = g_dbus_object_get_object_path (object); + g_debug ("New call obj at %s", path); + if (!g_str_has_prefix (path, OBJECT_PATHS_CALLS_PREFIX)) + return; + + phosh_calls_dbus_calls_call_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + BUS_NAME, + path, + self->cancel, + (GAsyncReadyCallback) on_call_proxy_new_for_bus_finish, + self); +} + + +static void +on_call_obj_removed (PhoshCallsManager *self, + GDBusObject *object) +{ + const char *path; + + g_return_if_fail (PHOSH_IS_CALLS_MANAGER (self)); + + path = g_dbus_object_get_object_path (object); + g_debug ("Call obj at %s gone", path); + if (!g_str_has_prefix (path, OBJECT_PATHS_CALLS_PREFIX)) + return; + + if (g_strcmp0 (path, self->active_call) == 0) { + g_clear_pointer (&self->active_call, g_free); + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ACTIVE_CALL]); + /* TODO: pick new active call from list once calls supports multiple active calls */ + } + + g_debug ("Removed call %s", path); + g_signal_emit (self, signals[CALL_REMOVED], 0, path); + /* This disposes the call object and hence the proxy */ + g_return_if_fail (g_hash_table_remove (self->calls, path)); +} + + +static void +phosh_calls_manager_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshCallsManager *self = PHOSH_CALLS_MANAGER (object); + + switch (property_id) { + case PROP_PRESENT: + g_value_set_boolean (value, self->present); + break; + case PROP_ACTIVE_CALL: + g_value_set_string (value, self->active_call); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +on_name_owner_changed (PhoshCallsManager *self, + GParamSpec *pspec, + GDBusObjectManagerClient *om) +{ + g_autofree char *owner = NULL; + gboolean present; + + g_return_if_fail (PHOSH_IS_CALLS_MANAGER (self)); + g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (om)); + + owner = g_dbus_object_manager_client_get_name_owner (om); + present = owner ? TRUE : FALSE; + + if (present) { + g_autolist (GDBusObject) objs = g_dbus_object_manager_get_objects ( + G_DBUS_OBJECT_MANAGER (self->om_client)); + + /* Catch up on ongoing calls */ + for (GList *elem = objs; elem; elem = elem->next) { + on_call_obj_added (self, elem->data); + } + } /* else {} is not necessary since we get object-removed signals + * when name owner quits + */ + + if (present != self->present) { + self->present = present; + g_debug ("Calls present: %d", self->present); + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PRESENT]); + } +} + + +static void +on_om_new_for_bus_finish (GObject *source_object, + GAsyncResult *res, + gpointer data) +{ + g_autoptr (GError) err = NULL; + PhoshCallsManager *self; + GDBusObjectManager *om; + GDBusObjectManagerClient *om_client; + + om = phosh_calls_dbus_object_manager_client_new_for_bus_finish (res, &err); + if (om == NULL) { + g_message ("Failed to get calls object manager client: %s", err->message); + return; + } + + self = PHOSH_CALLS_MANAGER (data); + self->om_client = PHOSH_CALLS_DBUS_OBJECT_MANAGER_CLIENT (om); + om_client = G_DBUS_OBJECT_MANAGER_CLIENT (om); + + g_signal_connect_object (self->om_client, + "notify::name-owner", + G_CALLBACK (on_name_owner_changed), + self, + G_CONNECT_SWAPPED); + on_name_owner_changed (self, NULL, G_DBUS_OBJECT_MANAGER_CLIENT (om)); + + g_signal_connect_object (self->om_client, + "object-added", + G_CALLBACK (on_call_obj_added), + self, + G_CONNECT_SWAPPED); + g_signal_connect_object (self->om_client, + "object-removed", + G_CALLBACK (on_call_obj_removed), + self, + G_CONNECT_SWAPPED); + + g_debug ("Calls manager initialized for name %s at %s", + g_dbus_object_manager_client_get_name (om_client), + g_dbus_object_manager_get_object_path (om)); +} + + +static void +phosh_calls_manager_idle_init (PhoshManager *manager) +{ + PhoshCallsManager *self = PHOSH_CALLS_MANAGER (manager); + + phosh_calls_dbus_object_manager_client_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, + BUS_NAME, + OBJECT_PATH, + self->cancel, + on_om_new_for_bus_finish, + self); +} + + +static void +phosh_calls_manager_dispose (GObject *object) +{ + PhoshCallsManager *self = PHOSH_CALLS_MANAGER (object); + + g_cancellable_cancel (self->cancel); + g_clear_object (&self->cancel); + g_clear_object (&self->om_client); + g_clear_pointer (&self->calls, g_hash_table_unref); + g_clear_pointer (&self->active_call, g_free); + + G_OBJECT_CLASS (phosh_calls_manager_parent_class)->dispose (object); +} + + +static void +phosh_calls_manager_class_init (PhoshCallsManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PhoshManagerClass *manager_class = PHOSH_MANAGER_CLASS (klass); + + object_class->get_property = phosh_calls_manager_get_property; + object_class->dispose = phosh_calls_manager_dispose; + + manager_class->idle_init = phosh_calls_manager_idle_init; + + /** + * PhoshCallsManager:present: + * + * Whether the call interface is present on the bus + */ + props[PROP_PRESENT] = + g_param_spec_boolean ("present", + "", + "", + FALSE, + G_PARAM_READABLE | + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_STATIC_STRINGS); + + /** + * PhoshCallsManager:active-call: + * + * The currently active call + */ + props[PROP_ACTIVE_CALL] = + g_param_spec_string ("active-call", + "", + "", + NULL, + G_PARAM_READABLE | + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); + + signals[CALL_INBOUND] = g_signal_new ("call-inbound", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + NULL, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + + signals[CALL_REMOVED] = g_signal_new ("call-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + NULL, + G_TYPE_NONE, + 1, + G_TYPE_STRING); +} + + +static void +phosh_calls_manager_init (PhoshCallsManager *self) +{ + self->calls = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + self->cancel = g_cancellable_new (); +} + + +PhoshCallsManager * +phosh_calls_manager_new (void) +{ + return g_object_new (PHOSH_TYPE_CALLS_MANAGER, NULL); +} + + +gboolean +phosh_calls_manager_get_present (PhoshCallsManager *self) +{ + g_return_val_if_fail (PHOSH_IS_CALLS_MANAGER (self), FALSE); + + return self->present; +} + + +int +phosh_calls_manager_get_incoming (PhoshCallsManager *self) +{ + g_return_val_if_fail (PHOSH_IS_CALLS_MANAGER (self), FALSE); + + return self->incoming; +} + + +const char * +phosh_calls_manager_get_active_call_handle (PhoshCallsManager *self) +{ + g_return_val_if_fail (PHOSH_IS_CALLS_MANAGER (self), NULL); + + return self->active_call; +} + + +PhoshCall * +phosh_calls_manager_get_call (PhoshCallsManager *self, const char *handle) +{ + g_return_val_if_fail (PHOSH_IS_CALLS_MANAGER (self), NULL); + + return g_hash_table_lookup (self->calls, handle); +} diff -Nru phosh-0.8.0/src/calls-manager.h phosh-0.13.1/src/calls-manager.h --- phosh-0.8.0/src/calls-manager.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/calls-manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "call.h" +#include "manager.h" + +#include + +G_BEGIN_DECLS + +/** + * PhoshCallState: + * + * The call state. Must match call's CallsCallState. + */ +typedef enum +{ + /*< private >*/ + PHOSH_CALL_STATE_ACTIVE = 1, + PHOSH_CALL_STATE_HELD, + PHOSH_CALL_STATE_DIALING, + PHOSH_CALL_STATE_ALERTING, + PHOSH_CALL_STATE_INCOMING, + PHOSH_CALL_STATE_WAITING, + PHOSH_CALL_STATE_DISCONNECTED +} PhoshCallState; + + +#define PHOSH_TYPE_CALLS_MANAGER (phosh_calls_manager_get_type ()) + +G_DECLARE_FINAL_TYPE (PhoshCallsManager, phosh_calls_manager, PHOSH, CALLS_MANAGER, PhoshManager) + +PhoshCallsManager *phosh_calls_manager_new (void); +gboolean phosh_calls_manager_get_present (PhoshCallsManager *self); +gboolean phosh_calls_manager_get_incoming (PhoshCallsManager *self); +const char *phosh_calls_manager_get_active_call_handle (PhoshCallsManager *self); +PhoshCall *phosh_calls_manager_get_call (PhoshCallsManager *self, const char *handle); + +G_END_DECLS diff -Nru phosh-0.8.0/src/connectivity-info.c phosh-0.13.1/src/connectivity-info.c --- phosh-0.8.0/src/connectivity-info.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/connectivity-info.c 2021-08-31 09:15:52.000000000 +0000 @@ -11,6 +11,7 @@ #include "config.h" #include "connectivity-info.h" +#include "util.h" #include @@ -38,6 +39,7 @@ gboolean connectivity; NMClient *nmclient; + GCancellable *cancel; }; G_DEFINE_TYPE (PhoshConnectivityInfo, phosh_connectivity_info, PHOSH_TYPE_STATUS_ICON); @@ -112,15 +114,17 @@ on_nm_client_ready (GObject *obj, GAsyncResult *res, PhoshConnectivityInfo *self) { g_autoptr (GError) err = NULL; + NMClient *nmclient; - g_return_if_fail (PHOSH_IS_CONNECTIVITY_INFO (self)); - - self->nmclient = nm_client_new_finish (res, &err); - if (err) { - g_warning ("Failed to init NM: %s", err->message); + nmclient = nm_client_new_finish (res, &err); + if (!nmclient) { + phosh_async_error_warn (err, "Failed to init NM"); return; } + g_return_if_fail (PHOSH_IS_CONNECTIVITY_INFO (self)); + self->nmclient = nmclient; + g_return_if_fail (NM_IS_CLIENT (self->nmclient)); g_signal_connect_swapped (self->nmclient, "notify::connectivity", @@ -137,7 +141,8 @@ G_OBJECT_CLASS (phosh_connectivity_info_parent_class)->constructed (object); - nm_client_new_async (NULL, (GAsyncReadyCallback)on_nm_client_ready, self); + self->cancel = g_cancellable_new (); + nm_client_new_async (self->cancel, (GAsyncReadyCallback)on_nm_client_ready, self); } @@ -146,6 +151,9 @@ { PhoshConnectivityInfo *self = PHOSH_CONNECTIVITY_INFO (object); + g_cancellable_cancel (self->cancel); + g_clear_object (&self->cancel); + g_clear_object (&self->nmclient); G_OBJECT_CLASS (phosh_connectivity_info_parent_class)->dispose (object); @@ -156,11 +164,14 @@ phosh_connectivity_info_class_init (PhoshConnectivityInfoClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->constructed = phosh_connectivity_info_constructed; object_class->dispose = phosh_connectivity_info_dispose; object_class->get_property = phosh_connectivity_info_get_property; + gtk_widget_class_set_css_name (widget_class, "phosh-connectivity-info"); + props[PROP_CONNECTIVITY] = g_param_spec_boolean ("connectivity", "Connectivity", diff -Nru phosh-0.8.0/src/dbus/meson.build phosh-0.13.1/src/dbus/meson.build --- phosh-0.8.0/src/dbus/meson.build 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/dbus/meson.build 2021-08-31 09:15:52.000000000 +0000 @@ -6,6 +6,11 @@ 'net.hadess.SensorProxy.xml', interface_prefix: 'net.hadess', namespace: 'PhoshDBus') +# Geoclue +generated_dbus_sources += gnome.gdbus_codegen('geoclue-manager-dbus', + 'org.freedesktop.GeoClue2.Manager.xml', + interface_prefix: 'org.freedesktop.GeoClue2', + namespace: 'PhoshGeoClueDBus') # org.freedesktop.hostname1 generated_dbus_sources += gnome.gdbus_codegen('hostname1-dbus', 'org.freedesktop.hostname1.xml', @@ -21,11 +26,17 @@ 'org.freedesktop.login1.Manager.xml', interface_prefix: 'org.freedesktop.login1', namespace: 'PhoshLogin1ManagerDBus') -# org.freedesktop.UPower.Torch -generated_dbus_sources += gnome.gdbus_codegen('upower-torch-dbus', - 'org.freedesktop.UPower.Torch.xml', - interface_prefix: 'org.freedesktop.UPower', - namespace: 'PhoshUPowerDBus') + +generated_dbus_sources += gnome.gdbus_codegen('phosh-wwan-mm-dbus', + 'org.freedesktop.ModemManager1.xml', + namespace: 'Phosh_MM_DBus', + interface_prefix: 'org.freedesktop.ModemManager1', + object_manager: true) +generated_dbus_sources += gnome.gdbus_codegen('calls-dbus', + 'org.gnome.Calls.Call.xml', + object_manager: true, + interface_prefix: 'org.gnome', + namespace: 'PhoshCallsDBus') # org.gnome.SessionManager generated_dbus_sources += gnome.gdbus_codegen('gnome-session-dbus', 'org.gnome.SessionManager.xml', @@ -52,7 +63,21 @@ interface_prefix: 'org.mpris', namespace: 'PhoshMprisDBus') +generated_dbus_sources += gnome.gdbus_codegen('phosh-wwan-ofono-dbus', + 'org.ofono.xml', + namespace: 'PhoshOfonoDBus', + interface_prefix: 'org.ofono') + +generated_dbus_sources += gnome.gdbus_codegen('phosh-osk0-dbus', + 'sm.puri.OSK0.xml', + namespace: 'PhoshOsk0') + # DBus server protocols +generated_dbus_sources += gnome.gdbus_codegen('geoclue-agent-dbus', + 'org.freedesktop.GeoClue2.Agent.xml', + interface_prefix: 'org.freedesktop.Agent', + namespace: 'PhoshGeoClueDBus') + generated_dbus_sources += gnome.gdbus_codegen('notify-dbus', 'org.freedesktop.Notifications.xml', interface_prefix: 'org.freedesktop', @@ -63,13 +88,33 @@ interface_prefix: 'org.gnome', namespace: 'PhoshGnomeShellDBus') +generated_dbus_sources += gnome.gdbus_codegen('phosh-display-dbus', + 'org.gnome.Mutter.DisplayConfig.xml', + interface_prefix: 'org.gnome.Mutter', + namespace: 'PhoshDBus') + generated_dbus_sources += gnome.gdbus_codegen('phosh-idle-dbus', - 'org.gnome.Mutter.IdleMonitor.xml', - interface_prefix: 'org.gnome.Mutter', - object_manager: true, - namespace: 'PhoshIdleDBus') + 'org.gnome.Mutter.IdleMonitor.xml', + interface_prefix: 'org.gnome.Mutter', + object_manager: true, + namespace: 'PhoshIdleDBus') generated_dbus_sources += gnome.gdbus_codegen('phosh-screen-saver-dbus', 'org.gnome.ScreenSaver.xml', interface_prefix: 'org.gnome', namespace: 'PhoshScreenSaverDBus') + +generated_dbus_sources += gnome.gdbus_codegen('phosh-screenshot-dbus', + 'org.gnome.Shell.Screenshot.xml', + interface_prefix: 'org.gnome.Shell', + namespace: 'PhoshDBus') + +generated_dbus_sources += gnome.gdbus_codegen('phosh-end-session-dialog-dbus', + 'org.gnome.SessionManager.EndSessionDialog.xml', + interface_prefix: 'org.gnome.SessionManager', + namespace: 'PhoshDBus') + +generated_dbus_sources += gnome.gdbus_codegen('phosh-gtk-mountoperation-dbus', + 'org.Gtk.MountOperationHandler.xml', + interface_prefix: 'org.Gtk', + namespace: 'PhoshDBus') diff -Nru phosh-0.8.0/src/dbus/org.freedesktop.GeoClue2.Agent.xml phosh-0.13.1/src/dbus/org.freedesktop.GeoClue2.Agent.xml --- phosh-0.8.0/src/dbus/org.freedesktop.GeoClue2.Agent.xml 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/dbus/org.freedesktop.GeoClue2.Agent.xml 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,11 @@ + + + + + + + + + + + diff -Nru phosh-0.8.0/src/dbus/org.freedesktop.GeoClue2.Manager.xml phosh-0.13.1/src/dbus/org.freedesktop.GeoClue2.Manager.xml --- phosh-0.8.0/src/dbus/org.freedesktop.GeoClue2.Manager.xml 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/dbus/org.freedesktop.GeoClue2.Manager.xml 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,9 @@ + + + + + + + + + diff -Nru phosh-0.8.0/src/dbus/org.freedesktop.login1.Session.xml phosh-0.13.1/src/dbus/org.freedesktop.login1.Session.xml --- phosh-0.8.0/src/dbus/org.freedesktop.login1.Session.xml 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/dbus/org.freedesktop.login1.Session.xml 2021-08-31 09:15:52.000000000 +0000 @@ -13,6 +13,12 @@ + + + + + + diff -Nru phosh-0.8.0/src/dbus/org.freedesktop.ModemManager1.xml phosh-0.13.1/src/dbus/org.freedesktop.ModemManager1.xml --- phosh-0.8.0/src/dbus/org.freedesktop.ModemManager1.xml 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/dbus/org.freedesktop.ModemManager1.xml 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff -Nru phosh-0.8.0/src/dbus/org.freedesktop.UPower.Torch.xml phosh-0.13.1/src/dbus/org.freedesktop.UPower.Torch.xml --- phosh-0.8.0/src/dbus/org.freedesktop.UPower.Torch.xml 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/dbus/org.freedesktop.UPower.Torch.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,148 +0,0 @@ - -]> - - - - - - org.freedesktop.UPower.Torch is a DBus interface implemented - by UPower. - It allows a torch (if present) to be controlled. - - - - - - - - - - The maximum value of the torch brightness. - - - - - - - Get the maximum brightness level for the torch. - - - - if an error occured while getting the maximum brightness - - - - - - - - - - The current value of the torch brightness. - - - - - - - Get the brightness level of the torch. - - - - if an error occured while getting the brightness - - - - - - - - - - The value to set the torch brightness. - - - - - - - Set the brightness level of the torch. - - - - if an error occured while setting the brightness - - - - - - - - - - The new brightness value of the torch. - - - - - - - The torch brightness level has changed. - - - - - - - - - - The new brightness value of the torch. - - - - - - - Source of the torch brightness change, either - "external" if SetBrightness was called, or "internal" if the - hardware changed the keyboard brightness itself. - - - - - - - The torch brightness level has changed including - information about the source of the change. - - - - - - - - - - The maximum value of the torch brightness. - - - - - - - - - - The current value of the torch brightness. - - - - - - - - diff -Nru phosh-0.8.0/src/dbus/org.gnome.Calls.Call.xml phosh-0.13.1/src/dbus/org.gnome.Calls.Call.xml --- phosh-0.8.0/src/dbus/org.gnome.Calls.Call.xml 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/dbus/org.gnome.Calls.Call.xml 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + The Id identifying the call, e.g. a phone number + + + + + + + The DisplayName of the calling party, e.g. from address book + + + + + + + The protocol used for this call + + + + + + + Whether the call is encrypted. This does not indicate anything about the + type of encryption being used. + + + + + diff -Nru phosh-0.8.0/src/dbus/org.gnome.Mutter.DisplayConfig.xml phosh-0.13.1/src/dbus/org.gnome.Mutter.DisplayConfig.xml --- phosh-0.8.0/src/dbus/org.gnome.Mutter.DisplayConfig.xml 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/dbus/org.gnome.Mutter.DisplayConfig.xml 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,459 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru phosh-0.8.0/src/dbus/org.gnome.SessionManager.EndSessionDialog.xml phosh-0.13.1/src/dbus/org.gnome.SessionManager.EndSessionDialog.xml --- phosh-0.8.0/src/dbus/org.gnome.SessionManager.EndSessionDialog.xml 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/dbus/org.gnome.SessionManager.EndSessionDialog.xml 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + + + + The type of dialog to show. + 0 for logout, 1 for shutdown, 2 for restart, 3 for hibernate, + 4 for suspend and 5 hybrid sleep. + + + + + + + Timestamp of the user-initiated event which triggered + the call, or 0 if the call was not triggered by an event. + + + + + + + The number of seconds which the dialog should stay open + before automatic action is taken. + + + + + + + The object paths of all inhibitors that are registered + for the action. + + + + + + This function opens a dialog which asks the user for confirmation + of a logout, poweroff or reboot action. The dialog has a timeout + after which the action is automatically taken, and it should show + the inhibitors to the user. + + + + + + + + + + + + + diff -Nru phosh-0.8.0/src/dbus/org.gnome.Shell.Screenshot.xml phosh-0.13.1/src/dbus/org.gnome.Shell.Screenshot.xml --- phosh-0.8.0/src/dbus/org.gnome.Shell.Screenshot.xml 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/dbus/org.gnome.Shell.Screenshot.xml 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru phosh-0.8.0/src/dbus/org.gnome.Shell.xml phosh-0.13.1/src/dbus/org.gnome.Shell.xml --- phosh-0.8.0/src/dbus/org.gnome.Shell.xml 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/dbus/org.gnome.Shell.xml 2021-08-31 09:15:52.000000000 +0000 @@ -25,6 +25,9 @@ + + + diff -Nru phosh-0.8.0/src/dbus/org.Gtk.MountOperationHandler.xml phosh-0.13.1/src/dbus/org.Gtk.MountOperationHandler.xml --- phosh-0.8.0/src/dbus/org.Gtk.MountOperationHandler.xml 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/dbus/org.Gtk.MountOperationHandler.xml 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru phosh-0.8.0/src/dbus/org.ofono.xml phosh-0.13.1/src/dbus/org.ofono.xml --- phosh-0.8.0/src/dbus/org.ofono.xml 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/dbus/org.ofono.xml 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru phosh-0.8.0/src/dbus/sm.puri.OSK0.xml phosh-0.13.1/src/dbus/sm.puri.OSK0.xml --- phosh-0.8.0/src/dbus/sm.puri.OSK0.xml 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/dbus/sm.puri.OSK0.xml 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,14 @@ + + + + + + + Switch keyboard visibility + + + + + + diff -Nru phosh-0.8.0/src/docked-info.c phosh-0.13.1/src/docked-info.c --- phosh-0.8.0/src/docked-info.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/docked-info.c 2021-08-31 09:15:52.000000000 +0000 @@ -101,9 +101,11 @@ } -static gboolean -on_idle (PhoshDockedInfo *self) +static void +phosh_docked_info_idle_init (PhoshStatusIcon *icon) { + PhoshDockedInfo *self = PHOSH_DOCKED_INFO (icon); + g_object_bind_property (self->manager, "icon-name", self, "icon-name", G_BINDING_SYNC_CREATE); @@ -120,8 +122,6 @@ G_CALLBACK (on_docked_mode_enabled), self); on_docked_mode_enabled (self, NULL, self->manager); - - return FALSE; } @@ -140,8 +140,6 @@ g_warning ("Failed to get docked manager"); return; } - - g_idle_add ((GSourceFunc) on_idle, self); } @@ -163,11 +161,17 @@ phosh_docked_info_class_init (PhoshDockedInfoClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + PhoshStatusIconClass *status_icon_class = PHOSH_STATUS_ICON_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->constructed = phosh_docked_info_constructed; object_class->dispose = phosh_docked_info_dispose; object_class->get_property = phosh_docked_info_get_property; + status_icon_class->idle_init = phosh_docked_info_idle_init; + + gtk_widget_class_set_css_name (widget_class, "phosh-docked-info"); + props[PROP_ENABLED] = g_param_spec_boolean ("enabled", "enabled", diff -Nru phosh-0.8.0/src/docked-manager.c phosh-0.13.1/src/docked-manager.c --- phosh-0.8.0/src/docked-manager.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/docked-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -276,6 +276,7 @@ const gchar *icon_name; g_return_if_fail (PHOSH_IS_DOCKED_MANAGER (self)); + g_return_if_fail ((enable && self->can_dock) || !enable); if (self->enabled == enable) return; diff -Nru phosh-0.8.0/src/end-session-dialog.c phosh-0.13.1/src/end-session-dialog.c --- phosh-0.8.0/src/end-session-dialog.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/end-session-dialog.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,557 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Parts taken from gnome-flashback which is: + * + * Copyright (C) 2008 William Jon McCann + * Copyright (C) 2015 Alberts Muktupāvels + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-end-session-dialog" + +#include "config.h" +#include "end-session-dialog.h" + +#include +#include + + +/** + * SECTION:end-session-dialog + * @short_description: A system modal prompt to authorize applications + * @Title: PhoshEndSessionDialog + * + * The #PhoshEndSessionDialog is used to confirm/decline the end of the session + * and is spawned by the #PhoshSessionManager. + */ + +#define SYNC_DBUS_TIMEOUT 500 + +enum { + CLOSED, + N_SIGNALS +}; +static guint signals[N_SIGNALS] = { 0 }; + + +enum { + PROP_0, + PROP_ACTION, + PROP_TIMEOUT, + PROP_INHIBITOR_PATHS, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + +static void end_session_dialog_update (PhoshEndSessionDialog *self); + +typedef struct _PhoshEndSessionDialog { + PhoshSystemModalDialog parent; + + int action; + gboolean action_confirmed; + int timeout; + int timeout_id; + GStrv inhibitor_paths; + + GtkWidget *lbl_subtitle; + GtkWidget *lbl_warn; + GtkWidget *listbox; + GtkWidget *btn_confirm; + GtkWidget *btn_cancel; + +} PhoshEndSessionDialog; + + +G_DEFINE_TYPE (PhoshEndSessionDialog, phosh_end_session_dialog, PHOSH_TYPE_SYSTEM_MODAL_DIALOG) + +static gboolean +is_inhibited (PhoshEndSessionDialog *self) +{ + return (self->inhibitor_paths && g_strv_length (self->inhibitor_paths)); +} + + +static char * +get_user_name (void) +{ + char *name; + + name = g_locale_to_utf8 (g_get_real_name (), -1, NULL, NULL, NULL); + + if (g_strcmp0 (name, "Unknown") == 0 || g_strcmp0 (name, "") == 0) { + g_free (name); + name = g_locale_to_utf8 (g_get_user_name (), -1, NULL, NULL, NULL); + } + + if (!name) + name = g_strdup (g_get_user_name ()); + + return name; +} + + +static void +on_btn_confirm_clicked (PhoshEndSessionDialog *self, GtkButton *btn) +{ + self->action_confirmed = TRUE; + + g_signal_emit (self, signals[CLOSED], 0); +} + + +static void +on_dialog_canceled (PhoshEndSessionDialog *self) +{ + g_return_if_fail (PHOSH_IS_END_SESSION_DIALOG (self)); + + g_signal_emit (self, signals[CLOSED], 0); +} + + +static gboolean +end_session_dialog_timeout (gpointer data) +{ + PhoshEndSessionDialog *self = PHOSH_END_SESSION_DIALOG (data); + + if (self->timeout == 0) { + on_btn_confirm_clicked (self, GTK_BUTTON (self->btn_confirm)); + self->timeout_id = 0; + return G_SOURCE_REMOVE; + } + + end_session_dialog_update (self); + self->timeout--; + + return G_SOURCE_CONTINUE; +} + + +static void +maybe_start_timer (PhoshEndSessionDialog *self) +{ + if (self->timeout_id == 0 && self->timeout) { + self->timeout_id = g_timeout_add_seconds (1, end_session_dialog_timeout, self); + g_source_set_name_by_id (self->timeout_id, "[phosh] end_session_dialog_timeout"); + } +} + + +static void +end_session_dialog_update (PhoshEndSessionDialog *self) +{ + gboolean inhibited; + gint seconds; + const char *title; + g_autofree char *description = NULL; + g_autofree char *user_name = NULL; + + maybe_start_timer (self); + seconds = self->timeout; + inhibited = is_inhibited (self); + + g_debug ("Action: %d, seconds: %d, inhibit: %d", + self->action, seconds, inhibited); + + switch (self->action) { + case PHOSH_END_SESSION_ACTION_LOGOUT: + title = _("Log Out"); + + user_name = get_user_name (); + description = g_strdup_printf (ngettext ("%s will be logged out automatically in %d second.", + "%s will be logged out automatically in %d seconds.", + seconds), + user_name, seconds); + break; + case PHOSH_END_SESSION_ACTION_SHUTDOWN: + title = _("Power Off"); + description = g_strdup_printf (ngettext ("The system will power off automatically in %d second.", + "The system will power off automatically in %d seconds.", + seconds), + seconds); + break; + case PHOSH_END_SESSION_ACTION_REBOOT: + title = _("Restart"); + description = g_strdup_printf (ngettext ("The system will restart automatically in %d second.", + "The system will restart automatically in %d seconds.", + seconds), + seconds); + break; + default: + g_return_if_reached (); + } + + phosh_system_modal_dialog_set_title (PHOSH_SYSTEM_MODAL_DIALOG (self), title); + + gtk_label_set_label (GTK_LABEL (self->lbl_subtitle), description); + gtk_button_set_label (GTK_BUTTON (self->btn_confirm), title); +} + + +static char * +inhibitor_get_app_id (GDBusProxy *proxy) +{ + g_autoptr (GError) error = NULL; + g_autoptr (GVariant) res = NULL; + char *app_id; + + res = g_dbus_proxy_call_sync (proxy, "GetAppId", NULL, + 0, SYNC_DBUS_TIMEOUT, NULL, &error); + if (!res) { + g_warning ("Failed to get Inhibitor app id: %s", error->message); + return NULL; + } + g_variant_get (res, "(s)", &app_id); + + return app_id; +} + + +static char * +inhibitor_get_reason (GDBusProxy *proxy) +{ + g_autoptr (GError) error = NULL; + g_autoptr (GVariant) res = NULL; + char *reason; + + res = g_dbus_proxy_call_sync (proxy, "GetReason", NULL, + 0, SYNC_DBUS_TIMEOUT, NULL, &error); + if (!res) { + g_warning ("Failed to get inhibit reason: %s", error->message); + return NULL; + } + g_variant_get (res, "(s)", &reason); + + return reason; +} + + +static void +add_inhibitor (PhoshEndSessionDialog *self, + GDBusProxy *inhibitor) +{ + g_autofree char *app_id = NULL; + g_autofree char *reason = NULL; + g_autofree char *desktop_file = NULL; + + g_autoptr (GDesktopAppInfo) app_info = NULL; + const char *icon_name = NULL; + const char *name = NULL; + GIcon *icon = NULL; + GtkWidget *box; + GtkWidget *box_text; + GtkWidget *label; + GtkWidget *lbl_reason; + GtkWidget *img; + + app_id = inhibitor_get_app_id (inhibitor); + reason = inhibitor_get_reason (inhibitor); + + if (app_id) { + if (g_str_has_suffix (app_id, ".desktop")) { + app_info = g_desktop_app_info_new (app_id); + } else { + desktop_file = g_strdup_printf ("%s.desktop", app_id); + app_info = g_desktop_app_info_new (desktop_file); + } + } + + if (app_info) { + icon = g_app_info_get_icon (G_APP_INFO (app_info)); + name = g_app_info_get_display_name (G_APP_INFO (app_info)); + } + + if (!name) + name = _("Unknown application"); + + if (!icon) + icon_name = "app-icon-unknown"; + + img = g_object_new (GTK_TYPE_IMAGE, + "visible", TRUE, + "can-focus", FALSE, + "gicon", icon, + "halign", GTK_ALIGN_START, + "pixel_size", 64, + NULL); + if (!icon) + g_object_set (img, "icon-name", icon_name, NULL); + + box_text = g_object_new (GTK_TYPE_BOX, + "visible", TRUE, + "can-focus", FALSE, + "halign", GTK_ALIGN_START, + "homogeneous", TRUE, + "orientation", GTK_ORIENTATION_VERTICAL, + "spacing", 0, + NULL); + + label = g_object_new (GTK_TYPE_LABEL, + "visible", TRUE, + "can-focus", FALSE, + "ellipsize", PANGO_ELLIPSIZE_MIDDLE, + "halign", GTK_ALIGN_START, + "label", name, + "valign", GTK_ALIGN_END, + NULL); + gtk_box_pack_start (GTK_BOX (box_text), label, TRUE, TRUE, 0); + + + if (reason) { + lbl_reason = g_object_new (GTK_TYPE_LABEL, + "visible", TRUE, + "can-focus", FALSE, + "ellipsize", PANGO_ELLIPSIZE_MIDDLE, + "halign", GTK_ALIGN_START, + "label", reason, + "valign", GTK_ALIGN_START, + NULL); + gtk_box_pack_end (GTK_BOX (box_text), lbl_reason, TRUE, TRUE, 0); + } else { + gtk_widget_set_valign (label, GTK_ALIGN_FILL); + } + + box = g_object_new (GTK_TYPE_BOX, + "visible", TRUE, + "can-focus", FALSE, + "halign", GTK_ALIGN_START, + "orientation", GTK_ORIENTATION_HORIZONTAL, + "spacing", 12, + NULL); + + gtk_box_pack_start (GTK_BOX (box), img, TRUE, TRUE, 0); + gtk_box_pack_end (GTK_BOX (box), box_text, FALSE, FALSE, 0); + + gtk_list_box_insert (GTK_LIST_BOX (self->listbox), GTK_WIDGET (box), -1); +} + + +static void +on_inhibitor_created (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + PhoshEndSessionDialog *self = PHOSH_END_SESSION_DIALOG (user_data); + + g_autoptr (GError) error = NULL; + g_autoptr (GDBusProxy) proxy = NULL; + + proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + + if (!proxy) { + g_warning ("Failed to create Inhibitor proxy: %s", error->message); + return; + } + + add_inhibitor (self, proxy); + g_object_unref (self); +} + + +static void +clear_inhibitors (PhoshEndSessionDialog *self) +{ + g_autoptr (GList) children = NULL; + + g_return_if_fail (GTK_IS_LIST_BOX (self->listbox)); + + children = gtk_container_get_children (GTK_CONTAINER (self->listbox)); + for (GList *child = children; child; child = child->next) + gtk_container_remove (GTK_CONTAINER (self->listbox), child->data); +} + + +static void +end_session_dialog_update_inhibitors (PhoshEndSessionDialog *self, GStrv paths) +{ + g_strfreev (self->inhibitor_paths); + self->inhibitor_paths = g_strdupv ((char **) paths); + + clear_inhibitors (self); + + if (!is_inhibited (self)) { + gtk_widget_hide (self->listbox); + return; + } + + for (int i = 0; self->inhibitor_paths[i]; i++) { + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, 0, NULL, + "org.gnome.SessionManager", + self->inhibitor_paths[i], + "org.gnome.SessionManager.Inhibitor", + NULL, on_inhibitor_created, g_object_ref (self)); + } + gtk_widget_show (GTK_WIDGET (self->listbox)); +} + + +static void +phosh_end_session_dialog_set_property (GObject *obj, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshEndSessionDialog *self = PHOSH_END_SESSION_DIALOG (obj); + + switch (prop_id) { + case PROP_ACTION: + self->action = g_value_get_int (value); + end_session_dialog_update (self); + break; + case PROP_TIMEOUT: + self->timeout = g_value_get_int (value); + end_session_dialog_update (self); + break; + case PROP_INHIBITOR_PATHS: + end_session_dialog_update_inhibitors (self, g_value_get_boxed (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + + +static void +phosh_end_session_dialog_get_property (GObject *obj, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshEndSessionDialog *self = PHOSH_END_SESSION_DIALOG (obj); + + switch (prop_id) { + case PROP_ACTION: + g_value_set_int (value, self->action); + break; + case PROP_TIMEOUT: + g_value_set_int (value, self->timeout); + break; + case PROP_INHIBITOR_PATHS: + g_value_set_boxed (value, self->inhibitor_paths); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + + +static void +phosh_end_session_dialog_dispose (GObject *obj) +{ + PhoshEndSessionDialog *self = PHOSH_END_SESSION_DIALOG (obj); + + if (self->listbox) + clear_inhibitors (self); + + G_OBJECT_CLASS (phosh_end_session_dialog_parent_class)->dispose (obj); +} + + +static void +phosh_end_session_dialog_finalize (GObject *obj) +{ + PhoshEndSessionDialog *self = PHOSH_END_SESSION_DIALOG (obj); + + g_clear_handle_id (&self->timeout_id, g_source_remove); + g_clear_pointer (&self->inhibitor_paths, g_strfreev); + + G_OBJECT_CLASS (phosh_end_session_dialog_parent_class)->finalize (obj); +} + + +static void +phosh_end_session_dialog_class_init (PhoshEndSessionDialogClass *klass) +{ + GObjectClass *object_class = (GObjectClass *)klass; + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->get_property = phosh_end_session_dialog_get_property; + object_class->set_property = phosh_end_session_dialog_set_property; + object_class->dispose = phosh_end_session_dialog_dispose; + object_class->finalize = phosh_end_session_dialog_finalize; + + props[PROP_ACTION] = + g_param_spec_int ("action", + "Action", + "The requested action", + -1, + G_MAXINT, + -1, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + props[PROP_TIMEOUT] = + g_param_spec_int ("timeout", + "Timeout", + "Timeout in seconds after which the action is performed", + -1, + G_MAXINT, + -1, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + props[PROP_INHIBITOR_PATHS] = + g_param_spec_boxed ("inhibitor-paths", + "Inhibitor paths", + "Paths to inhibitors that prevent atction", + G_TYPE_STRV, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); + + signals[CLOSED] = g_signal_new ("closed", + G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, + NULL, G_TYPE_NONE, 0); + + gtk_widget_class_set_template_from_resource (widget_class, + "/sm/puri/phosh/ui/end-session-dialog.ui"); + gtk_widget_class_bind_template_child (widget_class, PhoshEndSessionDialog, lbl_subtitle); + gtk_widget_class_bind_template_child (widget_class, PhoshEndSessionDialog, lbl_warn); + gtk_widget_class_bind_template_child (widget_class, PhoshEndSessionDialog, listbox); + gtk_widget_class_bind_template_child (widget_class, PhoshEndSessionDialog, btn_confirm); + gtk_widget_class_bind_template_child (widget_class, PhoshEndSessionDialog, btn_cancel); + gtk_widget_class_bind_template_callback (widget_class, on_btn_confirm_clicked); + gtk_widget_class_bind_template_callback (widget_class, on_dialog_canceled); +} + + +static void +phosh_end_session_dialog_init (PhoshEndSessionDialog *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} + + +GtkWidget * +phosh_end_session_dialog_new (gint action, + gint timeout, + const char *const *inhibitor_paths) +{ + return g_object_new (PHOSH_TYPE_END_SESSION_DIALOG, + "action", action, + "timeout", timeout, + "inhibitor-paths", inhibitor_paths, + NULL); +} + + +gboolean +phosh_end_session_dialog_get_action_confirmed (PhoshEndSessionDialog *self) +{ + g_return_val_if_fail (PHOSH_END_SESSION_DIALOG (self), FALSE); + + return self->action_confirmed; +} + + +gboolean +phosh_end_session_dialog_get_action (PhoshEndSessionDialog *self) +{ + g_return_val_if_fail (PHOSH_END_SESSION_DIALOG (self), 0); + + return self->action; +} diff -Nru phosh-0.8.0/src/end-session-dialog.h phosh-0.13.1/src/end-session-dialog.h --- phosh-0.8.0/src/end-session-dialog.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/end-session-dialog.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include +#include "system-modal-dialog.h" + +G_BEGIN_DECLS + +#define PHOSH_TYPE_END_SESSION_DIALOG (phosh_end_session_dialog_get_type ()) + +G_DECLARE_FINAL_TYPE (PhoshEndSessionDialog, phosh_end_session_dialog, PHOSH, + END_SESSION_DIALOG, PhoshSystemModalDialog) + +/** + * PhoshLogoutAction: + * @PHOSH_END_SESSION_ACTION_LOGOUT: Loguout + * @PHOSH_END_SESSION_ACTION_SHUTDOWN: Shutdown + * @PHOSH_END_SESSION_ACTION_REBOOT: Reboot + * + * The requested action the #PhoshEndSessionDialog should display. This matches + * the values of the DBus protocols 'open' request.. + */ +typedef enum { + PHOSH_END_SESSION_ACTION_LOGOUT, + PHOSH_END_SESSION_ACTION_SHUTDOWN, + PHOSH_END_SESSION_ACTION_REBOOT, + /* Not used by gnome-session */ + /**/ + PHOSH_END_SESSION_ACTION_HIBERNATE, + PHOSH_END_SESSION_ACTION_SUSPEND, + PHOSH_END_SESSION_ACTION_HYBRID_SLEEP, +} PhoshLogoutAction; + +GtkWidget *phosh_end_session_dialog_new (gint action, + gint seconds, + const char *const * paths); +gboolean phosh_end_session_dialog_get_action_confirmed (PhoshEndSessionDialog *self); +gint phosh_end_session_dialog_get_action (PhoshEndSessionDialog *self); + +G_END_DECLS diff -Nru phosh-0.8.0/src/fader.c phosh-0.13.1/src/fader.c --- phosh-0.8.0/src/fader.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/fader.c 2021-08-31 09:15:52.000000000 +0000 @@ -19,28 +19,89 @@ * @short_description: A fader * @Title: PhoshFader * - * A fullsreen surface that fades in + * A fullsreen surface that fades in or out. */ +#define PHOSH_FADER_DEFAULT_STYLE_CLASS "phosh-fader-default-fade" + +enum { + PROP_0, + PROP_MONITOR, + PROP_STYLE_CLASS, + PROP_LAST_PROP, +}; +static GParamSpec *props[PROP_LAST_PROP]; + typedef struct _PhoshFader { - PhoshLayerSurface parent; - + PhoshLayerSurface parent; + PhoshMonitor *monitor; + char *style_class; } PhoshFader; G_DEFINE_TYPE (PhoshFader, phosh_fader, PHOSH_TYPE_LAYER_SURFACE) static void +phosh_fader_set_property (GObject *obj, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshFader *self = PHOSH_FADER (obj); + + switch (prop_id) { + case PROP_MONITOR: + /* construct only */ + g_set_object (&self->monitor, g_value_get_object (value)); + break; + case PROP_STYLE_CLASS: + g_free (self->style_class); + self->style_class = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + + +static void +phosh_fader_get_property (GObject *obj, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshFader *self = PHOSH_FADER (obj); + + switch (prop_id) { + case PROP_MONITOR: + g_value_set_object (value, self->monitor); + break; + case PROP_STYLE_CLASS: + g_value_set_string (value, self->style_class); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + + +static void phosh_fader_show (GtkWidget *widget) { + PhoshFader *self = PHOSH_FADER (widget); gboolean enable_animations; GtkStyleContext *context; enable_animations = hdy_get_enable_animations (widget); if (enable_animations) { - context = gtk_widget_get_style_context(widget); - gtk_style_context_add_class (context, "phosh-fader-fade-in"); + const char *style_class; + + style_class = self->style_class ?: PHOSH_FADER_DEFAULT_STYLE_CLASS; + context = gtk_widget_get_style_context (widget); + gtk_style_context_add_class (context, style_class); } GTK_WIDGET_CLASS (phosh_fader_parent_class)->show (widget); @@ -48,37 +109,89 @@ static void +phosh_fader_dispose (GObject *object) +{ + PhoshFader *self = PHOSH_FADER (object); + + g_clear_object (&self->monitor); + g_clear_pointer (&self->style_class, g_free); + + G_OBJECT_CLASS (phosh_fader_parent_class)->dispose (object); +} + + +static void +phosh_fader_constructed (GObject *object) +{ + PhoshFader *self = PHOSH_FADER (object); + PhoshWayland *wl = phosh_wayland_get_default (); + + if (self->monitor == NULL) + self->monitor = g_object_ref (phosh_shell_get_primary_monitor (phosh_shell_get_default ())); + + g_object_set (PHOSH_LAYER_SURFACE (self), + "layer-shell", phosh_wayland_get_zwlr_layer_shell_v1 (wl), + "wl-output", phosh_monitor_get_wl_output (self->monitor), + "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, + "layer", ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, + "kbd-interactivity", FALSE, + "exclusive-zone", -1, + "namespace", "phosh fader", + NULL); + + G_OBJECT_CLASS (phosh_fader_parent_class)->constructed (object); +} + + +static void phosh_fader_class_init (PhoshFaderClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + object_class->get_property = phosh_fader_get_property; + object_class->set_property = phosh_fader_set_property; + object_class->constructed = phosh_fader_constructed; + object_class->dispose = phosh_fader_dispose; widget_class->show = phosh_fader_show; + + props[PROP_MONITOR] = g_param_spec_object ("monitor", + "", + "", + PHOSH_TYPE_MONITOR, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + /** + * PhoshFader:style-class + * + * The CSS style class used for the animation + */ + props[PROP_STYLE_CLASS] = g_param_spec_string ("style-class", + "", + "", + NULL, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); } static void phosh_fader_init (PhoshFader *self) { - GtkStyleContext *context; - - context = gtk_widget_get_style_context(GTK_WIDGET (self)); - gtk_style_context_remove_class(context, "phosh-fader-fade-in"); + self->style_class = g_strdup (PHOSH_FADER_DEFAULT_STYLE_CLASS); } PhoshFader * -phosh_fader_new (gpointer layer_shell, gpointer wl_output) +phosh_fader_new (PhoshMonitor *monitor) { - return g_object_new (PHOSH_TYPE_FADER, - "layer-shell", layer_shell, - "wl-output", wl_output, - "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, - "layer", ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, - "kbd-interactivity", FALSE, - "exclusive-zone", -1, - "namespace", "phosh fader", - NULL); + return g_object_new (PHOSH_TYPE_FADER, "monitor", monitor, NULL); } diff -Nru phosh-0.8.0/src/fader.h phosh-0.13.1/src/fader.h --- phosh-0.8.0/src/fader.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/fader.h 2021-08-31 09:15:52.000000000 +0000 @@ -5,6 +5,8 @@ */ #pragma once +#include "monitor/monitor.h" + #include G_BEGIN_DECLS @@ -13,6 +15,6 @@ G_DECLARE_FINAL_TYPE (PhoshFader, phosh_fader, PHOSH, FADER, PhoshLayerSurface) -PhoshFader *phosh_fader_new (gpointer layer_shell, - gpointer wl_output); +PhoshFader *phosh_fader_new (PhoshMonitor *monitor); + G_END_DECLS diff -Nru phosh-0.8.0/src/feedbackinfo.c phosh-0.13.1/src/feedbackinfo.c --- phosh-0.8.0/src/feedbackinfo.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/feedbackinfo.c 2021-08-31 09:15:52.000000000 +0000 @@ -93,9 +93,12 @@ phosh_feedback_info_class_init (PhoshFeedbackInfoClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->constructed = phosh_feedback_info_constructed; object_class->dispose = phosh_feedback_info_dispose; + + gtk_widget_class_set_css_name (widget_class, "phosh-feedback-info"); } diff -Nru phosh-0.8.0/src/feedback-manager.c phosh-0.13.1/src/feedback-manager.c --- phosh-0.8.0/src/feedback-manager.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/feedback-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -21,6 +21,7 @@ */ #define PHOSH_FEEDBACK_ICON_FULL "preferences-system-notifications-symbolic" +#define PHOSH_FEEDBACK_ICON_QUIET "feedback-quiet-symbolic" #define PHOSH_FEEDBACK_ICON_SILENT "notifications-disabled-symbolic" enum { @@ -94,10 +95,12 @@ const char *profile = self->profile; self->profile = lfb_get_feedback_profile (); - if (g_strcmp0 (self->profile, "quiet") && g_strcmp0 (self->profile, "silent")) - self->icon_name = PHOSH_FEEDBACK_ICON_FULL; - else + if (g_strcmp0 (self->profile, "quiet") == 0) + self->icon_name = PHOSH_FEEDBACK_ICON_QUIET; + else if (g_strcmp0 (self->profile, "silent") == 0) self->icon_name = PHOSH_FEEDBACK_ICON_SILENT; + else + self->icon_name = PHOSH_FEEDBACK_ICON_FULL; g_debug("Feedback profile set to: '%s', icon '%s'", self->profile, self->icon_name); @@ -215,12 +218,14 @@ void phosh_feedback_manager_toggle (PhoshFeedbackManager *self) { - const char *profile = "silent"; + const char *profile = "silent", *old = lfb_get_feedback_profile (); - if (g_strcmp0 (lfb_get_feedback_profile (), "full")) + if (!g_strcmp0 (old, "silent")) profile = "full"; + else if (!g_strcmp0 (old, "full")) + profile = "quiet"; - g_debug ("Setting feedback profile to %s", profile); + g_debug ("Setting feedback profile to %s, was %s", profile, old); lfb_set_feedback_profile (profile); } diff -Nru phosh-0.8.0/src/gnome-shell-manager.c phosh-0.13.1/src/gnome-shell-manager.c --- phosh-0.8.0/src/gnome-shell-manager.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/gnome-shell-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -12,7 +12,10 @@ #include "../config.h" #include "gnome-shell-manager.h" +#include "osd-window.h" #include "shell.h" +#include "util.h" +#include "lockscreen-manager.h" /** * SECTION:gnome-shell-manager @@ -21,17 +24,29 @@ * */ -#define NOTIFY_DBUS_NAME "org.gnome.Shell" - +#define GNOME_SHELL_DBUS_NAME "org.gnome.Shell" +#define OSD_HIDE_TIMEOUT 1 /* seconds */ static void phosh_gnome_shell_manager_shell_iface_init (PhoshGnomeShellDBusShellIface *iface); +enum { + PROP_0, + PROP_ACTION_MODE, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + typedef struct _PhoshGnomeShellManager { PhoshGnomeShellDBusShellSkeleton parent; GHashTable *info_by_action; guint last_action_id; int dbus_name_id; + ShellActionMode action_mode; + + PhoshOsdWindow *osd; + gint osd_timeoutid; + gboolean osd_continue; } PhoshGnomeShellManager; G_DEFINE_TYPE_WITH_CODE (PhoshGnomeShellManager, @@ -47,18 +62,17 @@ guint action_id; gchar *accelerator; gchar *sender; + guint mode_flags; + guint grab_flags; } AcceleratorInfo; static void -remove_action_entries (const gchar *accelerator) +remove_action_entries (gchar *accelerator) { - const GActionEntry action_entries[] = { - { accelerator, accelerator_activated_action, }, - }; + GStrv action_names = (char*[]){ accelerator, NULL }; phosh_shell_remove_global_keyboard_action_entries (phosh_shell_get_default (), - action_entries, - G_N_ELEMENTS (action_entries)); + action_names); } static void @@ -107,6 +121,80 @@ static gboolean +on_osd_timeout (PhoshGnomeShellManager *self) +{ + gboolean ret; + ret = self->osd_continue ? G_SOURCE_CONTINUE : G_SOURCE_REMOVE; + if (!self->osd_continue) { + g_debug ("Closing osd"); + self->osd_timeoutid = 0; + if (self->osd) + gtk_widget_destroy (GTK_WIDGET (self->osd)); + } + self->osd_continue = FALSE; + return ret; +} + +static void +on_osd_destroyed (PhoshGnomeShellManager *self) +{ + self->osd = NULL; + g_clear_handle_id (&self->osd_timeoutid, g_source_remove); +} + + +static gboolean +handle_show_osd (PhoshGnomeShellDBusShell *skeleton, + GDBusMethodInvocation *invocation, + GVariant *arg_params) +{ + PhoshGnomeShellManager *self = PHOSH_GNOME_SHELL_MANAGER (skeleton); + GVariantDict dict; + g_autofree char *connector = NULL, *icon = NULL, *label = NULL; + gdouble level = 0.0, maxlevel = 1.0; + + g_return_val_if_fail (PHOSH_IS_GNOME_SHELL_MANAGER (self), FALSE); + + g_variant_dict_init (&dict, arg_params); + g_variant_dict_lookup (&dict, "connector", "s", &connector); + g_variant_dict_lookup (&dict, "icon", "s", &icon); + g_variant_dict_lookup (&dict, "label", "s", &label); + g_variant_dict_lookup (&dict, "level", "d", &level); + g_variant_dict_lookup (&dict, "max_level", "d", &maxlevel); + + g_debug ("DBus show osd: connector: %s icon: %s, label: %s, level %f/%f", + connector, icon, label, level, maxlevel); + + if (self->osd) { + self->osd_continue = TRUE; + g_object_set (self->osd, + "connector", connector, + "label", label, + "icon-name", icon, + "level", level, + "max-level", maxlevel, + NULL); + } else { + self->osd = PHOSH_OSD_WINDOW (phosh_osd_window_new (connector, label, icon, level, maxlevel)); + g_signal_connect_swapped (self->osd, "destroy", G_CALLBACK (on_osd_destroyed), self); + gtk_widget_show (GTK_WIDGET (self->osd)); + } + + if (!self->osd_timeoutid) { + self->osd_timeoutid = g_timeout_add_seconds (OSD_HIDE_TIMEOUT, + (GSourceFunc)on_osd_timeout, + self); + g_source_set_name_by_id (self->osd_timeoutid, "[phosh] osd-timeout"); + } + + phosh_gnome_shell_dbus_shell_complete_show_osd ( + skeleton, invocation); + + return TRUE; +} + + +static gboolean grab_single_accelerator (PhoshGnomeShellManager *self, const gchar *accelerator, guint mode_flags, @@ -129,6 +217,8 @@ info->accelerator = g_strdup (accelerator); info->action_id = ++(self->last_action_id); info->sender = g_strdup (sender); + info->mode_flags = mode_flags; + info->grab_flags = grab_flags; g_debug ("Using action id %d for accelerator %s", info->action_id, info->accelerator); @@ -192,7 +282,7 @@ { PhoshGnomeShellManager *self = PHOSH_GNOME_SHELL_MANAGER (skeleton); g_autoptr (GVariantBuilder) builder = NULL; - GVariantIter *arg_iter; + g_autoptr (GVariantIter) arg_iter = NULL; gchar *accelerator_name; guint accelerator_mode_flags; guint accelerator_grab_flags; @@ -349,12 +439,37 @@ { iface->handle_show_monitor_labels = handle_show_monitor_labels; iface->handle_hide_monitor_labels = handle_hide_monitor_labels; + iface->handle_show_osd = handle_show_osd; iface->handle_grab_accelerator = handle_grab_accelerator; iface->handle_grab_accelerators = handle_grab_accelerators; iface->handle_ungrab_accelerator = handle_ungrab_accelerator; iface->handle_ungrab_accelerators = handle_ungrab_accelerators; } +static ShellActionMode +get_action_mode (PhoshShellStateFlags state) +{ + PhoshShell *shell = phosh_shell_get_default (); + + if (state & PHOSH_STATE_LOCKED) { + PhoshLockscreenManager *lockscreen_manager = phosh_shell_get_lockscreen_manager (shell); + PhoshLockscreenPage page = phosh_lockscreen_manager_get_page (lockscreen_manager); + + if (page == PHOSH_LOCKSCREEN_PAGE_UNLOCK) + return SHELL_ACTION_MODE_UNLOCK_SCREEN; + else + return SHELL_ACTION_MODE_LOCK_SCREEN; + } + + if (state & PHOSH_STATE_MODAL_SYSTEM_PROMPT) + return SHELL_ACTION_MODE_SYSTEM_MODAL; + + if (state & PHOSH_STATE_OVERVIEW) + return SHELL_ACTION_MODE_OVERVIEW; + + return SHELL_ACTION_MODE_NORMAL; +} + static void accelerator_activated_action (GSimpleAction *action, GVariant *param, @@ -362,13 +477,22 @@ { AcceleratorInfo *info = (AcceleratorInfo *) data; PhoshGnomeShellManager *self = phosh_gnome_shell_manager_get_default (); - g_autoptr (GVariantBuilder) builder; + g_autoptr (GVariantBuilder) builder = NULL; GVariant *parameters; uint32_t action_id; action_id = info->action_id; g_debug ("accelerator action activated for id %u", action_id); + if ((info->mode_flags & self->action_mode) == 0) { + g_autofree gchar *str_shell_mode = g_flags_to_string (SHELL_TYPE_ACTION_MODE, self->action_mode); + g_autofree gchar *str_grabbed_mode = g_flags_to_string (SHELL_TYPE_ACTION_MODE, info->mode_flags); + g_debug ("Accelerator registered for mode %s, but shell is currently in %s", + str_grabbed_mode, + str_shell_mode); + return; + } + builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); /* * Fill some dummy values @@ -412,31 +536,86 @@ const char *name, gpointer user_data) { - PhoshGnomeShellManager *self = user_data; + g_autoptr (GError) err = NULL; + PhoshGnomeShellManager *self = PHOSH_GNOME_SHELL_MANAGER (user_data); + PhoshSessionManager *sm; + gboolean success; - g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self), - connection, - "/org/gnome/Shell", - NULL); + success = g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self), + connection, + "/org/gnome/Shell", + NULL); + if (!success) { + g_warning ("Failed to export shell interface: %s", err->message); + return; + } + + sm = phosh_shell_get_session_manager (phosh_shell_get_default ()); + phosh_session_manager_export_end_session (sm, connection); } +static gboolean +transform_state_to_action_mode (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer unused) +{ + PhoshShellStateFlags shell_state = g_value_get_flags (from_value); + ShellActionMode action_mode = get_action_mode (shell_state); + + g_value_set_flags (to_value, action_mode); + return TRUE; +} + static void -phosh_gnome_shell_manager_dispose (GObject *object) +phosh_gnome_shell_manager_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) { PhoshGnomeShellManager *self = PHOSH_GNOME_SHELL_MANAGER (object); - GList *grabbed; - guint n = 0; - for (grabbed = g_hash_table_get_keys (self->info_by_action); grabbed != NULL; grabbed = grabbed->next) { - AcceleratorInfo *info = grabbed->data; + switch (property_id) { + case PROP_ACTION_MODE: + self->action_mode = g_value_get_flags (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} - g_hash_table_remove (self->info_by_action, GUINT_TO_POINTER (info->action_id)); - ++n; + +static void +phosh_gnome_shell_manager_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshGnomeShellManager *self = PHOSH_GNOME_SHELL_MANAGER (object); + + switch (property_id) { + case PROP_ACTION_MODE: + g_value_set_flags (value, self->action_mode); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; } - g_hash_table_unref (self->info_by_action); +} + +static void +phosh_gnome_shell_manager_dispose (GObject *object) +{ + PhoshGnomeShellManager *self = PHOSH_GNOME_SHELL_MANAGER (object); + + g_clear_handle_id (&self->dbus_name_id, g_bus_unown_name); - g_debug ("%d accelerators needed to be cleaned up!", n); + if (g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (self))) + g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self)); + + g_clear_pointer (&self->info_by_action, g_hash_table_unref); G_OBJECT_CLASS (phosh_gnome_shell_manager_parent_class)->dispose (object); } @@ -446,17 +625,25 @@ phosh_gnome_shell_manager_constructed (GObject *object) { PhoshGnomeShellManager *self = PHOSH_GNOME_SHELL_MANAGER (object); + PhoshShell *shell = phosh_shell_get_default (); G_OBJECT_CLASS (phosh_gnome_shell_manager_parent_class)->constructed (object); + + g_object_bind_property_full (shell, "shell-state", + object, "shell-action-mode", + G_BINDING_SYNC_CREATE, + (GBindingTransformFunc) transform_state_to_action_mode, + NULL, NULL, NULL); + self->dbus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION, - NOTIFY_DBUS_NAME, + GNOME_SHELL_DBUS_NAME, G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | G_BUS_NAME_OWNER_FLAGS_REPLACE, on_bus_acquired, on_name_acquired, on_name_lost, - g_object_ref (self), - g_object_unref); + self, + NULL); } @@ -465,8 +652,21 @@ { GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->get_property = phosh_gnome_shell_manager_get_property; + object_class->set_property = phosh_gnome_shell_manager_set_property; object_class->constructed = phosh_gnome_shell_manager_constructed; object_class->dispose = phosh_gnome_shell_manager_dispose; + + props[PROP_ACTION_MODE] = + g_param_spec_flags ("shell-action-mode", + "Shell Action Mode", + "The active action mode (used for keygrabbing)", + SHELL_TYPE_ACTION_MODE, + SHELL_ACTION_MODE_NONE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); + } diff -Nru phosh-0.8.0/src/gnome-shell-manager.h phosh-0.13.1/src/gnome-shell-manager.h --- phosh-0.8.0/src/gnome-shell-manager.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/gnome-shell-manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -5,12 +5,51 @@ * * Author: Guido Günther * Evangelos Ribeiro Tzaras + * + * ShellActionMode is from GNOME Shell's shell-action-modes.h + * which is GPL-2.0-or-later and authored by + * Florian Müllner */ #pragma once #include "dbus/phosh-gnome-shell-dbus.h" #include +/** + * ShellActionMode: + * @SHELL_ACTION_MODE_NONE: block action + * @SHELL_ACTION_MODE_NORMAL: allow action when in window mode, + * e.g. when the focus is in an application window + * @SHELL_ACTION_MODE_OVERVIEW: allow action while the overview + * is active + * @SHELL_ACTION_MODE_LOCK_SCREEN: allow action when the screen + * is locked, e.g. when the screen shield is shown + * @SHELL_ACTION_MODE_UNLOCK_SCREEN: allow action in the unlock + * dialog + * @SHELL_ACTION_MODE_LOGIN_SCREEN: allow action in the login screen + * @SHELL_ACTION_MODE_SYSTEM_MODAL: allow action when a system modal + * dialog (e.g. authentication or session dialogs) is open + * @SHELL_ACTION_MODE_LOOKING_GLASS: allow action in looking glass + * @SHELL_ACTION_MODE_POPUP: allow action while a shell menu is open + * @SHELL_ACTION_MODE_ALL: always allow action + * + * Controls in which GNOME Shell states an action (like keybindings and gestures) + * should be handled. +*/ +typedef enum { + SHELL_ACTION_MODE_NONE = 0, + SHELL_ACTION_MODE_NORMAL = 1 << 0, + SHELL_ACTION_MODE_OVERVIEW = 1 << 1, + SHELL_ACTION_MODE_LOCK_SCREEN = 1 << 2, + SHELL_ACTION_MODE_UNLOCK_SCREEN = 1 << 3, + SHELL_ACTION_MODE_LOGIN_SCREEN = 1 << 4, + SHELL_ACTION_MODE_SYSTEM_MODAL = 1 << 5, + SHELL_ACTION_MODE_LOOKING_GLASS = 1 << 6, + SHELL_ACTION_MODE_POPUP = 1 << 7, + + SHELL_ACTION_MODE_ALL = ~0, +} ShellActionMode; + G_BEGIN_DECLS #define PHOSH_TYPE_GNOME_SHELL_MANAGER (phosh_gnome_shell_manager_get_type ()) diff -Nru phosh-0.8.0/src/gtk-mount-manager.c phosh-0.13.1/src/gtk-mount-manager.c --- phosh-0.8.0/src/gtk-mount-manager.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/gtk-mount-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-gtk-mount-manager" + +#include "gtk-mount-manager.h" +#include "gtk-mount-prompt.h" +#include "shell.h" +#include "util.h" + +#include + +/** + * SECTION:gtk-mount-manager + * @short_description: Provides the org.Gtk.GtkMountOperationHandler DBus interface + * @Title: PhoshGtkMountManager + * + * The interface is responsible to handle the ui parts of a #GtkMountOperation. + */ + +#define GTK_MOUNT_DBUS_NAME "org.gtk.MountOperationHandler" + +enum { + NEW_PROMPT, + N_SIGNALS +}; +static guint signals[N_SIGNALS] = { 0 }; + +static void phosh_gtk_mount_manager_gtk_mount_iface_init ( + PhoshDBusMountOperationHandlerIface *iface); + +typedef struct _PhoshGtkMountManager { + PhoshDBusMountOperationHandlerSkeleton parent; + + int dbus_name_id; + PhoshGtkMountPrompt *prompt; + char *object_id; + + GDBusMethodInvocation *invocation; +} PhoshGtkMountManager; + +G_DEFINE_TYPE_WITH_CODE (PhoshGtkMountManager, + phosh_gtk_mount_manager, + PHOSH_DBUS_TYPE_MOUNT_OPERATION_HANDLER_SKELETON, + G_IMPLEMENT_INTERFACE ( + PHOSH_DBUS_TYPE_MOUNT_OPERATION_HANDLER, + phosh_gtk_mount_manager_gtk_mount_iface_init)); + + +static void +on_prompt_done (PhoshGtkMountManager *self, PhoshGtkMountPrompt *prompt) +{ + gboolean cancelled; + GMountOperationResult response = G_MOUNT_OPERATION_ABORTED; + g_autoptr (GVariantDict) response_details = g_variant_dict_new (NULL); + + g_return_if_fail (PHOSH_IS_GTK_MOUNT_MANAGER (self)); + g_return_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (prompt)); + + cancelled = phosh_gtk_mount_prompt_get_cancelled (prompt); + g_debug ("Prompt done, cancelled: %d", cancelled); + + if (phosh_gtk_mount_prompt_get_choices (prompt)) { /* AskQuestion / ShowProcesses */ + int choice = phosh_gtk_mount_prompt_get_choice (prompt); + + if (!cancelled) { + response = G_MOUNT_OPERATION_HANDLED; + g_variant_dict_insert (response_details, "choice", "i", choice); + } + } else { /* AskPassword / Default buttons */ + if (!cancelled) { + const char *password; + + response = G_MOUNT_OPERATION_HANDLED; + password = phosh_gtk_mount_prompt_get_password (prompt); + g_variant_dict_insert (response_details, "password", "s", password ?: "", NULL); + /* + * GTKs gtkmountoperation:call_password_proxy_cb only cares about + * 'password', 'password_save', 'hidden_volume', 'system_volume' and 'pim' + * so no need to bother with usernames and domains here + */ + /* TODO: 'password_save' */ + } + } + + if (self->invocation) { + /* + * phosh_dbus_mount_operation_handler_complete_ask_question has the same + * signature and params so we can use either one + */ + phosh_dbus_mount_operation_handler_complete_ask_password ( + PHOSH_DBUS_MOUNT_OPERATION_HANDLER (self), + self->invocation, response, + g_variant_dict_end (response_details)); + self->invocation = NULL; + } else { + g_warning ("No invocation!"); + } +} + + +static void +end_ask_invocation (PhoshGtkMountManager *self) +{ + g_autoptr (GVariantDict) response_details = g_variant_dict_new (NULL); + + if (!self->invocation) + return; + + /* + * phosh_dbus_mount_operation_handler_complete_* all have the same + * signature and params so we can any of them: + */ + phosh_dbus_mount_operation_handler_complete_ask_password ( + PHOSH_DBUS_MOUNT_OPERATION_HANDLER (self), + self->invocation, G_MOUNT_OPERATION_UNHANDLED, + g_variant_dict_end (response_details)); + self->invocation = NULL; +} + + +static void +new_prompt (PhoshGtkMountManager *self, + const char *message, + const char *icon_name, + const char *default_user, + const char *default_domain, + GVariant *pids, + const char *const *choices, + GAskPasswordFlags ask_flags) +{ + g_debug ("New prompt for '%s'", message); + + g_clear_pointer (&self->prompt, phosh_cp_widget_destroy); + + self->prompt = PHOSH_GTK_MOUNT_PROMPT (phosh_gtk_mount_prompt_new ( + message, + icon_name, + default_user, + default_domain, + pids, + choices, + ask_flags)); + g_signal_connect_swapped (self->prompt, + "closed", + G_CALLBACK (on_prompt_done), + self); + + gtk_widget_show (GTK_WIDGET (self->prompt)); + + g_signal_emit (self, signals[NEW_PROMPT], 0); +} + + +static gboolean +handle_ask_password (PhoshDBusMountOperationHandler *object, + GDBusMethodInvocation *invocation, + const char *arg_object_id, + const char *arg_message, + const char *arg_icon_name, + const char *arg_default_user, + const char *arg_default_domain, + guint arg_flags) +{ + PhoshGtkMountManager *self = PHOSH_GTK_MOUNT_MANAGER (object); + + g_debug ("DBus call AskPassword for '%s'", arg_object_id); + + if (self->invocation) + end_ask_invocation (self); + self->invocation = invocation; + + new_prompt (self, + arg_message, + arg_icon_name, + arg_default_user, + arg_default_domain, + NULL, + NULL, + arg_flags); + + return TRUE; +} + +static gboolean +handle_ask_question ( PhoshDBusMountOperationHandler *object, + GDBusMethodInvocation *invocation, + const char *arg_object_id, + const char *arg_message, + const char *arg_icon_name, + const char *const *arg_choices) +{ + PhoshGtkMountManager *self = PHOSH_GTK_MOUNT_MANAGER (object); + + g_debug ("DBus call AskQuestion: %s", arg_object_id); + + /* Cancel an ongoing dialog */ + if (self->invocation) + end_ask_invocation (self); + self->invocation = invocation; + + new_prompt (self, + arg_message, + arg_icon_name, + NULL, + NULL, + NULL, + arg_choices, + 0); + + return TRUE; +} + +static gboolean +handle_show_processes (PhoshDBusMountOperationHandler *object, + GDBusMethodInvocation *invocation, + const char *arg_object_id, + const char *arg_message, + const char *arg_icon_name, + GVariant *arg_application_pids, + const char *const *arg_choices) +{ + PhoshGtkMountManager *self = PHOSH_GTK_MOUNT_MANAGER (object); + + g_debug ("DBus call ShowProcesses: %s", arg_object_id); + + if (arg_object_id == NULL) { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_ACCESS_DENIED, + "No object id"); + invocation = NULL; + return TRUE; + } + + if (!g_strcmp0 (arg_object_id, self->object_id) && self->prompt) { + g_debug ("Updating dialog %s", self->object_id); + + phosh_gtk_mount_prompt_set_pids (self->prompt, arg_application_pids); + self->invocation = invocation; + return TRUE; + } + + g_clear_pointer (&self->object_id, g_free); + self->object_id = g_strdup (arg_object_id); + + if (self->invocation) + end_ask_invocation (self); + self->invocation = invocation; + + new_prompt (self, + arg_message, + arg_icon_name, + NULL, + NULL, + arg_application_pids, + arg_choices, + 0); + + return TRUE; +} + +static gboolean +handle_close (PhoshDBusMountOperationHandler *object, + GDBusMethodInvocation *invocation) +{ + PhoshGtkMountManager *self = PHOSH_GTK_MOUNT_MANAGER (object); + + g_debug ("DBus call Close"); + + end_ask_invocation (self); + + g_clear_pointer (&self->prompt, phosh_cp_widget_destroy); + g_clear_pointer (&self->object_id, g_free); + + phosh_dbus_mount_operation_handler_complete_close ( + object, invocation); + + return TRUE; +} + +static void +phosh_gtk_mount_manager_gtk_mount_iface_init (PhoshDBusMountOperationHandlerIface *iface) +{ + iface->handle_ask_password = handle_ask_password; + iface->handle_ask_question = handle_ask_question; + iface->handle_close = handle_close; + iface->handle_show_processes = handle_show_processes; +} + + +static void +on_name_acquired (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + PhoshGtkMountManager *self = PHOSH_GTK_MOUNT_MANAGER (user_data); + + g_debug ("Acquired name %s", name); + g_return_if_fail (PHOSH_IS_GTK_MOUNT_MANAGER (self)); +} + + +static void +on_name_lost (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + g_debug ("Lost or failed to acquire name %s", name); +} + + +static void +on_bus_acquired (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + PhoshGtkMountManager *self = user_data; + + g_autoptr (GError) err = NULL; + + if (g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self), + connection, + "/org/gtk/MountOperationHandler", + &err)) { + g_debug ("Mount operation handler exported"); + } else { + g_warning ("Failed to export on %s: %s", GTK_MOUNT_DBUS_NAME, err->message); + } +} + + +static void +phosh_gtk_mount_manager_dispose (GObject *object) +{ + PhoshGtkMountManager *self = PHOSH_GTK_MOUNT_MANAGER (object); + + end_ask_invocation (self); + g_clear_pointer (&self->prompt, phosh_cp_widget_destroy); + if (g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (self))) + g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self)); + + g_clear_handle_id (&self->dbus_name_id, g_bus_unown_name); + + G_OBJECT_CLASS (phosh_gtk_mount_manager_parent_class)->dispose (object); +} + + +static void +phosh_gtk_mount_manager_finalize (GObject *object) +{ + PhoshGtkMountManager *self = PHOSH_GTK_MOUNT_MANAGER (object); + + g_clear_pointer (&self->object_id, g_free); + + G_OBJECT_CLASS (phosh_gtk_mount_manager_parent_class)->finalize (object); +} + + +static void +phosh_gtk_mount_manager_constructed (GObject *object) +{ + PhoshGtkMountManager *self = PHOSH_GTK_MOUNT_MANAGER (object); + + G_OBJECT_CLASS (phosh_gtk_mount_manager_parent_class)->constructed (object); + self->dbus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION, + GTK_MOUNT_DBUS_NAME, + G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | + G_BUS_NAME_OWNER_FLAGS_REPLACE, + on_bus_acquired, + on_name_acquired, + on_name_lost, + self, + NULL); +} + + +static void +phosh_gtk_mount_manager_class_init (PhoshGtkMountManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = phosh_gtk_mount_manager_constructed; + object_class->dispose = phosh_gtk_mount_manager_dispose; + object_class->finalize = phosh_gtk_mount_manager_finalize; + + /** + * PhoshGtkMountManager::new-prompt + * @self: The #PhoshGtkMountManager emitting this signal + * + * Emitted when a new prompt is shown + */ + signals[NEW_PROMPT] = g_signal_new ( + "new-prompt", + G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, + NULL, G_TYPE_NONE, 0); +} + + +static void +phosh_gtk_mount_manager_init (PhoshGtkMountManager *self) +{ +} + + +PhoshGtkMountManager * +phosh_gtk_mount_manager_new (void) +{ + return g_object_new (PHOSH_TYPE_GTK_MOUNT_MANAGER, NULL); +} diff -Nru phosh-0.8.0/src/gtk-mount-manager.h phosh-0.13.1/src/gtk-mount-manager.h --- phosh-0.8.0/src/gtk-mount-manager.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/gtk-mount-manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#pragma once + +#include "dbus/phosh-gtk-mountoperation-dbus.h" +#include + +#define PHOSH_TYPE_GTK_MOUNT_MANAGER (phosh_gtk_mount_manager_get_type ()) +G_DECLARE_FINAL_TYPE (PhoshGtkMountManager, phosh_gtk_mount_manager, PHOSH, GTK_MOUNT_MANAGER, + PhoshDBusMountOperationHandlerSkeleton) + +PhoshGtkMountManager *phosh_gtk_mount_manager_new (void); diff -Nru phosh-0.8.0/src/gtk-mount-prompt.c phosh-0.13.1/src/gtk-mount-prompt.c --- phosh-0.8.0/src/gtk-mount-prompt.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/gtk-mount-prompt.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,570 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-gtk-mount-prompt" + +#include "config.h" + +#include "gtk-mount-prompt.h" + +#include + +/** + * SECTION:gtk-mount-prompt + * @short_description: A modal prompt for #PhoshGtkMountManager + * @Title: PhoshGtkMountPrompt + * + * The #PhoshGtkMountPrompt is used to query the needed information + * for the #PhoshGtkMountManager. + */ + +enum { + PROP_0, + PROP_MESSAGE, + PROP_ICON_NAME, + PROP_DEFAULT_USER, + PROP_DEFAULT_DOMAIN, + PROP_PIDS, + PROP_CHOICES, + PROP_ASK_FLAGS, + PROP_LAST_PROP, +}; +static GParamSpec *props[PROP_LAST_PROP]; + + +enum { + CLOSED, + N_SIGNALS +}; +static guint signals[N_SIGNALS] = { 0 }; + + +struct _PhoshGtkMountPrompt { + PhoshSystemModalDialog parent; + + GtkWidget *lbl_msg; + GtkWidget *lbl_password; + GtkWidget *img_icon; + GtkWidget *lbl_user; + GtkWidget *entry_user; + GtkWidget *lbl_domain; + GtkWidget *entry_domain; + GtkWidget *entry_password; + GtkEntryBuffer *password_buffer; + gboolean pw_visible; + + char *message; + char *icon_name; + char *default_user; + char *default_domain; + GStrv choices; + int choice; + GVariant *pids; + GAskPasswordFlags ask_flags; + + gboolean cancelled; +}; +G_DEFINE_TYPE (PhoshGtkMountPrompt, phosh_gtk_mount_prompt, PHOSH_TYPE_SYSTEM_MODAL_DIALOG); + + +static void G_GNUC_NULL_TERMINATED +set_visible (gboolean visible, ...) +{ + va_list args; + GtkWidget *widget; + + va_start (args, visible); + do { + widget = va_arg (args, gpointer); + if (widget == NULL) + break; + gtk_widget_set_visible (widget, visible); + } while (TRUE); + va_end (args); +} + + +static void +set_entries_visible (PhoshGtkMountPrompt *self, gboolean visible) +{ + set_visible (visible, self->lbl_password, self->entry_password, NULL); + set_visible (visible, self->lbl_user, self->entry_user, NULL); + set_visible (visible, self->lbl_domain, self->entry_domain, NULL); +} + + +static void +set_message (PhoshGtkMountPrompt *self, const char *message) +{ + g_autofree char *primary = NULL; + char *secondary = NULL; + + g_return_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (self)); + + if (!g_strcmp0 (self->message, message)) + return; + + g_clear_pointer (&self->message, g_free); + self->message = g_strdup (message); + + primary = strstr (message, "\n"); + if (primary) { + secondary = primary + 1; + primary = g_strndup (message, primary - message); + } + + phosh_system_modal_dialog_set_title (PHOSH_SYSTEM_MODAL_DIALOG (self), primary ?: message); + if (secondary) { + gtk_label_set_label (GTK_LABEL (self->lbl_msg), secondary); + gtk_widget_show (self->lbl_msg); + } else { + gtk_widget_hide (self->lbl_msg); + } + + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MESSAGE]); +} + + +static void +set_icon_name (PhoshGtkMountPrompt *self, const char *icon_name) +{ + g_return_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (self)); + + if (!g_strcmp0 (self->icon_name, icon_name)) + return; + + g_clear_pointer (&self->icon_name, g_free); + self->icon_name = g_strdup (icon_name); + + gtk_image_set_from_icon_name (GTK_IMAGE (self->img_icon), + (icon_name && strlen (icon_name)) ? + self->icon_name : "dialog-password", + GTK_ICON_SIZE_DIALOG); + + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ICON_NAME]); +} + + +static void +set_default_user (PhoshGtkMountPrompt *self, const char *default_user) +{ + g_return_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (self)); + + if (!g_strcmp0 (self->default_user, default_user)) + return; + + g_clear_pointer (&self->default_user, g_free); + self->default_user = g_strdup (default_user); + + gtk_entry_set_text (GTK_ENTRY (self->entry_domain), self->default_user); + + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DEFAULT_USER]); +} + + +static void +set_default_domain (PhoshGtkMountPrompt *self, const char *default_domain) +{ + g_return_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (self)); + + if (!g_strcmp0 (self->default_domain, default_domain)) + return; + + g_clear_pointer (&self->default_domain, g_free); + self->default_domain = g_strdup (default_domain); + + gtk_entry_set_text (GTK_ENTRY (self->entry_domain), self->default_domain); + + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DEFAULT_DOMAIN]); +} + + +static void +on_button_clicked (PhoshGtkMountPrompt *self, GtkButton *btn) +{ + int num; + + g_return_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (self)); + g_return_if_fail (GTK_IS_BUTTON (btn)); + + num = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (btn), "phosh-num")); + self->choice = num; + + g_signal_emit (self, signals[CLOSED], 0); +} + + +static void +set_choices (PhoshGtkMountPrompt *self, GStrv choices) +{ + g_autoptr (GList) buttons = NULL; + + g_return_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (self)); + + if (choices == NULL) + return; + + g_clear_pointer (&self->choices, g_strfreev); + self->choices = g_strdupv (choices); + buttons = phosh_system_modal_dialog_get_buttons (PHOSH_SYSTEM_MODAL_DIALOG (self)); + for (GList *elem = buttons; elem; elem = elem->next) + gtk_widget_destroy (GTK_WIDGET (elem->data)); + + for (int i = 0; i < g_strv_length (self->choices); i++) { + GtkWidget *btn = gtk_button_new_with_label (self->choices[i]); + g_object_set_data (G_OBJECT (btn), "phosh-num", GINT_TO_POINTER (i)); + gtk_widget_show (GTK_WIDGET (btn)); + phosh_system_modal_dialog_add_button (PHOSH_SYSTEM_MODAL_DIALOG (self), btn, -1); + g_signal_connect_swapped (btn, "clicked", G_CALLBACK (on_button_clicked), self); + + if (i == 0) { + GtkStyleContext *context = gtk_widget_get_style_context (btn); + gtk_style_context_add_class (context, "suggested-action"); + gtk_widget_grab_focus (btn); + } + } + set_entries_visible (self, FALSE); + + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CHOICES]); +} + + +static void +set_ask_flags (PhoshGtkMountPrompt *self, GAskPasswordFlags flags) +{ + g_return_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (self)); + + if (self->ask_flags == flags) + return; + + self->ask_flags = flags; + g_debug ("Flags 0x%.2x", flags); + + if (flags & G_ASK_PASSWORD_SAVING_SUPPORTED) { + /* TODO */ + } + + set_visible (!!(flags & G_ASK_PASSWORD_NEED_PASSWORD), + self->lbl_password, self->entry_password, NULL); + + set_visible (!!(flags & G_ASK_PASSWORD_NEED_USERNAME), + self->lbl_user, self->entry_user, NULL); + + set_visible (!!(flags & G_ASK_PASSWORD_NEED_DOMAIN), + self->lbl_domain, self->entry_domain, NULL); + + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ASK_FLAGS]); +} + + +static void +phosh_gtk_mount_prompt_set_property (GObject *obj, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshGtkMountPrompt *self = PHOSH_GTK_MOUNT_PROMPT (obj); + + switch (prop_id) { + case PROP_MESSAGE: + set_message (self, g_value_get_string (value)); + break; + case PROP_ICON_NAME: + set_icon_name (self, g_value_get_string (value)); + break; + case PROP_DEFAULT_USER: + set_default_user (self, g_value_get_string (value)); + break; + case PROP_DEFAULT_DOMAIN: + set_default_domain (self, g_value_get_string (value)); + break; + case PROP_CHOICES: + set_choices (self, g_value_get_boxed (value)); + break; + case PROP_PIDS: + phosh_gtk_mount_prompt_set_pids (self, g_value_get_variant (value)); + break; + case PROP_ASK_FLAGS: + set_ask_flags (self, g_value_get_flags (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + + +static void +phosh_gtk_mount_prompt_get_property (GObject *obj, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshGtkMountPrompt *self = PHOSH_GTK_MOUNT_PROMPT (obj); + + switch (prop_id) { + case PROP_MESSAGE: + g_value_set_string (value, self->message ?: ""); + break; + case PROP_ICON_NAME: + g_value_set_string (value, self->icon_name ?: ""); + break; + case PROP_DEFAULT_USER: + g_value_set_string (value, self->default_user ?: ""); + break; + case PROP_DEFAULT_DOMAIN: + g_value_set_string (value, self->default_domain ?: ""); + break; + case PROP_CHOICES: + g_value_set_boxed (value, self->choices); + break; + case PROP_PIDS: + g_value_set_variant (value, self->pids); + break; + case PROP_ASK_FLAGS: + g_value_set_enum (value, self->ask_flags); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + + +static void +on_connect_clicked (PhoshGtkMountPrompt *self) +{ + g_signal_emit (self, signals[CLOSED], 0); +} + + +static void +on_dialog_canceled (PhoshGtkMountPrompt *self) +{ + g_return_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (self)); + + self->cancelled = TRUE; + + g_signal_emit (self, signals[CLOSED], 0); +} + + +static void +on_pw_vis_icon_press (PhoshGtkMountPrompt *self, + GtkEntryIconPosition icon_pos, + GdkEvent *event, + GtkEntry *entry) +{ + const char *icon_name = "eye-not-looking-symbolic"; + + g_return_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (self)); + g_return_if_fail (GTK_IS_ENTRY (entry)); + g_return_if_fail (icon_pos == GTK_ENTRY_ICON_SECONDARY); + + self->pw_visible = !self->pw_visible; + gtk_entry_set_visibility (entry, self->pw_visible); + if (self->pw_visible) + icon_name = "eye-open-negative-filled-symbolic"; + + gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, + icon_name); +} + + +static void +phosh_gtk_mount_prompt_finalize (GObject *obj) +{ + PhoshGtkMountPrompt *self = PHOSH_GTK_MOUNT_PROMPT (obj); + + g_free (self->message); + g_free (self->icon_name); + g_free (self->default_user); + g_free (self->default_domain); + g_clear_pointer (&self->choices, g_strfreev); + g_clear_pointer (&self->pids, g_variant_unref); + + G_OBJECT_CLASS (phosh_gtk_mount_prompt_parent_class)->finalize (obj); +} + + +static void +phosh_gtk_mount_prompt_class_init (PhoshGtkMountPromptClass *klass) +{ + GObjectClass *object_class = (GObjectClass *)klass; + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->get_property = phosh_gtk_mount_prompt_get_property; + object_class->set_property = phosh_gtk_mount_prompt_set_property; + object_class->finalize = phosh_gtk_mount_prompt_finalize; + + props[PROP_MESSAGE] = + g_param_spec_string ("message", + "", + "", + "", + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_CONSTRUCT_ONLY); + props[PROP_ICON_NAME] = + g_param_spec_string ("icon-name", + "", + "", + "", + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_CONSTRUCT_ONLY); + props[PROP_DEFAULT_USER] = + g_param_spec_string ("default-user", + "", + "", + "", + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_CONSTRUCT_ONLY); + props[PROP_DEFAULT_DOMAIN] = + g_param_spec_string ("default-domain", + "", + "", + "", + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_CONSTRUCT_ONLY); + props[PROP_CHOICES] = + g_param_spec_boxed ("choices", + "", + "", + G_TYPE_STRV, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_CONSTRUCT_ONLY); + props[PROP_PIDS] = + g_param_spec_variant ("pids", + "", + "", + G_VARIANT_TYPE_ARRAY, + NULL, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + props[PROP_ASK_FLAGS] = + g_param_spec_flags ("ask-flags", + "", + "", + G_TYPE_ASK_PASSWORD_FLAGS, + 0, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); + + signals[CLOSED] = g_signal_new ("closed", + G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, + NULL, G_TYPE_NONE, 0); + + gtk_widget_class_set_template_from_resource (widget_class, + "/sm/puri/phosh/ui/gtk-mount-prompt.ui"); + gtk_widget_class_bind_template_child (widget_class, PhoshGtkMountPrompt, lbl_msg); + gtk_widget_class_bind_template_child (widget_class, PhoshGtkMountPrompt, lbl_password); + gtk_widget_class_bind_template_child (widget_class, PhoshGtkMountPrompt, lbl_user); + gtk_widget_class_bind_template_child (widget_class, PhoshGtkMountPrompt, lbl_domain); + gtk_widget_class_bind_template_child (widget_class, PhoshGtkMountPrompt, img_icon); + gtk_widget_class_bind_template_child (widget_class, PhoshGtkMountPrompt, entry_password); + gtk_widget_class_bind_template_child (widget_class, PhoshGtkMountPrompt, entry_user); + gtk_widget_class_bind_template_child (widget_class, PhoshGtkMountPrompt, entry_domain); + gtk_widget_class_bind_template_child (widget_class, PhoshGtkMountPrompt, password_buffer); + gtk_widget_class_bind_template_callback (widget_class, on_connect_clicked); + gtk_widget_class_bind_template_callback (widget_class, on_dialog_canceled); + gtk_widget_class_bind_template_callback (widget_class, on_pw_vis_icon_press); + + gtk_widget_class_set_css_name (widget_class, "phosh-gtk-mount-prompt"); +} + + +static void +phosh_gtk_mount_prompt_init (PhoshGtkMountPrompt *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} + + +GtkWidget * +phosh_gtk_mount_prompt_new (const char *message, + const char *icon_name, + const char *default_user, + const char *default_domain, + GVariant *pids, + const char *const *choices, + GAskPasswordFlags ask_flags) +{ + return g_object_new (PHOSH_TYPE_GTK_MOUNT_PROMPT, + "message", message, + "icon-name", icon_name, + "ask-flags", ask_flags, + "default-user", default_user, + "default-domain", default_domain, + "pids", pids, + "choices", choices, + NULL); +} + + +const char * +phosh_gtk_mount_prompt_get_password (PhoshGtkMountPrompt *self) +{ + g_return_val_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (self), NULL); + + return gtk_entry_buffer_get_text (self->password_buffer); +} + + +GAskPasswordFlags +phosh_gtk_mount_prompt_get_ask_flags (PhoshGtkMountPrompt *self) +{ + g_return_val_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (self), 0); + + return self->ask_flags; +} + + +/** + * phosh_gtk_mount_prompt_get_cancelled: + * @self: The #PhoshGtkMountPrompt + * + * Returns: %TRUE if the dialog was cancelled (e.g. via swipe + * away or pressing the Esc-key. + */ +gboolean +phosh_gtk_mount_prompt_get_cancelled (PhoshGtkMountPrompt *self) +{ + g_return_val_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (self), FALSE); + + return self->cancelled; +} + + +const GStrv +phosh_gtk_mount_prompt_get_choices (PhoshGtkMountPrompt *self) +{ + g_return_val_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (self), NULL); + + return self->choices; +} + + +int +phosh_gtk_mount_prompt_get_choice (PhoshGtkMountPrompt *self) +{ + g_return_val_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (self), -1); + + return self->choice; +} + + +void +phosh_gtk_mount_prompt_set_pids (PhoshGtkMountPrompt *self, GVariant *pids) +{ + g_return_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (self)); + + if (self->pids == pids) + return; + + g_clear_pointer (&self->pids, g_variant_unref); + + if (pids) + self->pids = g_variant_ref (pids); + + /* TODO: update ui */ + + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PIDS]); +} diff -Nru phosh-0.8.0/src/gtk-mount-prompt.h phosh-0.13.1/src/gtk-mount-prompt.h --- phosh-0.8.0/src/gtk-mount-prompt.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/gtk-mount-prompt.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include +#include "system-modal-dialog.h" + +#define PHOSH_TYPE_GTK_MOUNT_PROMPT (phosh_gtk_mount_prompt_get_type ()) + +G_DECLARE_FINAL_TYPE (PhoshGtkMountPrompt, phosh_gtk_mount_prompt, PHOSH, GTK_MOUNT_PROMPT, PhoshSystemModalDialog) + +GtkWidget *phosh_gtk_mount_prompt_new (const char *message, + const char *icon_name, + const char *default_user, + const char *default_domain, + GVariant *pids, + const char *const *choices, + GAskPasswordFlags ask_flags); +const gchar *phosh_gtk_mount_prompt_get_password (PhoshGtkMountPrompt *self); +GAskPasswordFlags phosh_gtk_mount_prompt_get_ask_flags (PhoshGtkMountPrompt *self); +gboolean phosh_gtk_mount_prompt_get_cancelled (PhoshGtkMountPrompt *self); +int phosh_gtk_mount_prompt_get_choice (PhoshGtkMountPrompt *self); +const GStrv phosh_gtk_mount_prompt_get_choices (PhoshGtkMountPrompt *self); +void phosh_gtk_mount_prompt_set_pids (PhoshGtkMountPrompt *self, GVariant *pids); diff -Nru phosh-0.8.0/src/hks-info.c phosh-0.13.1/src/hks-info.c --- phosh-0.8.0/src/hks-info.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/hks-info.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2020 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-hks-info" + +#include "config.h" + +#include "shell.h" +#include "hks-info.h" +#include "hks-manager.h" + +/** + * SECTION:hks-info + * @short_description: A widget to display the HKS status of a device + * @Title: PhoshHksInfo + * + * #PhoshHksInfo displays whether a device is disabled via a hardware + * kill switch (HKS). + */ + +enum { + PROP_0, + PROP_DEV_TYPE, + PROP_BLOCKED, + PROP_PRESENT, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + + +struct _PhoshHksInfo { + PhoshStatusIcon parent; + + char *dev_type; + gboolean blocked; + gboolean present; + PhoshHksManager *manager; +}; +G_DEFINE_TYPE (PhoshHksInfo, phosh_hks_info, PHOSH_TYPE_STATUS_ICON); + + +static void +phosh_hks_info_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshHksInfo *self = PHOSH_HKS_INFO (object); + + switch (property_id) { + case PROP_BLOCKED: + g_value_set_boolean (value, self->blocked); + break; + case PROP_PRESENT: + g_value_set_boolean (value, self->present); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_hks_info_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshHksInfo *self = PHOSH_HKS_INFO (object); + + switch (prop_id) { + case PROP_DEV_TYPE: + /* construct only */ + self->dev_type = g_value_dup_string (value); + break; + case PROP_BLOCKED: + self->blocked = g_value_get_boolean (value); + break; + case PROP_PRESENT: + self->present = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + + +static void +phosh_hks_info_constructed (GObject *object) +{ + PhoshHksInfo *self = PHOSH_HKS_INFO (object); + PhoshShell *shell; + g_autofree gchar *propname = NULL; + + G_OBJECT_CLASS (phosh_hks_info_parent_class)->constructed (object); + + shell = phosh_shell_get_default (); + self->manager = g_object_ref (phosh_shell_get_hks_manager (shell)); + + if (self->manager == NULL) { + g_warning ("Failed to get hks manager"); + return; + } + + propname = g_strdup_printf ("%s-present", self->dev_type); + g_object_bind_property (self->manager, + propname, + self, + "present", + G_BINDING_SYNC_CREATE); + + g_free (propname); + propname = g_strdup_printf ("%s-blocked", self->dev_type); + g_object_bind_property (self->manager, + propname, + self, + "blocked", + G_BINDING_SYNC_CREATE); + + g_free (propname); + propname = g_strdup_printf ("%s-icon-name", self->dev_type); + g_object_bind_property (self->manager, + propname, + self, + "icon-name", + G_BINDING_SYNC_CREATE); +} + + +static void +phosh_hks_info_dispose (GObject *object) +{ + PhoshHksInfo *self = PHOSH_HKS_INFO (object); + + g_clear_object (&self->manager); + + G_OBJECT_CLASS (phosh_hks_info_parent_class)->dispose (object); +} + + +static void +phosh_hks_info_finalize (GObject *object) +{ + PhoshHksInfo *self = PHOSH_HKS_INFO (object); + + g_clear_pointer (&self->dev_type, g_free); + + G_OBJECT_CLASS (phosh_hks_info_parent_class)->finalize (object); +} + + +static void +phosh_hks_info_class_init (PhoshHksInfoClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->constructed = phosh_hks_info_constructed; + object_class->dispose = phosh_hks_info_dispose; + object_class->finalize = phosh_hks_info_finalize; + object_class->get_property = phosh_hks_info_get_property; + object_class->set_property = phosh_hks_info_set_property; + + gtk_widget_class_set_css_name (widget_class, "phosh-hks-info"); + + props[PROP_DEV_TYPE] = + g_param_spec_string ("device-type", + "Device type", + "The moniored device type", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_CONSTRUCT_ONLY); + props[PROP_BLOCKED] = + g_param_spec_boolean ("blocked", + "blocked", + "Whether the device is blocked", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + props[PROP_PRESENT] = + g_param_spec_boolean ("present", + "Present", + "Whether hks hardware is present", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); +} + + +static void +phosh_hks_info_init (PhoshHksInfo *self) +{ + phosh_status_icon_set_info (PHOSH_STATUS_ICON (self), "HKS"); +} + + +GtkWidget * +phosh_hks_info_new (void) +{ + return g_object_new (PHOSH_TYPE_HKS_INFO, NULL); +} diff -Nru phosh-0.8.0/src/hks-info.h phosh-0.13.1/src/hks-info.h --- phosh-0.8.0/src/hks-info.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/hks-info.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2020 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include +#include "status-icon.h" + +G_BEGIN_DECLS + +#define PHOSH_TYPE_HKS_INFO (phosh_hks_info_get_type ()) + +G_DECLARE_FINAL_TYPE (PhoshHksInfo, phosh_hks_info, PHOSH, HKS_INFO, PhoshStatusIcon) + +GtkWidget * phosh_hks_info_new (void); + +G_END_DECLS diff -Nru phosh-0.8.0/src/hks-manager.c phosh-0.13.1/src/hks-manager.c --- phosh-0.8.0/src/hks-manager.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/hks-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,512 @@ +/* + * Copyright (C) 2020 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-hks-manager" + +#include "config.h" + +#include "hks-manager.h" +#include "shell.h" + +#include +#include +#include +#include +#include + + +#ifdef HAVE_RFKILL_EVENT_EXT +typedef struct rfkill_event_ext RfKillEvent; +#else +typedef struct rfkill_event RfKillEvent; +#endif +G_DEFINE_AUTOPTR_CLEANUP_FUNC (RfKillEvent, g_free); + +/* rfkill types not yet upstream */ +#define RFKILL_TYPE_CAMERA_ 9 +#define RFKILL_TYPE_MIC_ 10 + +/** + * SECTION:hks-manager + * @short_description: Tracks hardware kill switch state + * @Title: PhoshHksManager + * + * Monitor hardware kill switch state. This will be submitted to gnome-settings-daemon + * once we figured out the kernel interfaces. + */ + +typedef enum { + PROP_0, + /* Each hks must be in the order of present, blocked, icon_name */ + PROP_MIC_PRESENT, + PROP_MIC_BLOCKED, + PROP_MIC_ICON_NAME, + PROP_CAMERA_PRESENT, + PROP_CAMERA_BLOCKED, + PROP_CAMERA_ICON_NAME, + PROP_LAST_PROP +} PhoshHksManagerProps; +static GParamSpec *props[PROP_LAST_PROP]; + + +enum { + HKS_STATE_BLOCKED = 0, + HKS_STATE_UNBLOCKED = 1, +}; + + +typedef struct { + gboolean present; + gboolean blocked; + gchar *blocked_icon_name; + gchar *unblocked_icon_name; + GHashTable *killswitches; +} Hks; + + +struct _PhoshHksManager { + GObject parent; + + GIOChannel *channel; + int watch_id; + + Hks mic; + Hks camera; +}; +G_DEFINE_TYPE (PhoshHksManager, phosh_hks_manager, G_TYPE_OBJECT); + + +static void +phosh_hks_manager_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshHksManager *self = PHOSH_HKS_MANAGER (object); + const gchar *icon_name; + + switch (property_id) { + case PROP_MIC_PRESENT: + g_value_set_boolean (value, self->mic.present); + break; + case PROP_MIC_BLOCKED: + g_value_set_boolean (value, self->mic.blocked); + break; + case PROP_MIC_ICON_NAME: + icon_name = self->mic.blocked ? + self->mic.blocked_icon_name : self->mic.unblocked_icon_name; + g_value_set_string (value, icon_name); + break; + case PROP_CAMERA_PRESENT: + g_value_set_boolean (value, self->camera.present); + break; + case PROP_CAMERA_BLOCKED: + g_value_set_boolean (value, self->camera.blocked); + break; + case PROP_CAMERA_ICON_NAME: + icon_name = self->camera.blocked ? + self->camera.blocked_icon_name : self->camera.unblocked_icon_name; + g_value_set_string (value, icon_name); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static const char * +type_to_string (unsigned int type) +{ + switch (type) { + case RFKILL_TYPE_ALL: + return "ALL"; + case RFKILL_TYPE_WLAN: + return "WLAN"; + case RFKILL_TYPE_BLUETOOTH: + return "BLUETOOTH"; + case RFKILL_TYPE_UWB: + return "UWB"; + case RFKILL_TYPE_WIMAX: + return "WIMAX"; + case RFKILL_TYPE_WWAN: + return "WWAN"; + case RFKILL_TYPE_CAMERA_: + return "CAMERA"; + case RFKILL_TYPE_MIC_: + return "MIC"; + default: + return "UNKNOWN"; + } +} + + +static const char * +op_to_string (unsigned int op) +{ + switch (op) { + case RFKILL_OP_ADD: + return "ADD"; + case RFKILL_OP_DEL: + return "DEL"; + case RFKILL_OP_CHANGE: + return "CHANGE"; + case RFKILL_OP_CHANGE_ALL: + return "CHANGE_ALL"; + default: + return "Unknown"; + } +} + + +static void +print_event (RfKillEvent *event) +{ + g_debug ("RFKILL event: idx %u type %u (%s) op %u (%s) soft %u hard %u", + event->idx, + event->type, type_to_string (event->type), + event->op, op_to_string (event->op), + event->soft, event->hard); +} + + +static void +update_props (PhoshHksManager *self, Hks *hks, PhoshHksManagerProps prop) +{ + GHashTableIter iter; + gpointer key, value; + gboolean blocked = FALSE; + + if (g_hash_table_size (hks->killswitches) == 0) { + if (!hks->present) + return; + + if (hks->blocked) { + hks->blocked = FALSE; + g_object_notify_by_pspec (G_OBJECT (self), props[prop+1]); + g_object_notify_by_pspec (G_OBJECT (self), props[prop+2]); + } + + hks->present = FALSE; + g_object_notify_by_pspec (G_OBJECT (self), props[prop]); + return; + } + + g_hash_table_iter_init (&iter, hks->killswitches); + while (g_hash_table_iter_next (&iter, &key, &value)) { + int state; + + state = GPOINTER_TO_INT (value); + /* A single blocked switch is enough */ + if (state == HKS_STATE_BLOCKED) { + blocked = TRUE; + break; + } + } + + if (!hks->present) { + hks->present = TRUE; + g_object_notify_by_pspec (G_OBJECT (self), props[prop]); + } + + if (blocked == hks->blocked) + return; + hks->blocked = blocked; + + /* blocked property */ + g_object_notify_by_pspec (G_OBJECT (self), props[prop + 1]); + /* icon_name property */ + g_object_notify_by_pspec (G_OBJECT (self), props[prop + 2]); +} + + +static void +process_events (PhoshHksManager *self, GList *events) +{ + GList *l; + int value; + + for (l = events; l != NULL; l = l->next) { + RfKillEvent *event = l->data; + + switch (event->op) { + case RFKILL_OP_ADD: + case RFKILL_OP_CHANGE: + value = event->hard ? HKS_STATE_BLOCKED : HKS_STATE_UNBLOCKED; + + if (event->type == RFKILL_TYPE_MIC_) { + g_hash_table_insert (self->mic.killswitches, + GINT_TO_POINTER (event->idx), + GINT_TO_POINTER (value)); + } else if (event->type == RFKILL_TYPE_CAMERA_) { + g_hash_table_insert (self->camera.killswitches, + GINT_TO_POINTER (event->idx), + GINT_TO_POINTER (value)); + } + g_debug ("%s rfkill type %d, ID %d", + event->op == RFKILL_OP_ADD ? "Added" : "Changed", + event->type, event->idx); + break; + case RFKILL_OP_DEL: + if (event->type == RFKILL_TYPE_MIC_) { + g_hash_table_remove (self->mic.killswitches, + GINT_TO_POINTER (event->idx)); + } else if (event->type == RFKILL_TYPE_CAMERA_) { + g_hash_table_remove (self->camera.killswitches, + GINT_TO_POINTER (event->idx)); + } + g_debug ("Removed rfkill type %d, ID %d", + event->type, event->idx); + break; + default: + /* Nothing to do */ + break; + } + } + + g_object_freeze_notify (G_OBJECT (self)); + update_props (self, &self->mic, PROP_MIC_PRESENT); + update_props (self, &self->camera, PROP_CAMERA_PRESENT); + g_object_thaw_notify (G_OBJECT (self)); + + +} + + +static gboolean +rfkill_event_cb (GIOChannel *source, + GIOCondition condition, + PhoshHksManager *self) +{ + g_autolist (RfKillEvent) events = NULL; + + if (condition & G_IO_IN) { + GIOStatus status; + RfKillEvent event = { 0 }; + RfKillEvent *event_ptr; + gsize read; + + status = g_io_channel_read_chars (source, + (char *) &event, + sizeof(event), + &read, + NULL); + + while (status == G_IO_STATUS_NORMAL && read >= RFKILL_EVENT_SIZE_V1) { + print_event (&event); + event_ptr = g_memdup (&event, sizeof(event)); + events = g_list_prepend (events, event_ptr); + + status = g_io_channel_read_chars (source, + (char *) &event, + sizeof(event), + &read, + NULL); + } + events = g_list_reverse (events); + } else { + g_debug ("Something unexpected happened on rfkill fd"); + return FALSE; + } + + process_events (self, events); + return TRUE; +} + + +static gboolean +setup_rfkill (PhoshHksManager *self) +{ + int fd, ret; + g_autolist (RfKillEvent) events = NULL; + + fd = open ("/dev/rfkill", O_RDONLY); + if (fd < 0) + return FALSE; + + ret = fcntl (fd, F_SETFL, O_NONBLOCK); + if (ret < 0) { + g_warning ("Can't set RFKILL control device to non-blocking: %s", strerror (errno)); + close (fd); + return FALSE; + } + + while (1) { + RfKillEvent event; + RfKillEvent *event_ptr; + ssize_t len; + + len = read (fd, &event, sizeof(event)); + if (len < 0) { + if (errno == EAGAIN) + break; + g_debug ("Reading of RFKILL events failed"); + break; + } + + if (len < RFKILL_EVENT_SIZE_V1) { + g_warning ("Wrong size of RFKILL event\n"); + continue; + } + + if (event.op != RFKILL_OP_ADD) + continue; + + g_debug ("Read killswitch of type '%s' (idx=%d): soft %d hard %d", + type_to_string (event.type), + event.idx, event.soft, event.hard); + + event_ptr = g_memdup (&event, sizeof(event)); + events = g_list_prepend (events, event_ptr); + } + + /* Setup monitoring */ + self->channel = g_io_channel_unix_new (fd); + g_io_channel_set_encoding (self->channel, NULL, NULL); + self->watch_id = g_io_add_watch (self->channel, + G_IO_IN | G_IO_HUP | G_IO_ERR, + (GIOFunc) rfkill_event_cb, + self); + + if (events) { + events = g_list_reverse (events); + process_events (self, events); + } else { + g_debug ("No rfkill device available on startup"); + } + + return TRUE; +} + + +static void +phosh_hks_manager_constructed (GObject *object) +{ + PhoshHksManager *self = PHOSH_HKS_MANAGER (object); + + self->mic.killswitches = g_hash_table_new (g_direct_hash, g_direct_equal); + self->mic.blocked_icon_name = "microphone-hardware-disabled-symbolic"; + self->mic.unblocked_icon_name = "microphone-sensitivity-high-symbolic"; + + self->camera.killswitches = g_hash_table_new (g_direct_hash, g_direct_equal); + self->camera.blocked_icon_name = "camera-hardware-disabled-symbolic"; + self->camera.unblocked_icon_name = "camera-photo-symbolic"; + + setup_rfkill (self); + + G_OBJECT_CLASS (phosh_hks_manager_parent_class)->constructed (object); +} + + +static void +phosh_hks_manager_dispose (GObject *object) +{ + PhoshHksManager *self = PHOSH_HKS_MANAGER (object); + + if (self->watch_id > 0) { + g_source_remove (self->watch_id); + self->watch_id = 0; + g_io_channel_shutdown (self->channel, FALSE, NULL); + g_io_channel_unref (self->channel); + } + + G_OBJECT_CLASS (phosh_hks_manager_parent_class)->dispose (object); +} + + +static void +phosh_hks_manager_finalize (GObject *object) +{ + PhoshHksManager *self = PHOSH_HKS_MANAGER (object); + + g_clear_pointer (&self->mic.killswitches, g_hash_table_destroy); + g_clear_pointer (&self->camera.killswitches, g_hash_table_destroy); + + G_OBJECT_CLASS (phosh_hks_manager_parent_class)->finalize (object); +} + + +static void +phosh_hks_manager_class_init (PhoshHksManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = phosh_hks_manager_constructed; + object_class->dispose = phosh_hks_manager_dispose; + object_class->finalize = phosh_hks_manager_finalize; + object_class->get_property = phosh_hks_manager_get_property; + + props[PROP_MIC_PRESENT] = + g_param_spec_boolean ("mic-present", + "Mic present", + "HKS capable microphone present", + FALSE, + G_PARAM_READABLE | + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_STATIC_STRINGS); + + props[PROP_MIC_BLOCKED] = + g_param_spec_boolean ("mic-blocked", + "Mic blocked", + "Microphone blocked via hks", + TRUE, + G_PARAM_READABLE | + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_STATIC_STRINGS); + + props[PROP_MIC_ICON_NAME] = + g_param_spec_string ("mic-icon-name", + "Mic Icon Name", + "Icon for microphone hks", + "", + G_PARAM_READABLE | + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_STATIC_STRINGS); + + props[PROP_CAMERA_PRESENT] = + g_param_spec_boolean ("camera-present", + "Camera present", + "HKS capable camera present", + FALSE, + G_PARAM_READABLE | + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_STATIC_STRINGS); + + props[PROP_CAMERA_BLOCKED] = + g_param_spec_boolean ("camera-blocked", + "Camera blocked", + "Camera blocked via hks", + FALSE, + G_PARAM_READABLE | + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_STATIC_STRINGS); + + props[PROP_CAMERA_ICON_NAME] = + g_param_spec_string ("camera-icon-name", + "Camera Icon Name", + "Icon for camera hks", + "", + G_PARAM_READABLE | + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); +} + + +static void +phosh_hks_manager_init (PhoshHksManager *self) +{ +} + + +PhoshHksManager * +phosh_hks_manager_new (void) +{ + return PHOSH_HKS_MANAGER (g_object_new (PHOSH_TYPE_HKS_MANAGER, NULL)); +} diff -Nru phosh-0.8.0/src/hks-manager.h phosh-0.13.1/src/hks-manager.h --- phosh-0.8.0/src/hks-manager.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/hks-manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2020 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + + +G_BEGIN_DECLS + +/** + * PhoshHksDeviceType: + * @PHOSH_HKS_TYPE_MIC: Microphone hardware kill switch + * + * Keep in sync with kernels rfkill types + */ +typedef enum { + PHOSH_HKS_TYPE_MIC = 10, +} PhoshHksDeviceType; + + +#define PHOSH_TYPE_HKS_MANAGER (phosh_hks_manager_get_type ()) + +G_DECLARE_FINAL_TYPE (PhoshHksManager, phosh_hks_manager, PHOSH, HKS_MANAGER, GObject) + +PhoshHksManager *phosh_hks_manager_new (void); + +G_END_DECLS diff -Nru phosh-0.8.0/src/home.c phosh-0.13.1/src/home.c --- phosh-0.8.0/src/home.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/home.c 2021-08-31 09:15:52.000000000 +0000 @@ -14,7 +14,7 @@ #include "home.h" #include "shell.h" #include "phosh-enums.h" -#include "osk/osk-button.h" +#include "osk-button.h" #include @@ -67,7 +67,7 @@ PhoshHomeState state; /* Keybinding */ - GArray *actions; + GStrv action_names; GSettings *settings; /* osk button */ @@ -202,22 +202,32 @@ static gboolean -key_press_event_cb (PhoshHome *self, GdkEventKey *event, gpointer data) +window_key_press_event_cb (PhoshHome *self, GdkEvent *event, gpointer data) { - gboolean handled = FALSE; - g_return_val_if_fail (PHOSH_IS_HOME (self), FALSE); + gboolean ret = GDK_EVENT_PROPAGATE; + guint keyval; + g_return_val_if_fail (PHOSH_IS_HOME (self), GDK_EVENT_PROPAGATE); - switch (event->keyval) { + if (self->state != PHOSH_HOME_STATE_UNFOLDED) + return GDK_EVENT_PROPAGATE; + + if (!gdk_event_get_keyval (event, &keyval)) + return GDK_EVENT_PROPAGATE; + + switch (keyval) { case GDK_KEY_Escape: phosh_home_set_state (self, PHOSH_HOME_STATE_FOLDED); - handled = TRUE; + ret = GDK_EVENT_STOP; break; - default: - /* nothing to do */ + case GDK_KEY_Return: + ret = GDK_EVENT_PROPAGATE; break; + default: + /* Focus search when typing */ + ret = phosh_overview_handle_search (PHOSH_OVERVIEW (self->overview), event); } - return handled; + return ret; } @@ -253,74 +263,66 @@ static void add_keybindings (PhoshHome *self) { - g_auto (GStrv) bindings = NULL; + GStrv overview_bindings; + GStrv app_view_bindings; + GPtrArray *action_names = g_ptr_array_new (); g_autoptr (GSettings) settings = g_settings_new (KEYBINDINGS_SCHEMA_ID); + g_autoptr (GArray) actions = g_array_new (FALSE, TRUE, sizeof (GActionEntry)); - bindings = g_settings_get_strv (settings, KEYBINDING_KEY_TOGGLE_OVERVIEW); - for (int i = 0; i < g_strv_length (bindings); i++) { - GActionEntry entry = { bindings[i], + overview_bindings = g_settings_get_strv (settings, KEYBINDING_KEY_TOGGLE_OVERVIEW); + for (int i = 0; i < g_strv_length (overview_bindings); i++) { + GActionEntry entry = { overview_bindings[i], toggle_overview_action, }; - g_array_append_val (self->actions, entry); + g_array_append_val (actions, entry); + g_ptr_array_add (action_names, overview_bindings[i]); } + /* Free GStrv container but keep individual strings for action_names */ + g_free (overview_bindings); - bindings = g_settings_get_strv (settings, KEYBINDING_KEY_TOGGLE_APPLICATION_VIEW); - for (int i = 0; i < g_strv_length (bindings); i++) { - GActionEntry entry = { bindings[i], + app_view_bindings = g_settings_get_strv (settings, KEYBINDING_KEY_TOGGLE_APPLICATION_VIEW); + for (int i = 0; i < g_strv_length (app_view_bindings); i++) { + GActionEntry entry = { app_view_bindings[i], toggle_application_view_action, }; - g_array_append_val (self->actions, entry); + g_array_append_val (actions, entry); + g_ptr_array_add (action_names, app_view_bindings[i]); } + /* Free GStrv container but keep individual strings for action_names */ + g_free (app_view_bindings); + g_ptr_array_add (action_names, NULL); phosh_shell_add_global_keyboard_action_entries (phosh_shell_get_default (), - (GActionEntry*)self->actions->data, - self->actions->len, + (GActionEntry*) actions->data, + actions->len, self); + self->action_names = (GStrv) g_ptr_array_free (action_names, FALSE); } static void -on_keybindings_changed (PhoshHome *self, +on_keybindings_changed (PhoshHome *self, gchar *key, GSettings *settings) { /* For now just redo all keybindings */ g_debug ("Updating keybindings"); phosh_shell_remove_global_keyboard_action_entries (phosh_shell_get_default (), - (GActionEntry*)self->actions->data, - self->actions->len); - g_array_set_size (self->actions, 0); + self->action_names); + g_clear_pointer (&self->action_names, g_strfreev); add_keybindings (self); } -static gboolean -on_idle (PhoshOskButton *self) -{ - g_autoptr (GSettings) settings = NULL; - - settings = g_settings_new ("org.gnome.desktop.a11y.applications"); - g_settings_bind (settings, "screen-keyboard-enabled", - self, "osk-enabled", G_SETTINGS_BIND_GET); - - return FALSE; -} - - static void phosh_home_constructed (GObject *object) { PhoshHome *self = PHOSH_HOME (object); + g_autoptr (GSettings) settings = NULL; g_signal_connect (self, "configured", G_CALLBACK (phosh_home_resize), NULL); - gtk_widget_add_events (GTK_WIDGET (self), GDK_KEY_PRESS_MASK); - g_signal_connect (G_OBJECT (self), - "key_press_event", - G_CALLBACK (key_press_event_cb), - NULL); - g_object_connect (self->settings, "swapped-signal::changed::" KEYBINDING_KEY_TOGGLE_OVERVIEW, on_keybindings_changed, self, @@ -331,7 +333,9 @@ phosh_connect_feedback (self->btn_home); - g_idle_add ((GSourceFunc) on_idle, self); + settings = g_settings_new ("org.gnome.desktop.a11y.applications"); + g_settings_bind (settings, "screen-keyboard-enabled", + self, "osk-enabled", G_SETTINGS_BIND_GET); G_OBJECT_CLASS (phosh_home_parent_class)->constructed (object); } @@ -344,11 +348,10 @@ g_clear_object (&self->settings); - if (self->actions) { + if (self->action_names) { phosh_shell_remove_global_keyboard_action_entries (phosh_shell_get_default (), - (GActionEntry*)self->actions->data, - self->actions->len); - g_clear_pointer (&self->actions, g_array_unref); + self->action_names); + g_clear_pointer (&self->action_names, g_strfreev); } G_OBJECT_CLASS (phosh_home_parent_class)->dispose (object); @@ -403,6 +406,7 @@ gtk_widget_class_bind_template_callback (widget_class, home_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, on_has_activities_changed); gtk_widget_class_bind_template_callback (widget_class, osk_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, window_key_press_event_cb); gtk_widget_class_set_css_name (widget_class, "phosh-home"); } @@ -413,7 +417,6 @@ { self->state = PHOSH_HOME_STATE_FOLDED; self->animation.progress = 1.0; - self->actions = g_array_new (FALSE, TRUE, sizeof (GActionEntry)); self->settings = g_settings_new (KEYBINDINGS_SCHEMA_ID); gtk_widget_init_template (GTK_WIDGET (self)); @@ -462,7 +465,20 @@ phosh_home_resize (self); - return finished ? G_SOURCE_REMOVE : G_SOURCE_CONTINUE; + if (finished) { + if (self->state == PHOSH_HOME_STATE_FOLDED) + gtk_widget_hide (GTK_WIDGET (self->overview)); + return G_SOURCE_REMOVE; + } + + return G_SOURCE_CONTINUE; +} + + +static double +reverse_ease_out_cubic (double t) +{ + return cbrt(t - 1) + 1; } @@ -493,12 +509,13 @@ g_debug ("Setting state to %s", state_name); self->animation.last_frame = -1; - self->animation.progress = enable_animations ? (1.0 - self->animation.progress) : 1.0; + self->animation.progress = enable_animations ? reverse_ease_out_cubic (1.0 - hdy_ease_out_cubic (self->animation.progress)) : 1.0; gtk_widget_add_tick_callback (GTK_WIDGET (self), animate_cb, NULL, NULL); if (state == PHOSH_HOME_STATE_UNFOLDED) { kbd_interactivity = TRUE; phosh_overview_reset (PHOSH_OVERVIEW (self->overview)); + gtk_widget_show (GTK_WIDGET (self->overview)); } else { kbd_interactivity = FALSE; } @@ -509,3 +526,12 @@ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_HOME_STATE]); } + + +PhoshOverview* +phosh_home_get_overview (PhoshHome *self) +{ + g_return_val_if_fail (PHOSH_IS_HOME (self), NULL); + + return PHOSH_OVERVIEW (self->overview); +} diff -Nru phosh-0.8.0/src/home.h phosh-0.13.1/src/home.h --- phosh-0.8.0/src/home.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/home.h 2021-08-31 09:15:52.000000000 +0000 @@ -5,8 +5,10 @@ */ #pragma once -#include #include "layersurface.h" +#include "overview.h" + +#include #define PHOSH_TYPE_HOME (phosh_home_get_type()) @@ -29,3 +31,4 @@ GtkWidget * phosh_home_new (struct zwlr_layer_shell_v1 *layer_shell, struct wl_output *wl_output); void phosh_home_set_state (PhoshHome *self, PhoshHomeState state); +PhoshOverview *phosh_home_get_overview (PhoshHome *self); diff -Nru phosh-0.8.0/src/idle-manager.c phosh-0.13.1/src/idle-manager.c --- phosh-0.8.0/src/idle-manager.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/idle-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -367,7 +367,7 @@ const char *name, gpointer user_data) { - PhoshIdleManager *self = user_data; + PhoshIdleManager *self = PHOSH_IDLE_MANAGER (user_data); PhoshMonitor *monitor; g_autofree char *path = NULL; @@ -389,8 +389,10 @@ { PhoshIdleManager *self = PHOSH_IDLE_MANAGER (object); - g_hash_table_destroy (self->watches); - g_object_unref (self->manager); + g_clear_handle_id (&self->dbus_name_id, g_bus_unown_name); + + g_clear_pointer (&self->watches, g_hash_table_destroy); + g_clear_object (&self->manager); G_OBJECT_CLASS (phosh_idle_manager_parent_class)->dispose (object); } @@ -431,7 +433,7 @@ static void phosh_idle_manager_init (PhoshIdleManager *self) { - self->dbus_name_id = -1; + self->dbus_name_id = 0; } diff -Nru phosh-0.8.0/src/layersurface.c phosh-0.13.1/src/layersurface.c --- phosh-0.8.0/src/layersurface.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/layersurface.c 2021-08-31 09:15:52.000000000 +0000 @@ -327,7 +327,6 @@ g_return_if_fail (PHOSH_IS_LAYER_SURFACE (self)); priv = phosh_layer_surface_get_instance_private (self); - priv = phosh_layer_surface_get_instance_private (self); if (priv->layer_surface) { zwlr_layer_surface_v1_destroy (priv->layer_surface); priv->layer_surface = NULL; @@ -387,14 +386,14 @@ "layer-shell", "Wayland Layer Shell Global", "The layer shell wayland global", - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PHOSH_LAYER_SURFACE_PROP_WL_OUTPUT] = g_param_spec_pointer ( "wl-output", "Wayland Output", "The wl_output associated with this surface", - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PHOSH_LAYER_SURFACE_PROP_ANCHOR] = g_param_spec_uint ( @@ -404,7 +403,7 @@ 0, G_MAXUINT, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PHOSH_LAYER_SURFACE_PROP_LAYER] = g_param_spec_uint ( @@ -414,7 +413,7 @@ 0, G_MAXUINT, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PHOSH_LAYER_SURFACE_PROP_KBD_INTERACTIVITY] = g_param_spec_boolean ( @@ -521,7 +520,7 @@ "Namespace", "Namespace of the layer surface", "", - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, PHOSH_LAYER_SURFACE_PROP_LAST_PROP, props); diff -Nru phosh-0.8.0/src/location-info.c phosh-0.13.1/src/location-info.c --- phosh-0.8.0/src/location-info.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/location-info.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-location-info" + +#include "config.h" + +#include "location-info.h" +#include "location-manager.h" + +#include "shell.h" + +/** + * SECTION:location-info + * @short_description: A widget to display the location service status + * @Title: PhoshLocationInfo + * + * #PhoshLocationInfo indicates if the location service is active. + * The widgets container should hide the widget if + * #PhoshLocationInfo:active is %FALSE. + */ + +enum { + PROP_0, + PROP_ACTIVE, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + +struct _PhoshLocationInfo { + PhoshStatusIcon parent; + + gboolean active; + PhoshLocationManager *manager; +}; +G_DEFINE_TYPE (PhoshLocationInfo, phosh_location_info, PHOSH_TYPE_STATUS_ICON); + + +static void +phosh_location_info_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshLocationInfo *self = PHOSH_LOCATION_INFO (object); + + switch (property_id) { + case PROP_ACTIVE: + g_value_set_boolean (value, self->active); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_location_info_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshLocationInfo *self = PHOSH_LOCATION_INFO (object); + + switch (property_id) { + case PROP_ACTIVE: + self->active = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static gboolean +active_to_icon_name (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer user_data) +{ + gboolean active = g_value_get_boolean (from_value); + + g_value_set_string (to_value, active ? "location-services-active-symbolic" : + "location-services-disabled-symbolic"); + return TRUE; +} + + +static void +phosh_location_info_constructed (GObject *object) +{ + PhoshLocationInfo *self = PHOSH_LOCATION_INFO (object); + PhoshShell *shell = phosh_shell_get_default ();; + + self->manager = g_object_ref (phosh_shell_get_location_manager (shell)); + + g_object_bind_property (self->manager, "active", + self,"active", + G_BINDING_SYNC_CREATE); + + g_object_bind_property_full (self->manager, "active", + self,"icon-name", + G_BINDING_SYNC_CREATE, + active_to_icon_name, + NULL, NULL, NULL); + + G_OBJECT_CLASS (phosh_location_info_parent_class)->constructed (object); +} + + +static void +phosh_location_info_dispose (GObject *object) +{ + PhoshLocationInfo *self = PHOSH_LOCATION_INFO (object); + + g_clear_object (&self->manager); + + G_OBJECT_CLASS (phosh_location_info_parent_class)->dispose (object); +} + + +static void +phosh_location_info_class_init (PhoshLocationInfoClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->constructed = phosh_location_info_constructed; + object_class->dispose = phosh_location_info_dispose; + object_class->get_property = phosh_location_info_get_property; + object_class->set_property = phosh_location_info_set_property; + + gtk_widget_class_set_css_name (widget_class, "phosh-location-info"); + + props[PROP_ACTIVE] = + g_param_spec_boolean ("active", + "Active", + "Whether the location service is active (in use)", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); +} + + +static void +phosh_location_info_init (PhoshLocationInfo *self) +{ +} + + +GtkWidget * +phosh_location_info_new (void) +{ + return g_object_new (PHOSH_TYPE_LOCATION_INFO, NULL); +} diff -Nru phosh-0.8.0/src/location-info.h phosh-0.13.1/src/location-info.h --- phosh-0.8.0/src/location-info.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/location-info.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include +#include "status-icon.h" + +G_BEGIN_DECLS + +#define PHOSH_TYPE_LOCATION_INFO (phosh_location_info_get_type ()) + +G_DECLARE_FINAL_TYPE (PhoshLocationInfo, phosh_location_info, PHOSH, LOCATION_INFO, PhoshStatusIcon) + +GtkWidget * phosh_location_info_new (void); + +G_END_DECLS diff -Nru phosh-0.8.0/src/location-manager.c phosh-0.13.1/src/location-manager.c --- phosh-0.8.0/src/location-manager.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/location-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,531 @@ +/* + * Copyright (C) 2020 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-location-manager" + +#include "config.h" + +#include "app-auth-prompt.h" +#include "geoclue-manager-dbus.h" +#include "location-manager.h" +#include "shell.h" +#include "util.h" + +#include +#include + +/** + * SECTION:location-manager + * @short_description: Provides the org.freedesktop.GeoClue2.Agent DBus interface + * @Title: PhoshLocationManager + * + * The #PhoshLocationManager provides the agent interface and authorizes + * clients based on the org.gnome.system.location 'enabled' gsetting. Note + * the phosh needs to be enabled as agent in geoclue's config. + */ +#define LOCATION_AGENT_DBUS_NAME "org.freedesktop.GeoClue2.Agent" +#define LOCATION_AGENT_DBUS_PATH "/org/freedesktop/GeoClue2/Agent" + +#define GEOCLUE_SERVICE "org.freedesktop.GeoClue2" +#define GEOCLUE_MANAGER_PATH "/org/freedesktop/GeoClue2/Manager" + +/** + * AccuracyLevel: + * @LEVEL_NONE: Accuracy level unknown or unset. + * @LEVEL_COUNTRY: Country-level accuracy. + * @LEVEL_CITY: City-level accuracy. + * @LEVEL_NEIGHBORHOOD: neighborhood-level accuracy. + * @LEVEL_STREET: Street-level accuracy. + * @LEVEL_EXACT: Exact accuracy. Typically requires GPS receiver. + * + * Used to specify level of accuracy requested by, or allowed for a client. + **/ +typedef enum { + LEVEL_NONE = 0, + LEVEL_COUNTRY = 1, + LEVEL_CITY = 4, + LEVEL_NEIGHBORHOOD = 5, + LEVEL_STREET = 6, + LEVEL_EXACT = 8, +} AccuracyLevel; + + +enum { + PROP_0, + PROP_ENABLED, + PROP_ACTIVE, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + +typedef struct _PhoshLocationManager { + PhoshGeoClueDBusOrgFreedesktopGeoClue2AgentSkeleton parent; + + PhoshGeoClueDBusManager *manager_proxy; + guint dbus_name_id; + GSettings *location_settings; + gboolean enabled; + gboolean active; + + /* Current Request */ + GtkWidget *prompt; + GDBusMethodInvocation *invocation; + AccuracyLevel req_level; + + GCancellable *cancel; +} PhoshLocationManager; + +static void phosh_location_manager_geoclue2_agent_iface_init ( + PhoshGeoClueDBusOrgFreedesktopGeoClue2AgentIface *iface); + +G_DEFINE_TYPE_WITH_CODE (PhoshLocationManager, + phosh_location_manager, + PHOSH_GEO_CLUE_DBUS_TYPE_ORG_FREEDESKTOP_GEO_CLUE2_AGENT_SKELETON, + G_IMPLEMENT_INTERFACE ( + PHOSH_GEO_CLUE_DBUS_TYPE_ORG_FREEDESKTOP_GEO_CLUE2_AGENT, + phosh_location_manager_geoclue2_agent_iface_init)); + + +static guint +get_max_level (PhoshLocationManager *self) +{ + gint level = LEVEL_NONE; + + if (self->enabled) { + GDesktopLocationAccuracyLevel val = g_settings_get_enum (self->location_settings, "max-accuracy-level"); + + switch (val) { + case G_DESKTOP_LOCATION_ACCURACY_LEVEL_COUNTRY: + level = LEVEL_COUNTRY; + break; + case G_DESKTOP_LOCATION_ACCURACY_LEVEL_CITY: + level = LEVEL_CITY; + break; + case G_DESKTOP_LOCATION_ACCURACY_LEVEL_NEIGHBORHOOD: + level = LEVEL_NEIGHBORHOOD; + break; + case G_DESKTOP_LOCATION_ACCURACY_LEVEL_STREET: + level = LEVEL_STREET; + break; + case G_DESKTOP_LOCATION_ACCURACY_LEVEL_EXACT: + level = LEVEL_EXACT; + break; + default: + g_warn_if_reached (); + } + } + + return level; +} + + +static void +update_accuracy_level (PhoshLocationManager *self, gboolean enabled) +{ + int level; + + self->enabled = enabled; + level = get_max_level (self); + + g_debug ("Setting accuracy level to %d", level); + phosh_geo_clue_dbus_org_freedesktop_geo_clue2_agent_set_max_accuracy_level ( + PHOSH_GEO_CLUE_DBUS_ORG_FREEDESKTOP_GEO_CLUE2_AGENT (self), level); +} + + +static void +phosh_location_manager_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshLocationManager *self = PHOSH_LOCATION_MANAGER (object); + + switch (property_id) { + case PROP_ENABLED: + g_value_set_boolean (value, self->enabled); + break; + case PROP_ACTIVE: + g_value_set_boolean (value, self->active); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_location_manager_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshLocationManager *self = PHOSH_LOCATION_MANAGER (object); + + switch (property_id) { + case PROP_ENABLED: + update_accuracy_level (self, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +on_app_auth_prompt_closed (PhoshLocationManager *self, PhoshAppAuthPrompt *prompt) +{ + gboolean grant_access; + + g_return_if_fail (PHOSH_IS_LOCATION_MANAGER (self)); + g_return_if_fail (PHOSH_IS_APP_AUTH_PROMPT (prompt)); + + grant_access = phosh_app_auth_prompt_get_grant_access (GTK_WIDGET (prompt)); + + g_debug ("Granting access for %p at level %d: %s", + self->invocation, + self->req_level, + grant_access ? "yes" : "no"); + + phosh_geo_clue_dbus_org_freedesktop_geo_clue2_agent_complete_authorize_app ( + PHOSH_GEO_CLUE_DBUS_ORG_FREEDESKTOP_GEO_CLUE2_AGENT (self), + self->invocation, + grant_access, + self->req_level); + + /* TODO: save in permission store */ + + self->req_level = LEVEL_NONE; + self->invocation = NULL; + self->prompt = NULL; + + return; +} + + +static gboolean +handle_authorize_app (PhoshGeoClueDBusOrgFreedesktopGeoClue2Agent *object, + GDBusMethodInvocation *invocation, + const gchar *arg_desktop_id, + guint arg_req_accuracy_level) +{ + PhoshLocationManager *self = PHOSH_LOCATION_MANAGER (object); + g_autofree char *desktop_file = NULL; + g_autofree char *body = NULL; + g_autofree char *subtitle = NULL; + + g_autoptr (GDesktopAppInfo) app_info = NULL; + gint level; + + g_debug ("Authorizing %s: %d", arg_desktop_id, self->enabled); + + level = get_max_level (self); + if (arg_req_accuracy_level > level) { + g_debug ("Req accuracy level %d > max allowed %d", arg_req_accuracy_level, level); + phosh_geo_clue_dbus_org_freedesktop_geo_clue2_agent_complete_authorize_app ( + object, + invocation, + FALSE, + arg_req_accuracy_level); + return TRUE; + } + + desktop_file = g_strjoin (".", arg_desktop_id, "desktop", NULL); + app_info = g_desktop_app_info_new (desktop_file); + if (app_info == NULL) { + g_debug ("Failed to find %s", desktop_file); + phosh_geo_clue_dbus_org_freedesktop_geo_clue2_agent_complete_authorize_app ( + object, + invocation, + FALSE, + arg_req_accuracy_level); + + return TRUE; + } + + /* TODO: look at location permission store */ + + /* Cancel any ongoing prompt */ + if (self->prompt) + gtk_widget_destroy (GTK_WIDGET (self->prompt)); + + if (self->invocation) { + phosh_geo_clue_dbus_org_freedesktop_geo_clue2_agent_complete_authorize_app ( + object, + self->invocation, + FALSE, + arg_req_accuracy_level); + } + + self->req_level = arg_req_accuracy_level; + self->invocation = invocation; + subtitle = g_strdup_printf (_("Allow '%s' to access your location information?"), + g_app_info_get_display_name (G_APP_INFO (app_info))); + + body = g_desktop_app_info_get_string (app_info, "X-Geoclue-Reason"); + self->prompt = phosh_app_auth_prompt_new (g_app_info_get_icon (G_APP_INFO (app_info)), + _("Geolocation"), + subtitle, body, _("Yes"), _("No"), FALSE); + g_signal_connect_object (self->prompt, + "closed", + G_CALLBACK (on_app_auth_prompt_closed), + self, + G_CONNECT_SWAPPED); + + /* Show widget when not locked and keep that in sync */ + g_object_bind_property (phosh_shell_get_default (), "locked", + self->prompt, "visible", + G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); + + + return TRUE; +} + + +static guint +handle_get_max_accuracy_level (PhoshGeoClueDBusOrgFreedesktopGeoClue2Agent *object) +{ + PhoshLocationManager *self = PHOSH_LOCATION_MANAGER (object); + gint level = get_max_level (self); + + g_debug ("Accuracy level %d", level); + return level; +} + + +static void +phosh_location_manager_geoclue2_agent_iface_init (PhoshGeoClueDBusOrgFreedesktopGeoClue2AgentIface *iface) +{ + iface->handle_authorize_app = handle_authorize_app; + iface->get_max_accuracy_level = handle_get_max_accuracy_level; +} + + +static void +on_bus_acquired (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr (GError) err = NULL; + PhoshLocationManager *self; + GDBusConnection *connection; + + connection = g_bus_get_finish (res, &err); + if (!connection) { + phosh_async_error_warn (err, "Failed to connect to system bus"); + return; + } + + self = PHOSH_LOCATION_MANAGER (user_data); + g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self), + connection, + LOCATION_AGENT_DBUS_PATH, + NULL); + update_accuracy_level (self, self->enabled); +} + + +static void +on_add_agent_ready (PhoshGeoClueDBusManager *manager, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr (GError) err = NULL; + + if (phosh_geo_clue_dbus_manager_call_add_agent_finish (manager, res, &err)) + g_debug ("Added ourself as geoclue agent"); + else + g_warning ("Failed to add agent: %s", err->message); +} + + +static void +on_agent_in_use_changed (PhoshLocationManager *self) +{ + gboolean in_use; + + g_return_if_fail (PHOSH_IS_LOCATION_MANAGER (self)); + g_return_if_fail (PHOSH_GEO_CLUE_DBUS_IS_MANAGER (self->manager_proxy)); + + in_use = phosh_geo_clue_dbus_manager_get_in_use (self->manager_proxy); + g_debug ("In use: %d", in_use); + + if (in_use == self->active) + return; + + self->active = in_use; + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ACTIVE]); +} + + +static void +on_manager_proxy_ready (GObject *source_object, + GAsyncResult *res, + PhoshLocationManager *self) +{ + g_autoptr (GError) err = NULL; + + g_return_if_fail (PHOSH_IS_LOCATION_MANAGER (self)); + + self->manager_proxy = phosh_geo_clue_dbus_manager_proxy_new_for_bus_finish (res, &err); + if (self->manager_proxy == NULL) { + g_warning ("Failed to create proxy to %s: %s", + GEOCLUE_MANAGER_PATH, + err->message); + return; + } + + phosh_geo_clue_dbus_manager_call_add_agent (self->manager_proxy, + PHOSH_APP_ID, + NULL, + (GAsyncReadyCallback)on_add_agent_ready, + NULL); + g_signal_connect_swapped (self->manager_proxy, + "notify::in-use", + G_CALLBACK (on_agent_in_use_changed), + self); + on_agent_in_use_changed (self); +} + + +static void +on_manager_name_appeared (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + PhoshLocationManager *self) +{ + g_return_if_fail (PHOSH_IS_LOCATION_MANAGER (self)); + g_debug ("%s appeared", name); + + phosh_geo_clue_dbus_manager_proxy_new_for_bus ( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + GEOCLUE_SERVICE, + GEOCLUE_MANAGER_PATH, + NULL, + (GAsyncReadyCallback)on_manager_proxy_ready, + self); +} + +static void +on_manager_name_vanished (GDBusConnection *connection, + const gchar *name, + PhoshLocationManager *self) +{ + g_return_if_fail (PHOSH_IS_LOCATION_MANAGER (self)); + + g_debug ("%s vanished", name); + g_clear_object (&self->manager_proxy); +} + + +static void +phosh_location_manager_dispose (GObject *object) +{ + PhoshLocationManager *self = PHOSH_LOCATION_MANAGER (object); + + g_cancellable_cancel (self->cancel); + g_clear_object (&self->cancel); + + /* Close dialog and cancel pending request if ongoing */ + g_clear_pointer (&self->prompt, phosh_cp_widget_destroy); + + if (self->invocation) { + phosh_geo_clue_dbus_org_freedesktop_geo_clue2_agent_complete_authorize_app ( + PHOSH_GEO_CLUE_DBUS_ORG_FREEDESKTOP_GEO_CLUE2_AGENT (self), + self->invocation, + FALSE, + LEVEL_NONE); + self->invocation = NULL; + } + + g_clear_handle_id (&self->dbus_name_id, g_bus_unwatch_name); + + if (g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (self))) + g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self)); + + g_clear_object (&self->location_settings); + g_clear_object (&self->manager_proxy); + + G_OBJECT_CLASS (phosh_location_manager_parent_class)->dispose (object); +} + + +static void +phosh_location_manager_constructed (GObject *object) +{ + PhoshLocationManager *self = PHOSH_LOCATION_MANAGER (object); + + G_OBJECT_CLASS (phosh_location_manager_parent_class)->constructed (object); + + self->location_settings = g_settings_new ("org.gnome.system.location"); + g_settings_bind (self->location_settings, + "enabled", + self, + "enabled", + G_SETTINGS_BIND_DEFAULT); + + g_bus_get (G_BUS_TYPE_SYSTEM, + self->cancel, + on_bus_acquired, + self); + + self->dbus_name_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM, + GEOCLUE_SERVICE, + G_BUS_NAME_WATCHER_FLAGS_NONE, + (GBusNameAppearedCallback) on_manager_name_appeared, + (GBusNameVanishedCallback) on_manager_name_vanished, + self, + NULL); +} + + +static void +phosh_location_manager_class_init (PhoshLocationManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = phosh_location_manager_constructed; + object_class->dispose = phosh_location_manager_dispose; + + object_class->set_property = phosh_location_manager_set_property; + object_class->get_property = phosh_location_manager_get_property; + + props[PROP_ENABLED] = + g_param_spec_boolean ("enabled", + "enabled", + "Whether location services are enabled", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + props[PROP_ACTIVE] = + g_param_spec_boolean ("active", + "Active", + "Whether location services are currently active", + FALSE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); +} + + +static void +phosh_location_manager_init (PhoshLocationManager *self) +{ + self->cancel = g_cancellable_new (); +} + + +PhoshLocationManager * +phosh_location_manager_new (void) +{ + return g_object_new (PHOSH_TYPE_LOCATION_MANAGER, NULL); +} diff -Nru phosh-0.8.0/src/location-manager.h phosh-0.13.1/src/location-manager.h --- phosh-0.8.0/src/location-manager.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/location-manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2020 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * Author: Guido Günther + */ +#pragma once + +#include "dbus/geoclue-agent-dbus.h" +#include + +G_BEGIN_DECLS + +#define PHOSH_TYPE_LOCATION_MANAGER (phosh_location_manager_get_type ()) +G_DECLARE_FINAL_TYPE (PhoshLocationManager, phosh_location_manager, PHOSH, LOCATION_MANAGER, + PhoshGeoClueDBusOrgFreedesktopGeoClue2AgentSkeleton) + +PhoshLocationManager * phosh_location_manager_new (void); + +G_END_DECLS diff -Nru phosh-0.8.0/src/lockscreen.c phosh-0.13.1/src/lockscreen.c --- phosh-0.8.0/src/lockscreen.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/lockscreen.c 2021-08-31 09:15:52.000000000 +0000 @@ -12,8 +12,11 @@ #include "auth.h" #include "bt-info.h" +#include "calls-manager.h" #include "lockscreen.h" -#include "media-player.h" +#include "notifications/notify-manager.h" +#include "notifications/notification-frame.h" +#include "util.h" #include #include @@ -21,8 +24,9 @@ #include #include -#define HANDY_USE_UNSTABLE_API #include +#include + #define GNOME_DESKTOP_USE_UNSTABLE_API #include @@ -36,8 +40,25 @@ * * The lock screen featuring the clock * and unlock keypad. + * + * # CSS nodes + * + * #PhoshLockscreen has a CSS name with the name phosh-lockscreen. */ + +typedef enum { + POS_OVERVIEW = 0, + POS_UNLOCK = 1, +} PhoshLocksreenPos; + +enum { + PROP_0, + PROP_CALLS_MANAGER, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + enum { LOCKSCREEN_UNLOCK, WAKEUP_OUTPUT, @@ -45,7 +66,6 @@ }; static guint signals[N_SIGNALS] = { 0 }; - typedef struct _PhoshLockscreen { PhoshLayerSurface parent; @@ -53,33 +73,84 @@ typedef struct { - GtkWidget *carousel; + GtkWidget *carousel; /* info page */ - GtkWidget *box_info; - GtkWidget *lbl_clock; - GtkWidget *lbl_date; + GtkWidget *box_info; + GtkWidget *lbl_clock; + GtkWidget *lbl_date; + GtkWidget *list_notifications; + GtkWidget *sw_notifications; + GSettings *settings; /* unlock page */ - GtkWidget *box_unlock; - GtkWidget *keypad; - GtkWidget *entry_pin; - GtkGesture *long_press_del_gesture; - GtkWidget *lbl_unlock_status; - GtkWidget *btn_submit; - GtkWidget *btn_emergency; - guint idle_timer; - gint64 last_input; - PhoshAuth *auth; - - GnomeWallClock *wall_clock; + GtkWidget *box_unlock; + GtkWidget *keypad; + GtkWidget *entry_pin; + GtkGesture *long_press_del_gesture; + GtkWidget *lbl_unlock_status; + GtkWidget *btn_submit; + GtkWidget *btn_emergency; + guint idle_timer; + gint64 last_input; + PhoshAuth *auth; + + /* Call page */ + HdyDeck *deck; + GtkBox *box_call_display; + CuiCallDisplay *call_display; + + GnomeWallClock *wall_clock; + PhoshCallsManager *calls_manager; + char *active; /* opaque handle to the active call */ } PhoshLockscreenPrivate; G_DEFINE_TYPE_WITH_PRIVATE (PhoshLockscreen, phosh_lockscreen, PHOSH_TYPE_LAYER_SURFACE) static void -clear_input (PhoshLockscreen *self, gboolean clear_all) { +phosh_lockscreen_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshLockscreen *self = PHOSH_LOCKSCREEN (object); + PhoshLockscreenPrivate *priv = phosh_lockscreen_get_instance_private (self); + + switch (property_id) { + case PROP_CALLS_MANAGER: + priv->calls_manager = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_lockscreen_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshLockscreen *self = PHOSH_LOCKSCREEN (object); + PhoshLockscreenPrivate *priv = phosh_lockscreen_get_instance_private (self); + + switch (property_id) { + case PROP_CALLS_MANAGER: + g_value_set_object (value, priv->calls_manager); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +clear_input (PhoshLockscreen *self, gboolean clear_all) +{ PhoshLockscreenPrivate *priv = phosh_lockscreen_get_instance_private (self); if (clear_all) { @@ -95,6 +166,7 @@ show_info_page (PhoshLockscreen *self) { PhoshLockscreenPrivate *priv = phosh_lockscreen_get_instance_private (self); + if (hdy_carousel_get_position (HDY_CAROUSEL (priv->carousel)) <= 0) return; @@ -122,6 +194,7 @@ show_unlock_page (PhoshLockscreen *self) { PhoshLockscreenPrivate *priv = phosh_lockscreen_get_instance_private (self); + if (hdy_carousel_get_position (HDY_CAROUSEL (priv->carousel)) > 0) return; @@ -134,7 +207,8 @@ static gboolean -finish_shake_label (PhoshLockscreen *self) { +finish_shake_label (PhoshLockscreen *self) +{ clear_input (self, TRUE); gtk_widget_set_sensitive (GTK_WIDGET (self), TRUE); return FALSE; @@ -142,9 +216,10 @@ static gboolean -shake_label (GtkWidget *widget, - GdkFrameClock *frame_clock, - gpointer data) { +shake_label (GtkWidget *widget, + GdkFrameClock *frame_clock, + gpointer data) +{ PhoshLockscreen *self = PHOSH_LOCKSCREEN (widget); PhoshLockscreenPrivate *priv = phosh_lockscreen_get_instance_private (self); gint64 start_time = g_variant_get_int64 (data); @@ -185,7 +260,7 @@ g_object_ref (self); if (authenticated) { - g_signal_emit(self, signals[LOCKSCREEN_UNLOCK], 0); + g_signal_emit (self, signals[LOCKSCREEN_UNLOCK], 0); g_clear_object (&priv->auth); } else { GdkFrameClock *clock; @@ -207,7 +282,7 @@ static void delete_button_clicked_cb (PhoshLockscreen *self, - GtkWidget *widget) + GtkWidget *widget) { g_return_if_fail (PHOSH_IS_LOCKSCREEN (self)); @@ -382,14 +457,14 @@ static void wall_clock_notify_cb (PhoshLockscreen *self, - GParamSpec *pspec, - GnomeWallClock *wall_clock) + GParamSpec *pspec, + GnomeWallClock *wall_clock) { PhoshLockscreenPrivate *priv = phosh_lockscreen_get_instance_private (self); const char *time; g_autofree char *date = NULL; - time = gnome_wall_clock_get_clock(wall_clock); + time = gnome_wall_clock_get_clock (wall_clock); gtk_label_set_text (GTK_LABEL (priv->lbl_clock), time); date = local_date (); @@ -407,12 +482,12 @@ position = hdy_carousel_get_position (HDY_CAROUSEL (priv->carousel)); - if (position <= 0) { + if (position <= POS_OVERVIEW) { clear_input (self, TRUE); return; } - if (position >= 1) { + if (position >= POS_UNLOCK) { if (!priv->idle_timer) { priv->last_input = g_get_monotonic_time (); priv->idle_timer = g_timeout_add_seconds (LOCKSCREEN_IDLE_SECONDS, @@ -431,21 +506,109 @@ static void +on_calls_call_inbound (PhoshLockscreen *self, const gchar *path) +{ + PhoshLockscreenPrivate *priv; + PhoshCall *call; + + g_return_if_fail (PHOSH_IS_LOCKSCREEN (self)); + priv = phosh_lockscreen_get_instance_private (self); + g_return_if_fail (PHOSH_IS_CALLS_MANAGER (priv->calls_manager)); + + g_debug ("New inbound call %s", path); + g_signal_emit (self, signals[WAKEUP_OUTPUT], 0); + + g_free (priv->active); + priv->active = g_strdup (path); + + call = phosh_calls_manager_get_call (priv->calls_manager, path); + g_return_if_fail (PHOSH_IS_CALL (call)); + + hdy_deck_set_visible_child (priv->deck, GTK_WIDGET (priv->box_call_display)); + + cui_call_display_set_call (priv->call_display, CUI_CALL (call)); +} + + +static void +on_calls_call_removed (PhoshLockscreen *self, const gchar *path) +{ + PhoshLockscreenPrivate *priv; + + g_return_if_fail (path != NULL); + g_return_if_fail (PHOSH_IS_LOCKSCREEN (self)); + priv = phosh_lockscreen_get_instance_private (self); + + g_debug ("Call %s removed, active: %s", path, priv->active); + + if (g_strcmp0 (path, priv->active)) + return; + + g_clear_pointer (&priv->active, g_free); + hdy_deck_navigate (priv->deck, HDY_NAVIGATION_DIRECTION_BACK); +} + + +static GtkWidget * +create_notification_row (gpointer item, gpointer data) +{ + GtkWidget *row = NULL; + GtkWidget *frame = NULL; + + row = g_object_new (GTK_TYPE_LIST_BOX_ROW, + "activatable", FALSE, + "visible", TRUE, + NULL); + + frame = phosh_notification_frame_new (FALSE); + phosh_notification_frame_bind_model (PHOSH_NOTIFICATION_FRAME (frame), item); + + gtk_widget_show (frame); + gtk_container_add (GTK_CONTAINER (row), frame); + + return row; +} + + +static void +on_notifcation_items_changed (PhoshLockscreen *self, + guint position, + guint removed, + guint added, + GListModel *list) +{ + PhoshLockscreenPrivate *priv; + gboolean is_empty; + + g_return_if_fail (G_IS_LIST_MODEL (list)); + g_return_if_fail (PHOSH_IS_LOCKSCREEN (self)); + priv = phosh_lockscreen_get_instance_private (self); + + is_empty = !g_list_model_get_n_items (list); + g_debug("Notification list empty: %d", is_empty); + + /* Don't unhide when we don't want notification on the lock screen */ + if (!is_empty && !g_settings_get_boolean (priv->settings, "show-in-lock-screen")) + return; + + gtk_widget_set_visible (GTK_WIDGET (priv->sw_notifications), !is_empty); +} + + +static void phosh_lockscreen_constructed (GObject *object) { PhoshLockscreen *self = PHOSH_LOCKSCREEN (object); PhoshLockscreenPrivate *priv = phosh_lockscreen_get_instance_private (self); + const char *active; + PhoshNotifyManager *manager; G_OBJECT_CLASS (phosh_lockscreen_parent_class)->constructed (object); /* window properties */ gtk_window_set_title (GTK_WINDOW (self), "phosh lockscreen"); gtk_window_set_decorated (GTK_WINDOW (self), FALSE); - gtk_widget_realize(GTK_WIDGET (self)); - - gtk_style_context_add_class ( - gtk_widget_get_style_context (GTK_WIDGET (self)), - "phosh-lockscreen"); + gtk_widget_realize (GTK_WIDGET (self)); gtk_widget_add_events (GTK_WIDGET (self), GDK_KEY_PRESS_MASK); g_signal_connect (G_OBJECT (self), @@ -461,6 +624,50 @@ G_CALLBACK (wall_clock_notify_cb), self); wall_clock_notify_cb (self, NULL, priv->wall_clock); + + g_signal_connect_object (priv->calls_manager, + "call-inbound", + G_CALLBACK (on_calls_call_inbound), + self, + G_CONNECT_SWAPPED); + g_signal_connect_object (priv->calls_manager, + "call-removed", + G_CALLBACK (on_calls_call_removed), + self, + G_CONNECT_SWAPPED); + + /* If a call is ongoing show it when locking until we show a notification */ + active = phosh_calls_manager_get_active_call_handle (priv->calls_manager); + if (active) + on_calls_call_inbound (self, active); + + manager = phosh_notify_manager_get_default (); + /* TODO: deduplicate after !862 */ + priv->settings = g_settings_new("org.gnome.desktop.notifications"); + g_settings_bind (priv->settings, "show-in-lock-screen", + priv->list_notifications, "visible", + G_SETTINGS_BIND_GET); + gtk_list_box_bind_model (GTK_LIST_BOX (priv->list_notifications), + G_LIST_MODEL (phosh_notify_manager_get_list (manager)), + create_notification_row, + NULL, + NULL); + g_signal_connect_object (phosh_notify_manager_get_list (manager), + "items-changed", + G_CALLBACK (on_notifcation_items_changed), + self, + G_CONNECT_SWAPPED); + on_notifcation_items_changed (self, -1, -1, -1, + G_LIST_MODEL (phosh_notify_manager_get_list (manager))); +} + +static void +deck_back_clicked_cb (GtkWidget *sender, + PhoshLockscreen *self) +{ + PhoshLockscreenPrivate *priv = phosh_lockscreen_get_instance_private (self); + + hdy_deck_navigate (priv->deck, HDY_NAVIGATION_DIRECTION_BACK); } @@ -470,11 +677,11 @@ PhoshLockscreen *self = PHOSH_LOCKSCREEN (object); PhoshLockscreenPrivate *priv = phosh_lockscreen_get_instance_private (self); + g_clear_object (&priv->settings); g_clear_object (&priv->wall_clock); - if (priv->idle_timer) { - g_source_remove (priv->idle_timer); - priv->idle_timer = 0; - } + g_clear_handle_id (&priv->idle_timer, g_source_remove); + g_clear_object (&priv->calls_manager); + g_clear_pointer (&priv->active, g_free); G_OBJECT_CLASS (phosh_lockscreen_parent_class)->dispose (object); } @@ -486,25 +693,34 @@ GObjectClass *object_class = (GObjectClass *)klass; GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - g_type_ensure (PHOSH_TYPE_BT_INFO); - g_type_ensure (PHOSH_TYPE_MEDIA_PLAYER); - object_class->constructed = phosh_lockscreen_constructed; object_class->dispose = phosh_lockscreen_dispose; + object_class->set_property = phosh_lockscreen_set_property; + object_class->get_property = phosh_lockscreen_get_property; + + props[PROP_CALLS_MANAGER] = + g_param_spec_object ("calls-manager", + "", + "", + PHOSH_TYPE_CALLS_MANAGER, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); + signals[LOCKSCREEN_UNLOCK] = g_signal_new ("lockscreen-unlock", - G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, - NULL, G_TYPE_NONE, 0); + G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, + NULL, G_TYPE_NONE, 0); /** - * PhoshLockscreen::wakeup-screen + * PhoshLockscreen::wakeup-output * @self: The #PhoshLockscreen emitting this signal * * Emitted when the output showing the lock screen should be woken * up. */ signals[WAKEUP_OUTPUT] = g_signal_new ("wakeup-output", - G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, - NULL, G_TYPE_NONE, 0); + G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, + NULL, G_TYPE_NONE, 0); gtk_widget_class_set_css_name (widget_class, "phosh-lockscreen"); gtk_widget_class_set_template_from_resource (widget_class, @@ -512,7 +728,7 @@ gtk_widget_class_bind_template_child_private (widget_class, PhoshLockscreen, carousel); gtk_widget_class_bind_template_callback_full (widget_class, "carousel_position_notified_cb", - G_CALLBACK(carousel_position_notified_cb)); + G_CALLBACK (carousel_position_notified_cb)); /* unlock page */ gtk_widget_class_bind_template_child_private (widget_class, PhoshLockscreen, box_unlock); @@ -532,7 +748,15 @@ gtk_widget_class_bind_template_child_private (widget_class, PhoshLockscreen, box_info); gtk_widget_class_bind_template_child_private (widget_class, PhoshLockscreen, lbl_clock); gtk_widget_class_bind_template_child_private (widget_class, PhoshLockscreen, lbl_date); + gtk_widget_class_bind_template_child_private (widget_class, PhoshLockscreen, list_notifications); + gtk_widget_class_bind_template_child_private (widget_class, PhoshLockscreen, sw_notifications); gtk_widget_class_bind_template_callback (widget_class, show_unlock_page); + + /* Call UI */ + gtk_widget_class_bind_template_child_private (widget_class, PhoshLockscreen, deck); + gtk_widget_class_bind_template_child_private (widget_class, PhoshLockscreen, box_call_display); + gtk_widget_class_bind_template_child_private (widget_class, PhoshLockscreen, call_display); + gtk_widget_class_bind_template_callback (widget_class, deck_back_clicked_cb); } @@ -545,7 +769,8 @@ GtkWidget * phosh_lockscreen_new (gpointer layer_shell, - gpointer wl_output) + gpointer wl_output, + PhoshCallsManager *calls_manager) { return g_object_new (PHOSH_TYPE_LOCKSCREEN, "layer-shell", layer_shell, @@ -558,5 +783,49 @@ "kbd-interactivity", TRUE, "exclusive-zone", -1, "namespace", "phosh lockscreen", + "calls-manager", calls_manager, NULL); } + +/** + * phosh_lockscreen_get_page + * @self: The #PhoshLockscreen + * + * Returns: The #PhoshLockscreenPage that is currently shown + */ +PhoshLockscreenPage +phosh_lockscreen_get_page (PhoshLockscreen *self) +{ + PhoshLockscreenPrivate *priv; + gdouble position; + + g_return_val_if_fail (PHOSH_IS_LOCKSCREEN (self), PHOSH_LOCKSCREEN_PAGE_DEFAULT); + priv = phosh_lockscreen_get_instance_private (self); + position = hdy_carousel_get_position (HDY_CAROUSEL (priv->carousel)); + + if (position <= 0) + return PHOSH_LOCKSCREEN_PAGE_DEFAULT; + else + return PHOSH_LOCKSCREEN_PAGE_UNLOCK; +} + +/* + * phosh_lockscreen_set_page + * @self: The #PhoshLockscreen + * PhoshLockscreenPage: the page to scroll to + * + * Scrolls to a specific page in the carousel. The state of the deck isn't changed. + */ +void +phosh_lockscreen_set_page (PhoshLockscreen *self, PhoshLockscreenPage page) +{ + GtkWidget *scroll_to; + PhoshLockscreenPrivate *priv; + + g_return_if_fail (PHOSH_IS_LOCKSCREEN (self)); + priv = phosh_lockscreen_get_instance_private (self); + + scroll_to = (page == PHOSH_LOCKSCREEN_PAGE_UNLOCK) ? priv->box_unlock : priv->box_info; + + hdy_carousel_scroll_to (HDY_CAROUSEL (priv->carousel), scroll_to); +} diff -Nru phosh-0.8.0/src/lockscreen.h phosh-0.13.1/src/lockscreen.h --- phosh-0.8.0/src/lockscreen.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/lockscreen.h 2021-08-31 09:15:52.000000000 +0000 @@ -5,15 +5,32 @@ */ #pragma once +#include "calls-manager.h" #include "layersurface.h" G_BEGIN_DECLS +/** + * PhoshLockscreenPage: + * @PHOSH_LOCKSCREEN_PAGE_DEFAULT: The default locked page + * @PHOSH_LOCKSCREEN_PAGE_UNLOCK: The unlock page (where PIN is entered) + * + * This enum indicates which page is shown on the lockscreen. + * This helps #PhoshGnomeShellManager to decide when to emit + * AcceleratorActivated events over DBus + */ +typedef enum { + PHOSH_LOCKSCREEN_PAGE_DEFAULT, + PHOSH_LOCKSCREEN_PAGE_UNLOCK, +} PhoshLockscreenPage; + #define PHOSH_TYPE_LOCKSCREEN (phosh_lockscreen_get_type ()) G_DECLARE_FINAL_TYPE (PhoshLockscreen, phosh_lockscreen, PHOSH, LOCKSCREEN, PhoshLayerSurface) -GtkWidget * phosh_lockscreen_new (gpointer layer_shell, gpointer wl_output); +GtkWidget * phosh_lockscreen_new (gpointer layer_shell, gpointer wl_output, PhoshCallsManager *calls_manager); +void phosh_lockscreen_set_page (PhoshLockscreen *self, PhoshLockscreenPage page); +PhoshLockscreenPage phosh_lockscreen_get_page (PhoshLockscreen *self); G_END_DECLS diff -Nru phosh-0.8.0/src/lockscreen-manager.c phosh-0.13.1/src/lockscreen-manager.c --- phosh-0.8.0/src/lockscreen-manager.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/lockscreen-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -42,26 +42,26 @@ static guint signals[N_SIGNALS] = { 0 }; enum { - PHOSH_LOCKSCREEN_MANAGER_PROP_0, - PHOSH_LOCKSCREEN_MANAGER_PROP_LOCKED, - PHOSH_LOCKSCREEN_MANAGER_PROP_TIMEOUT, - PHOSH_LOCKSCREEN_MANAGER_PROP_LAST_PROP + PROP_0, + PROP_LOCKED, + PROP_CALLS_MANAGER, + PROP_LAST_PROP }; -static GParamSpec *props[PHOSH_LOCKSCREEN_MANAGER_PROP_LAST_PROP]; +static GParamSpec *props[PROP_LAST_PROP]; struct _PhoshLockscreenManager { GObject parent; - PhoshLockscreen *lockscreen; /* phone display lock screen */ - PhoshSessionPresence *presence; /* gnome-session's presence interface */ - GPtrArray *shields; /* other outputs */ - GSettings *settings; + PhoshLockscreen *lockscreen; /* phone display lock screen */ + PhoshSessionPresence *presence; /* gnome-session's presence interface */ + GPtrArray *shields; /* other outputs */ - int timeout; /* timeout in seconds before screen locks */ gboolean locked; - gint64 active_time; /* when lock was activated (in us) */ - int transform; /* the shell transform before locking */ + gint64 active_time; /* when lock was activated (in us) */ + int transform; /* the shell transform before locking */ + + PhoshCallsManager *calls_manager; /* Calls DBus Interface */ }; G_DEFINE_TYPE (PhoshLockscreenManager, phosh_lockscreen_manager, G_TYPE_OBJECT) @@ -77,10 +77,6 @@ g_return_if_fail (PHOSH_IS_LOCKSCREEN (lockscreen)); g_return_if_fail (lockscreen == PHOSH_LOCKSCREEN (self->lockscreen)); - /* Fixup transform in case the lockscreen needed to rotate to unlock */ - g_debug ("Restoring transform %d", self->transform); - phosh_shell_set_transform (shell, self->transform); - g_signal_handlers_disconnect_by_data (monitor_manager, self); g_signal_handlers_disconnect_by_data (primary_monitor, self); g_signal_handlers_disconnect_by_data (shell, self); @@ -91,7 +87,7 @@ self->locked = FALSE; self->active_time = 0; - g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LOCKSCREEN_MANAGER_PROP_LOCKED]); + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_LOCKED]); } @@ -171,35 +167,6 @@ lock_monitor (self, monitor); } -static void -on_primary_monitor_power_mode_changed (PhoshLockscreenManager *self, - GParamSpec *pspec, - PhoshMonitor *monitor) -{ - PhoshShell *shell = phosh_shell_get_default (); - PhoshModeManager *mode_manager = phosh_shell_get_mode_manager(shell); - - /* - * Only phones need to switch orientation so that the lock screen fits - * https://source.puri.sm/Librem5/phosh/-/issues/388 - */ - if (phosh_mode_manager_get_device_type(mode_manager) != PHOSH_MODE_DEVICE_TYPE_PHONE) - return; - - /* Don't mess with transforms on external screens either */ - if (!phosh_monitor_is_builtin (monitor)) - return; - - switch (phosh_monitor_get_power_save_mode (monitor)) { - case PHOSH_MONITOR_POWER_SAVE_MODE_ON: - phosh_shell_set_transform (shell, PHOSH_MONITOR_TRANSFORM_NORMAL); - break; - case PHOSH_MONITOR_POWER_SAVE_MODE_OFF: - break; - default: - g_warn_if_reached (); - } -} static void lock_primary_monitor (PhoshLockscreenManager *self) @@ -209,23 +176,18 @@ PhoshShell *shell = phosh_shell_get_default (); primary_monitor = phosh_shell_get_primary_monitor (shell); - self->transform = phosh_shell_get_transform (shell); /* The primary output gets the clock, keypad, ... */ self->lockscreen = PHOSH_LOCKSCREEN (phosh_lockscreen_new ( phosh_wayland_get_zwlr_layer_shell_v1 (wl), - primary_monitor->wl_output)); - + primary_monitor->wl_output, + self->calls_manager)); g_object_connect ( self->lockscreen, "swapped-object-signal::lockscreen-unlock", G_CALLBACK (lockscreen_unlock_cb), self, "swapped-object-signal::wakeup-output", G_CALLBACK (lockscreen_wakeup_output_cb), self, NULL); - g_signal_connect_swapped (primary_monitor, "notify::power-mode", - G_CALLBACK(on_primary_monitor_power_mode_changed), - self); - gtk_widget_show (GTK_WIDGET (self->lockscreen)); /* Old lockscreen gets remove due to `layer_surface_closed` */ } @@ -289,7 +251,7 @@ self->locked = TRUE; self->active_time = g_get_monotonic_time (); - g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LOCKSCREEN_MANAGER_PROP_LOCKED]); + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_LOCKED]); } @@ -313,11 +275,11 @@ PhoshLockscreenManager *self = PHOSH_LOCKSCREEN_MANAGER (object); switch (property_id) { - case PHOSH_LOCKSCREEN_MANAGER_PROP_LOCKED: + case PROP_LOCKED: phosh_lockscreen_manager_set_locked (self, g_value_get_boolean (value)); break; - case PHOSH_LOCKSCREEN_MANAGER_PROP_TIMEOUT: - phosh_lockscreen_manager_set_timeout (self, g_value_get_int (value)); + case PROP_CALLS_MANAGER: + self->calls_manager = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -335,11 +297,11 @@ PhoshLockscreenManager *self = PHOSH_LOCKSCREEN_MANAGER (object); switch (property_id) { - case PHOSH_LOCKSCREEN_MANAGER_PROP_LOCKED: + case PROP_LOCKED: g_value_set_boolean (value, self->locked); break; - case PHOSH_LOCKSCREEN_MANAGER_PROP_TIMEOUT: - g_value_set_uint (value, self->timeout); + case PROP_CALLS_MANAGER: + g_value_set_object (value, self->calls_manager); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -349,13 +311,23 @@ static void +on_calls_call_inbound (PhoshLockscreen *self) +{ + g_return_if_fail (PHOSH_IS_LOCKSCREEN_MANAGER (self)); + + g_signal_emit (self, signals[WAKEUP_OUTPUTS], 0); +} + + +static void phosh_lockscreen_manager_dispose (GObject *object) { PhoshLockscreenManager *self = PHOSH_LOCKSCREEN_MANAGER (object); g_clear_pointer (&self->shields, g_ptr_array_unref); g_clear_pointer (&self->lockscreen, phosh_cp_widget_destroy); - g_clear_object (&self->settings); + g_clear_object (&self->calls_manager); + g_clear_object (&self->presence); G_OBJECT_CLASS (phosh_lockscreen_manager_parent_class)->dispose (object); } @@ -368,9 +340,6 @@ G_OBJECT_CLASS (phosh_lockscreen_manager_parent_class)->constructed (object); - self->settings = g_settings_new ("org.gnome.desktop.session"); - g_settings_bind (self->settings, "idle-delay", self, "timeout", G_SETTINGS_BIND_GET); - self->presence = phosh_session_presence_get_default_failable (); if (self->presence) { g_signal_connect_swapped (self->presence, @@ -378,6 +347,12 @@ (GCallback) presence_status_changed_cb, self); } + + g_signal_connect_object (self->calls_manager, + "call-inbound", + G_CALLBACK (on_calls_call_inbound), + self, + G_CONNECT_SWAPPED); } @@ -392,21 +367,21 @@ object_class->set_property = phosh_lockscreen_manager_set_property; object_class->get_property = phosh_lockscreen_manager_get_property; - props[PHOSH_LOCKSCREEN_MANAGER_PROP_LOCKED] = + props[PROP_LOCKED] = g_param_spec_boolean ("locked", "Locked", "Whether the screen is locked", FALSE, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); - props[PHOSH_LOCKSCREEN_MANAGER_PROP_TIMEOUT] = - g_param_spec_int ("timeout", - "Timeout", - "Idle timeout in seconds until screen locks", - 0, - G_MAXINT, - 300, - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); - g_object_class_install_properties (object_class, PHOSH_LOCKSCREEN_MANAGER_PROP_LAST_PROP, props); + + props[PROP_CALLS_MANAGER] = + g_param_spec_object ("calls-manager", + "", + "", + PHOSH_TYPE_CALLS_MANAGER, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); /** * PhoshLockscreenManager::wakeup-outputs @@ -428,20 +403,28 @@ PhoshLockscreenManager * -phosh_lockscreen_manager_new (void) +phosh_lockscreen_manager_new (PhoshCallsManager *calls_manager) { - return g_object_new (PHOSH_TYPE_LOCKSCREEN_MANAGER, NULL); + return g_object_new (PHOSH_TYPE_LOCKSCREEN_MANAGER, + "calls-manager", calls_manager, + NULL); } - +/** + * phosh_lockscreen_set_locked: + * @self: The #PhoshLockscreenManager + * @lock: %TRUE to lock %FALSE to unlock + * + * Lock or unlock the screen. + */ void -phosh_lockscreen_manager_set_locked (PhoshLockscreenManager *self, gboolean state) +phosh_lockscreen_manager_set_locked (PhoshLockscreenManager *self, gboolean lock) { g_return_if_fail (PHOSH_IS_LOCKSCREEN_MANAGER (self)); - if (state == self->locked) + if (lock == self->locked) return; - if (state) + if (lock) lockscreen_lock (self); else lockscreen_unlock_cb (self, PHOSH_LOCKSCREEN (self->lockscreen)); @@ -456,35 +439,41 @@ return self->locked; } - -void -phosh_lockscreen_manager_set_timeout (PhoshLockscreenManager *self, int timeout) +/** + * phosh_lockscreen_manager_get_page + * @self: The #PhoshLockscreenManager + * + * Returns: The currently shown #PhoshLockscreenPage in the #PhoshLockscreen + */ +PhoshLockscreenPage +phosh_lockscreen_manager_get_page (PhoshLockscreenManager *self) { - g_return_if_fail (PHOSH_IS_LOCKSCREEN_MANAGER (self)); - - if (timeout == self->timeout) - return; - - g_debug ("Setting lock screen idle timeout to %d seconds", timeout); - self->timeout = timeout; + g_return_val_if_fail (PHOSH_IS_LOCKSCREEN_MANAGER (self), FALSE); - g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_LOCKSCREEN_MANAGER_PROP_TIMEOUT]); + return phosh_lockscreen_get_page (self->lockscreen); } -int -phosh_lockscreen_manager_get_timeout (PhoshLockscreenManager *self) +gint64 +phosh_lockscreen_manager_get_active_time (PhoshLockscreenManager *self) { g_return_val_if_fail (PHOSH_IS_LOCKSCREEN_MANAGER (self), 0); - return self->timeout; + return self->active_time; } -gint64 -phosh_lockscreen_manager_get_active_time (PhoshLockscreenManager *self) +gboolean +phosh_lockscreen_manager_set_page (PhoshLockscreenManager *self, + PhoshLockscreenPage page) { - g_return_val_if_fail (PHOSH_IS_LOCKSCREEN_MANAGER (self), 0); + g_return_val_if_fail (PHOSH_IS_LOCKSCREEN_MANAGER (self), FALSE); - return self->active_time; + if (!self->lockscreen) + return FALSE; + + g_return_val_if_fail (PHOSH_IS_LOCKSCREEN (self->lockscreen), FALSE); + + phosh_lockscreen_set_page (self->lockscreen, page); + return TRUE; } diff -Nru phosh-0.8.0/src/lockscreen-manager.h phosh-0.13.1/src/lockscreen-manager.h --- phosh-0.8.0/src/lockscreen-manager.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/lockscreen-manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -6,6 +6,8 @@ #pragma once +#include "calls-manager.h" +#include "lockscreen.h" #include #define PHOSH_TYPE_LOCKSCREEN_MANAGER (phosh_lockscreen_manager_get_type()) @@ -16,10 +18,13 @@ LOCKSCREEN_MANAGER, GObject) -PhoshLockscreenManager *phosh_lockscreen_manager_new (void); +PhoshLockscreenManager *phosh_lockscreen_manager_new (PhoshCallsManager *calls_manager); void phosh_lockscreen_manager_set_locked (PhoshLockscreenManager *self, gboolean state); gboolean phosh_lockscreen_manager_get_locked (PhoshLockscreenManager *self); +gboolean phosh_lockscreen_manager_set_page (PhoshLockscreenManager *self, + PhoshLockscreenPage page); +PhoshLockscreenPage phosh_lockscreen_manager_get_page (PhoshLockscreenManager *self); void phosh_lockscreen_manager_set_timeout (PhoshLockscreenManager *self, int timeout); int phosh_lockscreen_manager_get_timeout (PhoshLockscreenManager *self); diff -Nru phosh-0.8.0/src/main.c phosh-0.13.1/src/main.c --- phosh-0.8.0/src/main.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/main.c 2021-08-31 09:15:52.000000000 +0000 @@ -15,10 +15,12 @@ #include "phosh-wayland.h" #include +#include #include #include +#include static gboolean quit (gpointer unused) @@ -70,6 +72,19 @@ } +static void +on_shell_ready (PhoshShell *shell, GTimer *timer) +{ + g_timer_stop (timer); + g_debug ("Phosh ready after %.2fs", g_timer_elapsed (timer, NULL)); + + /* Inform systemd we're up */ + sd_notify (0, "READY=1"); + + g_signal_handlers_disconnect_by_data (shell, timer); +} + + int main(int argc, char *argv[]) { g_autoptr(GSource) sigterm = NULL; @@ -78,6 +93,7 @@ gboolean unlocked = FALSE, locked = FALSE, version = FALSE; g_autoptr(PhoshWayland) wl = NULL; g_autoptr(PhoshShell) shell = NULL; + g_autoptr (GTimer) timer = g_timer_new (); const GOptionEntry options [] = { {"unlocked", 'U', 0, G_OPTION_ARG_NONE, &unlocked, @@ -109,6 +125,7 @@ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); gtk_init (&argc, &argv); hdy_init (); + cui_init (TRUE); g_unix_signal_add (SIGTERM, on_shutdown_signal, NULL); g_unix_signal_add (SIGINT, on_shutdown_signal, NULL); @@ -116,10 +133,15 @@ wl = phosh_wayland_get_default (); shell = phosh_shell_get_default (); + + g_signal_connect (shell, "ready", G_CALLBACK (on_shell_ready), timer); + if (!(unlocked || phosh_shell_started_by_display_manager(shell)) || locked) phosh_shell_lock (shell); gtk_main (); + cui_uninit (); + return EXIT_SUCCESS; } diff -Nru phosh-0.8.0/src/manager.c phosh-0.13.1/src/manager.c --- phosh-0.8.0/src/manager.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-manager" + +#include "config.h" + +#include "manager.h" + +/** + * SECTION:manager + * @short_description: Base class for manager objects + * @Title: PhoshManager + * + * Common functionality for manager objects. + */ + +typedef struct +{ + guint idle_id; +} PhoshManagerPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (PhoshManager, phosh_manager, G_TYPE_OBJECT); + + +static gboolean +on_idle (PhoshManager *self) +{ + PhoshManagerClass *klass = PHOSH_MANAGER_GET_CLASS (self); + PhoshManagerPrivate *priv = phosh_manager_get_instance_private (self); + + if (klass->idle_init) + (*klass->idle_init) (self); + + priv->idle_id = 0; + return G_SOURCE_REMOVE; +} + + +static void +phosh_manager_dispose (GObject *object) +{ + PhoshManager *self = PHOSH_MANAGER (object); + PhoshManagerPrivate *priv = phosh_manager_get_instance_private (self); + + g_clear_handle_id (&priv->idle_id, g_source_remove); + + G_OBJECT_CLASS (phosh_manager_parent_class)->dispose (object); +} + + +static void +phosh_manager_constructed (GObject *object) +{ + PhoshManager *self = PHOSH_MANAGER (object); + PhoshManagerClass *klass = PHOSH_MANAGER_GET_CLASS (object); + PhoshManagerPrivate *priv = phosh_manager_get_instance_private (self); + + G_OBJECT_CLASS (phosh_manager_parent_class)->constructed (object); + + if (klass->idle_init) + priv->idle_id = g_idle_add ((GSourceFunc) on_idle, self); +} + + +static void +phosh_manager_class_init (PhoshManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = phosh_manager_constructed; + object_class->dispose = phosh_manager_dispose; +} + +static void +phosh_manager_init (PhoshManager *self) +{ +} diff -Nru phosh-0.8.0/src/manager.h phosh-0.13.1/src/manager.h --- phosh-0.8.0/src/manager.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define PHOSH_TYPE_MANAGER (phosh_manager_get_type()) + +G_DECLARE_DERIVABLE_TYPE (PhoshManager, phosh_manager, PHOSH, MANAGER, GObject) + +/** + * PhoshManagerClass: + * @parent_class: The parent class + * @idle_init: a callback to be invoked once on idle + */ +struct _PhoshManagerClass +{ + GObjectClass parent_class; + + void (*idle_init) (PhoshManager *self); +}; + +G_END_DECLS diff -Nru phosh-0.8.0/src/media-player.c phosh-0.13.1/src/media-player.c --- phosh-0.8.0/src/media-player.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/media-player.c 2021-08-31 09:15:52.000000000 +0000 @@ -68,6 +68,7 @@ GtkWidget *btn_prev; GtkWidget *btn_details; GtkWidget *img_art; + GtkWidget *img_play; GtkWidget *lbl_title; GtkWidget *lbl_artist; @@ -80,6 +81,8 @@ PhoshMediaPlayerStatus status; gboolean attached; gboolean playable; + + guint idle_id; } PhoshMediaPlayer; G_DEFINE_TYPE (PhoshMediaPlayer, phosh_media_player, GTK_TYPE_GRID); @@ -292,11 +295,9 @@ g_autoptr (GFile) file = g_file_new_for_uri (url); icon = g_file_icon_new (file); - gtk_image_set_from_gicon (GTK_IMAGE (self->img_art), icon, GTK_ICON_SIZE_DIALOG); + gtk_image_set_from_gicon (GTK_IMAGE (self->img_art), icon, -1); } else { - gtk_image_set_from_icon_name (GTK_IMAGE (self->img_art), - "audio-x-generic-symbolic", - GTK_ICON_SIZE_DIALOG); + gtk_image_set_from_icon_name (GTK_IMAGE (self->img_art), "audio-x-generic-symbolic", -1); } } @@ -337,8 +338,8 @@ } if (self->status != current) { - GtkWidget *image = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_SMALL_TOOLBAR); - gtk_button_set_image (GTK_BUTTON (self->btn_play), image); + gtk_image_set_from_icon_name (GTK_IMAGE (self->img_play), icon, -1); + gtk_widget_set_valign (self->img_play, GTK_ALIGN_START); } } @@ -390,11 +391,13 @@ { PhoshMediaPlayer *self = PHOSH_MEDIA_PLAYER (object); + g_clear_handle_id (&self->idle_id, g_source_remove); + if (self->dbus_id) { g_dbus_connection_signal_unsubscribe (self->session_bus, self->dbus_id); self->dbus_id = 0; - g_clear_object (&self->session_bus); } + g_clear_object (&self->session_bus); g_clear_object (&self->mpris); g_clear_object (&self->player); @@ -461,6 +464,7 @@ gtk_widget_class_bind_template_child (widget_class, PhoshMediaPlayer, btn_prev); gtk_widget_class_bind_template_child (widget_class, PhoshMediaPlayer, btn_details); gtk_widget_class_bind_template_child (widget_class, PhoshMediaPlayer, img_art); + gtk_widget_class_bind_template_child (widget_class, PhoshMediaPlayer, img_play); gtk_widget_class_bind_template_child (widget_class, PhoshMediaPlayer, lbl_artist); gtk_widget_class_bind_template_child (widget_class, PhoshMediaPlayer, lbl_title); gtk_widget_class_bind_template_callback (widget_class, btn_play_clicked_cb); @@ -724,6 +728,8 @@ NULL, (GAsyncReadyCallback)on_bus_get_finished, g_object_ref (self)); + + self->idle_id = 0; return G_SOURCE_REMOVE; } @@ -734,7 +740,7 @@ gtk_widget_init_template (GTK_WIDGET (self)); /* Perform DBus setup when idle */ - g_idle_add ((GSourceFunc)on_idle, self); + self->idle_id = g_idle_add ((GSourceFunc)on_idle, self); } diff -Nru phosh-0.8.0/src/meson.build phosh-0.13.1/src/meson.build --- phosh-0.8.0/src/meson.build 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/meson.build 2021-08-31 09:15:52.000000000 +0000 @@ -1,7 +1,6 @@ subdir('dbus') subdir('monitor') subdir('notifications') -subdir('osk') subdir('wwan') subdir('settings') subdir('gtk-list-models') @@ -13,15 +12,19 @@ c_name: 'phosh', ) -phosh_enum_headers = [ +phosh_enum_headers = files( 'app-grid-button.h', + 'gnome-shell-manager.h', 'home.h', + 'lockscreen.h', 'mode-manager.h', 'monitor/monitor.h', 'notifications/notification.h', 'notifications/notify-manager.h', 'phosh-wayland.h', -] + schema_enum_headers + 'rotation-manager.h', + 'shell.h', +) + schema_enum_headers phosh_enums = gnome.mkenums('phosh-enums', h_template: 'phosh-enums.h.in', @@ -29,8 +32,8 @@ sources: phosh_enum_headers, ) -phosh_settings_sources = [ - 'settings.c', +phosh_settings_sources = files( + 'settings.c') + [ phosh_settings_widgets_sources, ] @@ -41,7 +44,7 @@ generated_dbus_sources, ] -libphosh_tool_sources = [ +libphosh_tool_sources = files( 'activity.c', 'activity.h', 'animation.c', @@ -54,8 +57,18 @@ 'app-list-model.h', 'background.c', 'background.h', + 'call.c', + 'call.h', + 'calls-manager.c', + 'calls-manager.h', 'connectivity-info.c', 'connectivity-info.h', + 'end-session-dialog.c', + 'end-session-dialog.h', + 'hks-info.c', + 'hks-info.h', + 'hks-manager.c', + 'hks-manager.h', 'docked-info.c', 'docked-info.h', 'docked-manager.c', @@ -66,22 +79,36 @@ 'feedback-manager.h', 'gnome-shell-manager.c', 'gnome-shell-manager.h', + 'gtk-mount-manager.c', + 'gtk-mount-manager.h', + 'gtk-mount-prompt.c', + 'gtk-mount-prompt.h', 'layersurface.c', 'layersurface.h', 'lockshield.c', 'lockshield.h', 'log.h', 'log.c', + 'manager.h', + 'manager.c', 'media-player.c', 'media-player.h', 'mode-manager.c', 'mode-manager.h', 'mount-manager.c', 'mount-manager.h', + 'mount-operation.c', + 'mount-operation.h', 'overview.c', 'overview.h', + 'osd-window.c', + 'osd-window.h', 'status-icon.c', 'status-icon.h', + 'system-modal.c', + 'system-modal.h', + 'system-modal-dialog.c', + 'system-modal-dialog.h', 'thumbnail.c', 'thumbnail.h', 'quick-setting.c', @@ -92,12 +119,18 @@ 'swipe-away-bin.h', 'util.c', 'util.h', + 'wl-buffer.c', + 'wl-buffer.h', +) + [ + libphosh_generated_sources, phosh_gtk_list_models_sources, + phosh_monitor_sources, phosh_notifications_sources, - libphosh_generated_sources, ] -libphosh_sources = [ +libphosh_sources = files( + 'app-auth-prompt.c', + 'app-auth-prompt.h', 'arrow.c', 'arrow.h', 'auth.c', @@ -122,6 +155,10 @@ 'keyboard-events.h', 'idle-manager.c', 'idle-manager.h', + 'location-info.c', + 'location-info.h', + 'location-manager.c', + 'location-manager.h', 'lockscreen-manager.c', 'lockscreen-manager.h', 'lockscreen.c', @@ -130,22 +167,28 @@ 'monitor-manager.h', 'network-auth-prompt.c', 'network-auth-prompt.h', + 'osk-button.c', + 'osk-button.h', 'osk-manager.c', 'osk-manager.h', - 'panel.c', - 'panel.h', + 'top-panel.c', + 'top-panel.h', 'polkit-auth-agent.c', 'polkit-auth-agent.h', 'polkit-auth-prompt.c', 'polkit-auth-prompt.h', 'proximity.h', 'proximity.c', + 'rotation-manager.h', + 'rotation-manager.c', 'sensor-proxy-manager.c', 'sensor-proxy-manager.h', 'rotateinfo.c', 'rotateinfo.h', 'screen-saver-manager.c', 'screen-saver-manager.h', + 'screenshot-manager.c', + 'screenshot-manager.h', 'session-presence.c', 'session-presence.h', 'session-manager.c', @@ -172,10 +215,9 @@ 'wifimanager.h', 'wwaninfo.c', 'wwaninfo.h', +) + [ phosh_settings_sources, phosh_wwan_sources, - phosh_monitor_sources, - phosh_osk_sources, ] phosh_deps = [ @@ -185,8 +227,11 @@ glib_dep, gnome_desktop_dep, gobject_dep, + gsettings_desktop_schemas_dep, gtk_dep, gtk_wayland_dep, + libcall_ui_dep, + gudev_dep, libfeedback_dep, libgvc_dep, libhandy_dep, @@ -208,23 +253,33 @@ phosh_inc = include_directories('.') # A static library used by tests and tools -phosh_tool_lib = static_library('phosh-tool', libphosh_tool_sources, dependencies: phosh_deps) +phosh_tool_lib = static_library('phosh-tool', + libphosh_tool_sources, + include_directories: [root_inc, phosh_inc], + dependencies: phosh_deps) phosh_tool_dep = declare_dependency(sources: libphosh_generated_sources, include_directories: [root_inc, phosh_inc], link_with: phosh_tool_lib, dependencies: phosh_deps) -if get_option('gtk_doc') -# We only build the shared lib for gtk-doc: -phosh_doc_lib = library('phosh-doc', [libphosh_sources, libphosh_tool_sources], dependencies: phosh_deps) +phosh_lib = both_libraries('phosh', + libphosh_sources, + include_directories: [root_inc, phosh_inc], + dependencies: [phosh_tool_dep, phosh_deps]) + +# Shared lib used by docs phosh_doc_dep = declare_dependency(sources: libphosh_generated_sources, include_directories: [root_inc, phosh_inc], - link_with: phosh_doc_lib, + link_with: phosh_lib, dependencies: phosh_deps) -endif -phosh = executable('phosh', ['main.c', libphosh_sources], - dependencies: phosh_tool_dep, +# Static library used by shell and integration tests +phosh_dep = declare_dependency( + include_directories: [root_inc, phosh_inc], + link_with: phosh_lib.get_static_lib(), + dependencies: [phosh_deps, phosh_tool_dep]) + +phosh = executable('phosh', 'main.c', + dependencies: phosh_dep, install: true, install_dir: libexecdir) - diff -Nru phosh-0.8.0/src/mode-manager.c phosh-0.13.1/src/mode-manager.c --- phosh-0.8.0/src/mode-manager.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/mode-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -12,6 +12,7 @@ #include "mode-manager.h" #include "shell.h" +#include "util.h" #include "dbus/hostname1-dbus.h" #define BUS_NAME "org.freedesktop.hostname1" @@ -40,7 +41,7 @@ static GParamSpec *props[PROP_LAST_PROP]; struct _PhoshModeManager { - GObject parent; + PhoshManager parent; PhoshModeDeviceType device_type; PhoshModeDeviceType mimicry; @@ -49,10 +50,11 @@ PhoshMonitorManager *monitor_manager; PhoshHostname1DBusHostname1 *proxy; + GCancellable *cancel; gchar *chassis; PhoshWaylandSeatCapabilities wl_caps; }; -G_DEFINE_TYPE (PhoshModeManager, phosh_mode_manager, G_TYPE_OBJECT); +G_DEFINE_TYPE (PhoshModeManager, phosh_mode_manager, PHOSH_TYPE_MANAGER); static void @@ -206,15 +208,16 @@ PhoshModeManager *self) { g_autoptr (GError) err = NULL; - PhoshWayland *wl = phosh_wayland_get_default (); - - g_return_if_fail (PHOSH_IS_MODE_MANAGER (self)); + PhoshWayland *wl; + PhoshHostname1DBusHostname1 *proxy; - self->proxy = phosh_hostname1_dbus_hostname1_proxy_new_for_bus_finish (res, &err); - if (!self->proxy) { - g_warning ("Failed to get hostname1 proxy: %s", err->message); - goto out; + proxy = phosh_hostname1_dbus_hostname1_proxy_new_for_bus_finish (res, &err); + if (proxy == NULL) { + phosh_async_error_warn (err, "Failed to get hostname1 proxy"); + return; } + g_return_if_fail (PHOSH_IS_MODE_MANAGER (self)); + self->proxy = proxy; g_debug ("Hostname1 interface initialized"); g_signal_connect_object (self->proxy, @@ -224,6 +227,7 @@ G_CONNECT_SWAPPED); on_chassis_changed (self, NULL, self->proxy); + wl = phosh_wayland_get_default (); g_signal_connect_object (wl, "notify::seat-capabilities", G_CALLBACK (on_seat_capabilities_changed), @@ -237,24 +241,21 @@ self, G_CONNECT_SWAPPED); /* n_monitors is always updated in update_props () */ - -out: - g_object_unref (self); } -static gboolean -on_idle (PhoshTorchManager *self) +static void +phosh_mode_manager_idle_init (PhoshManager *manager) { + PhoshModeManager *self = PHOSH_MODE_MANAGER (manager); + phosh_hostname1_dbus_hostname1_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, BUS_NAME, OBJECT_PATH, - NULL, + self->cancel, (GAsyncReadyCallback) on_proxy_new_for_bus_finish, - g_object_ref (self)); - - return G_SOURCE_REMOVE; + self); } static void @@ -265,9 +266,6 @@ G_OBJECT_CLASS (phosh_mode_manager_parent_class)->constructed (object); self->monitor_manager = phosh_shell_get_monitor_manager (phosh_shell_get_default ()); - - /* Perform DBus setup when idle */ - g_idle_add ((GSourceFunc)on_idle, self); } @@ -276,6 +274,9 @@ { PhoshModeManager *self = PHOSH_MODE_MANAGER (object); + g_cancellable_cancel (self->cancel); + g_clear_object (&self->cancel); + g_clear_object (&self->proxy); G_OBJECT_CLASS (phosh_mode_manager_parent_class)->dispose (object); @@ -297,12 +298,15 @@ phosh_mode_manager_class_init (PhoshModeManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + PhoshManagerClass *manager_class = PHOSH_MANAGER_CLASS (klass); object_class->constructed = phosh_mode_manager_constructed; object_class->dispose = phosh_mode_manager_dispose; object_class->finalize = phosh_mode_manager_finalize; object_class->get_property = phosh_mode_manager_get_property; + manager_class->idle_init = phosh_mode_manager_idle_init; + props[PROP_DEVICE_TYPE] = g_param_spec_enum ("device-type", "Device Type", @@ -351,6 +355,7 @@ self->hw_flags = PHOSH_MODE_HW_NONE; self->device_type = PHOSH_MODE_DEVICE_TYPE_UNKNOWN; self->mimicry = PHOSH_MODE_DEVICE_TYPE_UNKNOWN; + self->cancel = g_cancellable_new (); } diff -Nru phosh-0.8.0/src/mode-manager.h phosh-0.13.1/src/mode-manager.h --- phosh-0.8.0/src/mode-manager.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/mode-manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -6,6 +6,8 @@ #pragma once +#include + #include @@ -54,7 +56,7 @@ #define PHOSH_TYPE_MODE_MANAGER (phosh_mode_manager_get_type ()) -G_DECLARE_FINAL_TYPE (PhoshModeManager, phosh_mode_manager, PHOSH, MODE_MANAGER, GObject) +G_DECLARE_FINAL_TYPE (PhoshModeManager, phosh_mode_manager, PHOSH, MODE_MANAGER, PhoshManager) PhoshModeManager *phosh_mode_manager_new (void); PhoshModeDeviceType phosh_mode_manager_get_device_type (PhoshModeManager *self); diff -Nru phosh-0.8.0/src/monitor/head.c phosh-0.13.1/src/monitor/head.c --- phosh-0.8.0/src/monitor/head.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/monitor/head.c 2021-08-31 09:15:52.000000000 +0000 @@ -38,8 +38,10 @@ #define MINIMUM_LOGICAL_AREA_LANDSCAPE (800 * 480) #define MINIMUM_LOGICAL_AREA_PORTRAIT (360 * 720) -#define MINIMUM_SCALE_FACTOR 1 -#define MAXIMUM_SCALE_FACTOR 4 +#define MINIMUM_SCALE_FACTOR 1.0f +#define MAXIMUM_SCALE_FACTOR 4.0f +#define SCALE_FACTORS_PER_INTEGER 4 +#define SCALE_FACTORS_STEPS (1.0 / (float) SCALE_FACTORS_PER_INTEGER) G_DEFINE_TYPE (PhoshHead, phosh_head, G_TYPE_OBJECT); @@ -71,29 +73,24 @@ static gboolean -is_logical_size_large_enough (int width, int height) +is_logical_size_large_enough (float width, float height) { - if (width > height) - return width * height >= MINIMUM_LOGICAL_AREA_LANDSCAPE; - else - return width * height >= MINIMUM_LOGICAL_AREA_PORTRAIT; + int area = (width > height) ? MINIMUM_LOGICAL_AREA_LANDSCAPE : MINIMUM_LOGICAL_AREA_PORTRAIT; + + return width * height >= area; } static gboolean -is_valid_scale (int width, int height, int scale) +is_valid_scale (float width, float height, float scale) { - int scaled_h = height / scale; - int scaled_w = width / scale; + float scaled_h = height / scale; + float scaled_w = width / scale; - if (scale < MINIMUM_SCALE_FACTOR || scale > MAXIMUM_SCALE_FACTOR || - !is_logical_size_large_enough (scaled_w, scaled_h)) + if (scale < MINIMUM_SCALE_FACTOR || scale > MAXIMUM_SCALE_FACTOR) return FALSE; - if (width % scale == 0 && height % scale == 0) - return TRUE; - - return FALSE; + return is_logical_size_large_enough (floorf (scaled_w), floorf(scaled_h)); } @@ -353,8 +350,8 @@ g_return_if_fail (PHOSH_IS_HEAD (self)); g_free (self->serial); - self->product = g_strdup (serial_number); - g_debug ("Head %p has serial %s", self, self->product); + self->serial = g_strdup (serial_number); + g_debug ("Head %p has serial %s", self, self->serial); } @@ -586,28 +583,108 @@ } -int * +static float +get_closest_scale_factor_for_resolution (float width, float height, float scale, float threshold) +{ + unsigned int i; + float scaled_h; + float scaled_w; + float best_scale; + int base_scaled_w; + gboolean found_one; + + best_scale = 0; + + if (!is_valid_scale (width, height, scale)) + return 0.0; + + if ((int)fmodf (width, scale) == 0 && (int)fmodf (height, scale) == 0) + return scale; + + i = 0; + found_one = FALSE; + base_scaled_w = floorf (width / scale); + + do { + for (int j = 0; j < 2; j++) { + float current_scale; + int offset = i * (j ? 1 : -1); + + scaled_w = base_scaled_w + offset; + current_scale = width / scaled_w; + scaled_h = height / current_scale; + + if (current_scale >= scale + threshold || + current_scale <= scale - threshold || + current_scale < MINIMUM_SCALE_FACTOR || + current_scale > MAXIMUM_SCALE_FACTOR) { + return best_scale; + } + +#pragma GCC diagnostic ignored "-Wfloat-equal" + if (floorf (scaled_h) == scaled_h) { +#pragma GCC diagnostic error "-Wfloat-equal" + found_one = TRUE; + + if (fabsf (current_scale - scale) < fabsf (best_scale - scale)) + best_scale = current_scale; + } + } + i++; + } while (!found_one); + + return best_scale; +} + + +float * phosh_head_calculate_supported_mode_scales (PhoshHead *head, PhoshHeadMode *mode, - int *n_supported_scales) + int *n_supported_scales, + gboolean fractional) { - unsigned int i; GArray *supported_scales; - supported_scales = g_array_new (FALSE, FALSE, sizeof (int)); + supported_scales = g_array_new (FALSE, FALSE, sizeof (float)); - for (i = MINIMUM_SCALE_FACTOR; i <= MAXIMUM_SCALE_FACTOR; i++) { - if (is_valid_scale (mode->width, mode->height, i)) - g_array_append_val (supported_scales, i); + if (fractional) { + for (int i = floorf (MINIMUM_SCALE_FACTOR); i <= ceilf (MAXIMUM_SCALE_FACTOR); i++) { + float max_bound; + +#pragma GCC diagnostic ignored "-Wfloat-equal" + if (i == floorf (MINIMUM_SCALE_FACTOR) || i == ceilf (MAXIMUM_SCALE_FACTOR)) { +#pragma GCC diagnostic error "-Wfloat-equal" + max_bound = SCALE_FACTORS_STEPS; + } else { + max_bound = SCALE_FACTORS_STEPS / 2.0; + } + + for (int j = 0; j < SCALE_FACTORS_PER_INTEGER; j++) { + float scale; + float scale_value = i + j * SCALE_FACTORS_STEPS; + + scale = get_closest_scale_factor_for_resolution (mode->width, mode->height, + scale_value, + max_bound); + if (scale > 0.0) + g_array_append_val (supported_scales, scale); + } + } + } else { + for (float f = floorf (MINIMUM_SCALE_FACTOR); f <= ceilf (MAXIMUM_SCALE_FACTOR); f++) { + if (is_valid_scale (mode->width, mode->height, f)) { + g_array_append_val (supported_scales, f); + } + } } if (supported_scales->len == 0) { - int fallback_scale = 1; + float fallback_scale = 1.0; g_array_append_val (supported_scales, fallback_scale); } *n_supported_scales = supported_scales->len; - return (int *) g_array_free (supported_scales, FALSE); + return (float *) g_array_free (supported_scales, FALSE); } /** diff -Nru phosh-0.8.0/src/monitor/head.h phosh-0.13.1/src/monitor/head.h --- phosh-0.8.0/src/monitor/head.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/monitor/head.h 2021-08-31 09:15:52.000000000 +0000 @@ -71,9 +71,10 @@ PhoshHeadMode *phosh_head_get_preferred_mode (PhoshHead *self); gboolean phosh_head_is_builtin (PhoshHead *self); PhoshHeadMode *phosh_head_find_mode_by_name (PhoshHead *self, const char *name); -int * phosh_head_calculate_supported_mode_scales (PhoshHead *head, +float * phosh_head_calculate_supported_mode_scales (PhoshHead *head, PhoshHeadMode *mode, - int *n); + int *n, + gboolean fractional); void phosh_head_clear_pending (PhoshHead *self); G_END_DECLS diff -Nru phosh-0.8.0/src/monitor/meson.build phosh-0.13.1/src/monitor/meson.build --- phosh-0.8.0/src/monitor/meson.build 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/monitor/meson.build 2021-08-31 09:15:52.000000000 +0000 @@ -1,14 +1,6 @@ -generated_monitor_sources = gnome.gdbus_codegen( - 'phosh-display-dbus', - 'org.gnome.Mutter.DisplayConfig.xml', - interface_prefix: 'org.gnome.Mutter', - namespace: 'PhoshDisplayDbus', -) - phosh_monitor_sources = [ 'monitor/head.c', 'monitor/head.h', 'monitor/monitor.c', 'monitor/monitor.h', - generated_monitor_sources, ] diff -Nru phosh-0.8.0/src/monitor/monitor.c phosh-0.13.1/src/monitor/monitor.c --- phosh-0.8.0/src/monitor/monitor.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/monitor/monitor.c 2021-08-31 09:15:52.000000000 +0000 @@ -89,8 +89,8 @@ { PhoshMonitor *self = PHOSH_MONITOR (data); + /* nothing to do */ self->wl_output_done = FALSE; - self->scale = scale; } @@ -168,7 +168,6 @@ g_debug ("Monitor %p: Logical size: %dx%d", self, width, height); self->logical.width = width; self->logical.height = height; - } @@ -259,7 +258,7 @@ wlr_output_power_handle_failed(void *data, struct zwlr_output_power_v1 *output_power) { - PhoshMonitor *self = data; + PhoshMonitor *self = PHOSH_MONITOR (data); g_return_if_fail (PHOSH_IS_MONITOR (self)); g_warning("Failed to set output power mode for %s\n", self->name); @@ -405,7 +404,6 @@ static void phosh_monitor_init (PhoshMonitor *self) { - self->scale = 1.0; self->modes = g_array_new (FALSE, FALSE, sizeof(PhoshMonitorMode)); self->power_mode = PHOSH_MONITOR_POWER_SAVE_MODE_OFF; } @@ -601,3 +599,40 @@ return FALSE; } } + +struct wl_output* +phosh_monitor_get_wl_output (PhoshMonitor *self) +{ + g_return_val_if_fail (PHOSH_IS_MONITOR (self), NULL); + + return self->wl_output; +} + +/** + * phosh_monitor_get_fractional_scale: + * @self: The monitor + * + * Get the fractinoal scale determined from the output width and the + * current logical width. + * Returns: the fractional scale +*/ +float +phosh_monitor_get_fractional_scale (PhoshMonitor *self) +{ + float width; + + g_return_val_if_fail (PHOSH_IS_MONITOR (self), 1.0); + g_return_val_if_fail (phosh_monitor_is_configured (self), 1.0); + + switch (self->transform) { + case PHOSH_MONITOR_TRANSFORM_NORMAL: + case PHOSH_MONITOR_TRANSFORM_180: + case PHOSH_MONITOR_TRANSFORM_FLIPPED: + case PHOSH_MONITOR_TRANSFORM_FLIPPED_180: + width = self->logical.width; + break; + default: + width = self->logical.height; + } + return self->width / width; +} diff -Nru phosh-0.8.0/src/monitor/monitor.h phosh-0.13.1/src/monitor/monitor.h --- phosh-0.8.0/src/monitor/monitor.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/monitor/monitor.h 2021-08-31 09:15:52.000000000 +0000 @@ -117,7 +117,7 @@ int x, y, width, height; int subpixel; - gint32 transform, scale; + gint32 transform; struct { gint32 x, y, width, height; @@ -154,5 +154,7 @@ PhoshMonitorPowerSaveMode phosh_monitor_get_power_save_mode (PhoshMonitor *self); PhoshMonitorConnectorType phosh_monitor_connector_type_from_name (const char *name); gboolean phosh_monitor_connector_is_builtin (PhoshMonitorConnectorType type); +struct wl_output * phosh_monitor_get_wl_output (PhoshMonitor *self); +float phosh_monitor_get_fractional_scale (PhoshMonitor *self); G_END_DECLS diff -Nru phosh-0.8.0/src/monitor/org.gnome.Mutter.DisplayConfig.xml phosh-0.13.1/src/monitor/org.gnome.Mutter.DisplayConfig.xml --- phosh-0.8.0/src/monitor/org.gnome.Mutter.DisplayConfig.xml 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/monitor/org.gnome.Mutter.DisplayConfig.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,453 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru phosh-0.8.0/src/monitor-manager.c phosh-0.13.1/src/monitor-manager.c --- phosh-0.8.0/src/monitor-manager.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/monitor-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -25,8 +25,10 @@ * @short_description: The singleton that manages available monitors * @Title: PhoshMonitorManager * - * #PhoshMonitorManager keeps tracks of and configure available monitors - * and handles the "org.gnome.Mutter.DisplayConfig" DBus protocol. + * This keeps track of all monitors and handles the + * org.gnome.Mutter.DisplayConfig DBus interface via + * #PhoshDBusDisplayConfig. This includes individual monitor + * configuration as well as blanking/power saving. */ /* Equivalent to the 'layout-mode' enum in org.gnome.Mutter.DisplayConfig */ @@ -37,6 +39,7 @@ enum { PROP_0, + PROP_SENSOR_PROXY_MANAGER, PROP_N_MONITORS, PROP_LAST_PROP }; @@ -50,11 +53,14 @@ static guint signals[N_SIGNALS] = { 0 }; static void phosh_monitor_manager_display_config_init ( - PhoshDisplayDbusDisplayConfigIface *iface); + PhoshDBusDisplayConfigIface *iface); typedef struct _PhoshMonitorManager { - PhoshDisplayDbusDisplayConfigSkeleton parent; + PhoshDBusDisplayConfigSkeleton parent; + + PhoshSensorProxyManager *sensor_proxy_manager; + GBinding *sensor_proxy_binding; GPtrArray *monitors; /* Currently known monitors */ GPtrArray *heads; /* Currently known heads */ @@ -67,9 +73,9 @@ G_DEFINE_TYPE_WITH_CODE (PhoshMonitorManager, phosh_monitor_manager, - PHOSH_DISPLAY_DBUS_TYPE_DISPLAY_CONFIG_SKELETON, + PHOSH_DBUS_TYPE_DISPLAY_CONFIG_SKELETON, G_IMPLEMENT_INTERFACE ( - PHOSH_DISPLAY_DBUS_TYPE_DISPLAY_CONFIG, + PHOSH_DBUS_TYPE_DISPLAY_CONFIG, phosh_monitor_manager_display_config_init)); @@ -130,7 +136,7 @@ return g_strdup_printf (C_("This is a monitor vendor name followed by " "product/model name where size in inches " "could not be calculated, e.g. Dell U2414H", - "%s %sn"), + "%s %s"), vendor_name, product_name); } } @@ -156,42 +162,13 @@ return NULL; } - -static gint32 -phosh_monitor_manager_flip_transform (PhoshMonitorTransform transform) -{ - /* Wayland rotation is opposite from DBus */ - switch (transform) { - case PHOSH_MONITOR_TRANSFORM_90: - return WL_OUTPUT_TRANSFORM_270; - break; - case PHOSH_MONITOR_TRANSFORM_270: - return WL_OUTPUT_TRANSFORM_90; - break; - case PHOSH_MONITOR_TRANSFORM_FLIPPED_90: - return WL_OUTPUT_TRANSFORM_FLIPPED_270; - break; - case PHOSH_MONITOR_TRANSFORM_FLIPPED_270: - return WL_OUTPUT_TRANSFORM_FLIPPED_90; - break; - case PHOSH_MONITOR_TRANSFORM_NORMAL: - case PHOSH_MONITOR_TRANSFORM_180: - case PHOSH_MONITOR_TRANSFORM_FLIPPED: - case PHOSH_MONITOR_TRANSFORM_FLIPPED_180: - default: - /* Nothing to be done */ - return transform; - } -} - /* * DBus Interface */ static gboolean -phosh_monitor_manager_handle_get_resources ( - PhoshDisplayDbusDisplayConfig *skeleton, - GDBusMethodInvocation *invocation) +phosh_monitor_manager_handle_get_resources (PhoshDBusDisplayConfig *skeleton, + GDBusMethodInvocation *invocation) { PhoshMonitorManager *self = PHOSH_MONITOR_MANAGER (skeleton); GVariantBuilder crtc_builder, output_builder, mode_builder; @@ -285,7 +262,7 @@ /* Don't bother setting up modes, they're ignored */ - phosh_display_dbus_display_config_complete_get_resources ( + phosh_dbus_display_config_complete_get_resources ( skeleton, invocation, self->serial, @@ -301,12 +278,11 @@ static gboolean -phosh_monitor_manager_handle_change_backlight ( - PhoshDisplayDbusDisplayConfig *skeleton, - GDBusMethodInvocation *invocation, - guint serial, - guint output_index, - int value) +phosh_monitor_manager_handle_change_backlight (PhoshDBusDisplayConfig *skeleton, + GDBusMethodInvocation *invocation, + guint serial, + guint output_index, + int value) { g_debug ("Unimplemented DBus call %s", __func__); g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, @@ -317,7 +293,7 @@ struct get_wl_gamma_callback_data { - PhoshDisplayDbusDisplayConfig *skeleton; + PhoshDBusDisplayConfig *skeleton; GDBusMethodInvocation *invocation; }; @@ -342,7 +318,7 @@ green_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), green_bytes, TRUE); blue_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), blue_bytes, TRUE); - phosh_display_dbus_display_config_complete_get_crtc_gamma ( + phosh_dbus_display_config_complete_get_crtc_gamma ( gamma_callback_data->skeleton, gamma_callback_data->invocation, red_v, green_v, blue_v); @@ -363,11 +339,10 @@ static gboolean -phosh_monitor_manager_handle_get_crtc_gamma ( - PhoshDisplayDbusDisplayConfig *skeleton, - GDBusMethodInvocation *invocation, - guint serial, - guint crtc_id) +phosh_monitor_manager_handle_get_crtc_gamma (PhoshDBusDisplayConfig *skeleton, + GDBusMethodInvocation *invocation, + guint serial, + guint crtc_id) { PhoshMonitorManager *self = PHOSH_MONITOR_MANAGER (skeleton); PhoshMonitor *monitor; @@ -415,14 +390,13 @@ static gboolean -phosh_monitor_manager_handle_set_crtc_gamma ( - PhoshDisplayDbusDisplayConfig *skeleton, - GDBusMethodInvocation *invocation, - guint serial, - guint crtc_id, - GVariant *red_v, - GVariant *green_v, - GVariant *blue_v) +phosh_monitor_manager_handle_set_crtc_gamma (PhoshDBusDisplayConfig *skeleton, + GDBusMethodInvocation *invocation, + guint serial, + guint crtc_id, + GVariant *red_v, + GVariant *green_v, + GVariant *blue_v) { PhoshMonitorManager *self = PHOSH_MONITOR_MANAGER (skeleton); PhoshMonitor *monitor; @@ -493,7 +467,7 @@ gamma_control_set_gamma(gamma_control, &wl_red, &wl_green, &wl_blue); gamma_control_destroy (gamma_control); - phosh_display_dbus_display_config_complete_set_crtc_gamma ( + phosh_dbus_display_config_complete_set_crtc_gamma ( skeleton, invocation); @@ -521,9 +495,8 @@ static gboolean -phosh_monitor_manager_handle_get_current_state ( - PhoshDisplayDbusDisplayConfig *skeleton, - GDBusMethodInvocation *invocation) +phosh_monitor_manager_handle_get_current_state (PhoshDBusDisplayConfig *skeleton, + GDBusMethodInvocation *invocation) { PhoshMonitorManager *self = PHOSH_MONITOR_MANAGER (skeleton); GVariantBuilder monitors_builder, logical_monitors_builder, properties_builder; @@ -567,7 +540,7 @@ for (int k = 0; k < head->modes->len; k++) { PhoshHeadMode *mode = g_ptr_array_index (head->modes, k); - g_autofree int *scales = NULL; + g_autofree float *scales = NULL; if (!mode->name) { g_warning ("Skipping unnamend mode %p", mode); continue; @@ -575,7 +548,7 @@ g_variant_builder_init (&supported_scales_builder, G_VARIANT_TYPE ("ad")); - scales = phosh_head_calculate_supported_mode_scales (head, mode, &n); + scales = phosh_head_calculate_supported_mode_scales (head, mode, &n, TRUE); for (int l = 0; l < n; l++) { g_variant_builder_add (&supported_scales_builder, "d", (double)scales[l]); @@ -657,9 +630,6 @@ } g_variant_builder_init (&properties_builder, G_VARIANT_TYPE ("a{sv}")); - g_variant_builder_add (&properties_builder, "{sv}", - "supports-mirroring", - g_variant_new_boolean (FALSE)); g_variant_builder_add (&properties_builder, "{sv}", "layout-mode", @@ -669,7 +639,7 @@ "supports-changing-layout-mode", g_variant_new_boolean (TRUE)); - phosh_display_dbus_display_config_complete_get_current_state ( + phosh_dbus_display_config_complete_get_current_state ( skeleton, invocation, self->serial, @@ -803,7 +773,7 @@ head->pending.scale = scale; head->pending.x = x; head->pending.y = y; - head->pending.transform = phosh_monitor_manager_flip_transform (transform); + head->pending.transform = transform; head->pending.enabled = TRUE; head->pending.seen = TRUE; } @@ -818,13 +788,12 @@ static gboolean -phosh_monitor_manager_handle_apply_monitors_config ( - PhoshDisplayDbusDisplayConfig *skeleton, - GDBusMethodInvocation *invocation, - guint serial, - guint method, - GVariant *logical_monitor_configs_variant, - GVariant *properties_variant) +phosh_monitor_manager_handle_apply_monitors_config (PhoshDBusDisplayConfig *skeleton, + GDBusMethodInvocation *invocation, + guint serial, + guint method, + GVariant *logical_monitor_configs_variant, + GVariant *properties_variant) { PhoshMonitorManager *self = PHOSH_MONITOR_MANAGER (skeleton); GVariantIter logical_monitor_configs_iter; @@ -940,7 +909,7 @@ phosh_monitor_manager_apply_monitor_config (self); } - phosh_display_dbus_display_config_complete_apply_monitors_config ( + phosh_dbus_display_config_complete_apply_monitors_config ( skeleton, invocation); @@ -949,7 +918,7 @@ static void -phosh_monitor_manager_display_config_init (PhoshDisplayDbusDisplayConfigIface *iface) +phosh_monitor_manager_display_config_init (PhoshDBusDisplayConfigIface *iface) { iface->handle_get_resources = phosh_monitor_manager_handle_get_resources; iface->handle_change_backlight = phosh_monitor_manager_handle_change_backlight; @@ -967,8 +936,8 @@ { int mode, ps_mode; - mode = phosh_display_dbus_display_config_get_power_save_mode ( - PHOSH_DISPLAY_DBUS_DISPLAY_CONFIG (self)); + mode = phosh_dbus_display_config_get_power_save_mode ( + PHOSH_DBUS_DISPLAY_CONFIG (self)); g_debug ("Power save mode %d requested", mode); switch (mode) { @@ -1011,7 +980,7 @@ const char *name, gpointer user_data) { - PhoshMonitorManager *self = user_data; + PhoshMonitorManager *self = PHOSH_MONITOR_MANAGER (user_data); /* We need to use Mutter's object path here to make gnome-settings happy */ g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self), @@ -1037,6 +1006,19 @@ static void +on_monitor_configured (PhoshMonitorManager *self, PhoshMonitor *monitor) +{ + g_return_if_fail (PHOSH_IS_MONITOR_MANAGER (self)); + g_return_if_fail (PHOSH_IS_MONITOR (monitor)); + + g_signal_emit (self, signals[SIGNAL_MONITOR_ADDED], 0, monitor); + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_N_MONITORS]); + + g_signal_handlers_disconnect_by_data (monitor, self); +} + + +static void on_monitor_removed (PhoshMonitorManager *self, PhoshMonitor *monitor, gpointer *data) @@ -1051,6 +1033,18 @@ static void +phosh_monitor_manager_add_monitor (PhoshMonitorManager *self, PhoshMonitor *monitor) +{ + g_ptr_array_add (self->monitors, monitor); + /* Delay emmission of 'monitor-added' until it's configured */ + g_signal_connect_swapped (monitor, + "configured", + G_CALLBACK (on_monitor_configured), + self); +} + + +static void on_wl_outputs_changed (PhoshMonitorManager *self, GParamSpec *pspec, PhoshWayland *wl) { GHashTable *wl_outputs = phosh_wayland_get_wl_outputs (wl); @@ -1098,7 +1092,7 @@ else g_warning ("Tried to remove inexistend head %p", head); - phosh_display_dbus_display_config_emit_monitors_changed (PHOSH_DISPLAY_DBUS_DISPLAY_CONFIG (self)); + phosh_dbus_display_config_emit_monitors_changed (PHOSH_DBUS_DISPLAY_CONFIG (self)); } @@ -1117,7 +1111,7 @@ g_ptr_array_add (self->heads, head); g_signal_connect_swapped (head, "head-finished", G_CALLBACK (on_head_finished), self); - phosh_display_dbus_display_config_emit_monitors_changed (PHOSH_DISPLAY_DBUS_DISPLAY_CONFIG (self)); + phosh_dbus_display_config_emit_monitors_changed (PHOSH_DBUS_DISPLAY_CONFIG (self)); } @@ -1133,7 +1127,7 @@ self->zwlr_output_serial = serial; self->serial++; - phosh_display_dbus_display_config_emit_monitors_changed (PHOSH_DISPLAY_DBUS_DISPLAY_CONFIG (self)); + phosh_dbus_display_config_emit_monitors_changed (PHOSH_DBUS_DISPLAY_CONFIG (self)); } @@ -1179,6 +1173,23 @@ static void +phosh_monitor_manager_dispose (GObject *object) +{ + PhoshMonitorManager *self = PHOSH_MONITOR_MANAGER (object); + + g_clear_handle_id (&self->dbus_name_id, g_bus_unown_name); + + if (g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (self))) + g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self)); + + g_clear_object (&self->sensor_proxy_manager); + g_clear_pointer (&self->sensor_proxy_binding, g_binding_unbind); + + G_OBJECT_CLASS (phosh_monitor_manager_parent_class)->dispose (object); +} + + +static void phosh_monitor_manager_finalize (GObject *object) { PhoshMonitorManager *self = PHOSH_MONITOR_MANAGER (object); @@ -1194,6 +1205,25 @@ */ static void +phosh_monitor_manager_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshMonitorManager *self = PHOSH_MONITOR_MANAGER (object); + + switch (property_id) { + case PROP_SENSOR_PROXY_MANAGER: + phosh_monitor_manager_set_sensor_proxy_manager (self, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void phosh_monitor_manager_get_property (GObject *object, guint property_id, GValue *value, @@ -1202,6 +1232,9 @@ PhoshMonitorManager *self = PHOSH_MONITOR_MANAGER (object); switch (property_id) { + case PROP_SENSOR_PROXY_MANAGER: + g_value_set_object (value, self->sensor_proxy_manager); + break; case PROP_N_MONITORS: g_value_set_int (value, self->monitors->len); break; @@ -1222,8 +1255,8 @@ on_bus_acquired, on_name_acquired, on_name_lost, - g_object_ref (self), - g_object_unref); + self, + NULL); return FALSE; } @@ -1268,8 +1301,18 @@ GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructed = phosh_monitor_manager_constructed; + object_class->dispose = phosh_monitor_manager_dispose; object_class->finalize = phosh_monitor_manager_finalize; object_class->get_property = phosh_monitor_manager_get_property; + object_class->set_property = phosh_monitor_manager_set_property; + + props[PROP_SENSOR_PROXY_MANAGER] = + g_param_spec_object ("sensor-proxy-manager", + "Sensor Proxy Manager", + "Sensor Proxy Manager", + PHOSH_TYPE_SENSOR_PROXY_MANAGER, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); props[PROP_N_MONITORS] = g_param_spec_int ("n-monitors", @@ -1289,10 +1332,7 @@ * @manager: The #PhoshMonitorManager emitting the signal. * @monitor: The #PhoshMonitor being added. * - * Emitted whenever a monitor is about to be added. Note - * that the monitor might not yet be fully initialized. Use - * phosh_monitor_is_configured() to check or listen for - * the #PhoshMonitor::configured signal. + * Emitted whenever a monitor was added. */ signals[SIGNAL_MONITOR_ADDED] = g_signal_new ( "monitor-added", @@ -1325,18 +1365,11 @@ PhoshMonitorManager * -phosh_monitor_manager_new (void) +phosh_monitor_manager_new (PhoshSensorProxyManager *proxy) { - return g_object_new (PHOSH_TYPE_MONITOR_MANAGER, NULL); -} - - -void -phosh_monitor_manager_add_monitor (PhoshMonitorManager *self, PhoshMonitor *monitor) -{ - g_ptr_array_add (self->monitors, monitor); - g_signal_emit (self, signals[SIGNAL_MONITOR_ADDED], 0, monitor); - g_object_notify_by_pspec (G_OBJECT (self), props[PROP_N_MONITORS]); + return g_object_new (PHOSH_TYPE_MONITOR_MANAGER, + "sensor-proxy-manager", proxy, + NULL); } @@ -1369,9 +1402,10 @@ } /** - * phosh_monitor_set_transform: + * phosh_monitor_manager_set_monitor_transform: * @self: A #PhoshMonitor - * @mode: The #PhoshMonitorPowerSaveMode + * @monitor: The #PhoshMonitor to set the tansform on + * @transform: The #PhoshMonitorTransform to set * * Sets monitor's transform. This will become active after the next * call to #phosh_monitor_manager_apply_monitor_config(). @@ -1446,3 +1480,24 @@ zwlr_output_configuration_v1_apply (config); } + +void +phosh_monitor_manager_set_sensor_proxy_manager (PhoshMonitorManager *self, + PhoshSensorProxyManager *manager) +{ + g_return_if_fail (PHOSH_IS_MONITOR_MANAGER (self)); + g_return_if_fail (PHOSH_IS_SENSOR_PROXY_MANAGER (manager) || manager == NULL); + + g_clear_object (&self->sensor_proxy_manager); + g_clear_pointer (&self->sensor_proxy_binding, g_binding_unbind); + + if (manager == NULL) + return; + + self->sensor_proxy_manager = g_object_ref (manager); + self->sensor_proxy_binding = g_object_bind_property (manager, "has-accelerometer", + self, "panel-orientation-managed", + G_BINDING_SYNC_CREATE); + + +} diff -Nru phosh-0.8.0/src/monitor-manager.h phosh-0.13.1/src/monitor-manager.h --- phosh-0.8.0/src/monitor-manager.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/monitor-manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -7,8 +7,11 @@ */ #pragma once -#include "monitor/phosh-display-dbus.h" +#include "phosh-display-dbus.h" #include "monitor/monitor.h" + +#include "sensor-proxy-manager.h" + #include G_BEGIN_DECLS @@ -30,11 +33,9 @@ #define PHOSH_TYPE_MONITOR_MANAGER (phosh_monitor_manager_get_type ()) G_DECLARE_FINAL_TYPE (PhoshMonitorManager, phosh_monitor_manager, PHOSH, MONITOR_MANAGER, - PhoshDisplayDbusDisplayConfigSkeleton) + PhoshDBusDisplayConfigSkeleton) -PhoshMonitorManager * phosh_monitor_manager_new (void); -void phosh_monitor_manager_add_monitor (PhoshMonitorManager *self, - PhoshMonitor *monitor); +PhoshMonitorManager * phosh_monitor_manager_new (PhoshSensorProxyManager *proxy); PhoshMonitor * phosh_monitor_manager_get_monitor (PhoshMonitorManager *self, guint num); guint phosh_monitor_manager_get_num_monitors (PhoshMonitorManager *self); @@ -44,5 +45,6 @@ PhoshMonitor *monitor, PhoshMonitorTransform transform); void phosh_monitor_manager_apply_monitor_config (PhoshMonitorManager *self); - +void phosh_monitor_manager_set_sensor_proxy_manager (PhoshMonitorManager *self, + PhoshSensorProxyManager *manager); G_END_DECLS diff -Nru phosh-0.8.0/src/mount-manager.c phosh-0.13.1/src/mount-manager.c --- phosh-0.8.0/src/mount-manager.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/mount-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -11,6 +11,7 @@ #include "config.h" #include "feedback-manager.h" #include "mount-manager.h" +#include "mount-operation.h" #include "notifications/mount-notification.h" #include "notifications/notify-manager.h" #include "shell.h" @@ -101,8 +102,9 @@ on_volume_added (PhoshMountManager *self, GVolume *vol, GVolumeMonitor *monitor) { gboolean automount; - gpointer ignore_lock; + gboolean mount_all; GCancellable *cancellable; + g_autoptr (PhoshMountOperation) op = NULL; g_autoptr (GMount) mount = NULL; g_autofree gchar *name = NULL; @@ -116,8 +118,9 @@ if (!phosh_shell_is_session_active (phosh_shell_get_default ())) return; - ignore_lock = g_object_get_data (G_OBJECT (vol), "phosh-ignore-lock"); - if (phosh_shell_get_locked (phosh_shell_get_default ()) && !ignore_lock) + mount_all = !!g_object_get_data (G_OBJECT (vol), "phosh-mount-all"); + /* Initial mount-all is o.k. even when locked */ + if (phosh_shell_get_locked (phosh_shell_get_default ()) && !mount_all) return; mount = g_volume_get_mount (vol); @@ -133,12 +136,16 @@ return; } + /* If this is not the intial 'mount-all' run allow UI interaction */ + if (!mount_all) + op = phosh_mount_operation_new (); + cancellable = g_cancellable_new (); g_object_set_data (G_OBJECT (vol), "phosh-cancel", cancellable); g_ptr_array_add (self->cancellables, cancellable); g_ptr_array_ref (self->cancellables); g_debug ("Mounting '%s'", name); - g_volume_mount (g_object_ref (vol), G_MOUNT_MOUNT_NONE, NULL, cancellable, + g_volume_mount (g_object_ref (vol), G_MOUNT_MOUNT_NONE, G_MOUNT_OPERATION (op), cancellable, (GAsyncReadyCallback)on_mount_finished, g_object_ref (self)); } @@ -243,7 +250,7 @@ for (GList *elem = volumes; elem != NULL; elem = elem->next) { GVolume *vol = G_VOLUME (elem->data); /* Ignore screen lock on initial startup */ - g_object_set_data (G_OBJECT (vol), "phosh-ignore-lock", GINT_TO_POINTER (TRUE)); + g_object_set_data (G_OBJECT (vol), "phosh-mount-all", GINT_TO_POINTER (TRUE)); on_volume_added (self, vol, self->monitor); } diff -Nru phosh-0.8.0/src/mount-operation.c phosh-0.13.1/src/mount-operation.c --- phosh-0.8.0/src/mount-operation.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/mount-operation.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-mount-operation" + +#include "config.h" + +#include "gtk-mount-prompt.h" +#include "mount-operation.h" +#include "util.h" + +/** + * SECTION:mount-operation + * @short_description: #GMountOperation using UI + * @Title: PhoshMountOperation + * + * A #GMountOperation that uses system modal dialogs for input. + */ + +struct _PhoshMountOperation { + GMountOperation parent; + + PhoshGtkMountPrompt *prompt; +}; +G_DEFINE_TYPE (PhoshMountOperation, phosh_mount_operation, G_TYPE_MOUNT_OPERATION) + + +static void +on_prompt_done (PhoshMountOperation *self, PhoshGtkMountPrompt *prompt) +{ + gboolean cancelled; + GMountOperationResult result = G_MOUNT_OPERATION_ABORTED; + + g_return_if_fail (PHOSH_IS_MOUNT_OPERATION (self)); + g_return_if_fail (PHOSH_IS_GTK_MOUNT_PROMPT (prompt)); + + cancelled = phosh_gtk_mount_prompt_get_cancelled (prompt); + g_debug ("Prompt done, cancelled: %d", cancelled); + + if (!cancelled) { + GAskPasswordFlags flags = phosh_gtk_mount_prompt_get_ask_flags (prompt); + + if (flags & G_ASK_PASSWORD_NEED_PASSWORD) { + const char *password; + + password = phosh_gtk_mount_prompt_get_password (prompt); + g_mount_operation_set_password (G_MOUNT_OPERATION (self), password); + result = G_MOUNT_OPERATION_HANDLED; + } + } + + g_mount_operation_reply (G_MOUNT_OPERATION (self), result); + g_clear_pointer (&self->prompt, phosh_cp_widget_destroy); +} + + +static void +new_prompt (PhoshMountOperation *self, + const char *message, + const char *icon_name, + const char *default_user, + const char *default_domain, + GVariant *pids, + const char *const *choices, + GAskPasswordFlags ask_flags) +{ + g_debug ("New prompt for '%s'", message); + + g_clear_pointer (&self->prompt, phosh_cp_widget_destroy); + + self->prompt = PHOSH_GTK_MOUNT_PROMPT (phosh_gtk_mount_prompt_new ( + message, + icon_name, + default_user, + default_domain, + pids, + choices, + ask_flags)); + g_signal_connect_swapped (self->prompt, + "closed", + G_CALLBACK (on_prompt_done), + self); + + gtk_widget_show (GTK_WIDGET (self->prompt)); +} + + +static void +phosh_mount_operation_ask_password (GMountOperation *op, + const char *message, + const char *default_user, + const char *default_domain, + GAskPasswordFlags flags) +{ + PhoshMountOperation *self = PHOSH_MOUNT_OPERATION (op); + + new_prompt (self, message, + NULL, /* icon */ + default_user, + default_domain, + NULL, /* default_user */ + NULL, /* choices */ + flags); +} + + +static void +phosh_mount_operation_dispose (GObject *object) +{ + PhoshMountOperation *self = PHOSH_MOUNT_OPERATION (object); + + g_clear_pointer (&self->prompt, phosh_cp_widget_destroy); + + G_OBJECT_CLASS (phosh_mount_operation_parent_class)->dispose (object); +} + + +static void +phosh_mount_operation_class_init (PhoshMountOperationClass *klass) +{ + GMountOperationClass *mount_op_class = G_MOUNT_OPERATION_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = phosh_mount_operation_dispose; + + mount_op_class->ask_password = phosh_mount_operation_ask_password; +} + + +static void +phosh_mount_operation_init (PhoshMountOperation *self) +{ +} + + +PhoshMountOperation * +phosh_mount_operation_new (void) +{ + return PHOSH_MOUNT_OPERATION (g_object_new (PHOSH_TYPE_MOUNT_OPERATION, NULL)); +} diff -Nru phosh-0.8.0/src/mount-operation.h phosh-0.13.1/src/mount-operation.h --- phosh-0.8.0/src/mount-operation.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/mount-operation.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define PHOSH_TYPE_MOUNT_OPERATION (phosh_mount_operation_get_type ()) + +G_DECLARE_FINAL_TYPE (PhoshMountOperation, phosh_mount_operation, PHOSH, MOUNT_OPERATION, GMountOperation) + +PhoshMountOperation *phosh_mount_operation_new (void); + +G_END_DECLS diff -Nru phosh-0.8.0/src/network-auth-prompt.c phosh-0.13.1/src/network-auth-prompt.c --- phosh-0.8.0/src/network-auth-prompt.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/network-auth-prompt.c 2021-08-31 09:15:52.000000000 +0000 @@ -37,7 +37,7 @@ struct _PhoshNetworkAuthPrompt { - PhoshLayerSurface parent; + PhoshSystemModalDialog parent; GtkWidget *cancel_button; GtkWidget *connect_button; @@ -62,7 +62,7 @@ gboolean visible; /* is input visible */ }; -G_DEFINE_TYPE(PhoshNetworkAuthPrompt, phosh_network_auth_prompt, PHOSH_TYPE_LAYER_SURFACE); +G_DEFINE_TYPE(PhoshNetworkAuthPrompt, phosh_network_auth_prompt, PHOSH_TYPE_SYSTEM_MODAL_DIALOG); static void @@ -216,11 +216,12 @@ gtk_entry_buffer_set_text (GTK_ENTRY_BUFFER (self->password_buffer), password, -1); } + gtk_widget_grab_focus (self->wpa_password_entry); } static void -network_prompt_cancel_clicked_cb (PhoshNetworkAuthPrompt *self) +on_dialog_canceled (PhoshNetworkAuthPrompt *self) { g_return_if_fail (PHOSH_IS_NETWORK_AUTH_PROMPT (self)); @@ -353,7 +354,7 @@ gtk_widget_class_bind_template_child (widget_class, PhoshNetworkAuthPrompt, wpa_password_entry); gtk_widget_class_bind_template_child (widget_class, PhoshNetworkAuthPrompt, password_buffer); - gtk_widget_class_bind_template_callback (widget_class, network_prompt_cancel_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, on_dialog_canceled); gtk_widget_class_bind_template_callback (widget_class, network_prompt_connect_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, network_prompt_key_press_event_cb); gtk_widget_class_bind_template_callback (widget_class, network_prompt_wpa_password_changed_cb); @@ -370,28 +371,14 @@ GtkWidget * phosh_network_auth_prompt_new (ShellNetworkAgent *agent, - NMClient *nm_client, - gpointer layer_shell, - gpointer wl_output) + NMClient *nm_client) { PhoshNetworkAuthPrompt *self; g_return_val_if_fail (SHELL_IS_NETWORK_AGENT (agent), NULL); g_return_val_if_fail (NM_CLIENT (nm_client), NULL); - self = g_object_new (PHOSH_TYPE_NETWORK_AUTH_PROMPT, - /* layer shell */ - "layer-shell", layer_shell, - "wl-output", wl_output, - "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, - "layer", ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, - "kbd-interactivity", TRUE, - "exclusive-zone", -1, - "namespace", "phosh prompter", - NULL); + self = g_object_new (PHOSH_TYPE_NETWORK_AUTH_PROMPT, NULL); self->nm_client = g_object_ref (nm_client); self->agent = g_object_ref (agent); diff -Nru phosh-0.8.0/src/network-auth-prompt.h phosh-0.13.1/src/network-auth-prompt.h --- phosh-0.8.0/src/network-auth-prompt.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/network-auth-prompt.h 2021-08-31 09:15:52.000000000 +0000 @@ -7,18 +7,16 @@ #include #include -#include "layersurface.h" +#include "system-modal-dialog.h" G_BEGIN_DECLS #define PHOSH_TYPE_NETWORK_AUTH_PROMPT (phosh_network_auth_prompt_get_type()) -G_DECLARE_FINAL_TYPE (PhoshNetworkAuthPrompt, phosh_network_auth_prompt, PHOSH, NETWORK_AUTH_PROMPT, PhoshLayerSurface); +G_DECLARE_FINAL_TYPE (PhoshNetworkAuthPrompt, phosh_network_auth_prompt, PHOSH, NETWORK_AUTH_PROMPT, PhoshSystemModalDialog); GtkWidget *phosh_network_auth_prompt_new (ShellNetworkAgent *agent, - NMClient *nm_client, - gpointer layer_shell, - gpointer wl_output); + NMClient *nm_client); void phosh_network_auth_prompt_set_request (PhoshNetworkAuthPrompt *self, char *request_id, NMConnection *connection, diff -Nru phosh-0.8.0/src/notifications/meson.build phosh-0.13.1/src/notifications/meson.build --- phosh-0.8.0/src/notifications/meson.build 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/notifications/meson.build 2021-08-31 09:15:52.000000000 +0000 @@ -17,6 +17,8 @@ 'notifications/notification-source.h', 'notifications/notify-manager.c', 'notifications/notify-manager.h', + 'notifications/notify-feedback.c', + 'notifications/notify-feedback.h', 'notifications/timestamp-label.c', 'notifications/timestamp-label.h', ] diff -Nru phosh-0.8.0/src/notifications/mount-notification.c phosh-0.13.1/src/notifications/mount-notification.c --- phosh-0.8.0/src/notifications/mount-notification.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/notifications/mount-notification.c 2021-08-31 09:15:52.000000000 +0000 @@ -35,7 +35,6 @@ G_DEFINE_TYPE (PhoshMountNotification, phosh_mount_notification, PHOSH_TYPE_NOTIFICATION) -#if GLIB_CHECK_VERSION(2,60,0) static void on_launch_finished (GAppInfo *source, GAsyncResult *result, @@ -51,7 +50,7 @@ g_object_unref (self); } -#endif + static void phosh_mount_notification_do_action (PhoshNotification *notification, guint id, const char *action) @@ -70,7 +69,6 @@ l = g_list_append (l, (gpointer)action); context = phosh_shell_get_app_launch_context (phosh_shell_get_default ()); -#if GLIB_CHECK_VERSION(2,60,0) self->cancellable = g_cancellable_new (); g_app_info_launch_uris_async (info, l, @@ -78,19 +76,6 @@ self->cancellable, (GAsyncReadyCallback)on_launch_finished, g_object_ref (self)); -#else - { - g_autoptr (GError) err = NULL; - if (!g_app_info_launch_uris (info, - l, - G_APP_LAUNCH_CONTEXT (context), - &err)) { - g_warning ("Failed to open %s: %s", - phosh_notification_get_summary (PHOSH_NOTIFICATION (self)), - err->message); - } - } -#endif } diff -Nru phosh-0.8.0/src/notifications/notification-banner.c phosh-0.13.1/src/notifications/notification-banner.c --- phosh-0.8.0/src/notifications/notification-banner.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/notifications/notification-banner.c 2021-08-31 09:15:52.000000000 +0000 @@ -14,7 +14,6 @@ #include "shell.h" #include "util.h" -#define HANDY_USE_UNSTABLE_API #include /** @@ -52,8 +51,8 @@ static void clear_handler (PhoshNotificationBanner *self) { - phosh_clear_handler (&self->handler_expired, self->notification); - phosh_clear_handler (&self->handler_closed, self->notification); + g_clear_signal_handler (&self->handler_expired, self->notification); + g_clear_signal_handler (&self->handler_closed, self->notification); } @@ -94,7 +93,7 @@ g_set_object (&self->notification, notification); - content = phosh_notification_frame_new (); + content = phosh_notification_frame_new (TRUE); phosh_notification_frame_bind_notification (PHOSH_NOTIFICATION_FRAME (content), self->notification); gtk_container_add (GTK_CONTAINER (self), content); @@ -265,7 +264,9 @@ phosh_notification_banner_new (PhoshNotification *notification) { PhoshWayland *wl = phosh_wayland_get_default (); + PhoshMonitor *monitor = phosh_shell_get_primary_monitor (phosh_shell_get_default ()); int width = 360; + phosh_shell_get_usable_area (phosh_shell_get_default (), NULL, NULL, &width, NULL); @@ -274,6 +275,7 @@ /* layer surface */ "margin-top", -300, "layer-shell", phosh_wayland_get_zwlr_layer_shell_v1 (wl), + "wl-output", monitor ? monitor->wl_output : NULL, "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, "height", 50, "width", MIN (width, 450), diff -Nru phosh-0.8.0/src/notifications/notification.c phosh-0.13.1/src/notifications/notification.c --- phosh-0.8.0/src/notifications/notification.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/notifications/notification.c 2021-08-31 09:15:52.000000000 +0000 @@ -19,6 +19,8 @@ * SECTION:notification * @short_description: A notification * @Title: PhoshNotification + * + * A #PhoshNotification with summary, body, icon, actions, etc. */ enum { diff -Nru phosh-0.8.0/src/notifications/notification-content.c phosh-0.13.1/src/notifications/notification-content.c --- phosh-0.8.0/src/notifications/notification-content.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/notifications/notification-content.c 2021-08-31 09:15:52.000000000 +0000 @@ -21,6 +21,7 @@ enum { PROP_0, PROP_NOTIFICATION, + PROP_SHOW_BODY, LAST_PROP }; static GParamSpec *props[LAST_PROP]; @@ -35,6 +36,8 @@ GtkWidget *lbl_body; GtkWidget *img_image; GtkWidget *box_actions; + + gboolean show_body; }; typedef struct _PhoshNotificationContent PhoshNotificationContent; @@ -90,7 +93,7 @@ const char* body = g_value_get_string (from_value); gboolean visible; - visible = body != NULL && g_strcmp0 (body, ""); + visible = body != NULL && g_strcmp0 (body, "") && self->show_body; gtk_widget_set_visible (self->lbl_body, visible); g_value_set_string (to_value, body); @@ -180,8 +183,8 @@ self, NULL); - g_signal_connect (self->notification, "notify::actions", - G_CALLBACK (set_actions), self); + g_signal_connect_object (self->notification, "notify::actions", + G_CALLBACK (set_actions), self, 0); set_actions (self->notification, NULL, self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NOTIFICATION]); @@ -201,6 +204,10 @@ phosh_notification_content_set_notification (self, g_value_get_object (value)); break; + case PROP_SHOW_BODY: + self->show_body = g_value_get_boolean (value); + break; + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -220,6 +227,9 @@ case PROP_NOTIFICATION: g_value_set_object (value, self->notification); break; + case PROP_SHOW_BODY: + g_value_set_boolean (value, self->show_body); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -262,6 +272,19 @@ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + /** + * PhoshNotificationContent:show-body: + * + * Whether the body of the notification is shown + */ + props[PROP_SHOW_BODY] = + g_param_spec_boolean ("show-body", + "", + "", + TRUE, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, LAST_PROP, props); gtk_widget_class_set_template_from_resource (widget_class, @@ -302,6 +325,8 @@ { g_autoptr (GActionMap) map = NULL; + self->show_body = TRUE; + map = G_ACTION_MAP (g_simple_action_group_new ()); g_action_map_add_action_entries (map, entries, @@ -312,14 +337,28 @@ G_ACTION_GROUP (map)); gtk_widget_init_template (GTK_WIDGET (self)); + + + g_object_bind_property (self, + "show-body", + self->lbl_body, + "visible", + G_BINDING_DEFAULT); + + g_object_bind_property (self, + "show-body", + self->box_actions, + "visible", + G_BINDING_DEFAULT); } GtkWidget * -phosh_notification_content_new (PhoshNotification *notification) +phosh_notification_content_new (PhoshNotification *notification, gboolean show_body) { return g_object_new (PHOSH_TYPE_NOTIFICATION_CONTENT, "notification", notification, + "show-body", show_body, NULL); } diff -Nru phosh-0.8.0/src/notifications/notification-content.h phosh-0.13.1/src/notifications/notification-content.h --- phosh-0.8.0/src/notifications/notification-content.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/notifications/notification-content.h 2021-08-31 09:15:52.000000000 +0000 @@ -21,7 +21,8 @@ G_DECLARE_FINAL_TYPE (PhoshNotificationContent, phosh_notification_content, PHOSH, NOTIFICATION_CONTENT, GtkListBoxRow) -GtkWidget *phosh_notification_content_new (PhoshNotification *notification); +GtkWidget *phosh_notification_content_new (PhoshNotification *notification, + gboolean show_body); PhoshNotification *phosh_notification_content_get_notification (PhoshNotificationContent *self); diff -Nru phosh-0.8.0/src/notifications/notification-frame.c phosh-0.13.1/src/notifications/notification-frame.c --- phosh-0.8.0/src/notifications/notification-frame.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/notifications/notification-frame.c 2021-08-31 09:15:52.000000000 +0000 @@ -22,6 +22,14 @@ */ +enum { + PROP_0, + PROP_SHOW_BODY, + LAST_PROP +}; +static GParamSpec *props[LAST_PROP]; + + struct _PhoshNotificationFrame { GtkBox parent; @@ -36,6 +44,8 @@ GtkWidget *img_icon; GtkWidget *list_notifs; GtkWidget *updated; + + gboolean show_body; }; typedef struct _PhoshNotificationFrame PhoshNotificationFrame; @@ -51,13 +61,51 @@ static void +phosh_notification_frame_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshNotificationFrame *self = PHOSH_NOTIFICATION_FRAME (object); + + switch (property_id) { + case PROP_SHOW_BODY: + self->show_body = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_notification_frame_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshNotificationFrame *self = PHOSH_NOTIFICATION_FRAME (object); + + switch (property_id) { + case PROP_SHOW_BODY: + g_value_set_boolean (value, self->show_body); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void phosh_notification_frame_finalize (GObject *object) { PhoshNotificationFrame *self = PHOSH_NOTIFICATION_FRAME (object); /* Don't clear bindings, they're already unref'd before here */ - phosh_clear_handler (&self->model_watch, self->model); + g_clear_signal_handler (&self->model_watch, self->model); g_clear_object (&self->model); @@ -109,6 +157,23 @@ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->finalize = phosh_notification_frame_finalize; + object_class->set_property = phosh_notification_frame_set_property; + object_class->get_property = phosh_notification_frame_get_property; + + /** + * PhoshNotificationFrame:show-body: + * + * Whether notificaions in this frame should show the notification body + */ + props[PROP_SHOW_BODY] = + g_param_spec_boolean ("show-body", + "", + "", + TRUE, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, LAST_PROP, props); signals[SIGNAL_EMPTY] = g_signal_new ("empty", G_TYPE_FROM_CLASS (klass), @@ -138,14 +203,15 @@ static void phosh_notification_frame_init (PhoshNotificationFrame *self) { + self->show_body = TRUE; gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * -phosh_notification_frame_new (void) +phosh_notification_frame_new (gboolean show_body) { - return g_object_new (PHOSH_TYPE_NOTIFICATION_FRAME, NULL); + return g_object_new (PHOSH_TYPE_NOTIFICATION_FRAME, "show-body", show_body, NULL); } @@ -153,8 +219,11 @@ create_row (gpointer item, gpointer data) { PhoshNotification *notification = item; + PhoshNotificationFrame *self = PHOSH_NOTIFICATION_FRAME (data); + + g_return_val_if_fail (PHOSH_IS_NOTIFICATION_FRAME (self), NULL); - return phosh_notification_content_new (notification); + return phosh_notification_content_new (notification, self->show_body); } diff -Nru phosh-0.8.0/src/notifications/notification-frame.h phosh-0.13.1/src/notifications/notification-frame.h --- phosh-0.8.0/src/notifications/notification-frame.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/notifications/notification-frame.h 2021-08-31 09:15:52.000000000 +0000 @@ -21,7 +21,7 @@ G_DECLARE_FINAL_TYPE (PhoshNotificationFrame, phosh_notification_frame, PHOSH, NOTIFICATION_FRAME, GtkBox) -GtkWidget *phosh_notification_frame_new (void); +GtkWidget *phosh_notification_frame_new (gboolean show_body); void phosh_notification_frame_bind_notification (PhoshNotificationFrame *self, PhoshNotification *notification); void phosh_notification_frame_bind_model (PhoshNotificationFrame *self, diff -Nru phosh-0.8.0/src/notifications/notification-list.c phosh-0.13.1/src/notifications/notification-list.c --- phosh-0.8.0/src/notifications/notification-list.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/notifications/notification-list.c 2021-08-31 09:15:52.000000000 +0000 @@ -16,6 +16,9 @@ * SECTION:notification-list * @short_description: A list containing one or more #PhoshNotificationSource * @Title: PhoshNotificationList + * + * #PhoshNotificationList maps between #PhoshNotificationSource objects and their + * notifications creating and removing sources on the fly. */ diff -Nru phosh-0.8.0/src/notifications/notification-source.c phosh-0.13.1/src/notifications/notification-source.c --- phosh-0.8.0/src/notifications/notification-source.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/notifications/notification-source.c 2021-08-31 09:15:52.000000000 +0000 @@ -15,6 +15,9 @@ * SECTION:notification-source * @short_description: A #GListModel containing one or more notifications * @Title: PhoshNotificationSource + * + * A #PhoshNotificationSource groups notifications. A source has a name + * which is usually the app_id of the sending application. */ diff -Nru phosh-0.8.0/src/notifications/notify-feedback.c phosh-0.13.1/src/notifications/notify-feedback.c --- phosh-0.8.0/src/notifications/notify-feedback.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/notifications/notify-feedback.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-notify-feedback" + +#include "config.h" + +#include "shell.h" +#include "notify-feedback.h" +#include "notification-source.h" + +#define LIBFEEDBACK_USE_UNSTABLE_API +#include + +/** + * SECTION:notify-feedback + * @short_description: Provider feedback on notifications + * @Title: PhoshNotifyFeedback + * + * #PhoshNotifyFeedback is responsible to provider proper feedback + * on new notifications or when notifcations are being closed. + */ + +enum { + PROP_0, + PROP_NOTIFICATION_LIST, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + +struct _PhoshNotifyFeedback { + GObject parent; + + LfbEvent *event; + PhoshNotificationList *list; +}; +G_DEFINE_TYPE (PhoshNotifyFeedback, phosh_notify_feedback, G_TYPE_OBJECT) + +static void +end_notify_feedback (PhoshNotifyFeedback *self) +{ + if (self->event == NULL) + return; + + if (lfb_event_get_state (self->event) == LFB_EVENT_STATE_RUNNING) + lfb_event_end_feedback_async (self->event, NULL, NULL, NULL); +} + + +static const char * +find_event (const char *category) +{ + gboolean locked = phosh_shell_get_locked (phosh_shell_get_default ()); + /* If shell is unlocked and we don't have a specific category don't + trigger any event to not distract the user*/ + const char *ret = NULL; + + if (locked) { + if (g_strcmp0 (category, "email.arrived") == 0) + ret = "message-missed-email"; + else if (g_strcmp0 (category, "im.received") == 0) + ret = "message-missed-instant"; + else if (g_strcmp0 (category, "x-gnome.call.unanswered") == 0) + ret = "phone-missed-call"; + else + ret = "message-missed-notification"; + } else { + if (g_strcmp0 (category, "email.arrived") == 0) + ret = "message-new-email"; + else if (g_strcmp0 (category, "im.received") == 0) + ret = "message-new-instant"; + else if (g_strcmp0 (category, "x-gnome.call.unanswered") == 0) + ret = "phone-missed-call"; + /* no additional feedback when not locked */ + } + + return ret; +} + + +static void +on_notifcation_source_items_changed (PhoshNotifyFeedback *self, + guint position, + guint removed, + guint added, + GListModel *list) +{ + if (!added) + return; + + /* TODO: add pending events to queue instead of just skipping them. */ + if (self->event && lfb_event_get_state (self->event) == LFB_EVENT_STATE_RUNNING) + return; + + for (int i = 0; i < added; i++) { + g_autoptr (PhoshNotification) new = g_list_model_get_item (list, position); + g_autoptr (LfbEvent) event = NULL; + const char *category, *event_name; + + g_return_if_fail (PHOSH_IS_NOTIFICATION (new)); + + category = phosh_notification_get_category (new); + event_name = find_event (category); + if (event_name == NULL) + continue; + + g_debug ("Emitting event %s", event_name); + event = lfb_event_new (event_name); + g_set_object (&self->event, event); + lfb_event_trigger_feedback_async (self->event, NULL, NULL, NULL); + /* TODO: add additional events to queue instead of just skipping them */ + break; + } +} + + +static void +on_notifcation_list_items_changed (PhoshNotifyFeedback *self, + guint position, + guint removed, + guint added, + GListModel *list) +{ + g_autoptr (PhoshNotificationSource) first = g_list_model_get_item (list, 0); + + if (!first) { + g_debug ("Notification list empty, ending feedback"); + end_notify_feedback (self); + } + + /* No need to worry about removed sources, signals get detached due + * to g_signal_connect_object () */ + for (int i = position; i < position + added; i++) { + g_autoptr (PhoshNotificationSource) source = g_list_model_get_item (list, position); + /* Listen to new notification on the store for feedback triggering */ + g_signal_connect_object (source, + "items-changed", + G_CALLBACK (on_notifcation_source_items_changed), + self, + G_CONNECT_SWAPPED); + on_notifcation_source_items_changed (self, 0, 0, + g_list_model_get_n_items (G_LIST_MODEL (source)), + G_LIST_MODEL (source)); + } +} + + +static void +phosh_notify_feedback_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshNotifyFeedback *self = PHOSH_NOTIFY_FEEDBACK (object); + + switch (property_id) { + case PROP_NOTIFICATION_LIST: + self->list = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_notify_feedback_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshNotifyFeedback *self = PHOSH_NOTIFY_FEEDBACK (object); + + switch (property_id) { + case PROP_NOTIFICATION_LIST: + g_value_set_object (value, self->list); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_notify_feedback_constructed (GObject *object) +{ + PhoshNotifyFeedback *self = PHOSH_NOTIFY_FEEDBACK (object); + + G_OBJECT_CLASS (phosh_notify_feedback_parent_class)->constructed (object); + + g_signal_connect_swapped (self->list, + "items-changed", + G_CALLBACK (on_notifcation_list_items_changed), + self); +} + + +static void +phosh_notify_feedback_dispose (GObject *object) +{ + PhoshNotifyFeedback *self = PHOSH_NOTIFY_FEEDBACK (object); + + if (self->event) { + end_notify_feedback (self); + g_clear_object (&self->event); + } + + g_signal_handlers_disconnect_by_data (self->list, self); + g_clear_object (&self->list); + + G_OBJECT_CLASS (phosh_notify_feedback_parent_class)->dispose (object); +} + + +static void +phosh_notify_feedback_class_init (PhoshNotifyFeedbackClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = phosh_notify_feedback_get_property; + object_class->set_property = phosh_notify_feedback_set_property; + object_class->constructed = phosh_notify_feedback_constructed; + object_class->dispose = phosh_notify_feedback_dispose; + + /** + * PhoshNotifyFeedback:notification-list + * + * The list of notifications that drives the feedback emission + */ + props[PROP_NOTIFICATION_LIST] = + g_param_spec_object ("notification-list", + "", + "", + PHOSH_TYPE_NOTIFICATION_LIST, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); +} + + +static void +phosh_notify_feedback_init (PhoshNotifyFeedback *self) +{ +} + + +PhoshNotifyFeedback * +phosh_notify_feedback_new (PhoshNotificationList *list) +{ + return PHOSH_NOTIFY_FEEDBACK (g_object_new (PHOSH_TYPE_NOTIFY_FEEDBACK, + "notification-list", list, + NULL)); +} diff -Nru phosh-0.8.0/src/notifications/notify-feedback.h phosh-0.13.1/src/notifications/notify-feedback.h --- phosh-0.8.0/src/notifications/notify-feedback.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/notifications/notify-feedback.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "notification-list.h" + +#include + +G_BEGIN_DECLS + +#define PHOSH_TYPE_NOTIFY_FEEDBACK (phosh_notify_feedback_get_type ()) + +G_DECLARE_FINAL_TYPE (PhoshNotifyFeedback, phosh_notify_feedback, PHOSH, NOTIFY_FEEDBACK, GObject) + +PhoshNotifyFeedback *phosh_notify_feedback_new (PhoshNotificationList *list); + +G_END_DECLS diff -Nru phosh-0.8.0/src/notifications/notify-manager.c phosh-0.13.1/src/notifications/notify-manager.c --- phosh-0.8.0/src/notifications/notify-manager.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/notifications/notify-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -16,6 +16,7 @@ #include "notification-banner.h" #include "notification-list.h" #include "notify-manager.h" +#include "notify-feedback.h" #include "shell.h" #include "phosh-enums.h" #include "util.h" @@ -40,6 +41,8 @@ * #PhoshNotifyManager manages notifications sent from the shell * iself and via the org.freedesktop.Notification DBus interface. * See https://developer.gnome.org/notification-spec/ + * + * It maintains a list of notifications via a #PhoshNotificationList. */ #define NOTIFY_DBUS_NAME "org.freedesktop.Notifications" @@ -59,7 +62,14 @@ GSettings *settings; + /* Notification to be handled on unlock */ + struct { + PhoshNotification *notification; + char *action; + } unlock_notify; + PhoshNotificationList *list; + PhoshNotifyFeedback *feedback; } PhoshNotifyManager; G_DEFINE_TYPE_WITH_CODE (PhoshNotifyManager, @@ -158,19 +168,39 @@ static void -on_notification_actioned (PhoshNotifyManager *self, - const char *action, - PhoshNotification *notification) +on_unlock_notify_ref_gone (gpointer data, GObject *gone) { - guint id; + PhoshNotifyManager *self = PHOSH_NOTIFY_MANAGER (data); g_return_if_fail (PHOSH_IS_NOTIFY_MANAGER (self)); - g_return_if_fail (PHOSH_IS_NOTIFICATION (notification)); + + self->unlock_notify.notification = NULL; + g_clear_pointer (&self->unlock_notify.action, g_free); +} + + +static void +forget_unlock_notify (PhoshNotifyManager *self) +{ + if (!self->unlock_notify.notification) + return; + + g_object_weak_unref (G_OBJECT (self->unlock_notify.notification), + on_unlock_notify_ref_gone, + self); + self->unlock_notify.notification = NULL; + g_clear_pointer (&self->unlock_notify.action, g_free); +} + + +static void +invoke_action (PhoshNotification *notification, const gchar *action) +{ + guint id; id = phosh_notification_get_id (notification); g_return_if_fail (id); - g_debug ("Emitting ActionInvoked: %d, %s", id, action); phosh_notification_do_action (notification, id, action); @@ -183,6 +213,55 @@ } + +static void +on_shell_lock_changed (PhoshNotifyManager* self, GParamSpec *pspec, PhoshShell *shell) +{ + gboolean locked; + + g_return_if_fail (PHOSH_IS_NOTIFY_MANAGER (self)); + + locked = phosh_shell_get_locked (shell); + if (!locked && self->unlock_notify.notification) { + invoke_action (self->unlock_notify.notification, self->unlock_notify.action); + forget_unlock_notify (self); + } +} + + +static void +on_notification_actioned (PhoshNotifyManager *self, + const char *action, + PhoshNotification *notification) +{ + PhoshShell *shell = phosh_shell_get_default(); + + g_return_if_fail (PHOSH_IS_NOTIFY_MANAGER (self)); + g_return_if_fail (PHOSH_IS_NOTIFICATION (notification)); + + /* Postpone action when shell is locked */ + if (phosh_shell_get_locked (shell)) { + PhoshLockscreenManager *lm; + + /* Forget any pending actions */ + forget_unlock_notify (self); + + /* Clear out notification if it goes away in the meantime */ + g_object_weak_ref (G_OBJECT (notification), + on_unlock_notify_ref_gone, + self); + self->unlock_notify.notification = notification; + self->unlock_notify.action = g_strdup (action); + + /* Scroll to unlock page */ + lm = phosh_shell_get_lockscreen_manager (shell); + phosh_lockscreen_manager_set_page (lm, PHOSH_LOCKSCREEN_PAGE_UNLOCK); + } else { + invoke_action (notification, action); + } +} + + static void on_notification_closed (PhoshNotifyManager *self, PhoshNotificationReason reason, @@ -548,8 +627,13 @@ { PhoshNotifyManager *self = PHOSH_NOTIFY_MANAGER (object); - g_clear_object (&self->settings); + g_clear_handle_id (&self->dbus_name_id, g_bus_unown_name); + if (g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (self))) + g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self)); + + g_clear_object (&self->settings); + g_clear_object (&self->feedback); g_clear_object (&self->list); G_OBJECT_CLASS (phosh_notify_manager_parent_class)->dispose (object); @@ -572,6 +656,7 @@ phosh_notify_manager_constructed (GObject *object) { PhoshNotifyManager *self = PHOSH_NOTIFY_MANAGER (object); + PhoshShell *shell = phosh_shell_get_default(); G_OBJECT_CLASS (phosh_notify_manager_parent_class)->constructed (object); self->dbus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION, @@ -581,8 +666,8 @@ on_bus_acquired, on_name_acquired, on_name_lost, - g_object_ref (self), - g_object_unref); + self, + NULL); self->settings = g_settings_new (NOTIFICATIONS_SCHEMA_ID); g_signal_connect_swapped (self->settings, "changed::" NOTIFICATIONS_KEY_SHOW_BANNERS, @@ -592,6 +677,10 @@ g_signal_connect_swapped (self->settings, "changed::" NOTIFICATIONS_KEY_APP_CHILDREN, G_CALLBACK (on_notification_apps_setting_changed), self); on_notification_apps_setting_changed (self, NULL, self->settings); + + g_signal_connect_swapped (shell, "notify::locked", G_CALLBACK (on_shell_lock_changed), self); + + self->feedback = phosh_notify_feedback_new (self->list); } @@ -705,8 +794,7 @@ * @expire_timeout: When the notification should expire * @notification: The notification * - * Returns: Adds a notification - * notifications. + * Adds @notification to the current list of notifications. */ void phosh_notify_manager_add_notification (PhoshNotifyManager *self, @@ -803,3 +891,28 @@ g_debug ("Show banners for %s: %d", munged_id, show); return show; } + +/** + * phosh_notify_manager_close_all: + * @self: the #PhoshNotifyManager + * @rease: the #PhoshNotificationReason + * + * Closes all notifications using #PhoshNotificationReason as reason. + */ +void +phosh_notify_manager_close_all_notifications (PhoshNotifyManager *self, + PhoshNotificationReason reason) +{ + GListModel *source_list; + + source_list = G_LIST_MODEL (phosh_notify_manager_get_list (self)); + + for (int i = g_list_model_get_n_items(G_LIST_MODEL (source_list)); i > 0; i--) { + g_autoptr (GListModel) notif_list = G_LIST_MODEL (g_list_model_get_object (source_list, i-1)); + + for (int j = g_list_model_get_n_items(G_LIST_MODEL (notif_list)); j > 0; j--) { + g_autoptr (PhoshNotification) notification = PHOSH_NOTIFICATION (g_list_model_get_object (notif_list, j-1)); + phosh_notification_close (notification, PHOSH_NOTIFICATION_REASON_DISMISSED); + } + } +} diff -Nru phosh-0.8.0/src/notifications/notify-manager.h phosh-0.13.1/src/notifications/notify-manager.h --- phosh-0.8.0/src/notifications/notify-manager.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/notifications/notify-manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -27,11 +27,11 @@ const gchar *source_id, int expire_timeout, PhoshNotification *notification); -gboolean phosh_notify_manager_close_notification_by_id (PhoshNotifyManager *self, - int id, - PhoshNotificationReason reason); -gboolean - phosh_notify_manager_get_show_notification_banner ( - PhoshNotifyManager *self, +gboolean phosh_notify_manager_close_notification_by_id (PhoshNotifyManager *self, + int id, + PhoshNotificationReason reason); +void phosh_notify_manager_close_all_notifications (PhoshNotifyManager *self, + PhoshNotificationReason reaseon); +gboolean phosh_notify_manager_get_show_notification_banner (PhoshNotifyManager *self, PhoshNotification *notification); G_END_DECLS diff -Nru phosh-0.8.0/src/osd-window.c phosh-0.13.1/src/osd-window.c --- phosh-0.8.0/src/osd-window.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/osd-window.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-osd-window" + +#include "config.h" + +#include "osd-window.h" + +/** + * SECTION:osd-window + * @short_description: A OSD Window + * @Title: PhoshOsdWindow + * + * The #PhoshOsdWindow displays contents fed via the + * OSD (on screen display) DBus interface. + */ + +enum { + PROP_0, + PROP_CONNECTOR, + PROP_LABEL, + PROP_ICON_NAME, + PROP_LEVEL, + PROP_MAX_LEVEL, + PROP_LAST_PROP, +}; +static GParamSpec *props[PROP_LAST_PROP]; + +typedef struct _PhoshOsdWindow { + PhoshSystemModal parent; + + char *connector; + char *label; + char *icon_name; + gdouble level; + gdouble max_level; + + GtkWidget *lbl; + GtkWidget *icon; + GtkWidget *bar; + GtkGesture *click_gesture; +} PhoshOsdWindow; + + +G_DEFINE_TYPE (PhoshOsdWindow, phosh_osd_window, PHOSH_TYPE_SYSTEM_MODAL) + +static void +phosh_osd_window_set_property (GObject *obj, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshOsdWindow *self = PHOSH_OSD_WINDOW (obj); + + switch (prop_id) { + case PROP_CONNECTOR: + g_free (self->connector); + self->connector = g_value_dup_string (value); + break; + case PROP_LABEL: + g_free (self->label); + self->label = g_value_dup_string (value); + gtk_label_set_label (GTK_LABEL (self->lbl), self->label); + break; + case PROP_ICON_NAME: + g_free (self->icon_name); + self->icon_name = g_value_dup_string (value); + gtk_image_set_from_icon_name (GTK_IMAGE (self->icon), self->icon_name, GTK_ICON_SIZE_INVALID); + break; + case PROP_LEVEL: + self->level = g_value_get_double (value); + gtk_level_bar_set_value (GTK_LEVEL_BAR (self->bar), self->level); + break; + case PROP_MAX_LEVEL: + self->max_level = g_value_get_double (value); + gtk_level_bar_set_max_value (GTK_LEVEL_BAR (self->bar), self->max_level); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + + +static void +phosh_osd_window_get_property (GObject *obj, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshOsdWindow *self = PHOSH_OSD_WINDOW (obj); + + switch (prop_id) { + case PROP_CONNECTOR: + g_value_set_string (value, self->connector ? self->connector : ""); + break; + case PROP_LABEL: + g_value_set_string (value, self->label ? self->label : ""); + break; + case PROP_ICON_NAME: + g_value_set_string (value, self->icon_name ? self->icon_name : ""); + break; + case PROP_LEVEL: + g_value_set_double (value, self->level); + break; + case PROP_MAX_LEVEL: + g_value_set_double (value, self->max_level); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + + +static void +on_button_released (PhoshOsdWindow *self) +{ + gtk_widget_destroy (GTK_WIDGET (self)); +} + + +static void +phosh_osd_window_finalize (GObject *obj) +{ + PhoshOsdWindow *self = PHOSH_OSD_WINDOW (obj); + + g_free (self->connector); + g_free (self->label); + g_free (self->icon_name); + + G_OBJECT_CLASS (phosh_osd_window_parent_class)->finalize (obj); +} + + +static void +phosh_osd_window_class_init (PhoshOsdWindowClass *klass) +{ + GObjectClass *object_class = (GObjectClass *)klass; + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->get_property = phosh_osd_window_get_property; + object_class->set_property = phosh_osd_window_set_property; + object_class->finalize = phosh_osd_window_finalize; + + /* TODO: currently unused */ + props[PROP_CONNECTOR] = + g_param_spec_string ("connector", + "Connector", + "Connector to use for osd display", + NULL, + G_PARAM_READWRITE); + + props[PROP_LABEL] = + g_param_spec_string ("label", + "Label", + "Label to show on osd", + NULL, + G_PARAM_READWRITE); + + props[PROP_ICON_NAME] = + g_param_spec_string ("icon-name", + "Icon Name", + "Name of icon to use on osd", + NULL, + G_PARAM_READWRITE); + + props[PROP_LEVEL] = + g_param_spec_double ("level", + "Level", + "Level of bar to display on osd", + 0.0, + G_MAXDOUBLE, + 0.0, + G_PARAM_READWRITE); + + props[PROP_MAX_LEVEL] = + g_param_spec_double ("max-level", + "Maximum Level", + "Maximum level of bar to display on osd", + 0.0, + G_MAXDOUBLE, + 0.0, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); + + gtk_widget_class_set_template_from_resource (widget_class, + "/sm/puri/phosh/ui/osd-window.ui"); + gtk_widget_class_bind_template_child (widget_class, PhoshOsdWindow, lbl); + gtk_widget_class_bind_template_child (widget_class, PhoshOsdWindow, icon); + gtk_widget_class_bind_template_child (widget_class, PhoshOsdWindow, bar); + gtk_widget_class_bind_template_child (widget_class, PhoshOsdWindow, click_gesture); + gtk_widget_class_bind_template_callback (widget_class, on_button_released); + + gtk_widget_class_set_css_name (widget_class, "phosh-osd-window"); +} + + +static void +phosh_osd_window_init (PhoshOsdWindow *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); + + gtk_widget_add_events (GTK_WIDGET (self), GDK_BUTTON_RELEASE_MASK); +} + + +GtkWidget * +phosh_osd_window_new (char *connector, + char *label, + char *icon_name, + double level, + double max_level) +{ + return g_object_new (PHOSH_TYPE_OSD_WINDOW, + "connector", connector, + "label",label, + "icon-name", icon_name, + "level", level, + "max-level", max_level, + NULL); +} diff -Nru phosh-0.8.0/src/osd-window.h phosh-0.13.1/src/osd-window.h --- phosh-0.8.0/src/osd-window.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/osd-window.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include +#include "system-modal.h" + +#define PHOSH_TYPE_OSD_WINDOW (phosh_osd_window_get_type ()) + +G_DECLARE_FINAL_TYPE (PhoshOsdWindow, phosh_osd_window, PHOSH, OSD_WINDOW, PhoshSystemModal) + +GtkWidget *phosh_osd_window_new (char *connector, + char *label, + char *icon_name, + double level, + double max_level); diff -Nru phosh-0.8.0/src/osk/meson.build phosh-0.13.1/src/osk/meson.build --- phosh-0.8.0/src/osk/meson.build 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/osk/meson.build 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -iface = 'phosh-osk0-dbus' -generated_osk_sources = gnome.gdbus_codegen(iface, - iface + '.xml', - namespace: 'PhoshOsk0', - object_manager: true) - -phosh_osk_sources = [ - 'osk/osk-button.c', - generated_osk_sources, -] diff -Nru phosh-0.8.0/src/osk/osk-button.c phosh-0.13.1/src/osk/osk-button.c --- phosh-0.8.0/src/osk/osk-button.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/osk/osk-button.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2018 Purism SPC - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - * Author: Guido Günther - */ - -#define G_LOG_DOMAIN "phosh-osk-button" - -#include "osk-button.h" -#include "osk-manager.h" -#include "shell.h" - -#include -#include - -/** - * SECTION:osk-button - * @short_description: A button that toggles the OSK - * @Title: PhoshOsk - * - * The #PhoshOskButton is responsible for toggling the on screen keyboard - */ -struct _PhoshOskButton -{ - GtkToggleButton parent; - - PhoshOskManager *osk; - gboolean setting_visibility; -}; - -G_DEFINE_TYPE (PhoshOskButton, phosh_osk_button, GTK_TYPE_TOGGLE_BUTTON) - - -static void -toggled_cb (PhoshOskButton *self, gpointer data) -{ - gboolean visible, active; - - self->setting_visibility = TRUE; - visible = phosh_osk_manager_get_visible (self->osk); - - active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self)); - if (visible != active) - phosh_osk_manager_set_visible (self->osk, active); - - self->setting_visibility = FALSE; -} - - -static void -on_osk_availability_changed (PhoshOskButton *self, GParamSpec *pspec, PhoshOskManager *osk) -{ - gboolean available; - - g_return_if_fail (PHOSH_IS_OSK_BUTTON (self)); - g_return_if_fail (PHOSH_IS_OSK_MANAGER (osk)); - g_return_if_fail (self->osk == osk); - - available = phosh_osk_manager_get_available (osk); - gtk_widget_set_sensitive (GTK_WIDGET (self), available); -} - - -static void -on_osk_visibility_changed (PhoshOskButton *self, GParamSpec *pspec, PhoshOskManager *osk) -{ - gboolean visible; - - g_return_if_fail (PHOSH_IS_OSK_BUTTON (self)); - g_return_if_fail (PHOSH_IS_OSK_MANAGER (osk)); - g_return_if_fail (self->osk == osk); - - visible = phosh_osk_manager_get_visible (osk); - if (!self->setting_visibility) - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self), visible); -} - - -static void -phosh_osk_button_constructed (GObject *object) -{ - PhoshOskButton *self = PHOSH_OSK_BUTTON (object); - PhoshShell *shell; - GtkWidget *image; - - G_OBJECT_CLASS (phosh_osk_button_parent_class)->constructed (object); - - shell = phosh_shell_get_default (); - self->osk = g_object_ref(phosh_shell_get_osk_manager (shell)); - - g_signal_connect_swapped ( - self->osk, - "notify::visible", - G_CALLBACK (on_osk_visibility_changed), - self); - - g_signal_connect_swapped ( - self->osk, - "notify::available", - G_CALLBACK (on_osk_availability_changed), - self); - - g_signal_connect (self, - "toggled", - G_CALLBACK (toggled_cb), - NULL); - - image = gtk_image_new_from_icon_name ("input-keyboard-symbolic", GTK_ICON_SIZE_BUTTON); - gtk_button_set_image (GTK_BUTTON (self), image); - gtk_button_set_always_show_image (GTK_BUTTON (self), TRUE); - - on_osk_availability_changed (self, NULL, self->osk); - on_osk_visibility_changed (self, NULL, self->osk); -} - - -static void -phosh_osk_button_dispose (GObject *object) -{ - PhoshOskButton *self = PHOSH_OSK_BUTTON (object); - - g_clear_object (&self->osk); - G_OBJECT_CLASS (phosh_osk_button_parent_class)->dispose (object); -} - - -static void -phosh_osk_button_class_init (PhoshOskButtonClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->constructed = phosh_osk_button_constructed; - object_class->dispose = phosh_osk_button_dispose; -} - - -static void -phosh_osk_button_init (PhoshOskButton *self) -{ -} - - -GtkWidget * -phosh_osk_button_new (void) -{ - return g_object_new (PHOSH_TYPE_OSK_BUTTON, NULL); -} diff -Nru phosh-0.8.0/src/osk/osk-button.h phosh-0.13.1/src/osk/osk-button.h --- phosh-0.8.0/src/osk/osk-button.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/osk/osk-button.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2018 Purism SPC - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - * Author: Guido Günther - */ - -#pragma once - -#include - -G_BEGIN_DECLS - -#define PHOSH_TYPE_OSK_BUTTON (phosh_osk_button_get_type()) - -G_DECLARE_FINAL_TYPE (PhoshOskButton, phosh_osk_button, PHOSH, OSK_BUTTON, GtkToggleButton) - -GtkWidget * phosh_osk_button_new (void); - -G_END_DECLS diff -Nru phosh-0.8.0/src/osk/phosh-osk0-dbus.xml phosh-0.13.1/src/osk/phosh-osk0-dbus.xml --- phosh-0.8.0/src/osk/phosh-osk0-dbus.xml 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/osk/phosh-osk0-dbus.xml 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ - - - - - - - Switch keyboard visibility - - - - - - diff -Nru phosh-0.8.0/src/osk-button.c phosh-0.13.1/src/osk-button.c --- phosh-0.8.0/src/osk-button.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/osk-button.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2018 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-osk-button" + +#include "osk-button.h" +#include "osk-manager.h" +#include "shell.h" + +#include +#include + +/** + * SECTION:osk-button + * @short_description: A button that toggles the OSK + * @Title: PhoshOsk + * + * The #PhoshOskButton is responsible for toggling the on screen keyboard + */ +struct _PhoshOskButton +{ + GtkToggleButton parent; + + PhoshOskManager *osk; + gboolean setting_visibility; +}; + +G_DEFINE_TYPE (PhoshOskButton, phosh_osk_button, GTK_TYPE_TOGGLE_BUTTON) + + +static void +toggled_cb (PhoshOskButton *self, gpointer data) +{ + gboolean visible, active; + + self->setting_visibility = TRUE; + visible = phosh_osk_manager_get_visible (self->osk); + + active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self)); + if (visible != active) + phosh_osk_manager_set_visible (self->osk, active); + + self->setting_visibility = FALSE; +} + + +static void +on_osk_availability_changed (PhoshOskButton *self, GParamSpec *pspec, PhoshOskManager *osk) +{ + gboolean available; + + g_return_if_fail (PHOSH_IS_OSK_BUTTON (self)); + g_return_if_fail (PHOSH_IS_OSK_MANAGER (osk)); + g_return_if_fail (self->osk == osk); + + available = phosh_osk_manager_get_available (osk); + gtk_widget_set_sensitive (GTK_WIDGET (self), available); +} + + +static void +on_osk_visibility_changed (PhoshOskButton *self, GParamSpec *pspec, PhoshOskManager *osk) +{ + gboolean visible; + + g_return_if_fail (PHOSH_IS_OSK_BUTTON (self)); + g_return_if_fail (PHOSH_IS_OSK_MANAGER (osk)); + g_return_if_fail (self->osk == osk); + + visible = phosh_osk_manager_get_visible (osk); + if (!self->setting_visibility) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self), visible); +} + + +static void +phosh_osk_button_constructed (GObject *object) +{ + PhoshOskButton *self = PHOSH_OSK_BUTTON (object); + PhoshShell *shell; + GtkWidget *image; + + G_OBJECT_CLASS (phosh_osk_button_parent_class)->constructed (object); + + shell = phosh_shell_get_default (); + self->osk = g_object_ref(phosh_shell_get_osk_manager (shell)); + + g_signal_connect_swapped ( + self->osk, + "notify::visible", + G_CALLBACK (on_osk_visibility_changed), + self); + + g_signal_connect_swapped ( + self->osk, + "notify::available", + G_CALLBACK (on_osk_availability_changed), + self); + + g_signal_connect (self, + "toggled", + G_CALLBACK (toggled_cb), + NULL); + + image = gtk_image_new_from_icon_name ("input-keyboard-symbolic", GTK_ICON_SIZE_BUTTON); + gtk_button_set_image (GTK_BUTTON (self), image); + gtk_button_set_always_show_image (GTK_BUTTON (self), TRUE); + + on_osk_availability_changed (self, NULL, self->osk); + on_osk_visibility_changed (self, NULL, self->osk); +} + + +static void +phosh_osk_button_dispose (GObject *object) +{ + PhoshOskButton *self = PHOSH_OSK_BUTTON (object); + + g_clear_object (&self->osk); + G_OBJECT_CLASS (phosh_osk_button_parent_class)->dispose (object); +} + + +static void +phosh_osk_button_class_init (PhoshOskButtonClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = phosh_osk_button_constructed; + object_class->dispose = phosh_osk_button_dispose; +} + + +static void +phosh_osk_button_init (PhoshOskButton *self) +{ +} + + +GtkWidget * +phosh_osk_button_new (void) +{ + return g_object_new (PHOSH_TYPE_OSK_BUTTON, NULL); +} diff -Nru phosh-0.8.0/src/osk-button.h phosh-0.13.1/src/osk-button.h --- phosh-0.8.0/src/osk-button.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/osk-button.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define PHOSH_TYPE_OSK_BUTTON (phosh_osk_button_get_type()) + +G_DECLARE_FINAL_TYPE (PhoshOskButton, phosh_osk_button, PHOSH, OSK_BUTTON, GtkToggleButton) + +GtkWidget * phosh_osk_button_new (void); + +G_END_DECLS diff -Nru phosh-0.8.0/src/overview.c phosh-0.13.1/src/overview.c --- phosh-0.8.0/src/overview.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/overview.c 2021-08-31 09:15:52.000000000 +0000 @@ -10,20 +10,20 @@ #include "config.h" -#include "overview.h" #include "activity.h" -#include "app-grid.h" #include "app-grid-button.h" +#include "app-grid.h" +#include "overview.h" +#include "wlr-screencopy-unstable-v1-client-protocol.h" +#include "phosh-private-client-protocol.h" +#include "phosh-wayland.h" #include "shell.h" -#include "util.h" #include "toplevel-manager.h" #include "toplevel-thumbnail.h" -#include "phosh-private-client-protocol.h" -#include "phosh-wayland.h" +#include "util.h" #include -#define HANDY_USE_UNSTABLE_API #include #define OVERVIEW_ICON_SIZE 64 @@ -60,7 +60,7 @@ /* Running activities */ GtkWidget *carousel_running_activities; GtkWidget *app_grid; - GtkWidget *activity; + PhoshActivity *activity; int has_activities; } PhoshOverviewPrivate; @@ -170,11 +170,21 @@ static void -on_toplevel_closed (PhoshToplevel *toplevel, PhoshActivity *activity) +on_toplevel_closed (PhoshToplevel *toplevel, PhoshOverview *overview) { + PhoshActivity *activity; + PhoshOverviewPrivate *priv; + g_return_if_fail (PHOSH_IS_TOPLEVEL (toplevel)); + g_return_if_fail (PHOSH_IS_OVERVIEW (overview)); + priv = phosh_overview_get_instance_private (overview); + + activity = find_activity_by_toplevel (overview, toplevel); g_return_if_fail (PHOSH_IS_ACTIVITY (activity)); gtk_widget_destroy (GTK_WIDGET (activity)); + + if (priv->activity == activity) + priv->activity = NULL; } @@ -187,9 +197,9 @@ g_return_if_fail (PHOSH_IS_TOPLEVEL (toplevel)); priv = phosh_overview_get_instance_private (overview); - activity = find_activity_by_toplevel (overview, toplevel); if (phosh_toplevel_is_activated (toplevel)) { - priv->activity = GTK_WIDGET (activity); + activity = find_activity_by_toplevel (overview, toplevel); + priv->activity = activity; hdy_carousel_scroll_to (HDY_CAROUSEL (priv->carousel_running_activities), GTK_WIDGET (activity)); } } @@ -248,6 +258,7 @@ PhoshOverviewPrivate *priv; GtkWidget *activity; const char *app_id, *title; + float scale; g_return_if_fail (PHOSH_IS_OVERVIEW (self)); priv = phosh_overview_get_instance_private (self); @@ -257,9 +268,10 @@ g_debug ("Building activator for '%s' (%s)", app_id, title); activity = phosh_activity_new (app_id, title); + scale = phosh_monitor_get_fractional_scale (monitor); g_object_set (activity, - "win-width", monitor->width / monitor->scale, /* TODO: Get the real size somehow */ - "win-height", monitor->height / monitor->scale, + "win-width", (int)(monitor->width / scale), + "win-height", (int)(monitor->height / scale), "maximized", phosh_toplevel_is_maximized (toplevel), NULL); g_object_set_data (G_OBJECT (activity), "toplevel", toplevel); @@ -271,7 +283,7 @@ g_signal_connect_swapped (activity, "closed", G_CALLBACK (on_activity_closed), self); - g_signal_connect_object (toplevel, "closed", G_CALLBACK (on_toplevel_closed), activity, 0); + g_signal_connect_object (toplevel, "closed", G_CALLBACK (on_toplevel_closed), self, 0); g_signal_connect_object (toplevel, "notify::activated", G_CALLBACK (on_toplevel_activated_changed), self, 0); g_object_bind_property (toplevel, "maximized", activity, "maximized", G_BINDING_DEFAULT); @@ -282,7 +294,7 @@ if (phosh_toplevel_is_activated (toplevel)) { hdy_carousel_scroll_to (HDY_CAROUSEL (priv->carousel_running_activities), activity); - priv->activity = GTK_WIDGET (activity); + priv->activity = PHOSH_ACTIVITY (activity); } } @@ -438,8 +450,6 @@ object_class->get_property = phosh_overview_get_property; widget_class->size_allocate = phosh_overview_size_allocate; - gtk_widget_class_set_css_name (widget_class, "phosh-overview"); - props[PROP_HAS_ACTIVITIES] = g_param_spec_boolean ( "has-activities", @@ -509,6 +519,18 @@ phosh_app_grid_focus_search (PHOSH_APP_GRID (priv->app_grid)); } + +gboolean +phosh_overview_handle_search (PhoshOverview *self, GdkEvent *event) +{ + PhoshOverviewPrivate *priv; + + g_return_val_if_fail(PHOSH_IS_OVERVIEW (self), GDK_EVENT_PROPAGATE); + priv = phosh_overview_get_instance_private (self); + return phosh_app_grid_handle_search (PHOSH_APP_GRID (priv->app_grid), event); +} + + gboolean phosh_overview_has_running_activities (PhoshOverview *self) { @@ -519,3 +541,15 @@ return priv->has_activities; } + + +PhoshAppGrid * +phosh_overview_get_app_grid (PhoshOverview *self) +{ + PhoshOverviewPrivate *priv; + + g_return_val_if_fail (PHOSH_IS_OVERVIEW (self), NULL); + priv = phosh_overview_get_instance_private (self); + + return PHOSH_APP_GRID (priv->app_grid); +} diff -Nru phosh-0.8.0/src/overview.h phosh-0.13.1/src/overview.h --- phosh-0.8.0/src/overview.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/overview.h 2021-08-31 09:15:52.000000000 +0000 @@ -6,8 +6,12 @@ #pragma once +#include "app-grid.h" + #include +G_BEGIN_DECLS + #define PHOSH_TYPE_OVERVIEW (phosh_overview_get_type()) G_DECLARE_FINAL_TYPE (PhoshOverview, phosh_overview, PHOSH, OVERVIEW, GtkBox) @@ -17,3 +21,7 @@ void phosh_overview_reset (PhoshOverview *self); void phosh_overview_focus_app_search (PhoshOverview *self); gboolean phosh_overview_has_running_activities (PhoshOverview *self); +gboolean phosh_overview_handle_search (PhoshOverview *self, GdkEvent *event); +PhoshAppGrid *phosh_overview_get_app_grid (PhoshOverview *self); + +G_END_DECLS diff -Nru phosh-0.8.0/src/panel.c phosh-0.13.1/src/panel.c --- phosh-0.8.0/src/panel.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/panel.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,497 +0,0 @@ -/* - * Copyright (C) 2018 Purism SPC - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - * Author: Guido Günther - * - * Somewhat based on maynard's panel which is - * Copyright (C) 2014 Collabora Ltd. * - * Author: Jonny Lamb - */ - -#define G_LOG_DOMAIN "phosh-panel" - -#include "config.h" - -#include "bt-info.h" -#include "connectivity-info.h" -#include "docked-info.h" -#include "panel.h" -#include "shell.h" -#include "session-manager.h" -#include "settings.h" -#include "util.h" - -#define GNOME_DESKTOP_USE_UNSTABLE_API -#include -#include - -#include - -/** - * SECTION:panel - * @short_description: The top panel - * @Title: PhoshPanel - * - * The top panel containing the clock and status indicators. - */ - -enum { - SETTINGS_ACTIVATED, - N_SIGNALS -}; -static guint signals[N_SIGNALS] = { 0 }; - -typedef struct { - PhoshPanelState state; - - GtkWidget *stack; - GtkWidget *box; /* main content box */ - GtkWidget *btn_top_panel; - GtkWidget *lbl_clock; - GtkWidget *lbl_lang; - GtkWidget *settings; /* settings menu */ - - GnomeWallClock *wall_clock; - GnomeXkbInfo *xkbinfo; - GSettings *input_settings; - GdkSeat *seat; - - GSimpleActionGroup *actions; -} PhoshPanelPrivate; - -typedef struct _PhoshPanel -{ - PhoshLayerSurface parent; -} PhoshPanel; - -G_DEFINE_TYPE_WITH_PRIVATE (PhoshPanel, phosh_panel, PHOSH_TYPE_LAYER_SURFACE) - - -static void -on_shutdown_action (GSimpleAction *action, - GVariant *parameter, - gpointer data) -{ - PhoshPanel *self = PHOSH_PANEL(data); - PhoshSessionManager *sm = phosh_shell_get_session_manager (phosh_shell_get_default ()); - - g_return_if_fail (PHOSH_IS_PANEL (self)); - phosh_session_manager_shutdown (sm); - /* TODO: Since we don't implement - * gnome.SessionManager.EndSessionDialog yet */ - phosh_session_manager_shutdown (sm); - phosh_panel_fold (self); -} - - -static void -on_restart_action (GSimpleAction *action, - GVariant *parameter, - gpointer data) -{ - PhoshPanel *self = PHOSH_PANEL(data); - PhoshSessionManager *sm = phosh_shell_get_session_manager (phosh_shell_get_default ()); - - g_return_if_fail (PHOSH_IS_PANEL (self)); - g_return_if_fail (PHOSH_IS_SESSION_MANAGER (sm)); - - phosh_session_manager_reboot (sm); - /* TODO: Since we don't implement - * gnome.SessionManager.EndSessionDialog yet */ - phosh_session_manager_reboot (sm); - phosh_panel_fold (self); -} - - -static void -on_lockscreen_action (GSimpleAction *action, - GVariant *parameter, - gpointer data) -{ - PhoshPanel *self = PHOSH_PANEL(data); - - g_return_if_fail (PHOSH_IS_PANEL (self)); - phosh_shell_lock (phosh_shell_get_default ()); - phosh_panel_fold (self); -} - - -static void -on_logout_action (GSimpleAction *action, - GVariant *parameter, - gpointer data) -{ - PhoshPanel *self = PHOSH_PANEL(data); - PhoshSessionManager *sm = phosh_shell_get_session_manager (phosh_shell_get_default ()); - - g_return_if_fail (PHOSH_IS_PANEL (self)); - g_return_if_fail (PHOSH_IS_SESSION_MANAGER (sm)); - phosh_session_manager_logout (sm); - phosh_panel_fold (self); -} - - -static void -top_panel_clicked_cb (PhoshPanel *self, GtkButton *btn) -{ - g_return_if_fail (PHOSH_IS_PANEL (self)); - g_return_if_fail (GTK_IS_BUTTON (btn)); - g_signal_emit(self, signals[SETTINGS_ACTIVATED], 0); -} - - -static void -wall_clock_notify_cb (PhoshPanel *self, - GParamSpec *pspec, - GnomeWallClock *wall_clock) -{ - PhoshPanelPrivate *priv = phosh_panel_get_instance_private (self); - const char *str; - - g_return_if_fail (PHOSH_IS_PANEL (self)); - g_return_if_fail (GNOME_IS_WALL_CLOCK (wall_clock)); - - str = gnome_wall_clock_get_clock(wall_clock); - gtk_label_set_text (GTK_LABEL (priv->lbl_clock), str); -} - - -static gboolean -needs_keyboard_label (PhoshPanel *self) -{ - PhoshPanelPrivate *priv; - GList *slaves; - g_autoptr(GVariant) sources = NULL; - - priv = phosh_panel_get_instance_private (self); - g_return_val_if_fail (GDK_IS_SEAT (priv->seat), FALSE); - g_return_val_if_fail (G_IS_SETTINGS (priv->input_settings), FALSE); - - sources = g_settings_get_value(priv->input_settings, "sources"); - if (g_variant_n_children (sources) < 2) - return FALSE; - - slaves = gdk_seat_get_slaves (priv->seat, GDK_SEAT_CAPABILITY_KEYBOARD); - if (!slaves) - return FALSE; - - g_list_free (slaves); - return TRUE; -} - - -static void -on_seat_device_changed (PhoshPanel *self, GdkDevice *device, GdkSeat *seat) -{ - gboolean visible; - PhoshPanelPrivate *priv; - - g_return_if_fail (PHOSH_IS_PANEL (self)); - g_return_if_fail (GDK_IS_SEAT (seat)); - - priv = phosh_panel_get_instance_private (self); - visible = needs_keyboard_label (self); - gtk_widget_set_visible (priv->lbl_lang, visible); -} - - -static void -on_input_setting_changed (PhoshPanel *self, - const char *key, - GSettings *settings) -{ - PhoshPanelPrivate *priv = phosh_panel_get_instance_private (self); - g_autoptr(GVariant) sources = NULL; - GVariantIter iter; - g_autofree char *id = NULL; - g_autofree char *type = NULL; - const char *name; - - if (!needs_keyboard_label (self)) { - gtk_widget_hide (priv->lbl_lang); - return; - } - - sources = g_settings_get_value(settings, "sources"); - g_variant_iter_init (&iter, sources); - g_variant_iter_next (&iter, "(ss)", &type, &id); - - if (g_strcmp0 (type, "xkb")) { - g_debug ("Not a xkb layout: '%s' - ignoring", id); - return; - } - - if (!gnome_xkb_info_get_layout_info (priv->xkbinfo, id, - NULL, &name, NULL, NULL)) { - g_debug ("Failed to get layout info for %s", id); - name = id; - } - g_debug ("Layout is %s", name); - gtk_label_set_text (GTK_LABEL (priv->lbl_lang), name); - gtk_widget_show (priv->lbl_lang); -} - - -static gboolean -on_key_press_event (PhoshPanel *self, GdkEventKey *event, gpointer data) -{ - gboolean handled = FALSE; - PhoshPanelPrivate *priv; - - g_return_val_if_fail (PHOSH_IS_PANEL (self), FALSE); - priv = phosh_panel_get_instance_private (self); - - if (!priv->settings) - return handled; - - switch (event->keyval) { - case GDK_KEY_Escape: - phosh_panel_fold (self); - handled = TRUE; - break; - default: - /* nothing to do */ - break; - } - return handled; -} - - -static gboolean -on_button_press_event (PhoshPanel *self, GdkEventKey *event, gpointer data) -{ - phosh_trigger_feedback ("button-pressed"); - phosh_panel_fold (self); - return FALSE; -} - - -static GActionEntry entries[] = { - { "poweroff", on_shutdown_action, NULL, NULL, NULL }, - { "restart", on_restart_action, NULL, NULL, NULL }, - { "lockscreen", on_lockscreen_action, NULL, NULL, NULL }, - { "logout", on_logout_action, NULL, NULL, NULL }, -}; - - -static void -phosh_panel_constructed (GObject *object) -{ - PhoshPanel *self = PHOSH_PANEL (object); - PhoshPanelPrivate *priv = phosh_panel_get_instance_private (self); - GdkDisplay *display = gdk_display_get_default (); - - G_OBJECT_CLASS (phosh_panel_parent_class)->constructed (object); - - priv->state = PHOSH_PANEL_STATE_FOLDED; - priv->wall_clock = gnome_wall_clock_new (); - - g_signal_connect_object (priv->wall_clock, - "notify::clock", - G_CALLBACK (wall_clock_notify_cb), - self, - G_CONNECT_SWAPPED); - - g_signal_connect_object (priv->btn_top_panel, - "clicked", - G_CALLBACK (top_panel_clicked_cb), - self, - G_CONNECT_SWAPPED); - - phosh_connect_feedback (priv->btn_top_panel); - - gtk_window_set_title (GTK_WINDOW (self), "phosh panel"); - gtk_style_context_add_class ( - gtk_widget_get_style_context (GTK_WIDGET (self)), - "phosh-panel"); - - /* Button properites */ - gtk_style_context_remove_class (gtk_widget_get_style_context (priv->btn_top_panel), - "button"); - gtk_style_context_remove_class (gtk_widget_get_style_context (priv->btn_top_panel), - "image-button"); - - wall_clock_notify_cb (self, NULL, priv->wall_clock); - - /* language indicator */ - if (display) { - priv->input_settings = g_settings_new ("org.gnome.desktop.input-sources"); - priv->xkbinfo = gnome_xkb_info_new (); - priv->seat = gdk_display_get_default_seat (display); - g_object_connect (priv->seat, - "swapped_signal::device-added", G_CALLBACK (on_seat_device_changed), self, - "swapped_signal::device-removed", G_CALLBACK (on_seat_device_changed), self, - NULL); - g_signal_connect_swapped (priv->input_settings, - "changed::sources", G_CALLBACK (on_input_setting_changed), - self); - on_input_setting_changed (self, NULL, priv->input_settings); - } - - /* Settings menu and it's top-bar / menu */ - gtk_widget_add_events (GTK_WIDGET (self), GDK_KEY_PRESS_MASK); - g_signal_connect (G_OBJECT (self), - "key-press-event", - G_CALLBACK (on_key_press_event), - NULL); - g_signal_connect (G_OBJECT (self), - "button-press-event", - G_CALLBACK (on_button_press_event), - NULL); - - priv->actions = g_simple_action_group_new (); - gtk_widget_insert_action_group (GTK_WIDGET (self), "panel", - G_ACTION_GROUP (priv->actions)); - g_action_map_add_action_entries (G_ACTION_MAP (priv->actions), - entries, G_N_ELEMENTS (entries), - self); - if (!phosh_shell_started_by_display_manager (phosh_shell_get_default ())) { - GAction *action = g_action_map_lookup_action (G_ACTION_MAP (priv->actions), - "logout"); - g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE); - } -} - - -static void -phosh_panel_dispose (GObject *object) -{ - PhoshPanel *self = PHOSH_PANEL (object); - PhoshPanelPrivate *priv = phosh_panel_get_instance_private (self); - - g_clear_object (&priv->wall_clock); - g_clear_object (&priv->xkbinfo); - g_clear_object (&priv->input_settings); - g_clear_object (&priv->actions); - priv->seat = NULL; - - G_OBJECT_CLASS (phosh_panel_parent_class)->dispose (object); -} - - -static void -phosh_panel_class_init (PhoshPanelClass *klass) -{ - GObjectClass *object_class = (GObjectClass *)klass; - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - object_class->constructed = phosh_panel_constructed; - object_class->dispose = phosh_panel_dispose; - - signals[SETTINGS_ACTIVATED] = g_signal_new ("settings-activated", - G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, - NULL, G_TYPE_NONE, 0); - - g_type_ensure (PHOSH_TYPE_BT_INFO); - g_type_ensure (PHOSH_TYPE_CONNECTIVITY_INFO); - g_type_ensure (PHOSH_TYPE_DOCKED_INFO); - g_type_ensure (PHOSH_TYPE_SETTINGS); - - gtk_widget_class_set_template_from_resource (widget_class, - "/sm/puri/phosh/ui/top-panel.ui"); - gtk_widget_class_bind_template_child_private (widget_class, PhoshPanel, btn_top_panel); - gtk_widget_class_bind_template_child_private (widget_class, PhoshPanel, lbl_clock); - gtk_widget_class_bind_template_child_private (widget_class, PhoshPanel, lbl_lang); - gtk_widget_class_bind_template_child_private (widget_class, PhoshPanel, box); - gtk_widget_class_bind_template_child_private (widget_class, PhoshPanel, stack); - gtk_widget_class_bind_template_child_private (widget_class, PhoshPanel, settings); -} - - -static void -phosh_panel_init (PhoshPanel *self) -{ - gtk_widget_init_template (GTK_WIDGET (self)); -} - - -GtkWidget * -phosh_panel_new (struct zwlr_layer_shell_v1 *layer_shell, - struct wl_output *wl_output) -{ - return g_object_new (PHOSH_TYPE_PANEL, - "layer-shell", layer_shell, - "wl-output", wl_output, - "height", PHOSH_PANEL_HEIGHT, - "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, - "layer", ZWLR_LAYER_SHELL_V1_LAYER_TOP, - "kbd-interactivity", FALSE, - "exclusive-zone", PHOSH_PANEL_HEIGHT, - "namespace", "phosh", - NULL); -} - - -void -phosh_panel_fold (PhoshPanel *self) -{ - PhoshPanelPrivate *priv; - int width; - - g_return_if_fail (PHOSH_IS_PANEL (self)); - priv = phosh_panel_get_instance_private (self); - - if (priv->state == PHOSH_PANEL_STATE_FOLDED) - return; - - gtk_stack_set_transition_type (GTK_STACK (priv->stack), GTK_STACK_TRANSITION_TYPE_SLIDE_UP); - gtk_stack_set_visible_child_name (GTK_STACK (priv->stack), "topbar"); - gtk_widget_hide (priv->settings); - phosh_layer_surface_set_kbd_interactivity (PHOSH_LAYER_SURFACE (self), FALSE); - gtk_window_get_size (GTK_WINDOW (self), &width, NULL); - gtk_window_resize (GTK_WINDOW (self), width, PHOSH_PANEL_HEIGHT); - priv->state = PHOSH_PANEL_STATE_FOLDED; -} - - -void -phosh_panel_unfold (PhoshPanel *self) -{ - PhoshPanelPrivate *priv; - - g_return_if_fail (PHOSH_IS_PANEL (self)); - priv = phosh_panel_get_instance_private (self); - - if (priv->state == PHOSH_PANEL_STATE_UNFOLDED) - return; - - phosh_layer_surface_set_kbd_interactivity (PHOSH_LAYER_SURFACE (self), TRUE); - gtk_widget_show (priv->settings); - gtk_stack_set_transition_type (GTK_STACK (priv->stack), GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN); - gtk_stack_set_visible_child_name(GTK_STACK (priv->stack), "settings"); - g_signal_connect_swapped (priv->settings, - "setting-done", - G_CALLBACK(phosh_panel_fold), - self); - priv->state =PHOSH_PANEL_STATE_UNFOLDED; -} - - -void -phosh_panel_toggle_fold (PhoshPanel *self) -{ - PhoshPanelPrivate *priv; - g_return_if_fail (PHOSH_IS_PANEL (self)); - - priv = phosh_panel_get_instance_private (self); - if (priv->state == PHOSH_PANEL_STATE_UNFOLDED) { - phosh_panel_fold (self); - } else { - phosh_panel_unfold (self); - } -} - - -PhoshPanelState -phosh_panel_get_state (PhoshPanel *self) -{ - PhoshPanelPrivate *priv; - g_return_val_if_fail (PHOSH_IS_PANEL (self), PHOSH_PANEL_STATE_FOLDED); - - priv = phosh_panel_get_instance_private (self); - return priv->state; -} diff -Nru phosh-0.8.0/src/panel.h phosh-0.13.1/src/panel.h --- phosh-0.8.0/src/panel.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/panel.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2018 Purism SPC - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#pragma once - -#include "layersurface.h" - -#define PHOSH_TYPE_PANEL (phosh_panel_get_type ()) - -G_DECLARE_FINAL_TYPE (PhoshPanel, phosh_panel, PHOSH, PANEL, PhoshLayerSurface) - -#define PHOSH_PANEL_HEIGHT 32 - -/** - * PhoshPanelState: - * @PHOSH_PANEL_STATE_FOLDED: Only top-bar is visible - * @PHOSH_PANEL_STATE_UNFOLDED: Settings menu is unfolded - */ -typedef enum { - PHOSH_PANEL_STATE_FOLDED, - PHOSH_PANEL_STATE_UNFOLDED, -} PhoshPanelState; - -GtkWidget * phosh_panel_new (struct zwlr_layer_shell_v1 *layer_shell, - struct wl_output *wl_output); -void phosh_panel_toggle_fold (PhoshPanel *self); -void phosh_panel_fold (PhoshPanel *self); -void phosh_panel_unfold (PhoshPanel *self); -PhoshPanelState phosh_panel_get_state (PhoshPanel *self); diff -Nru phosh-0.8.0/src/phosh-enums.c.in phosh-0.13.1/src/phosh-enums.c.in --- phosh-0.8.0/src/phosh-enums.c.in 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/phosh-enums.c.in 2021-08-31 09:15:52.000000000 +0000 @@ -2,13 +2,18 @@ #include "config.h" +#include "app-grid.h" #include "app-grid-button.h" +#include "gnome-shell-manager.h" #include "home.h" +#include "lockscreen.h" #include "mode-manager.h" #include "monitor/monitor.h" #include "notifications/notification.h" #include "notifications/notify-manager.h" #include "phosh-wayland.h" +#include "rotation-manager.h" +#include "shell.h" #include "wwan/phosh-wwan-backend.h" #include "phosh-enums.h" diff -Nru phosh-0.8.0/src/phosh.gresources.xml phosh-0.13.1/src/phosh.gresources.xml --- phosh-0.8.0/src/phosh.gresources.xml 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/phosh.gresources.xml 2021-08-31 09:15:52.000000000 +0000 @@ -2,8 +2,11 @@ ui/activity.ui + ui/app-auth-prompt.ui ui/app-grid.ui ui/app-grid-button.ui + ui/end-session-dialog.ui + ui/gtk-mount-prompt.ui ui/overview.ui ui/home.ui ui/lockscreen.ui @@ -12,11 +15,15 @@ ui/notification-frame.ui ui/polkit-auth-prompt.ui ui/network-auth-prompt.ui + ui/osd-window.ui ui/settings-menu.ui + ui/system-modal-dialog.ui ui/system-prompt.ui ui/top-panel.ui ui/quick-setting.ui - style.css + stylesheet/adwaita-dark.css + stylesheet/adwaita-hc-light.css + stylesheet/common.css ../data/fake-app.svg @@ -26,8 +33,11 @@ ../data/auth-sim-locked-symbolic.svg ../data/auth-sim-missing-symbolic.svg + ../data/camera-hardware-disabled-symbolic.svg ../data/eye-not-looking-symbolic.svg ../data/eye-open-negative-filled-symbolic.svg + ../data/feedback-quiet-symbolic.svg + ../data/microphone-hardware-disabled-symbolic.svg ../data/network-cellular-disabled-symbolic.svg ../data/network-wireless-disabled-symbolic.svg ../data/phone-docked-symbolic.svg diff -Nru phosh-0.8.0/src/phosh-wayland.c phosh-0.13.1/src/phosh-wayland.c --- phosh-0.8.0/src/phosh-wayland.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/phosh-wayland.c 2021-08-31 09:15:52.000000000 +0000 @@ -38,6 +38,7 @@ struct gamma_control_manager *gamma_control_manager; struct org_kde_kwin_idle *idle_manager; struct phosh_private *phosh_private; + struct zwp_virtual_keyboard_manager_v1 *zwp_virtual_keyboard_manager_v1; struct wl_display *display; struct wl_registry *registry; struct wl_seat *wl_seat; @@ -48,6 +49,7 @@ struct zwlr_output_manager_v1 *zwlr_output_manager_v1; struct zwlr_output_power_manager_v1 *zwlr_output_power_manager_v1; struct zxdg_output_manager_v1 *zxdg_output_manager_v1; + struct zwlr_screencopy_manager_v1 *zwlr_screencopy_manager_v1; struct wl_shm *wl_shm; GHashTable *wl_outputs; PhoshWaylandSeatCapabilities seat_capabilities; @@ -142,6 +144,18 @@ name, &zwlr_foreign_toplevel_manager_v1_interface, 2); + } else if (!strcmp (interface, zwlr_screencopy_manager_v1_interface.name)) { + self->zwlr_screencopy_manager_v1 = wl_registry_bind ( + registry, + name, + &zwlr_screencopy_manager_v1_interface, + 2); + } else if (!strcmp (interface, zwp_virtual_keyboard_manager_v1_interface.name)) { + self->zwp_virtual_keyboard_manager_v1 = wl_registry_bind ( + registry, + name, + &zwp_virtual_keyboard_manager_v1_interface, + 1); } } @@ -436,6 +450,24 @@ return self->zwlr_foreign_toplevel_manager_v1; } + +struct zwlr_screencopy_manager_v1* +phosh_wayland_get_zwlr_screencopy_manager_v1 (PhoshWayland *self) +{ + g_return_val_if_fail (PHOSH_IS_WAYLAND (self), NULL); + + return self->zwlr_screencopy_manager_v1; +} + +struct zwp_virtual_keyboard_manager_v1* +phosh_wayland_get_zwp_virtual_keyboard_manager_v1 (PhoshWayland *self) +{ + g_return_val_if_fail (PHOSH_IS_WAYLAND (self), NULL); + + return self->zwp_virtual_keyboard_manager_v1; +} + + /** * phosh_wayland_get_wl_outputs: * @self: The #PhoshWayland singleton diff -Nru phosh-0.8.0/src/phosh-wayland.h phosh-0.13.1/src/phosh-wayland.h --- phosh-0.8.0/src/phosh-wayland.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/phosh-wayland.h 2021-08-31 09:15:52.000000000 +0000 @@ -9,16 +9,20 @@ #include "gamma-control-client-protocol.h" #include "idle-client-protocol.h" -#include "wlr-screencopy-unstable-v1-client-protocol.h" -#include "phosh-private-client-protocol.h" +#include "virtual-keyboard-unstable-v1-client-protocol.h" #include "wlr-foreign-toplevel-management-unstable-v1-client-protocol.h" #include "wlr-input-inhibitor-unstable-v1-client-protocol.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "wlr-output-management-unstable-v1-client-protocol.h" #include "wlr-output-power-management-unstable-v1-client-protocol.h" +#include "wlr-screencopy-unstable-v1-client-protocol.h" +#include "wlr-screencopy-unstable-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h" #include "xdg-shell-client-protocol.h" +/* This goes past the other wl protocols since it might need their structs */ +#include "phosh-private-client-protocol.h" + #include G_BEGIN_DECLS @@ -59,6 +63,8 @@ struct zwlr_output_manager_v1 *phosh_wayland_get_zwlr_output_manager_v1 (PhoshWayland *self); struct zwlr_output_power_manager_v1 *phosh_wayland_get_zwlr_output_power_manager_v1 (PhoshWayland *self); struct zxdg_output_manager_v1 *phosh_wayland_get_zxdg_output_manager_v1 (PhoshWayland *self); +struct zwlr_screencopy_manager_v1 *phosh_wayland_get_zwlr_screencopy_manager_v1 (PhoshWayland *self); +struct zwp_virtual_keyboard_manager_v1 *phosh_wayland_get_zwp_virtual_keyboard_manager_v1 (PhoshWayland *self); void phosh_wayland_roundtrip (PhoshWayland *self); PhoshWaylandSeatCapabilities phosh_wayland_get_seat_capabilities (PhoshWayland *self); diff -Nru phosh-0.8.0/src/polkit-auth-agent.c phosh-0.13.1/src/polkit-auth-agent.c --- phosh-0.8.0/src/polkit-auth-agent.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/polkit-auth-agent.c 2021-08-31 09:15:52.000000000 +0000 @@ -11,7 +11,6 @@ #include "polkit-auth-agent.h" #include "polkit-auth-prompt.h" #include "shell.h" -#include "phosh-wayland.h" #include #include @@ -65,27 +64,30 @@ static gboolean agent_register (PhoshPolkitAuthAgent *self) { - GError *err = NULL; - g_autoptr(PolkitSubject) subject; + g_autoptr (GError) err = NULL; + g_autoptr (PolkitSubject) subject; subject = polkit_unix_session_new_for_process_sync (getpid (), - NULL, /* GCancellable* */ + NULL, /* GCancellable */ &err); if (subject == NULL) { - g_warning("PolKit failed to properly get our session"); + if (g_str_has_prefix (err->message, "No session for pid")) + g_message ("PolKit failed to properly get our session: %s", err->message); + else + g_warning ("PolKit failed to properly get our session: %s", err->message); return FALSE; } /* FIXME: this blocks so we should do it async */ self->handle = polkit_agent_listener_register (POLKIT_AGENT_LISTENER (self), - POLKIT_AGENT_REGISTER_FLAGS_NONE, - subject, - NULL, /* use default object path */ - NULL, /* GCancellable */ - &err); + POLKIT_AGENT_REGISTER_FLAGS_NONE, + subject, + NULL, /* use default object path */ + NULL, /* GCancellable */ + &err); if (!self->handle) { - g_warning("Auth agent failed to register: %s", err->message); + g_warning ("Auth agent failed to register: %s", err->message); return FALSE; } @@ -131,9 +133,6 @@ static void auth_request_initiate (AuthRequest *request) { - PhoshWayland *wl = phosh_wayland_get_default (); - PhoshShell *shell = phosh_shell_get_default (); - PhoshMonitor *primary_monitor; g_auto(GStrv) user_names; GPtrArray *p; GList *l; @@ -167,8 +166,7 @@ user_names = (char **) g_ptr_array_free (p, FALSE); g_debug("New prompt for %s", request->message); - primary_monitor = phosh_shell_get_primary_monitor (shell); - /* We must not issue a new prompt when there's one alread */ + /* We must not issue a new prompt when there's one already */ g_return_if_fail (!request->agent->current_prompt); request->agent->current_prompt = PHOSH_POLKIT_AUTH_PROMPT ( phosh_polkit_auth_prompt_new ( @@ -176,9 +174,7 @@ request->message, request->icon_name, request->cookie, - user_names, - phosh_wayland_get_zwlr_layer_shell_v1(wl), - primary_monitor->wl_output)); + user_names)); g_signal_connect (request->agent->current_prompt, "done", @@ -195,8 +191,8 @@ maybe_process_next_request (PhoshPolkitAuthAgent *self) { auth_debug ("cur=%p len(scheduled)=%d", - self->current_request, - g_list_length (self->scheduled_requests)); + self->current_request, + g_list_length (self->scheduled_requests)); if (self->current_request == NULL && self->scheduled_requests != NULL) { AuthRequest *request; @@ -219,7 +215,7 @@ gboolean is_current = self->current_request == request; auth_debug ("completing %s %s cookie %s", is_current ? "current" : "scheduled", - request->action_id, request->cookie); + request->action_id, request->cookie); if (!is_current) self->scheduled_requests = g_list_remove (self->scheduled_requests, request); @@ -256,7 +252,7 @@ } /* - * on_request_canelled: + * on_request_cancelled: * * This happens when the application requesting authentication * is closed. diff -Nru phosh-0.8.0/src/polkit-auth-prompt.c phosh-0.13.1/src/polkit-auth-prompt.c --- phosh-0.8.0/src/polkit-auth-prompt.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/polkit-auth-prompt.c 2021-08-31 09:15:52.000000000 +0000 @@ -51,7 +51,7 @@ struct _PhoshPolkitAuthPrompt { - PhoshLayerSurface parent; + PhoshSystemModalDialog parent; GtkWidget *lbl_message; GtkWidget *lbl_user_name; @@ -75,7 +75,7 @@ gboolean done_emitted; }; -G_DEFINE_TYPE(PhoshPolkitAuthPrompt, phosh_polkit_auth_prompt, PHOSH_TYPE_LAYER_SURFACE); +G_DEFINE_TYPE(PhoshPolkitAuthPrompt, phosh_polkit_auth_prompt, PHOSH_TYPE_SYSTEM_MODAL_DIALOG); static void phosh_polkit_auth_prompt_initiate (PhoshPolkitAuthPrompt *self); @@ -289,7 +289,7 @@ PolkitAgentSession *session) { g_debug ("%s", text); - gtk_entry_set_text (GTK_ENTRY (self->lbl_info), text); + gtk_label_set_text (GTK_LABEL (self->lbl_info), text); } @@ -299,7 +299,7 @@ PolkitAgentSession *session) { g_debug ("%s", text); - gtk_entry_set_text (GTK_ENTRY (self->lbl_info), text); + gtk_label_set_text (GTK_LABEL (self->lbl_info), text); } @@ -365,8 +365,10 @@ static void -on_btn_cancel_clicked (PhoshPolkitAuthPrompt *self, GtkButton *btn) +on_dialog_canceled (PhoshPolkitAuthPrompt *self, gpointer unused) { + g_return_if_fail (PHOSH_IS_POLKIT_AUTH_PROMPT (self)); + polkit_agent_session_cancel (self->session); emit_done (self, TRUE); } @@ -389,27 +391,6 @@ } -static gboolean -on_key_press_event (PhoshPolkitAuthPrompt *self, GdkEventKey *event, gpointer data) -{ - gboolean handled = FALSE; - g_return_val_if_fail (PHOSH_IS_POLKIT_AUTH_PROMPT (self), FALSE); - - switch (event->keyval) { - case GDK_KEY_Escape: - polkit_agent_session_cancel (self->session); - emit_done (self, TRUE); - handled = TRUE; - break; - default: - /* nothing to do */ - break; - } - - return handled; -} - - static void phosh_polkit_auth_prompt_dispose (GObject *obj) { @@ -448,35 +429,6 @@ gtk_entry_set_buffer (GTK_ENTRY (self->entry_password), GTK_ENTRY_BUFFER (self->password_buffer)); - g_signal_connect_object (self->btn_cancel, - "clicked", - G_CALLBACK (on_btn_cancel_clicked), - self, - G_CONNECT_SWAPPED); - g_signal_connect_object (self->btn_authenticate, - "clicked", - G_CALLBACK (on_btn_authenticate_clicked), - self, - G_CONNECT_SWAPPED); - - gtk_widget_add_events (GTK_WIDGET (self), GDK_KEY_PRESS_MASK); - g_signal_connect (G_OBJECT (self), - "key_press_event", - G_CALLBACK (on_key_press_event), - NULL); - - { - GtkWidget *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); - GtkWidget *lbl = gtk_label_new (_("Authenticate")); - - self->spinner_authenticate = gtk_spinner_new (); - gtk_widget_set_no_show_all (self->spinner_authenticate, TRUE); - gtk_container_add (GTK_CONTAINER (self->btn_authenticate), box); - gtk_container_add (GTK_CONTAINER (box), self->spinner_authenticate); - gtk_container_add (GTK_CONTAINER (box), lbl); - gtk_widget_show_all (self->btn_authenticate); - } - phosh_polkit_auth_prompt_initiate (self); } @@ -546,6 +498,9 @@ gtk_widget_class_bind_template_child (widget_class, PhoshPolkitAuthPrompt, btn_authenticate); gtk_widget_class_bind_template_child (widget_class, PhoshPolkitAuthPrompt, btn_cancel); gtk_widget_class_bind_template_child (widget_class, PhoshPolkitAuthPrompt, entry_password); + gtk_widget_class_bind_template_child (widget_class, PhoshPolkitAuthPrompt, spinner_authenticate); + gtk_widget_class_bind_template_callback (widget_class, on_dialog_canceled); + gtk_widget_class_bind_template_callback (widget_class, on_btn_authenticate_clicked); } @@ -561,9 +516,7 @@ const char *message, const char *icon_name, const char *cookie, - GStrv user_names, - gpointer layer_shell, - gpointer wl_output) + GStrv user_names) { return g_object_new (PHOSH_TYPE_POLKIT_AUTH_PROMPT, /* polkit prompt */ @@ -572,16 +525,5 @@ "message", message, "icon-name", icon_name, "user-names", user_names, - /* layer shell */ - "layer-shell", layer_shell, - "wl-output", wl_output, - "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, - "layer", ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, - "kbd-interactivity", TRUE, - "exclusive-zone", -1, - "namespace", "phosh prompter", NULL); } diff -Nru phosh-0.8.0/src/polkit-auth-prompt.h phosh-0.13.1/src/polkit-auth-prompt.h --- phosh-0.8.0/src/polkit-auth-prompt.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/polkit-auth-prompt.h 2021-08-31 09:15:52.000000000 +0000 @@ -7,18 +7,16 @@ #pragma once #include -#include "layersurface.h" +#include "system-modal-dialog.h" #define PHOSH_TYPE_POLKIT_AUTH_PROMPT (phosh_polkit_auth_prompt_get_type()) -G_DECLARE_FINAL_TYPE (PhoshPolkitAuthPrompt, phosh_polkit_auth_prompt, PHOSH, POLKIT_AUTH_PROMPT, PhoshLayerSurface); +G_DECLARE_FINAL_TYPE (PhoshPolkitAuthPrompt, phosh_polkit_auth_prompt, PHOSH, POLKIT_AUTH_PROMPT, PhoshSystemModalDialog); GtkWidget *phosh_polkit_auth_prompt_new (const char *action_id, const char *message, const char *icon_name, const char *cookie, - GStrv user_names, - gpointer layer_shell, - gpointer wl_output); + GStrv user_names); diff -Nru phosh-0.8.0/src/proximity.c phosh-0.13.1/src/proximity.c --- phosh-0.8.0/src/proximity.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/proximity.c 2021-08-31 09:15:52.000000000 +0000 @@ -19,13 +19,16 @@ * SECTION:proximity * @short_description: Proximity sensor handling * @Title: PhoshProximity + * + * #PhoshProximity handles enabling and disabling the proximity detection + * based on e.g. active calls. */ enum { PROP_0, PROP_SENSOR_PROXY_MANAGER, - PROP_LOCKSCREEN_MANAGER, + PROP_CALLS_MANAGER, LAST_PROP, }; static GParamSpec *props[LAST_PROP]; @@ -35,7 +38,7 @@ gboolean claimed; PhoshSensorProxyManager *sensor_proxy_manager; - PhoshLockscreenManager *lockscreen_manager; + PhoshCallsManager *calls_manager; PhoshFader *fader; } PhoshProximity; @@ -65,6 +68,7 @@ } } + static void on_proximity_released (PhoshSensorProxyManager *sensor_proxy_manager, GAsyncResult *res, @@ -86,8 +90,10 @@ } else { g_warning ("Failed to release proximity sensor: %s", err->message); } + g_clear_pointer (&self->fader, phosh_cp_widget_destroy); } + static void phosh_proximity_claim_proximity (PhoshProximity *self, gboolean claim) { @@ -117,28 +123,32 @@ { gboolean has_proximity; - /* Don't claim if locked to save power */ - if (phosh_lockscreen_manager_get_locked(self->lockscreen_manager)) - return; - has_proximity = phosh_dbus_sensor_proxy_get_has_proximity ( PHOSH_DBUS_SENSOR_PROXY (self->sensor_proxy_manager)); g_debug ("Found %s proximity sensor", has_proximity ? "a" : "no"); + + /* If prox went a way we always unclaim but only claim on ongoing calls: */ + if (!phosh_calls_manager_get_active_call_handle (self->calls_manager) && has_proximity) + return; + phosh_proximity_claim_proximity (self, has_proximity); } + static void -on_lockscreen_manager_locked (PhoshProximity *self, GParamSpec *pspec, - PhoshLockscreenManager *lockscreen_manager) +on_calls_manager_active_call_changed (PhoshProximity *self, + GParamSpec *pspec, + PhoshCallsManager *calls_manager) { - gboolean locked; + gboolean active; g_return_if_fail (PHOSH_IS_PROXIMITY (self)); - g_return_if_fail (PHOSH_IS_LOCKSCREEN_MANAGER (lockscreen_manager)); + g_return_if_fail (PHOSH_IS_CALLS_MANAGER (calls_manager)); - locked = phosh_lockscreen_manager_get_locked(self->lockscreen_manager); - phosh_proximity_claim_proximity (self, !locked); + active = !!phosh_calls_manager_get_active_call_handle (self->calls_manager); + phosh_proximity_claim_proximity (self, active); + /* TODO: if call is over wait until we hit the threshold */ } @@ -148,19 +158,19 @@ PhoshSensorProxyManager *sensor) { gboolean near; + PhoshShell *shell = phosh_shell_get_default (); + PhoshMonitor *monitor = phosh_shell_get_builtin_monitor (shell); near = phosh_dbus_sensor_proxy_get_proximity_near ( PHOSH_DBUS_SENSOR_PROXY (self->sensor_proxy_manager)); g_debug ("Proximity near changed: %d", near); - if (near) { - PhoshShell *shell = phosh_shell_get_default (); - PhoshWayland *wl = phosh_wayland_get_default (); - PhoshMonitor *monitor = phosh_shell_get_builtin_monitor (shell); - + if (near && monitor) { if (!self->fader) { - self->fader = phosh_fader_new (phosh_wayland_get_zwlr_layer_shell_v1 (wl), - monitor->wl_output); + self->fader = g_object_new (PHOSH_TYPE_FADER, + "monitor", monitor, + "style-class", "phosh-fader-proximity-fade", + NULL); gtk_widget_show (GTK_WIDGET (self->fader)); } } else { @@ -181,9 +191,9 @@ /* construct only */ self->sensor_proxy_manager = g_value_dup_object (value); break; - case PROP_LOCKSCREEN_MANAGER: + case PROP_CALLS_MANAGER: /* construct only */ - self->lockscreen_manager = g_value_dup_object (value); + self->calls_manager = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -191,6 +201,7 @@ } } + static void phosh_proximity_get_property (GObject *object, guint property_id, @@ -203,8 +214,8 @@ case PROP_SENSOR_PROXY_MANAGER: g_value_set_object (value, self->sensor_proxy_manager); break; - case PROP_LOCKSCREEN_MANAGER: - g_value_set_object (value, self->lockscreen_manager); + case PROP_CALLS_MANAGER: + g_value_set_object (value, self->calls_manager); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -212,14 +223,15 @@ } } + static void phosh_proximity_constructed (GObject *object) { PhoshProximity *self = PHOSH_PROXIMITY (object); - g_signal_connect_swapped (self->lockscreen_manager, - "notify::locked", - G_CALLBACK (on_lockscreen_manager_locked), + g_signal_connect_swapped (self->calls_manager, + "notify::active-call", + G_CALLBACK (on_calls_manager_active_call_changed), self); g_signal_connect_swapped (self->sensor_proxy_manager, @@ -236,6 +248,7 @@ G_OBJECT_CLASS (phosh_proximity_parent_class)->constructed (object); } + static void phosh_proximity_dispose (GObject *object) { @@ -249,16 +262,17 @@ g_clear_object (&self->sensor_proxy_manager); } - if (self->lockscreen_manager) { - g_signal_handlers_disconnect_by_data (self->lockscreen_manager, + if (self->calls_manager) { + g_signal_handlers_disconnect_by_data (self->calls_manager, self); - g_clear_object (&self->lockscreen_manager); + g_clear_object (&self->calls_manager); } g_clear_pointer (&self->fader, phosh_cp_widget_destroy); G_OBJECT_CLASS (phosh_proximity_parent_class)->dispose (object); } + static void phosh_proximity_class_init (PhoshProximityClass *klass) { @@ -278,18 +292,19 @@ PHOSH_TYPE_SENSOR_PROXY_MANAGER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - props[PROP_LOCKSCREEN_MANAGER] = + props[PROP_CALLS_MANAGER] = g_param_spec_object ( - "lockscreen-manager", - "Lockscren manager", - "The object managing the lock screen", - PHOSH_TYPE_LOCKSCREEN_MANAGER, + "calls-manager", + "", + "", + PHOSH_TYPE_CALLS_MANAGER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); } + static void phosh_proximity_init (PhoshProximity *self) { @@ -298,10 +313,10 @@ PhoshProximity * phosh_proximity_new (PhoshSensorProxyManager *sensor_proxy_manager, - PhoshLockscreenManager *lockscreen_manager) + PhoshCallsManager *calls_manager) { return g_object_new (PHOSH_TYPE_PROXIMITY, "sensor-proxy-manager", sensor_proxy_manager, - "lockscreen-manager", lockscreen_manager, + "calls-manager", calls_manager, NULL); } diff -Nru phosh-0.8.0/src/proximity.h phosh-0.13.1/src/proximity.h --- phosh-0.8.0/src/proximity.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/proximity.h 2021-08-31 09:15:52.000000000 +0000 @@ -6,7 +6,7 @@ #pragma once -#include "lockscreen-manager.h" +#include "calls-manager.h" #include "sensor-proxy-manager.h" G_BEGIN_DECLS @@ -16,6 +16,6 @@ G_DECLARE_FINAL_TYPE (PhoshProximity, phosh_proximity, PHOSH, PROXIMITY, GObject); PhoshProximity *phosh_proximity_new (PhoshSensorProxyManager *sensor_proxy_manager, - PhoshLockscreenManager *lockscreen_manager); + PhoshCallsManager *calls_manager); G_END_DECLS diff -Nru phosh-0.8.0/src/rotateinfo.c phosh-0.13.1/src/rotateinfo.c --- phosh-0.8.0/src/rotateinfo.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/rotateinfo.c 2021-08-31 09:15:52.000000000 +0000 @@ -15,29 +15,45 @@ /** * SECTION:rotateinfo - * @short_description: A widget to display the rotate status + * @short_description: A widget to display the rotate lock status * @Title: PhoshRotateInfo * - * Rotate Info widget + * A #PhoshStatusIcon to display the rotation lock status. + * It can either display whether a rotation lock is currently active or + * if the output is in portrait/landscape mode. */ +enum { + PROP_0, + PROP_PRESENT, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + typedef struct _PhoshRotateInfo { - PhoshStatusIcon parent; + PhoshStatusIcon parent; + + PhoshRotationManager *manager; + gboolean present; } PhoshRotateInfo; G_DEFINE_TYPE (PhoshRotateInfo, phosh_rotate_info, PHOSH_TYPE_STATUS_ICON) - static void -set_state (PhoshRotateInfo *self) +on_transform_changed (PhoshRotateInfo *self) { - PhoshShell *shell = phosh_shell_get_default (); - PhoshMonitor *monitor = phosh_shell_get_primary_monitor (shell); + PhoshMonitor *monitor = phosh_rotation_manager_get_monitor (self->manager); gboolean monitor_is_landscape; gboolean portrait; - switch (phosh_shell_get_transform (shell)) { + if (phosh_rotation_manager_get_mode (self->manager) != PHOSH_ROTATION_MANAGER_MODE_OFF) + return; + + if (!monitor) + return; + + switch (phosh_rotation_manager_get_transform (self->manager)) { case PHOSH_MONITOR_TRANSFORM_NORMAL: case PHOSH_MONITOR_TRANSFORM_FLIPPED: case PHOSH_MONITOR_TRANSFORM_180: @@ -59,7 +75,7 @@ monitor_is_landscape = ((double)monitor->width / (double)monitor->height) > 1.0; portrait = monitor_is_landscape ? !portrait : portrait; - g_debug ("Potrait: %d, width: %d, height: %d", portrait, monitor->width , monitor->height); + g_debug ("Potrait: %d, width: %d, height: %d", portrait, monitor->width, monitor->height); if (portrait) { phosh_status_icon_set_icon_name (PHOSH_STATUS_ICON (self), "screen-rotation-portrait-symbolic"); phosh_status_icon_set_info (PHOSH_STATUS_ICON (self), _("Portrait")); @@ -71,13 +87,69 @@ static void -phosh_rotate_info_finalize (GObject *object) +on_orientation_lock_changed (PhoshRotateInfo *self) +{ + gboolean locked = phosh_rotation_manager_get_orientation_locked (self->manager); + const char *icon_name; + + if (phosh_rotation_manager_get_mode (self->manager) != PHOSH_ROTATION_MANAGER_MODE_SENSOR) + return; + + g_debug ("Orientation locked: %d", locked); + + icon_name = locked ? "rotation-locked-symbolic" : "rotation-allowed-symbolic"; + phosh_status_icon_set_icon_name (PHOSH_STATUS_ICON (self), icon_name); + /* Translators: Automatic screen orientation is either on (enabled) or off (locked/disabled) */ + phosh_status_icon_set_info (PHOSH_STATUS_ICON (self), locked ? _("Off") : _("On")); + + return; +} + + +static void +on_mode_or_monitor_changed (PhoshRotateInfo *self) { - PhoshRotateInfo *self = PHOSH_ROTATE_INFO(object); + PhoshRotationManagerMode mode = phosh_rotation_manager_get_mode (self->manager); + gboolean present = !!phosh_rotation_manager_get_monitor (self->manager); + + g_debug ("Rotation manager mode: %d, has-builtin: %d", mode, present); + switch (mode) { + case PHOSH_ROTATION_MANAGER_MODE_OFF: + on_transform_changed (self); + break; + case PHOSH_ROTATION_MANAGER_MODE_SENSOR: + on_orientation_lock_changed (self); + break; + default: + g_assert_not_reached (); + } + + if (self->present == present) + return; + + self->present = present; + g_debug ("Built-in monitor present: %d", present); + + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PRESENT]); +} - g_signal_handlers_disconnect_by_data (phosh_shell_get_default (), self); - G_OBJECT_CLASS (phosh_rotate_info_parent_class)->finalize (object); +static void +phosh_rotate_info_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshRotateInfo *self = PHOSH_ROTATE_INFO (object); + + switch (property_id) { + case PROP_PRESENT: + g_value_set_boolean (value, self->present); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } } @@ -85,23 +157,55 @@ phosh_rotate_info_class_init (PhoshRotateInfoClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->finalize = phosh_rotate_info_finalize; + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->get_property = phosh_rotate_info_get_property; + + gtk_widget_class_set_css_name (widget_class, "phosh-rotate-info"); + + props[PROP_PRESENT] = + g_param_spec_boolean ("present", + "Present", + "Whether a builtin display to rotate is present", + FALSE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); } static void phosh_rotate_info_init (PhoshRotateInfo *self) { - g_signal_connect_swapped (phosh_shell_get_default (), - "notify::transform", - G_CALLBACK (set_state), - self); - set_state (self); -} + self->manager = phosh_shell_get_rotation_manager (phosh_shell_get_default()); + phosh_status_icon_set_icon_name (PHOSH_STATUS_ICON (self), "rotation-locked-symbolic"); + /* Translators: Automatic screen orientation is off (locked/disabled) */ + phosh_status_icon_set_info (PHOSH_STATUS_ICON (self), _("Off")); + + /* We don't use property bindings since we flip info/icon based on rotation and lock */ + g_signal_connect_object (self->manager, + "notify::transform", + G_CALLBACK (on_transform_changed), + self, + G_CONNECT_SWAPPED); + g_signal_connect_object (self->manager, + "notify::orientation-locked", + G_CALLBACK (on_orientation_lock_changed), + self, + G_CONNECT_SWAPPED); + g_signal_connect_object (self->manager, + "notify::mode", + G_CALLBACK (on_mode_or_monitor_changed), + self, + G_CONNECT_SWAPPED); + g_signal_connect_object (self->manager, + "notify::monitor", + G_CALLBACK (on_mode_or_monitor_changed), + self, + G_CONNECT_SWAPPED); -GtkWidget * -phosh_rotate_info_new (void) -{ - return g_object_new (PHOSH_TYPE_ROTATE_INFO, NULL); + on_mode_or_monitor_changed (self); } diff -Nru phosh-0.8.0/src/rotateinfo.h phosh-0.13.1/src/rotateinfo.h --- phosh-0.8.0/src/rotateinfo.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/rotateinfo.h 2021-08-31 09:15:52.000000000 +0000 @@ -11,10 +11,24 @@ G_BEGIN_DECLS +/** + * PhoshRotateInfoMode: + * @PHOSH_ROTATE_INFO_MODE_LOCK: Button toggles rotation lock + * @PHOSH_ROTATE_INFO_MODE_TOGGLE: Button toggles potrait/landscape + * + * The power save mode of a monitor + */ +typedef enum { + PHOSH_ROTATE_INFO_MODE_LOCK, + PHOSH_ROTATE_INFO_MODE_TOGGLE, +} PhoshRotateInfoMode; + #define PHOSH_TYPE_ROTATE_INFO (phosh_rotate_info_get_type()) G_DECLARE_FINAL_TYPE (PhoshRotateInfo, phosh_rotate_info, PHOSH, ROTATE_INFO, PhoshStatusIcon) -GtkWidget * phosh_rotate_info_new (void); +GtkWidget *phosh_rotate_info_new (void); +PhoshRotateInfoMode phosh_rotate_info_get_mode (PhoshRotateInfo *self); +void phosh_rotate_info_set_mode (PhoshRotateInfo *self, PhoshRotateInfoMode mode); G_END_DECLS diff -Nru phosh-0.8.0/src/rotation-manager.c phosh-0.13.1/src/rotation-manager.c --- phosh-0.8.0/src/rotation-manager.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/rotation-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,709 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-rotation-manager" + +#include "config.h" +#include "rotation-manager.h" +#include "shell.h" +#include "sensor-proxy-manager.h" +#include "util.h" + +#define ORIENTATION_LOCK_SCHEMA_ID "org.gnome.settings-daemon.peripherals.touchscreen" +#define ORIENTATION_LOCK_KEY "orientation-lock" + +/** + * SECTION:rotation-manager + * @short_description: The Rotation Manager + * @Title: PhoshRotationManager + * + * #PhoshRotationManager is responsible for managing the rotation of + * a given #PhoshMonitor. Depending on the #PhoshRotationManagerMode + * this can happen by interfacing with a #PhoshSensorProxyManager or + * by setting the #PhoshMonitorTransform explicitly. + * It also takes the #PhoshLockscreenManager:locked status into account + * to ensure the lockscreen is rotated accordingly on small phones. + */ + +enum { + PROP_0, + PROP_SENSOR_PROXY_MANAGER, + PROP_LOCKSCREEN_MANAGER, + PROP_ORIENTATION_LOCKED, + PROP_MONITOR, + PROP_MODE, + PROP_TRANSFORM, + LAST_PROP, +}; +static GParamSpec *props[LAST_PROP]; + +typedef struct _PhoshRotationManager { + GObject parent; + + gboolean claimed; + GCancellable *cancel; + PhoshSensorProxyManager *sensor_proxy_manager; + PhoshLockscreenManager *lockscreen_manager; + PhoshMonitor *monitor; + PhoshMonitorTransform transform; + PhoshMonitorTransform prelock_transform; + + GSettings *settings; + gboolean orientation_locked; + + PhoshRotationManagerMode mode; +} PhoshRotationManager; + +G_DEFINE_TYPE (PhoshRotationManager, phosh_rotation_manager, G_TYPE_OBJECT); + + +static void +apply_transform (PhoshRotationManager *self, PhoshMonitorTransform transform) +{ + PhoshMonitorTransform current; + PhoshMonitorManager *monitor_manager = phosh_shell_get_monitor_manager (phosh_shell_get_default()); + + g_return_if_fail (PHOSH_IS_MONITOR_MANAGER (monitor_manager)); + + if (!self->monitor) + return; + + g_debug ("Rotating %s: %d", self->monitor->name, transform); + + current = phosh_monitor_get_transform (self->monitor); + if (current == transform) + return; + + phosh_monitor_manager_set_monitor_transform (monitor_manager, + self->monitor, + transform); + phosh_monitor_manager_apply_monitor_config (monitor_manager); +} + +/** + * match_orientation: + * @self: The #PhoshRotationManager + * + * Match the screen orientation to the sensor output. + * Do nothing if orientation lock is on or there's no + * sensor claimed. + */ +static void +match_orientation (PhoshRotationManager *self) +{ + const gchar *orient; + PhoshMonitorTransform transform; + + if (self->orientation_locked || !self->claimed || + self->mode == PHOSH_ROTATION_MANAGER_MODE_OFF) + return; + + orient = phosh_dbus_sensor_proxy_get_accelerometer_orientation ( + PHOSH_DBUS_SENSOR_PROXY (self->sensor_proxy_manager)); + + g_debug ("Orientation changed: %s, locked: %d, claimed: %d", + orient, self->orientation_locked, self->claimed); + + if (!g_strcmp0 ("normal", orient)) { + transform = PHOSH_MONITOR_TRANSFORM_NORMAL; + } else if (!g_strcmp0 ("right-up", orient)) { + transform = PHOSH_MONITOR_TRANSFORM_270; + } else if (!g_strcmp0 ("bottom-up", orient)) { + transform = PHOSH_MONITOR_TRANSFORM_180; + } else if (!g_strcmp0 ("left-up", orient)) { + transform = PHOSH_MONITOR_TRANSFORM_90; + } else if (!g_strcmp0 ("undefined", orient)) { + return; /* just leave as is */ + } else { + g_warning ("Unknown orientation '%s'", orient); + return; + } + + apply_transform (self, transform); +} + +static void +on_accelerometer_claimed (PhoshSensorProxyManager *sensor_proxy_manager, + GAsyncResult *res, + PhoshRotationManager *self) +{ + g_autoptr (GError) err = NULL; + gboolean success; + + g_return_if_fail (PHOSH_IS_SENSOR_PROXY_MANAGER (sensor_proxy_manager)); + + success = phosh_dbus_sensor_proxy_call_claim_accelerometer_finish ( + PHOSH_DBUS_SENSOR_PROXY (sensor_proxy_manager), + res, &err); + + if (!success) { + phosh_async_error_warn (err, "Failed to claim accelerometer"); + return; + } + + g_return_if_fail (PHOSH_IS_ROTATION_MANAGER (self)); + g_return_if_fail (sensor_proxy_manager == self->sensor_proxy_manager); + + g_debug ("Claimed accelerometer"); + self->claimed = TRUE; + match_orientation (self); +} + +static void +on_accelerometer_released (PhoshSensorProxyManager *sensor_proxy_manager, + GAsyncResult *res, + PhoshRotationManager *self) +{ + g_autoptr (GError) err = NULL; + gboolean success; + + g_return_if_fail (PHOSH_IS_SENSOR_PROXY_MANAGER (sensor_proxy_manager)); + + success = phosh_dbus_sensor_proxy_call_release_accelerometer_finish ( + PHOSH_DBUS_SENSOR_PROXY (sensor_proxy_manager), + res, &err); + + if (!success) { + phosh_async_error_warn (err, "Failed to release accelerometer"); + return; + } + + g_debug ("Released rotation sensor"); + self->claimed = FALSE; +} + +static void +phosh_rotation_manager_claim_accelerometer (PhoshRotationManager *self, gboolean claim) +{ + if (claim == self->claimed) + return; + + if (!self->sensor_proxy_manager) + return; + + if (claim) { + phosh_dbus_sensor_proxy_call_claim_accelerometer ( + PHOSH_DBUS_SENSOR_PROXY (self->sensor_proxy_manager), + self->cancel, + (GAsyncReadyCallback)on_accelerometer_claimed, + self); + } else { + phosh_dbus_sensor_proxy_call_release_accelerometer ( + PHOSH_DBUS_SENSOR_PROXY (self->sensor_proxy_manager), + self->cancel, + (GAsyncReadyCallback)on_accelerometer_released, + self); + } +} + +static void +on_has_accelerometer_changed (PhoshRotationManager *self, + GParamSpec *pspec, + PhoshSensorProxyManager *proxy) +{ + gboolean has_accel; + PhoshRotationManagerMode mode; + + has_accel = phosh_dbus_sensor_proxy_get_has_accelerometer ( + PHOSH_DBUS_SENSOR_PROXY (self->sensor_proxy_manager)); + + g_debug ("Found %s accelerometer", has_accel ? "a" : "no"); + + mode = has_accel ? PHOSH_ROTATION_MANAGER_MODE_SENSOR : PHOSH_ROTATION_MANAGER_MODE_OFF; + phosh_rotation_manager_set_mode (self, mode); +} + +/** + * fixup_lockscreen_orientation: + * @self: The PhoshRotationManager + * @force: Whether to force the monitor to portait orientation + * + * On phones the lock screen doesn't work in landscape so fix that up + * until https://source.puri.sm/Librem5/phosh/-/issues/388 + * is fixed. Keep all of this local to this function. + */ +static void +fixup_lockscreen_orientation (PhoshRotationManager *self, gboolean force) +{ + PhoshShell *shell = phosh_shell_get_default (); + PhoshModeManager *mode_manager = phosh_shell_get_mode_manager(shell); + + g_return_if_fail (PHOSH_IS_MODE_MANAGER (mode_manager)); + + if (!self->monitor) + return; + + /* Only bother on phones */ + if (phosh_mode_manager_get_device_type(mode_manager) != PHOSH_MODE_DEVICE_TYPE_PHONE && + phosh_mode_manager_get_device_type(mode_manager) != PHOSH_MODE_DEVICE_TYPE_UNKNOWN) + return; + + /* Don't mess with transforms on external screens either */ + if (!phosh_monitor_is_builtin (self->monitor)) + return; + + if (phosh_lockscreen_manager_get_locked (self->lockscreen_manager)) { + if (force) { + PhoshMonitorTransform transform; + /* Use prelock transform if portrait, else use normal */ + transform = (self->prelock_transform % 2) == 0 ? self->prelock_transform : + PHOSH_MONITOR_TRANSFORM_NORMAL; + g_debug ("Forcing portrait transform: %d", transform); + apply_transform (self, transform); + } else { + self->prelock_transform = phosh_monitor_get_transform (self->monitor); + g_debug ("Saving transform %d", self->prelock_transform); + } + } else { + g_debug ("Restoring transform %d", self->prelock_transform); + apply_transform (self, self->prelock_transform); + } +} + + +static void +on_power_mode_changed (PhoshRotationManager *self, + GParamSpec *pspec, + PhoshMonitor *monitor) +{ + PhoshMonitorPowerSaveMode mode; + + g_return_if_fail (PHOSH_IS_ROTATION_MANAGER (self)); + g_return_if_fail (PHOSH_IS_MONITOR (monitor)); + + mode = phosh_monitor_get_power_save_mode (monitor); + g_debug ("Powersave mode: %d", mode); + if (mode != PHOSH_MONITOR_POWER_SAVE_MODE_ON) + return; + + fixup_lockscreen_orientation (self, TRUE); +} + + +static void +claim_or_release_accelerometer (PhoshRotationManager *self) +{ + gboolean claim = TRUE; + + /* No need for accel on screen lock, saves power */ + if (phosh_lockscreen_manager_get_locked (self->lockscreen_manager)) + claim = FALSE; + + /* No need for accel on orientation lock, saves power */ + if (self->orientation_locked) + claim = FALSE; + + /* No need for accel when automatic rotation is not requested or possible */ + if (self->mode == PHOSH_ROTATION_MANAGER_MODE_OFF) + claim = FALSE; + + if (claim == self->claimed) + return; + + phosh_rotation_manager_claim_accelerometer (self, claim); +} + + +static void +on_lockscreen_manager_locked (PhoshRotationManager *self, GParamSpec *pspec, + PhoshLockscreenManager *lockscreen_manager) +{ + g_return_if_fail (PHOSH_IS_ROTATION_MANAGER (self)); + g_return_if_fail (PHOSH_IS_LOCKSCREEN_MANAGER (lockscreen_manager)); + + claim_or_release_accelerometer (self); + fixup_lockscreen_orientation (self, FALSE); +} + + +static void +on_accelerometer_orientation_changed (PhoshRotationManager *self, + GParamSpec *pspec, + PhoshSensorProxyManager *sensor) +{ + g_return_if_fail (PHOSH_IS_ROTATION_MANAGER (self)); + g_return_if_fail (self->sensor_proxy_manager == sensor); + + match_orientation (self); +} + + +static void +on_monitor_configured (PhoshRotationManager *self, + PhoshMonitor *monitor) +{ + PhoshMonitorTransform transform; + + g_return_if_fail (PHOSH_IS_ROTATION_MANAGER (self)); + g_return_if_fail (PHOSH_IS_MONITOR (monitor)); + + transform = phosh_monitor_get_transform (monitor); + if (transform == self->transform) + return; + + self->transform = transform; + g_debug ("Rotation-manager transform %d", transform); + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TRANSFORM]); +} + + +static void +phosh_rotation_manager_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshRotationManager *self = PHOSH_ROTATION_MANAGER (object); + + switch (property_id) { + case PROP_SENSOR_PROXY_MANAGER: + /* construct only */ + self->sensor_proxy_manager = g_value_dup_object (value); + break; + case PROP_LOCKSCREEN_MANAGER: + /* construct only */ + self->lockscreen_manager = g_value_dup_object (value); + break; + case PROP_MONITOR: + phosh_rotation_manager_set_monitor (self, g_value_get_object (value)); + break; + case PROP_ORIENTATION_LOCKED: + phosh_rotation_manager_set_orientation_locked (self, + g_value_get_boolean (value)); + break; + case PROP_MODE: + phosh_rotation_manager_set_mode (self, g_value_get_enum (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +phosh_rotation_manager_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshRotationManager *self = PHOSH_ROTATION_MANAGER (object); + + switch (property_id) { + case PROP_SENSOR_PROXY_MANAGER: + g_value_set_object (value, self->sensor_proxy_manager); + break; + case PROP_LOCKSCREEN_MANAGER: + g_value_set_object (value, self->lockscreen_manager); + break; + case PROP_ORIENTATION_LOCKED: + g_value_set_boolean (value, self->orientation_locked); + break; + case PROP_MODE: + g_value_set_enum (value, self->mode); + break; + case PROP_TRANSFORM: + g_value_set_enum (value, self->transform); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +phosh_rotation_manager_constructed (GObject *object) +{ + PhoshRotationManager *self = PHOSH_ROTATION_MANAGER (object); + + G_OBJECT_CLASS (phosh_rotation_manager_parent_class)->constructed (object); + + self->settings = g_settings_new (ORIENTATION_LOCK_SCHEMA_ID); + + g_settings_bind (self->settings, + ORIENTATION_LOCK_KEY, + self, + "orientation-locked", + G_BINDING_SYNC_CREATE + | G_BINDING_BIDIRECTIONAL); + + g_signal_connect_swapped (self->lockscreen_manager, + "notify::locked", + (GCallback) on_lockscreen_manager_locked, + self); + on_lockscreen_manager_locked (self, NULL, self->lockscreen_manager); + + if (!self->sensor_proxy_manager) { + g_message ("Got no sensor-proxy, no automatic rotation"); + return; + } + + g_signal_connect_swapped (self->sensor_proxy_manager, + "notify::accelerometer-orientation", + (GCallback) on_accelerometer_orientation_changed, + self); + + g_signal_connect_swapped (self->sensor_proxy_manager, + "notify::has-accelerometer", + (GCallback) on_has_accelerometer_changed, + self); + on_has_accelerometer_changed (self, NULL, self->sensor_proxy_manager); +} + + +static void +phosh_rotation_manager_dispose (GObject *object) +{ + PhoshRotationManager *self = PHOSH_ROTATION_MANAGER (object); + + g_cancellable_cancel (self->cancel); + g_clear_object (&self->cancel); + + g_clear_object (&self->settings); + + if (self->sensor_proxy_manager) { + g_signal_handlers_disconnect_by_data (self->sensor_proxy_manager, + self); + /* Sync call since we're going away */ + phosh_dbus_sensor_proxy_call_release_accelerometer_sync ( + PHOSH_DBUS_SENSOR_PROXY (self->sensor_proxy_manager), NULL, NULL); + g_clear_object (&self->sensor_proxy_manager); + } + + if (self->lockscreen_manager) { + g_signal_handlers_disconnect_by_data (self->lockscreen_manager, + self); + g_clear_object (&self->lockscreen_manager); + } + + if (self->monitor) { + g_signal_handlers_disconnect_by_data (self->monitor, + self); + g_clear_object (&self->monitor); + } + + G_OBJECT_CLASS (phosh_rotation_manager_parent_class)->dispose (object); +} + +static void +phosh_rotation_manager_class_init (PhoshRotationManagerClass *klass) +{ + GObjectClass *object_class = (GObjectClass *)klass; + + object_class->constructed = phosh_rotation_manager_constructed; + object_class->dispose = phosh_rotation_manager_dispose; + + object_class->set_property = phosh_rotation_manager_set_property; + object_class->get_property = phosh_rotation_manager_get_property; + + props[PROP_SENSOR_PROXY_MANAGER] = + g_param_spec_object ( + "sensor-proxy-manager", + "Sensor proxy manager", + "The object inerfacing with iio-sensor-proxy", + PHOSH_TYPE_SENSOR_PROXY_MANAGER, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + props[PROP_LOCKSCREEN_MANAGER] = + g_param_spec_object ( + "lockscreen-manager", + "Lockscren manager", + "The object managing the lock screen", + PHOSH_TYPE_LOCKSCREEN_MANAGER, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + props[PROP_MONITOR] = + g_param_spec_object ( + "monitor", + "Monitor", + "The monitor to rotate", + PHOSH_TYPE_MONITOR, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + props[PROP_ORIENTATION_LOCKED] = + g_param_spec_boolean ( + "orientation-locked", + "Screen orientation locked", + "Whether the screen orientation is locked", + TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + props[PROP_MODE] = + g_param_spec_enum ( + "mode", + "Rotation mode", + "The current rotation mode", + PHOSH_TYPE_ROTATION_MANAGER_MODE, + PHOSH_ROTATION_MANAGER_MODE_OFF, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + props[PROP_TRANSFORM] = + g_param_spec_enum ("transform", + "Transform", + "Monitor transform of the rotation monitor", + PHOSH_TYPE_MONITOR_TRANSFORM, + PHOSH_MONITOR_TRANSFORM_NORMAL, + G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, LAST_PROP, props); +} + +static void +phosh_rotation_manager_init (PhoshRotationManager *self) +{ + self->cancel = g_cancellable_new (); +} + + +PhoshRotationManager * +phosh_rotation_manager_new (PhoshSensorProxyManager *sensor_proxy_manager, + PhoshLockscreenManager *lockscreen_manager, + PhoshMonitor *monitor) +{ + return g_object_new (PHOSH_TYPE_ROTATION_MANAGER, + "sensor-proxy-manager", sensor_proxy_manager, + "lockscreen-manager", lockscreen_manager, + "monitor", monitor, + NULL); +} + +void +phosh_rotation_manager_set_orientation_locked (PhoshRotationManager *self, gboolean locked) +{ + g_return_if_fail (PHOSH_IS_ROTATION_MANAGER (self)); + + if (locked == self->orientation_locked) + return; + + self->orientation_locked = locked; + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ORIENTATION_LOCKED]); + + /* We don't need accel if orientation locked and vice versa */ + if (self->claimed == self->orientation_locked) + claim_or_release_accelerometer (self); + else + match_orientation (self); +} + +gboolean +phosh_rotation_manager_get_orientation_locked (PhoshRotationManager *self) +{ + g_return_val_if_fail (PHOSH_IS_ROTATION_MANAGER (self), TRUE); + + return self->orientation_locked; +} + +PhoshRotationManagerMode +phosh_rotation_manager_get_mode (PhoshRotationManager *self) +{ + g_return_val_if_fail (PHOSH_IS_ROTATION_MANAGER (self), PHOSH_ROTATION_MANAGER_MODE_OFF); + + return self->mode; +} + +/** + * phosh_rotation_manager_set_mode: + * @self: The #PhoshRotationManager + * @mode: The #PhoshRotationManagerMode to set + * + * Sets the given mode. + * Returns: %TRUE if setting the mode was possible, otherwise %FALSE (e.g. when trying + * to set %PHOSH_ROTATION_MANAGER_MODE_SENSOR without having a sensor. + */ +gboolean +phosh_rotation_manager_set_mode (PhoshRotationManager *self, PhoshRotationManagerMode mode) +{ + gboolean has_accel; + + g_return_val_if_fail (PHOSH_IS_ROTATION_MANAGER (self), FALSE); + + if (mode == self->mode) + return TRUE; + + has_accel = phosh_dbus_sensor_proxy_get_has_accelerometer ( + PHOSH_DBUS_SENSOR_PROXY (self->sensor_proxy_manager)); + + if (mode == PHOSH_ROTATION_MANAGER_MODE_SENSOR && !has_accel) + return FALSE; + + self->mode = mode; + + g_debug ("Setting mode: %d", mode); + claim_or_release_accelerometer (self); + + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MODE]); + return TRUE; +} + + +void +phosh_rotation_manager_set_transform (PhoshRotationManager *self, + PhoshMonitorTransform transform) +{ + g_return_if_fail (PHOSH_IS_ROTATION_MANAGER (self)); + g_return_if_fail (self->mode == PHOSH_ROTATION_MANAGER_MODE_OFF); + + apply_transform (self, transform); +} + +PhoshMonitorTransform +phosh_rotation_manager_get_transform (PhoshRotationManager *self) +{ + g_return_val_if_fail (PHOSH_IS_ROTATION_MANAGER (self), PHOSH_MONITOR_TRANSFORM_NORMAL); + g_return_val_if_fail (PHOSH_IS_MONITOR (self->monitor), PHOSH_MONITOR_TRANSFORM_NORMAL); + + return self->monitor->transform; +} + +/** + * phosh_rotation_manager_get_monitor: + * @self: The PhoshRotationManager + * + * Returns: The #PhoshMonitor this manager acts on + */ +PhoshMonitor * +phosh_rotation_manager_get_monitor (PhoshRotationManager *self) +{ + g_return_val_if_fail (PHOSH_IS_ROTATION_MANAGER (self), NULL); + + return self->monitor; +} + + +void +phosh_rotation_manager_set_monitor (PhoshRotationManager *self, PhoshMonitor *monitor) +{ + g_return_if_fail (PHOSH_IS_ROTATION_MANAGER (self)); + g_return_if_fail (PHOSH_IS_MONITOR (monitor) || monitor == NULL); + + g_debug ("Using monitor %p", monitor); + + if (self->monitor == monitor) + return; + + if (self->monitor) { + g_signal_handlers_disconnect_by_data (self->monitor, self); + g_clear_object (&self->monitor); + } + + if (monitor == NULL) { + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MONITOR]); + return; + } + + self->monitor = g_object_ref (monitor); + g_signal_connect_swapped (self->monitor, + "notify::power-mode", + G_CALLBACK (on_power_mode_changed), + self); + on_power_mode_changed (self, NULL, self->monitor); + + g_signal_connect_swapped (self->monitor, + "configured", + G_CALLBACK (on_monitor_configured), + self); + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MONITOR]); +} diff -Nru phosh-0.8.0/src/rotation-manager.h phosh-0.13.1/src/rotation-manager.h --- phosh-0.8.0/src/rotation-manager.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/rotation-manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +#pragma once + +#include "lockscreen-manager.h" +#include "sensor-proxy-manager.h" +#include "monitor/monitor.h" + +G_BEGIN_DECLS + +/** + * PhoshRotationManagerMode: + * @PHOSH_ROTATION_MANAGER_MODE_OFF: automatic rotation off + * @PHOSH_ROTATION_MANAGER_MODE_SENSOR: rotation driven by sensor orientation + * + * The mode of a #PhoshRotationManager + */ +typedef enum { + PHOSH_ROTATION_MANAGER_MODE_OFF, + PHOSH_ROTATION_MANAGER_MODE_SENSOR, +} PhoshRotationManagerMode; + +#define PHOSH_TYPE_ROTATION_MANAGER (phosh_rotation_manager_get_type ()) + +G_DECLARE_FINAL_TYPE (PhoshRotationManager, phosh_rotation_manager, PHOSH, ROTATION_MANAGER, GObject); + +PhoshRotationManager *phosh_rotation_manager_new (PhoshSensorProxyManager *sensor_proxy_manager, + PhoshLockscreenManager *lockscreen_manager, + PhoshMonitor *monitor); +void phosh_rotation_manager_set_orientation_locked (PhoshRotationManager *self, + gboolean locked); +gboolean phosh_rotation_manager_get_orientation_locked (PhoshRotationManager *self); + +PhoshRotationManagerMode phosh_rotation_manager_get_mode (PhoshRotationManager *self); +gboolean phosh_rotation_manager_set_mode (PhoshRotationManager *self, + PhoshRotationManagerMode mode); +void phosh_rotation_manager_set_transform (PhoshRotationManager *self, + PhoshMonitorTransform tranform); +PhoshMonitorTransform phosh_rotation_manager_get_transform (PhoshRotationManager *self); +PhoshMonitor *phosh_rotation_manager_get_monitor (PhoshRotationManager *self); +void phosh_rotation_manager_set_monitor (PhoshRotationManager *self, + PhoshMonitor *monitor); + +G_END_DECLS diff -Nru phosh-0.8.0/src/screen-saver-manager.c phosh-0.13.1/src/screen-saver-manager.c --- phosh-0.8.0/src/screen-saver-manager.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/screen-saver-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -45,6 +45,7 @@ { PhoshScreenSaverDBusScreenSaverSkeleton parent; + int idle_id; int dbus_name_id; PhoshLockscreenManager *lockscreen_manager; @@ -69,7 +70,7 @@ switch (property_id) { case PROP_LOCKSCREEN_MANAGER: - self->lockscreen_manager = g_value_get_object (value); + self->lockscreen_manager = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -205,7 +206,7 @@ skeleton = G_DBUS_INTERFACE_SKELETON (self); locked = phosh_lockscreen_manager_get_locked(self->lockscreen_manager); - g_debug ("Signal ActiveChanged: %d", locked); + g_debug ("Signaling ActiveChanged: %d", locked); g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (skeleton), NULL, g_dbus_interface_skeleton_get_object_path (skeleton), @@ -227,7 +228,7 @@ g_return_if_fail (PHOSH_IS_LOCKSCREEN_MANAGER (lockscreen_manager)); skeleton = G_DBUS_INTERFACE_SKELETON (self); - g_debug ("Signal WakeUpScreen"); + g_debug ("Signaling WakeUpScreen"); g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (skeleton), NULL, g_dbus_interface_skeleton_get_object_path (skeleton), @@ -292,7 +293,7 @@ const char *name, gpointer user_data) { - PhoshScreenSaverManager *self = user_data; + PhoshScreenSaverManager *self = PHOSH_SCREEN_SAVER_MANAGER (user_data); g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self), connection, @@ -306,6 +307,12 @@ { PhoshScreenSaverManager *self = PHOSH_SCREEN_SAVER_MANAGER (object); + g_clear_handle_id (&self->idle_id, g_source_remove); + g_clear_handle_id (&self->dbus_name_id, g_bus_unown_name); + + if (g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (self))) + g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self)); + g_clear_object (&self->lockscreen_manager); g_clear_object (&self->logind_session_proxy); g_clear_object (&self->logind_manager_proxy); @@ -324,7 +331,7 @@ self->logind_session_proxy = phosh_login1_session_dbus_login_session_proxy_new_for_bus_finish ( res, &err); if (!self->logind_session_proxy) { - g_warning ("Failed to get login1 session proxy: %s", err->message); + phosh_dbus_service_error_warn (err, "Failed to get login1 session proxy"); goto out; } @@ -382,7 +389,7 @@ phosh_login1_manager_dbus_login_manager_proxy_new_for_bus_finish (res, &err); if (!self->logind_manager_proxy) { - g_warning ("Failed to get login1 manager proxy: %s", err->message); + phosh_dbus_service_error_warn (err, "Failed to get login1 manager proxy"); goto out; } @@ -405,7 +412,7 @@ static gboolean -on_idle (PhoshTorchManager *self) +on_idle (PhoshScreenSaverManager *self) { /* Connect to logind's session manager */ phosh_login1_manager_dbus_login_manager_proxy_new_for_bus ( @@ -417,6 +424,7 @@ (GAsyncReadyCallback) on_logind_manager_proxy_new_for_bus_finish, g_object_ref (self)); + self->idle_id = 0; return G_SOURCE_REMOVE; } @@ -434,13 +442,13 @@ on_bus_acquired, on_name_acquired, on_name_lost, - g_object_ref (self), - g_object_unref); + self, + NULL); g_return_if_fail (PHOSH_IS_LOCKSCREEN_MANAGER (self->lockscreen_manager)); /* Perform login1 setup when idle */ - g_idle_add ((GSourceFunc)on_idle, self); + self->idle_id = g_idle_add ((GSourceFunc)on_idle, self); } diff -Nru phosh-0.8.0/src/screenshot-manager.c phosh-0.13.1/src/screenshot-manager.c --- phosh-0.8.0/src/screenshot-manager.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/screenshot-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,532 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-screenshot-manager" + +#include "config.h" +#include "fader.h" +#include "phosh-wayland.h" +#include "screenshot-manager.h" +#include "shell.h" +#include "util.h" +#include "wl-buffer.h" + +#include "dbus/phosh-screenshot-dbus.h" + +#define BUS_NAME "org.gnome.Shell.Screenshot" +#define OBJECT_PATH "/org/gnome/Shell/Screenshot" + +#define FLASH_FADER_TIMEOUT 500 + +/** + * SECTION:screenshot-manager + * @short_description: Screenshot interaction + * @Title: PhoshScreenshotManager + * + * The #PhoshScreenshotManager is responsible for + * taking screenshots. + */ + +static void phosh_screenshot_manager_screenshot_iface_init ( + PhoshDBusScreenshotIface *iface); + + +typedef struct _ScreencopyFrame { + struct zwlr_screencopy_frame_v1 *frame; + uint32_t flags; + char *filename; + GDBusMethodInvocation *invocation; + PhoshWlBuffer *buffer; + gboolean flash; + GdkPixbuf *pixbuf; +} ScreencopyFrame; + + +typedef struct _PhoshScreenshotManager { + PhoshDBusScreenshotSkeleton parent; + + int dbus_name_id; + struct zwlr_screencopy_manager_v1 *wl_scm; + ScreencopyFrame *frame; + + PhoshFader *fader; + guint fader_id; + PhoshFader *opaque; + guint opaque_id; +} PhoshScreenshotManager; + + +G_DEFINE_TYPE_WITH_CODE (PhoshScreenshotManager, + phosh_screenshot_manager, + PHOSH_DBUS_TYPE_SCREENSHOT_SKELETON, + G_IMPLEMENT_INTERFACE ( + PHOSH_DBUS_TYPE_SCREENSHOT, + phosh_screenshot_manager_screenshot_iface_init)); + + +static void +screencopy_frame_dispose (ScreencopyFrame *frame) +{ + phosh_wl_buffer_destroy (frame->buffer); + g_clear_pointer (&frame->frame, zwlr_screencopy_frame_v1_destroy); + g_clear_object (&frame->pixbuf); + g_free (frame->filename); + g_free (frame); +} + + +static void +screencopy_frame_handle_buffer (void *data, + struct zwlr_screencopy_frame_v1 *frame, + uint32_t format, + uint32_t width, + uint32_t height, + uint32_t stride) +{ + PhoshScreenshotManager *self = PHOSH_SCREENSHOT_MANAGER (data); + + g_return_if_fail (PHOSH_IS_SCREENSHOT_MANAGER (self)); + + g_debug ("Handling buffer %dx%d for %s", width, height, + self->frame->filename ?: ""); + self->frame->buffer = phosh_wl_buffer_new (format, width, height, stride); + g_return_if_fail (self->frame->buffer); + + zwlr_screencopy_frame_v1_copy (frame, self->frame->buffer->wl_buffer); +} + + +static void +screencopy_frame_handle_flags (void *data, + struct zwlr_screencopy_frame_v1 *frame, + uint32_t flags) +{ + PhoshScreenshotManager *self = PHOSH_SCREENSHOT_MANAGER (data); + + g_return_if_fail (PHOSH_IS_SCREENSHOT_MANAGER (self)); + g_return_if_fail (self->frame); + + self->frame->flags = flags; +} + +static gboolean +on_fader_timeout (gpointer user_data) +{ + PhoshScreenshotManager *self = PHOSH_SCREENSHOT_MANAGER (user_data); + + g_clear_pointer (&self->fader, phosh_cp_widget_destroy); + + self->fader_id = 0; + return G_SOURCE_REMOVE; +} + + +static void +show_fader (PhoshScreenshotManager *self) +{ + PhoshMonitor *monitor = phosh_shell_get_primary_monitor (phosh_shell_get_default ()); + + self->fader_id = g_timeout_add (FLASH_FADER_TIMEOUT, on_fader_timeout, self); + g_source_set_name_by_id (self->fader_id, "[phosh] screenshot fader"); + self->fader = g_object_new (PHOSH_TYPE_FADER, + "monitor", monitor, + "style-class", "phosh-fader-flash-fade", + NULL); + gtk_widget_show (GTK_WIDGET (self->fader)); +} + + +static void +screencopy_done (PhoshScreenshotManager *self, gboolean success) +{ + phosh_dbus_screenshot_complete_screenshot (PHOSH_DBUS_SCREENSHOT (self), + self->frame->invocation, + success, + self->frame->filename ?: ""); + /* TODO: GNOME >= 40 wants us to emit the click sound from here */ + if (self->frame->flash && success) + show_fader (self); + + g_clear_pointer (&self->frame, screencopy_frame_dispose); +} + + +static void +on_save_pixbuf_ready (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + gboolean success; + g_autoptr (GError) err = NULL; + PhoshScreenshotManager *self = PHOSH_SCREENSHOT_MANAGER (user_data); + + g_return_if_fail (PHOSH_IS_SCREENSHOT_MANAGER (self)); + + success = gdk_pixbuf_save_to_stream_finish (res, &err); + if (!success) + g_warning ("Failed to save screenshot to %s: %s", self->frame->filename, err->message); + + screencopy_done (self, success); + g_object_unref (self); +} + + +static gboolean +on_opaque_timeout (PhoshScreenshotManager *self) +{ + GdkDisplay *display = gdk_display_get_default (); + GtkClipboard *clipboard; + + if (!display) { + g_critical ("Couldn't get GDK display"); + goto out; + } + + clipboard = gtk_clipboard_get_for_display (display, GDK_SELECTION_CLIPBOARD); + gtk_clipboard_set_image (clipboard, self->frame->pixbuf); + g_debug ("Updated clipboard with %p", self->frame); + screencopy_done (self, TRUE); + + out: + g_clear_pointer (&self->opaque, phosh_cp_widget_destroy); + self->opaque_id = 0; + return G_SOURCE_REMOVE; +} + + +static void +screencopy_frame_handle_ready (void *data, + struct zwlr_screencopy_frame_v1 *frame, + uint32_t tv_sec_hi, + uint32_t tv_sec_lo, + uint32_t tv_nsec) +{ + PhoshScreenshotManager *self = PHOSH_SCREENSHOT_MANAGER (data); + + g_autoptr (GdkPixbuf) pixbuf = NULL; + g_autoptr (GError) err = NULL; + g_autoptr (GFileOutputStream) stream = NULL; + g_autoptr (GFile) file = NULL; + g_autoptr (GBytes) bytes = NULL; + + g_return_if_fail (PHOSH_IS_SCREENSHOT_MANAGER (self)); + g_debug ("Frame %p %dx%d, stride %d, format 0x%x ready, saving to %s", + frame, + self->frame->buffer->width, + self->frame->buffer->height, + self->frame->buffer->stride, + self->frame->buffer->format, + self->frame->filename ?: ""); + + switch ((uint32_t) self->frame->buffer->format) { + case WL_SHM_FORMAT_ABGR8888: + case WL_SHM_FORMAT_XBGR8888: + break; + case WL_SHM_FORMAT_ARGB8888: + case WL_SHM_FORMAT_XRGB8888: { /* ARGB -> ABGR */ + PhoshWlBuffer *buffer = self->frame->buffer; + uint8_t *d = buffer->data; + for (int i = 0; i < buffer->height; ++i) { + for (int j = 0; j < buffer->width; ++j) { + uint32_t *px = (uint32_t *)(d + i * buffer->stride + j * 4); + uint8_t a = (*px >> 24) & 0xFF; + uint8_t b = (*px >> 16) & 0xFF; + uint8_t g = (*px >> 8) & 0xFF; + uint8_t r = *px & 0xFF; + *px = (a << 24) | (r << 16) | (g << 8) | b; + } + } + if (buffer->format == WL_SHM_FORMAT_ARGB8888) + buffer->format = WL_SHM_FORMAT_ABGR8888; + else + buffer->format = WL_SHM_FORMAT_XBGR8888; + } + break; + default: + goto error; + } + + bytes = phosh_wl_buffer_get_bytes (self->frame->buffer); + pixbuf = gdk_pixbuf_new_from_bytes (bytes, + GDK_COLORSPACE_RGB, + TRUE, + 8, + self->frame->buffer->width, + self->frame->buffer->height, + self->frame->buffer->stride); + if (self->frame->flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT) { + GdkPixbuf *tmp = gdk_pixbuf_flip (pixbuf, FALSE); + g_object_unref (pixbuf); + pixbuf = tmp; + } + + if (self->frame->filename) { + file = g_file_new_for_path (self->frame->filename); + stream = g_file_create (file, G_FILE_CREATE_NONE, NULL, &err); + if (!stream) { + g_warning ("Failed to save screenshot %s: %s", self->frame->filename, err->message); + goto error; + } + + gdk_pixbuf_save_to_stream_async (pixbuf, + G_OUTPUT_STREAM (stream), + "png", + NULL, + on_save_pixbuf_ready, + g_object_ref (self), + NULL); + } else { + PhoshMonitor *monitor = phosh_shell_get_primary_monitor (phosh_shell_get_default ()); + + /* The wayland clipboard only works if we have focus so use a fully opaque surface */ + self->opaque = g_object_new (PHOSH_TYPE_FADER, + "monitor", monitor, + "style-class", "phosh-fader-screenshot-opaque", + "kbd-interactivity", TRUE, + NULL); + self->frame->pixbuf = g_steal_pointer (&pixbuf); + /* FIXME: Would be better to trigger when the opaque window is up and got + input focus but all such attempts failed */ + self->opaque_id = g_timeout_add_seconds (1, (GSourceFunc) on_opaque_timeout, self); + g_source_set_name_by_id (self->opaque_id, "[phosh] screenshot opaque"); + + gtk_widget_show (GTK_WIDGET (self->opaque)); + } + return; + +error: + screencopy_done (self, FALSE); +} + + +static void +screencopy_frame_handle_failed (void *data, + struct zwlr_screencopy_frame_v1 *frame) +{ + PhoshScreenshotManager *self = PHOSH_SCREENSHOT_MANAGER (data); + + g_return_if_fail (PHOSH_IS_SCREENSHOT_MANAGER (self)); + + g_warning ("Failed to copy output\n"); + screencopy_done (self, FALSE); +} + + +static const struct zwlr_screencopy_frame_v1_listener screencopy_frame_listener = { + .buffer = screencopy_frame_handle_buffer, + .flags = screencopy_frame_handle_flags, + .ready = screencopy_frame_handle_ready, + .failed = screencopy_frame_handle_failed, +}; + + +/** + * build_screenshot_filename: + * @pattern: Absolute path or relative name without extension + * + * Builds an absolute filename based on the given input pattern. + * Returns: The target filename or %NULL on errors. + */ +static char * +build_screenshot_filename (const char *pattern) +{ + g_autofree char *filename = NULL; + + if (g_path_is_absolute (pattern)) { + return g_strdup (pattern); + } else { + const char *dir = NULL; + const char *const *dirs = (const char * []) { + g_get_user_special_dir (G_USER_DIRECTORY_PICTURES), + g_get_home_dir (), + NULL + }; + + for (int i = 0; i < g_strv_length ((GStrv) dirs); i++) { + if (g_file_test (dirs[i], G_FILE_TEST_EXISTS)) { + dir = dirs[i]; + break; + } + } + + if (!dir) + return NULL; + + filename = g_build_filename (dir, pattern, NULL); + } + if (!g_str_has_suffix (filename, ".png")) { + g_autofree gchar *tmp = filename; + filename = g_strdup_printf ("%s.png", filename); + } + + return g_steal_pointer (&filename); +} + + +static gboolean +handle_screenshot (PhoshDBusScreenshot *object, + GDBusMethodInvocation *invocation, + gboolean arg_include_cursor, + gboolean arg_flash, + const char *arg_filename) +{ + PhoshScreenshotManager *self = PHOSH_SCREENSHOT_MANAGER (object); + PhoshWayland *wl = phosh_wayland_get_default (); + struct zwlr_screencopy_manager_v1 *wl_scm; + PhoshMonitor *monitor; + ScreencopyFrame *frame; + + g_debug ("DBus call %s, cursor: %d, flash %d, to %s", + __func__, arg_include_cursor, arg_flash, arg_filename); + + g_return_val_if_fail (PHOSH_IS_WAYLAND (wl), FALSE); + + wl_scm = phosh_wayland_get_zwlr_screencopy_manager_v1 (wl); + if (!wl_scm) { + phosh_dbus_screenshot_complete_screenshot (object, invocation, FALSE, ""); + return TRUE; + } + + if (self->frame) { + g_debug ("Screenshot already in progress"); + phosh_dbus_screenshot_complete_screenshot (object, invocation, FALSE, ""); + return TRUE; + } + + monitor = phosh_shell_get_primary_monitor (phosh_shell_get_default ()); + frame = g_new0 (ScreencopyFrame, 1); + + frame->frame = zwlr_screencopy_manager_v1_capture_output ( + self->wl_scm, arg_include_cursor, monitor->wl_output); + frame->invocation = invocation; + frame->flash = arg_flash; + self->frame = frame; + + if (STR_IS_NULL_OR_EMPTY (arg_filename)) { + /* Copy to clipboard */ + frame->filename = NULL; + } else { + frame->filename = build_screenshot_filename (arg_filename); + if (!frame->filename) { + screencopy_done (self, FALSE); + return TRUE; + } + } + + zwlr_screencopy_frame_v1_add_listener (frame->frame, &screencopy_frame_listener, self); + return TRUE; +} + + +static void +phosh_screenshot_manager_screenshot_iface_init (PhoshDBusScreenshotIface *iface) +{ + iface->handle_screenshot = handle_screenshot; +} + + +static void +on_name_acquired (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + PhoshScreenshotManager *self = PHOSH_SCREENSHOT_MANAGER (user_data); + + g_return_if_fail (PHOSH_IS_SCREENSHOT_MANAGER (self)); + g_debug ("Acquired name %s", name); +} + + +static void +on_name_lost (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + g_debug ("Lost or failed to acquire name %s", name); +} + + +static void +on_bus_acquired (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + PhoshScreenshotManager *self = PHOSH_SCREENSHOT_MANAGER (user_data); + g_autoptr (GError) err = NULL; + + if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self), + connection, + OBJECT_PATH, + &err)) { + g_warning ("Failed to export screensaver interface skeleton: %s", err->message); + } + +} + + +static void +phosh_screenshot_manager_constructed (GObject *object) +{ + PhoshScreenshotManager *self = PHOSH_SCREENSHOT_MANAGER (object); + PhoshWayland *wl = phosh_wayland_get_default (); + + G_OBJECT_CLASS (phosh_screenshot_manager_parent_class)->constructed (object); + + self->dbus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION, + BUS_NAME, + G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | + G_BUS_NAME_OWNER_FLAGS_REPLACE, + on_bus_acquired, + on_name_acquired, + on_name_lost, + self, + NULL); + + g_return_if_fail (PHOSH_IS_WAYLAND (wl)); + self->wl_scm = phosh_wayland_get_zwlr_screencopy_manager_v1 (wl); +} + + +static void +phosh_screenshot_manager_dispose (GObject *object) +{ + PhoshScreenshotManager *self = PHOSH_SCREENSHOT_MANAGER (object); + + g_clear_handle_id (&self->dbus_name_id, g_bus_unown_name); + + if (g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (self))) + g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self)); + + g_clear_handle_id (&self->fader_id, g_source_remove); + g_clear_handle_id (&self->opaque_id, g_source_remove); + g_clear_pointer (&self->fader, phosh_cp_widget_destroy); + + G_OBJECT_CLASS (phosh_screenshot_manager_parent_class)->dispose (object); +} + + +static void +phosh_screenshot_manager_class_init (PhoshScreenshotManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = phosh_screenshot_manager_constructed; + object_class->dispose = phosh_screenshot_manager_dispose; +} + + +static void +phosh_screenshot_manager_init (PhoshScreenshotManager *self) +{ +} + +PhoshScreenshotManager * +phosh_screenshot_manager_new (void) +{ + return PHOSH_SCREENSHOT_MANAGER (g_object_new (PHOSH_TYPE_SCREENSHOT_MANAGER, NULL)); +} diff -Nru phosh-0.8.0/src/screenshot-manager.h phosh-0.13.1/src/screenshot-manager.h --- phosh-0.8.0/src/screenshot-manager.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/screenshot-manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "dbus/phosh-screenshot-dbus.h" + +#include + +G_BEGIN_DECLS + +#define PHOSH_TYPE_SCREENSHOT_MANAGER phosh_screenshot_manager_get_type () + +G_DECLARE_FINAL_TYPE (PhoshScreenshotManager, phosh_screenshot_manager, + PHOSH, SCREENSHOT_MANAGER, PhoshDBusScreenshotSkeleton) + +PhoshScreenshotManager *phosh_screenshot_manager_new (void); + +G_END_DECLS diff -Nru phosh-0.8.0/src/sensor-proxy-manager.c phosh-0.13.1/src/sensor-proxy-manager.c --- phosh-0.8.0/src/sensor-proxy-manager.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/sensor-proxy-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -52,27 +52,13 @@ PhoshSensorProxyManager * -phosh_sensor_proxy_manager_get_default_failable (void) +phosh_sensor_proxy_manager_new (GError **err) { - static PhoshSensorProxyManager *instance; - GError *err = NULL; - GInitable *ret; - - if (instance == NULL) { - ret = g_initable_new (PHOSH_TYPE_SENSOR_PROXY_MANAGER, NULL, &err, - "g-flags", G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, - "g-name", IIO_SENSOR_PROXY_DBUS_NAME, - "g-bus-type", G_BUS_TYPE_SYSTEM, - "g-object-path", IIO_SENSOR_PROXY_DBUS_OBJECT, - "g-interface-name", IIO_SENSOR_PROXY_DBUS_IFACE_NAME, - NULL); - if (ret != NULL) { - instance = PHOSH_SENSOR_PROXY_MANAGER (ret); - } else { - g_warning ("Can't connect to iio-sensor-sensor proxy: %s", err->message); - return NULL; - } - g_object_add_weak_pointer (G_OBJECT (instance), (gpointer *)&instance); - } - return instance; + return g_initable_new (PHOSH_TYPE_SENSOR_PROXY_MANAGER, NULL, err, + "g-flags", G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, + "g-name", IIO_SENSOR_PROXY_DBUS_NAME, + "g-bus-type", G_BUS_TYPE_SYSTEM, + "g-object-path", IIO_SENSOR_PROXY_DBUS_OBJECT, + "g-interface-name", IIO_SENSOR_PROXY_DBUS_IFACE_NAME, + NULL); } diff -Nru phosh-0.8.0/src/sensor-proxy-manager.h phosh-0.13.1/src/sensor-proxy-manager.h --- phosh-0.8.0/src/sensor-proxy-manager.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/sensor-proxy-manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -13,6 +13,6 @@ G_DECLARE_FINAL_TYPE (PhoshSensorProxyManager, phosh_sensor_proxy_manager, PHOSH, SENSOR_PROXY_MANAGER, PhoshDBusSensorProxyProxy) -PhoshSensorProxyManager *phosh_sensor_proxy_manager_get_default_failable (void); +PhoshSensorProxyManager *phosh_sensor_proxy_manager_new (GError **err); gboolean phosh_sensor_proxy_manager_claim_proximity_sync (PhoshSensorProxyManager *self, GError **err); diff -Nru phosh-0.8.0/src/session-manager.c phosh-0.13.1/src/session-manager.c --- phosh-0.8.0/src/session-manager.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/session-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -9,8 +9,10 @@ #define G_LOG_DOMAIN "phosh-session-manager" #include "config.h" +#include "end-session-dialog.h" #include "session-manager.h" #include "shell.h" +#include "util.h" #include "dbus/gnome-session-dbus.h" #include "dbus/gnome-session-client-private-dbus.h" @@ -18,6 +20,8 @@ #define BUS_NAME "org.gnome.SessionManager" #define OBJECT_PATH "/org/gnome/SessionManager" +#define END_SESSION_DIALOG_OBJECT_PATH "/org/gnome/SessionManager/EndSessionDialog" + #define SESSION_SHUTDOWN_TIMEOUT 15 /** @@ -36,17 +40,114 @@ }; static GParamSpec *props[PHOSH_SESSION_MANAGER_PROP_LAST_PROP]; +static void phosh_session_manager_end_session_dialog_iface_init ( + PhoshDBusEndSessionDialogIface *iface); typedef struct _PhoshSessionManager { - GObject parent; + PhoshDBusEndSessionDialogSkeleton parent; gboolean active; PhoshSessionDBusSessionManager *proxy; + GCancellable *cancel; PhoshSessionClientPrivateDBusClientPrivate *priv_proxy; + + PhoshEndSessionDialog *dialog; + } PhoshSessionManager; -G_DEFINE_TYPE (PhoshSessionManager, phosh_session_manager, G_TYPE_OBJECT) +G_DEFINE_TYPE_WITH_CODE (PhoshSessionManager, + phosh_session_manager, + PHOSH_DBUS_TYPE_END_SESSION_DIALOG_SKELETON, + G_IMPLEMENT_INTERFACE ( + PHOSH_DBUS_TYPE_END_SESSION_DIALOG, + phosh_session_manager_end_session_dialog_iface_init)) + + +static void +on_end_session_dialog_closed (PhoshSessionManager *self, PhoshEndSessionDialog *dialog) +{ + gint action; + gboolean confirmed; + PhoshDBusEndSessionDialog *object; + + g_return_if_fail (PHOSH_IS_SESSION_MANAGER (self)); + g_return_if_fail (PHOSH_IS_END_SESSION_DIALOG (dialog)); + + object = PHOSH_DBUS_END_SESSION_DIALOG (self); + + confirmed = phosh_end_session_dialog_get_action_confirmed (dialog); + action = phosh_end_session_dialog_get_action (dialog); + g_clear_pointer (&self->dialog, phosh_cp_widget_destroy); + + g_debug ("Action %d confirmed: %d", action, confirmed); + + if (!confirmed) { + phosh_dbus_end_session_dialog_emit_canceled (object); + return; + } + + switch (action) { + case PHOSH_END_SESSION_ACTION_LOGOUT: + phosh_dbus_end_session_dialog_emit_confirmed_logout (object); + break; + case PHOSH_END_SESSION_ACTION_SHUTDOWN: + phosh_dbus_end_session_dialog_emit_confirmed_shutdown (object); + break; + case PHOSH_END_SESSION_ACTION_REBOOT: + phosh_dbus_end_session_dialog_emit_confirmed_reboot (object); + break; + /* not used by gnome-session */ + case PHOSH_END_SESSION_ACTION_HIBERNATE: + case PHOSH_END_SESSION_ACTION_SUSPEND: + case PHOSH_END_SESSION_ACTION_HYBRID_SLEEP: + default: + g_return_if_reached (); + } +} + + +static gboolean +handle_end_session_open (PhoshDBusEndSessionDialog *object, + GDBusMethodInvocation *invocation, + guint arg_type, + guint arg_timestamp, + guint arg_seconds_to_stay_open, + const gchar *const *arg_inhibitor_object_paths) +{ + PhoshSessionManager *self = PHOSH_SESSION_MANAGER (object); + + g_debug ("DBus call %s, type: %d, seconds %d", + __func__, arg_type, arg_seconds_to_stay_open); + + if (self->dialog != NULL) { + g_object_set (self->dialog, + "inhibitor-paths", arg_inhibitor_object_paths, + NULL); + gtk_widget_show (GTK_WIDGET (self->dialog)); + phosh_dbus_end_session_dialog_complete_open ( + object, invocation); + return TRUE; + } + + self->dialog = PHOSH_END_SESSION_DIALOG (phosh_end_session_dialog_new (arg_type, + arg_seconds_to_stay_open, + arg_inhibitor_object_paths)); + g_signal_connect_swapped (self->dialog, "closed", + G_CALLBACK (on_end_session_dialog_closed), self); + + gtk_widget_show (GTK_WIDGET (self->dialog)); + phosh_dbus_end_session_dialog_complete_open (object, invocation); + + return TRUE; +} + + +static void +phosh_session_manager_end_session_dialog_iface_init (PhoshDBusEndSessionDialogIface *iface) +{ + iface->handle_open = handle_end_session_open; +} static void @@ -184,14 +285,12 @@ PhoshSessionManager *self) { g_autofree gchar *client_id = NULL; - g_autoptr (GError) err = NULL; if (!phosh_session_dbus_session_manager_call_register_client_finish (proxy, &client_id, res, &err)) { - g_warning ("Failed to register client: %s", err->message); - goto out; + phosh_async_error_warn (err, "Failed to register client"); + return; } - g_debug ("Registered client at '%s'", client_id); phosh_session_client_private_dbus_client_private_proxy_new_for_bus ( @@ -202,9 +301,6 @@ NULL, (GAsyncReadyCallback)on_client_private_proxy_new_for_bus_finish, g_object_ref (self)); - -out: - g_object_unref (self); } @@ -283,6 +379,13 @@ { PhoshSessionManager *self = PHOSH_SESSION_MANAGER (object); + g_cancellable_cancel (self->cancel); + g_clear_object (&self->cancel); + + if (g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (self))) + g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self)); + + g_clear_pointer (&self->dialog, phosh_cp_widget_destroy); g_clear_object (&self->priv_proxy); g_clear_object (&self->proxy); @@ -318,6 +421,7 @@ static void phosh_session_manager_init (PhoshSessionManager *self) { + self->cancel = g_cancellable_new (); } @@ -348,9 +452,9 @@ phosh_session_dbus_session_manager_call_register_client (self->proxy, app_id, startup_id ? startup_id : "", - NULL, + self->cancel, (GAsyncReadyCallback) on_client_registered, - g_object_ref (self)); + self); } void @@ -391,3 +495,15 @@ (GAsyncReadyCallback)on_reboot_finished, g_object_ref (self)); } + +void +phosh_session_manager_export_end_session (PhoshSessionManager *self, + GDBusConnection *connection) +{ + g_return_if_fail (PHOSH_IS_SESSION_MANAGER (self)); + + g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self), + connection, + END_SESSION_DIALOG_OBJECT_PATH, + NULL); +} diff -Nru phosh-0.8.0/src/session-manager.h phosh-0.13.1/src/session-manager.h --- phosh-0.8.0/src/session-manager.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/session-manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -6,14 +6,17 @@ #pragma once +#include "dbus/phosh-end-session-dialog-dbus.h" + #include +#include G_BEGIN_DECLS #define PHOSH_TYPE_SESSION_MANAGER phosh_session_manager_get_type () G_DECLARE_FINAL_TYPE (PhoshSessionManager, phosh_session_manager, - PHOSH, SESSION_MANAGER, GObject) + PHOSH, SESSION_MANAGER, PhoshDBusEndSessionDialogSkeleton) PhoshSessionManager *phosh_session_manager_new (void); gboolean phosh_session_manager_is_active (PhoshSessionManager *self); @@ -22,4 +25,7 @@ void phosh_session_manager_shutdown (PhoshSessionManager *self); void phosh_session_manager_reboot (PhoshSessionManager *self); +void phosh_session_manager_export_end_session (PhoshSessionManager *self, + GDBusConnection *connection); + G_END_DECLS diff -Nru phosh-0.8.0/src/settings/brightness.c phosh-0.13.1/src/settings/brightness.c --- phosh-0.8.0/src/settings/brightness.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/settings/brightness.c 2021-08-31 09:15:52.000000000 +0000 @@ -12,9 +12,11 @@ #include #include "settings/brightness.h" +#include "util.h" GDBusProxy *brightness_proxy; +GCancellable *gsd_power_cancel; gboolean setting_brightness; @@ -51,8 +53,8 @@ int value; brightness_proxy = g_dbus_proxy_new_finish (res, &err); - if (!brightness_proxy || err) { - g_warning ("Could not connect to brightness service %s", err->message); + if (brightness_proxy == NULL) { + phosh_async_error_warn (err, "Could not connect to brightness service"); return; } @@ -83,17 +85,18 @@ session_con = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &err); if (err != NULL) { - g_error ("Can not connect to session bus: %s", err->message); + g_warning ("Can not connect to session bus: %s", err->message); return; } + gsd_power_cancel = g_cancellable_new (); g_dbus_proxy_new (session_con, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.gnome.SettingsDaemon.Power", "/org/gnome/SettingsDaemon/Power", "org.gnome.SettingsDaemon.Power.Screen", - NULL, + gsd_power_cancel, (GAsyncReadyCallback)brightness_init_cb, scale); } @@ -148,5 +151,7 @@ void brightness_dispose (void) { - g_clear_pointer (&brightness_proxy, g_object_unref); + g_cancellable_cancel (gsd_power_cancel); + g_clear_object (&gsd_power_cancel); + g_clear_object (&brightness_proxy); } diff -Nru phosh-0.8.0/src/settings/meson.build phosh-0.13.1/src/settings/meson.build --- phosh-0.8.0/src/settings/meson.build 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/settings/meson.build 2021-08-31 09:15:52.000000000 +0000 @@ -1,4 +1,4 @@ -phosh_settings_widgets_sources = [ - 'settings/brightness.c', - 'settings/gvc-channel-bar.c', -] +phosh_settings_widgets_sources = files( + 'brightness.c', + 'gvc-channel-bar.c', +) diff -Nru phosh-0.8.0/src/settings.c phosh-0.13.1/src/settings.c --- phosh-0.8.0/src/settings.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/settings.c 2021-08-31 09:15:52.000000000 +0000 @@ -10,8 +10,6 @@ #include -#include "bt-info.h" -#include "docked-info.h" #include "mode-manager.h" #include "shell.h" #include "settings.h" @@ -19,13 +17,11 @@ #include "settings/brightness.h" #include "settings/gvc-channel-bar.h" #include "torch-info.h" +#include "torch-manager.h" #include "wwan/phosh-wwan-mm.h" -#include "rotateinfo.h" -#include "feedbackinfo.h" -#include "feedback-manager.h" #include "notifications/notify-manager.h" #include "notifications/notification-frame.h" -#include "media-player.h" +#include "rotateinfo.h" #include #include "gvc-mixer-control.h" @@ -35,9 +31,6 @@ #include -#define LIBFEEDBACK_USE_UNSTABLE_API -#include - /** * SECTION:settings * @short_description: The settings menu @@ -67,8 +60,12 @@ /* Notifications */ GtkWidget *list_notifications; - GtkWidget *sw_notifications; - LfbEvent *notify_event; + GtkWidget *box_notifications; + + /* Torch */ + PhoshTorchManager *torch_manager; + GtkWidget *scale_torch; + gboolean setting_torch; } PhoshSettings; @@ -76,6 +73,13 @@ static void +close_settings_menu (PhoshSettings *self) +{ + g_signal_emit (self, signals[SETTING_DONE], 0); + phosh_trigger_feedback ("button-pressed"); +} + +static void brightness_value_changed_cb (GtkScale *scale_brightness, gpointer *unused) { int brightness; @@ -88,14 +92,56 @@ rotation_setting_clicked_cb (PhoshSettings *self) { PhoshShell *shell = phosh_shell_get_default (); + PhoshRotationManager *rotation_manager; + PhoshRotationManagerMode mode; PhoshMonitorTransform transform; + gboolean locked; g_return_if_fail (PHOSH_IS_SETTINGS (self)); - transform = phosh_shell_get_transform (shell); - phosh_shell_set_transform (shell, transform == PHOSH_MONITOR_TRANSFORM_NORMAL - ? PHOSH_MONITOR_TRANSFORM_270 - : PHOSH_MONITOR_TRANSFORM_NORMAL); - g_signal_emit (self, signals[SETTING_DONE], 0); + + rotation_manager = phosh_shell_get_rotation_manager (shell); + g_return_if_fail (rotation_manager); + mode = phosh_rotation_manager_get_mode (PHOSH_ROTATION_MANAGER (rotation_manager)); + + switch (mode) { + case PHOSH_ROTATION_MANAGER_MODE_OFF: + transform = phosh_rotation_manager_get_transform (rotation_manager) ? + PHOSH_MONITOR_TRANSFORM_NORMAL : PHOSH_MONITOR_TRANSFORM_270; + phosh_rotation_manager_set_transform (rotation_manager, transform); + g_signal_emit (self, signals[SETTING_DONE], 0); + break; + case PHOSH_ROTATION_MANAGER_MODE_SENSOR: + locked = phosh_rotation_manager_get_orientation_locked (rotation_manager); + phosh_rotation_manager_set_orientation_locked (rotation_manager, !locked); + break; + default: + g_assert_not_reached (); + } +} + +static void +rotation_setting_long_pressed_cb (PhoshSettings *self) +{ + PhoshShell *shell = phosh_shell_get_default (); + PhoshRotateInfoMode mode; + PhoshRotationManager *rotation_manager; + + rotation_manager = phosh_shell_get_rotation_manager (shell); + g_return_if_fail (rotation_manager); + + mode = phosh_rotation_manager_get_mode (rotation_manager); + switch (mode) { + case PHOSH_ROTATION_MANAGER_MODE_OFF: + mode = PHOSH_ROTATION_MANAGER_MODE_SENSOR; + break; + case PHOSH_ROTATION_MANAGER_MODE_SENSOR: + mode = PHOSH_ROTATION_MANAGER_MODE_OFF; + break; + default: + g_assert_not_reached (); + } + g_debug ("Rotation manager mode: %d", mode); + phosh_rotation_manager_set_mode (rotation_manager, mode); } static void @@ -108,43 +154,90 @@ g_return_if_fail (PHOSH_IS_SHELL (shell)); manager = phosh_shell_get_feedback_manager (shell); g_return_if_fail (PHOSH_IS_FEEDBACK_MANAGER (manager)); - manager = phosh_shell_get_feedback_manager (shell); phosh_feedback_manager_toggle (manager); } static void wifi_setting_clicked_cb (PhoshSettings *self) { + PhoshShell *shell = phosh_shell_get_default (); + PhoshWifiManager *manager; + gboolean enabled; + + g_return_if_fail (PHOSH_IS_SETTINGS (self)); + + manager = phosh_shell_get_wifi_manager (shell); + g_return_if_fail (PHOSH_IS_WIFI_MANAGER (manager)); + + enabled = phosh_wifi_manager_get_enabled (manager); + phosh_wifi_manager_set_enabled (manager, !enabled); +} + +static void +wifi_setting_long_pressed_cb (PhoshSettings *self) +{ phosh_quick_setting_open_settings_panel ("wifi"); - g_signal_emit (self, signals[SETTING_DONE], 0); + close_settings_menu (self); } static void wwan_setting_clicked_cb (PhoshSettings *self) { + PhoshShell *shell = phosh_shell_get_default (); + PhoshWWan *wwan; + gboolean enabled; + + g_return_if_fail (PHOSH_IS_SETTINGS (self)); + + wwan = phosh_shell_get_wwan (shell); + g_return_if_fail (PHOSH_IS_WWAN (wwan)); + + enabled = phosh_wwan_is_enabled (wwan); + phosh_wwan_set_enabled (wwan, !enabled); +} + +static void +wwan_setting_long_pressed_cb (PhoshSettings *self) +{ phosh_quick_setting_open_settings_panel ("wwan"); - g_signal_emit (self, signals[SETTING_DONE], 0); + close_settings_menu (self); } static void bt_setting_clicked_cb (PhoshSettings *self) { + PhoshShell *shell = phosh_shell_get_default (); + PhoshBtManager *manager; + gboolean enabled; + + g_return_if_fail (PHOSH_IS_SETTINGS (self)); + + manager = phosh_shell_get_bt_manager (shell); + g_return_if_fail (PHOSH_IS_BT_MANAGER (manager)); + + enabled = phosh_bt_manager_get_enabled (manager); + phosh_bt_manager_set_enabled (manager, !enabled); +} + +static void +bt_setting_long_pressed_cb (PhoshSettings *self) +{ phosh_quick_setting_open_settings_panel ("bluetooth"); - g_signal_emit (self, signals[SETTING_DONE], 0); + close_settings_menu (self); } static void feedback_setting_long_pressed_cb (PhoshSettings *self) { phosh_quick_setting_open_settings_panel ("notifications"); - g_signal_emit (self, signals[SETTING_DONE], 0); + close_settings_menu (self); } static void battery_setting_clicked_cb (PhoshSettings *self) { phosh_quick_setting_open_settings_panel ("power"); - g_signal_emit (self, signals[SETTING_DONE], 0); + close_settings_menu (self); } @@ -178,6 +271,13 @@ phosh_docked_manager_set_enabled (manager, !enabled); } +static void +docked_setting_long_pressed_cb (PhoshSettings *self) +{ + phosh_quick_setting_open_settings_panel ("display"); + close_settings_menu (self); +} + static void update_output_vol_bar (PhoshSettings *self) @@ -229,18 +329,20 @@ if (self->output_stream) g_signal_handlers_disconnect_by_data (self->output_stream, self); - self->output_stream = gvc_mixer_control_get_default_sink (self->mixer_control); + g_set_object (&self->output_stream, + gvc_mixer_control_get_default_sink (self->mixer_control)); g_return_if_fail (self->output_stream); - g_signal_connect (self->output_stream, - "notify::volume", - G_CALLBACK (output_stream_notify_volume_cb), - self); + g_signal_connect_object (self->output_stream, + "notify::volume", + G_CALLBACK (output_stream_notify_volume_cb), + self, 0); + + g_signal_connect_object (self->output_stream, + "notify::is-muted", + G_CALLBACK (output_stream_notify_is_muted_cb), + self, 0); - g_signal_connect (self->output_stream, - "notify::is-muted", - G_CALLBACK (output_stream_notify_is_muted_cb), - self); update_output_vol_bar (self); } @@ -253,7 +355,7 @@ g_autofree char *name = NULL; if (!self->output_stream) - self->output_stream = gvc_mixer_control_get_default_sink (self->mixer_control); + self->output_stream = g_object_ref (gvc_mixer_control_get_default_sink (self->mixer_control)); volume = gtk_adjustment_get_value (adjustment); rounded = round (volume); @@ -287,6 +389,18 @@ g_signal_emit (self, signals[SETTING_DONE], 0); } + +static void +on_notifications_clear_all_clicked (PhoshSettings *self) +{ + PhoshNotifyManager *manager; + + manager = phosh_notify_manager_get_default (); + phosh_notify_manager_close_all_notifications (manager, PHOSH_NOTIFICATION_REASON_DISMISSED); + g_signal_emit (self, signals[SETTING_DONE], 0); +} + + static GtkWidget * create_notification_row (gpointer item, gpointer data) { @@ -298,7 +412,7 @@ "visible", TRUE, NULL); - frame = phosh_notification_frame_new (); + frame = phosh_notification_frame_new (TRUE); phosh_notification_frame_bind_model (PHOSH_NOTIFICATION_FRAME (frame), item); gtk_widget_show (frame); @@ -310,19 +424,46 @@ static void -end_notify_feedback (PhoshSettings *self) +on_torch_scale_value_changed (PhoshSettings *self, GtkScale *scale_torch) { - if (lfb_event_get_state (self->notify_event) == LFB_EVENT_STATE_RUNNING) - lfb_event_end_feedback_async (self->notify_event, NULL, NULL, NULL); + double value; + + g_return_if_fail (PHOSH_IS_SETTINGS (self)); + g_return_if_fail (PHOSH_IS_TORCH_MANAGER (self->torch_manager)); + + /* Only react to scale changes when torch is enabled */ + if (!phosh_torch_manager_get_enabled (self->torch_manager)) + return; + + self->setting_torch = TRUE; + value = gtk_range_get_value (GTK_RANGE (self->scale_torch)); + g_debug ("Setting torch brightness to %.2f", value); + phosh_torch_manager_set_scaled_brightness (self->torch_manager, value / 100.0); } static void -on_notifcation_items_changed (PhoshSettings *self, - guint position, - guint removed, - guint added, - GListModel *list) +on_torch_brightness_changed (PhoshSettings *self, GParamSpec *pspec, PhoshTorchManager *manager) +{ + g_return_if_fail (PHOSH_IS_SETTINGS (self)); + g_return_if_fail (PHOSH_IS_TORCH_MANAGER (manager)); + + if (self->setting_torch) { + self->setting_torch = FALSE; + return; + } + + gtk_range_set_value (GTK_RANGE (self->scale_torch), + 100.0 * phosh_torch_manager_get_scaled_brightness (self->torch_manager)); +} + + +static void +on_notifcation_frames_items_changed (PhoshSettings *self, + guint position, + guint removed, + guint added, + GListModel *list) { gboolean is_empty; @@ -332,14 +473,9 @@ is_empty = !g_list_model_get_n_items (list); g_debug("Notification list empty: %d", is_empty); - gtk_widget_set_visible (GTK_WIDGET (self->sw_notifications), !is_empty); - if (is_empty) { + gtk_widget_set_visible (GTK_WIDGET (self->box_notifications), !is_empty); + if (is_empty) g_signal_emit (self, signals[SETTING_DONE], 0); - end_notify_feedback (self); - } else if (phosh_shell_get_locked (phosh_shell_get_default ())) { - if (lfb_event_get_state (self->notify_event) != LFB_EVENT_STATE_RUNNING) - lfb_event_trigger_feedback_async (self->notify_event, NULL, NULL, NULL); - } } @@ -358,6 +494,24 @@ static void +setup_torch (PhoshSettings *self) +{ + PhoshShell *shell = phosh_shell_get_default (); + + self->torch_manager = g_object_ref(phosh_shell_get_torch_manager (shell)); + + gtk_range_set_range (GTK_RANGE (self->scale_torch), 40, 100); + gtk_range_set_value (GTK_RANGE (self->scale_torch), + phosh_torch_manager_get_scaled_brightness (self->torch_manager) * 100.0); + g_signal_connect_object (self->torch_manager, + "notify::brightness", + G_CALLBACK(on_torch_brightness_changed), + self, + G_CONNECT_SWAPPED); +} + + +static void setup_volume_bar (PhoshSettings *self) { GtkAdjustment *adj; @@ -393,6 +547,7 @@ setup_brightness_range (self); setup_volume_bar (self); + setup_torch (self); g_signal_connect (self->quick_settings, "child-activated", @@ -407,11 +562,11 @@ NULL); g_signal_connect_object (phosh_notify_manager_get_list (manager), "items-changed", - G_CALLBACK (on_notifcation_items_changed), + G_CALLBACK (on_notifcation_frames_items_changed), self, G_CONNECT_SWAPPED); - on_notifcation_items_changed (self, -1, -1, -1, - G_LIST_MODEL (phosh_notify_manager_get_list (manager))); + on_notifcation_frames_items_changed (self, -1, -1, -1, + G_LIST_MODEL (phosh_notify_manager_get_list (manager))); G_OBJECT_CLASS (phosh_settings_parent_class)->constructed (object); } @@ -424,10 +579,9 @@ brightness_dispose (); - if (self->notify_event) { - end_notify_feedback (self); - g_clear_object (&self->notify_event); - } + g_clear_object (&self->output_stream); + + g_clear_object (&self->torch_manager); G_OBJECT_CLASS (phosh_settings_parent_class)->dispose (object); } @@ -462,38 +616,36 @@ G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); - g_type_ensure (PHOSH_TYPE_BT_INFO); - g_type_ensure (PHOSH_TYPE_DOCKED_INFO); - g_type_ensure (PHOSH_TYPE_FEEDBACK_INFO); - g_type_ensure (PHOSH_TYPE_MEDIA_PLAYER); - g_type_ensure (PHOSH_TYPE_QUICK_SETTING); - g_type_ensure (PHOSH_TYPE_ROTATE_INFO); - g_type_ensure (PHOSH_TYPE_TORCH_INFO); - gtk_widget_class_bind_template_child (widget_class, PhoshSettings, box_settings); gtk_widget_class_bind_template_child (widget_class, PhoshSettings, list_notifications); gtk_widget_class_bind_template_child (widget_class, PhoshSettings, quick_settings); gtk_widget_class_bind_template_child (widget_class, PhoshSettings, scale_brightness); - gtk_widget_class_bind_template_child (widget_class, PhoshSettings, sw_notifications); + gtk_widget_class_bind_template_child (widget_class, PhoshSettings, scale_torch); + gtk_widget_class_bind_template_child (widget_class, PhoshSettings, box_notifications); gtk_widget_class_bind_template_callback (widget_class, battery_setting_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, bt_setting_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, bt_setting_long_pressed_cb); gtk_widget_class_bind_template_callback (widget_class, docked_setting_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, docked_setting_long_pressed_cb); gtk_widget_class_bind_template_callback (widget_class, feedback_setting_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, feedback_setting_long_pressed_cb); gtk_widget_class_bind_template_callback (widget_class, on_media_player_raised); gtk_widget_class_bind_template_callback (widget_class, rotation_setting_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, rotation_setting_long_pressed_cb); gtk_widget_class_bind_template_callback (widget_class, torch_setting_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, wifi_setting_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, wifi_setting_long_pressed_cb); gtk_widget_class_bind_template_callback (widget_class, wwan_setting_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, wwan_setting_long_pressed_cb); + gtk_widget_class_bind_template_callback (widget_class, on_torch_scale_value_changed); + gtk_widget_class_bind_template_callback (widget_class, on_notifications_clear_all_clicked); } static void phosh_settings_init (PhoshSettings *self) { - self->notify_event = lfb_event_new ("message-missed-notification"); - gtk_widget_init_template (GTK_WIDGET (self)); } diff -Nru phosh-0.8.0/src/shell.c phosh-0.13.1/src/shell.c --- phosh-0.8.0/src/shell.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/shell.c 2021-08-31 09:15:52.000000000 +0000 @@ -25,34 +25,50 @@ #include "config.h" #include "shell.h" - #include "batteryinfo.h" #include "background-manager.h" +#include "bt-info.h" #include "bt-manager.h" +#include "connectivity-info.h" +#include "calls-manager.h" +#include "docked-info.h" #include "docked-manager.h" #include "fader.h" +#include "feedbackinfo.h" #include "feedback-manager.h" #include "gnome-shell-manager.h" +#include "gtk-mount-manager.h" +#include "hks-info.h" #include "home.h" #include "idle-manager.h" #include "keyboard-events.h" +#include "location-info.h" +#include "location-manager.h" #include "lockscreen-manager.h" +#include "media-player.h" #include "mode-manager.h" #include "monitor-manager.h" #include "monitor/monitor.h" #include "mount-manager.h" +#include "settings.h" +#include "system-modal-dialog.h" #include "notifications/notify-manager.h" #include "notifications/notification-banner.h" #include "osk-manager.h" -#include "panel.h" #include "phosh-wayland.h" #include "polkit-auth-agent.h" #include "proximity.h" +#include "quick-setting.h" +#include "rotateinfo.h" +#include "rotation-manager.h" #include "sensor-proxy-manager.h" #include "screen-saver-manager.h" +#include "screenshot-manager.h" #include "session-manager.h" #include "system-prompter.h" +#include "top-panel.h" #include "torch-manager.h" +#include "torch-info.h" #include "util.h" #include "wifiinfo.h" #include "wwaninfo.h" @@ -66,19 +82,26 @@ * @Title: PhoshShell * * #PhoshShell is responsible for instantiating the GUI - * parts of the shell#PhoshPanel, #PhoshHome,… and the managers that + * parts of the shell#PhoshTopPanel, #PhoshHome,… and the managers that * interface with DBus #PhoshMonitorManager, #PhoshFeedbackManager, … * and coordinates between them. */ enum { - PHOSH_SHELL_PROP_0, - PHOSH_SHELL_PROP_TRANSFORM, - PHOSH_SHELL_PROP_LOCKED, - PHOSH_SHELL_PROP_PRIMARY_MONITOR, - PHOSH_SHELL_PROP_LAST_PROP + PROP_0, + PROP_LOCKED, + PROP_BUILTIN_MONITOR, + PROP_PRIMARY_MONITOR, + PROP_SHELL_STATE, + PROP_LAST_PROP +}; +static GParamSpec *props[PROP_LAST_PROP]; + +enum { + READY, + N_SIGNALS }; -static GParamSpec *props[PHOSH_SHELL_PROP_LAST_PROP]; +static guint signals[N_SIGNALS] = { 0 }; typedef struct { @@ -90,6 +113,7 @@ PhoshSessionManager *session_manager; PhoshBackgroundManager *background_manager; + PhoshCallsManager *calls_manager; PhoshMonitor *primary_monitor; PhoshMonitor *builtin_monitor; PhoshMonitorManager *monitor_manager; @@ -100,6 +124,7 @@ PhoshWifiManager *wifi_manager; PhoshPolkitAuthAgent *polkit_auth_agent; PhoshScreenSaverManager *screen_saver_manager; + PhoshScreenshotManager *screenshot_manager; PhoshNotifyManager *notify_manager; PhoshFeedbackManager *feedback_manager; PhoshBtManager *bt_manager; @@ -108,19 +133,26 @@ PhoshTorchManager *torch_manager; PhoshModeManager *mode_manager; PhoshDockedManager *docked_manager; + PhoshGtkMountManager *gtk_mount_manager; + PhoshHksManager *hks_manager; PhoshKeyboardEvents *keyboard_events; + PhoshLocationManager *location_manager; PhoshGnomeShellManager *gnome_shell_manager; /* sensors */ PhoshSensorProxyManager *sensor_proxy_manager; PhoshProximity *proximity; + PhoshRotationManager *rotation_manager; gboolean startup_finished; - PhoshMonitorTransform transform; /* current rotation of primary monitor */ /* Mirrors PhoshLockscreenManager's locked property */ gboolean locked; + PhoshShellStateFlags shell_state; + + char *theme_name; + GtkCssProvider *css_provider; } PhoshShellPrivate; @@ -133,63 +165,16 @@ static void -settings_activated_cb (PhoshShell *self, - PhoshPanel *window) +settings_activated_cb (PhoshShell *self, + PhoshTopPanel *window) { PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); - g_return_if_fail (PHOSH_IS_PANEL (priv->panel)); - phosh_panel_toggle_fold (PHOSH_PANEL(priv->panel)); + g_return_if_fail (PHOSH_IS_TOP_PANEL (priv->panel)); + phosh_top_panel_toggle_fold (PHOSH_TOP_PANEL(priv->panel)); } -void -phosh_shell_lock (PhoshShell *self) -{ - phosh_shell_set_locked (self, TRUE); -} - - -void -phosh_shell_unlock (PhoshShell *self) -{ - phosh_shell_set_locked (self, FALSE); -} - -/** - * phosh_shell_get_locked: - * @self: The #PhoshShell singleton - * - * Returns: %TRUE if the shell is currently locked, otherwise %FALSE. - */ -gboolean -phosh_shell_get_locked (PhoshShell *self) -{ - PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); - - return priv->locked; -} - -/** - * phosh_shell_set_locked: - * @self: The #PhoshShell singleton - * @locked: %TRUE to lock the shell - * - * Lock the shell. We proxy to lockscreen-manager to avoid - * that other parts of the shell need to care about this - * abstraction. - */ -void -phosh_shell_set_locked (PhoshShell *self, gboolean locked) -{ - PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); - - if (locked == priv->locked) - return; - - phosh_lockscreen_manager_set_locked (priv->lockscreen_manager, locked); -} - static void on_home_state_changed (PhoshShell *self, GParamSpec *pspec, PhoshHome *home) { @@ -203,9 +188,10 @@ g_object_get (priv->home, "state", &state, NULL); if (state == PHOSH_HOME_STATE_UNFOLDED) { - phosh_panel_fold (PHOSH_PANEL (priv->panel)); + phosh_top_panel_fold (PHOSH_TOP_PANEL (priv->panel)); phosh_osk_manager_set_visible (priv->osk_manager, FALSE); } + phosh_shell_set_state (self, PHOSH_STATE_OVERVIEW, state == PHOSH_HOME_STATE_UNFOLDED); } @@ -215,11 +201,12 @@ PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); PhoshMonitor *monitor; PhoshWayland *wl = phosh_wayland_get_default (); + PhoshAppGrid *app_grid; monitor = phosh_shell_get_primary_monitor (self); g_return_if_fail (monitor); - priv->panel = PHOSH_LAYER_SURFACE(phosh_panel_new (phosh_wayland_get_zwlr_layer_shell_v1(wl), + priv->panel = PHOSH_LAYER_SURFACE(phosh_top_panel_new (phosh_wayland_get_zwlr_layer_shell_v1(wl), monitor->wl_output)); gtk_widget_show (GTK_WIDGET (priv->panel)); @@ -238,6 +225,13 @@ "notify::state", G_CALLBACK(on_home_state_changed), self); + + app_grid = phosh_overview_get_app_grid (phosh_home_get_overview (PHOSH_HOME (priv->home))); + g_object_bind_property (priv->docked_manager, + "enabled", + app_grid, + "filter-adaptive", + G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); } @@ -251,25 +245,38 @@ } +/* Select proper style sheet in case of high contrast */ static void -css_setup (PhoshShell *self) +on_gtk_theme_name_changed (PhoshShell *self, GParamSpec *pspec, GtkSettings *settings) { - GtkCssProvider *provider; - GFile *file; - GError *error = NULL; - - provider = gtk_css_provider_new (); - file = g_file_new_for_uri ("resource:///sm/puri/phosh/style.css"); - - if (!gtk_css_provider_load_from_file (provider, file, &error)) { - g_warning ("Failed to load CSS file: %s", error->message); - g_clear_error (&error); - g_object_unref (file); + const char *style; + g_autofree char *name = NULL; + PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); + g_autoptr (GtkCssProvider) provider = gtk_css_provider_new (); + + g_object_get (settings, "gtk-theme-name", &name, NULL); + + if (g_strcmp0 (priv->theme_name, name) == 0) return; + + priv->theme_name = g_steal_pointer (&name); + g_debug ("GTK theme: %s", priv->theme_name); + + if (priv->css_provider) { + gtk_style_context_remove_provider_for_screen(gdk_screen_get_default (), + GTK_STYLE_PROVIDER (priv->css_provider)); } + + if (g_strcmp0 (priv->theme_name, "HighContrast") == 0) + style = "/sm/puri/phosh/stylesheet/adwaita-hc-light.css"; + else + style = "/sm/puri/phosh/stylesheet/adwaita-dark.css"; + + gtk_css_provider_load_from_resource (provider, style); gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), - GTK_STYLE_PROVIDER (provider), 600); - g_object_unref (file); + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_set_object (&priv->css_provider, provider); } @@ -283,10 +290,11 @@ PhoshShellPrivate *priv = phosh_shell_get_instance_private(self); switch (property_id) { - case PHOSH_SHELL_PROP_LOCKED: + case PROP_LOCKED: priv->locked = g_value_get_boolean (value); + phosh_shell_set_state (self, PHOSH_STATE_LOCKED, priv->locked); break; - case PHOSH_SHELL_PROP_PRIMARY_MONITOR: + case PROP_PRIMARY_MONITOR: phosh_shell_set_primary_monitor (self, g_value_get_object (value)); break; default: @@ -306,15 +314,18 @@ PhoshShellPrivate *priv = phosh_shell_get_instance_private(self); switch (property_id) { - case PHOSH_SHELL_PROP_TRANSFORM: - g_value_set_enum (value, phosh_monitor_get_transform(priv->primary_monitor)); - break; - case PHOSH_SHELL_PROP_LOCKED: + case PROP_LOCKED: g_value_set_boolean (value, priv->locked); break; - case PHOSH_SHELL_PROP_PRIMARY_MONITOR: + case PROP_BUILTIN_MONITOR: + g_value_set_object (value, phosh_shell_get_builtin_monitor (self)); + break; + case PROP_PRIMARY_MONITOR: g_value_set_object (value, phosh_shell_get_primary_monitor (self)); break; + case PROP_SHELL_STATE: + g_value_set_flags (value, priv->shell_state); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -328,20 +339,17 @@ PhoshShell *self = PHOSH_SHELL (object); PhoshShellPrivate *priv = phosh_shell_get_instance_private(self); - if (priv->sensor_proxy_manager) { - phosh_dbus_sensor_proxy_call_release_accelerometer_sync ( - PHOSH_DBUS_SENSOR_PROXY(priv->sensor_proxy_manager), - NULL, NULL); - g_clear_object (&priv->sensor_proxy_manager); - } - panels_dispose (self); g_clear_pointer (&priv->faders, g_ptr_array_unref); g_clear_object (&priv->notification_banner); - g_clear_object (&priv->keyboard_events); /* dispose managers in opposite order of declaration */ + g_clear_object (&priv->screenshot_manager); + g_clear_object (&priv->calls_manager); + g_clear_object (&priv->location_manager); + g_clear_object (&priv->hks_manager); + g_clear_object (&priv->gtk_mount_manager); g_clear_object (&priv->docked_manager); g_clear_object (&priv->mode_manager); g_clear_object (&priv->torch_manager); @@ -362,13 +370,19 @@ g_clear_object (&priv->builtin_monitor); g_clear_object (&priv->primary_monitor); g_clear_object (&priv->background_manager); + g_clear_object (&priv->keyboard_events); /* sensors */ g_clear_object (&priv->proximity); + g_clear_object (&priv->rotation_manager); g_clear_object (&priv->sensor_proxy_manager); + phosh_system_prompter_unregister (); g_clear_object (&priv->session_manager); + g_clear_pointer (&priv->theme_name, g_free); + g_clear_object (&priv->css_provider); + G_OBJECT_CLASS (phosh_shell_parent_class)->dispose (object); } @@ -421,7 +435,7 @@ } if (phosh_notify_manager_get_show_notification_banner (manager, notification) && - phosh_panel_get_state (PHOSH_PANEL (priv->panel)) == PHOSH_PANEL_STATE_FOLDED && + phosh_top_panel_get_state (PHOSH_TOP_PANEL (priv->panel)) == PHOSH_TOP_PANEL_STATE_FOLDED && !priv->locked) { g_set_weak_pointer (&priv->notification_banner, phosh_notification_banner_new (notification)); @@ -450,11 +464,16 @@ static gboolean setup_idle_cb (PhoshShell *self) { + g_autoptr (GError) err = NULL; PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); priv->session_manager = phosh_session_manager_new (); priv->mode_manager = phosh_mode_manager_new (); + priv->sensor_proxy_manager = phosh_sensor_proxy_manager_new (&err); + if (!priv->sensor_proxy_manager) + g_message ("Failed to connect to sensor-proxy: %s", err->message); + panels_create (self); /* Create background after panel since it needs the panel's size */ priv->background_manager = phosh_background_manager_new (); @@ -483,24 +502,27 @@ self, G_CONNECT_SWAPPED); - priv->sensor_proxy_manager = phosh_sensor_proxy_manager_get_default_failable (); + phosh_shell_get_location_manager (self); if (priv->sensor_proxy_manager) { priv->proximity = phosh_proximity_new (priv->sensor_proxy_manager, - priv->lockscreen_manager); - /* TODO: accelerometer */ + priv->calls_manager); + phosh_monitor_manager_set_sensor_proxy_manager (priv->monitor_manager, + priv->sensor_proxy_manager); } + priv->mount_manager = phosh_mount_manager_new (); + priv->gtk_mount_manager = phosh_gtk_mount_manager_new (); phosh_session_manager_register (priv->session_manager, PHOSH_APP_ID, g_getenv ("DESKTOP_AUTOSTART_ID")); g_unsetenv ("DESKTOP_AUTOSTART_ID"); - /* If we start rotated, fix this up */ - if (phosh_shell_get_transform (self) != PHOSH_MONITOR_TRANSFORM_NORMAL) - phosh_shell_set_transform (self, PHOSH_MONITOR_TRANSFORM_NORMAL); + priv->gnome_shell_manager = phosh_gnome_shell_manager_get_default (); + priv->screenshot_manager = phosh_screenshot_manager_new (); priv->startup_finished = TRUE; + g_signal_emit (self, signals[READY], 0); return FALSE; } @@ -510,9 +532,22 @@ static void type_setup (void) { - phosh_battery_info_get_type(); - phosh_wifi_info_get_type(); - phosh_wwan_info_get_type(); + g_type_ensure (PHOSH_TYPE_BATTERY_INFO); + g_type_ensure (PHOSH_TYPE_BT_INFO); + g_type_ensure (PHOSH_TYPE_CONNECTIVITY_INFO); + g_type_ensure (PHOSH_TYPE_DOCKED_INFO); + g_type_ensure (PHOSH_TYPE_FEEDBACK_INFO); + g_type_ensure (PHOSH_TYPE_HKS_INFO); + g_type_ensure (PHOSH_TYPE_LOCATION_INFO); + g_type_ensure (PHOSH_TYPE_MEDIA_PLAYER); + g_type_ensure (PHOSH_TYPE_QUICK_SETTING); + g_type_ensure (PHOSH_TYPE_ROTATE_INFO); + g_type_ensure (PHOSH_TYPE_SETTINGS); + g_type_ensure (PHOSH_TYPE_SYSTEM_MODAL); + g_type_ensure (PHOSH_TYPE_SYSTEM_MODAL_DIALOG); + g_type_ensure (PHOSH_TYPE_TORCH_INFO); + g_type_ensure (PHOSH_TYPE_WIFI_INFO); + g_type_ensure (PHOSH_TYPE_WWAN_INFO); } @@ -520,34 +555,48 @@ on_builtin_monitor_power_mode_changed (PhoshShell *self, GParamSpec *pspec, PhoshMonitor *monitor) { PhoshMonitorPowerSaveMode mode; + PhoshShellPrivate *priv; g_return_if_fail (PHOSH_IS_SHELL (self)); g_return_if_fail (PHOSH_IS_MONITOR (monitor)); + priv = phosh_shell_get_instance_private (self); g_object_get (monitor, "power-mode", &mode, NULL); - if (mode == PHOSH_MONITOR_POWER_SAVE_MODE_OFF) + /* Might be emitted on startup before lockscreen_manager is up */ + if (mode == PHOSH_MONITOR_POWER_SAVE_MODE_OFF && priv->lockscreen_manager) phosh_shell_lock (self); -} + phosh_shell_set_state (self, PHOSH_STATE_BLANKED, mode == PHOSH_MONITOR_POWER_SAVE_MODE_OFF); +} static void -on_primary_monitor_configured (PhoshShell *self, - PhoshMonitor *monitor) +on_monitor_added (PhoshShell *self, PhoshMonitor *monitor) { PhoshShellPrivate *priv; - PhoshMonitorTransform transform; g_return_if_fail (PHOSH_IS_SHELL (self)); g_return_if_fail (PHOSH_IS_MONITOR (monitor)); - priv = phosh_shell_get_instance_private (self); - transform = phosh_monitor_get_transform (monitor); - if (transform == priv->transform) + + g_debug ("Monitor %p (%s)", monitor, monitor->name); + + if (priv->builtin_monitor) + return; + + if (!phosh_monitor_is_builtin (monitor)) return; - priv->transform = transform; - g_debug ("Primary monitor transform %d", transform); - g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_SHELL_PROP_TRANSFORM]); + priv->builtin_monitor = g_object_ref (monitor); + g_signal_connect_swapped (priv->builtin_monitor, + "notify::power-mode", + G_CALLBACK(on_builtin_monitor_power_mode_changed), + self); + + g_debug ("Updating builtin monitor to %s", monitor->name); + if (priv->rotation_manager) + phosh_rotation_manager_set_monitor (priv->rotation_manager, monitor); + + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_BUILTIN_MONITOR]); } @@ -560,27 +609,64 @@ g_return_if_fail (PHOSH_IS_MONITOR (monitor)); priv = phosh_shell_get_instance_private (self); - if (priv->primary_monitor != monitor) - return; + if (priv->builtin_monitor == monitor) { + g_debug ("Builtin monitor %p (%s) removed", monitor, monitor->name); - g_debug ("Primary monitor removed %p", monitor); + if (priv->builtin_monitor) { + /* Power mode listener */ + g_signal_handlers_disconnect_by_data (priv->builtin_monitor, self); + g_clear_object (&priv->builtin_monitor); + } - /* Prefer built in monitor when primary is gone... */ - if (priv->builtin_monitor && monitor != priv->builtin_monitor) { - phosh_shell_set_primary_monitor (self, priv->builtin_monitor); - return; + if (priv->rotation_manager) + phosh_rotation_manager_set_monitor (priv->rotation_manager, NULL); + + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_BUILTIN_MONITOR]); + } + + if (priv->primary_monitor == monitor) { + g_debug ("Primary monitor %p (%s) removed", monitor, monitor->name); + + /* Prefer built in monitor when primary is gone... */ + if (priv->builtin_monitor) { + phosh_shell_set_primary_monitor (self, priv->builtin_monitor); + return; + } + + /* ...just pick the first one available otherwise */ + for (int i = 0; i < phosh_monitor_manager_get_num_monitors (priv->monitor_manager); i++) { + PhoshMonitor *new_primary = phosh_monitor_manager_get_monitor (priv->monitor_manager, i); + if (new_primary != monitor) { + phosh_shell_set_primary_monitor (self, new_primary); + break; + } + } + g_assert (priv->primary_monitor && priv->primary_monitor != monitor); } +} + + +static PhoshMonitor * +find_builtin_monitor (PhoshShell *self) +{ + PhoshShellPrivate *priv; + PhoshMonitor *monitor = NULL; + + g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); + priv = phosh_shell_get_instance_private (self); + + if (priv->builtin_monitor) + return priv->builtin_monitor; - /* ...just pick the first one available otherwise */ for (int i = 0; i < phosh_monitor_manager_get_num_monitors (priv->monitor_manager); i++) { - PhoshMonitor *new_primary = phosh_monitor_manager_get_monitor (priv->monitor_manager, i); - if (new_primary != monitor) { - phosh_shell_set_primary_monitor (self, new_primary); + PhoshMonitor *tmp = phosh_monitor_manager_get_monitor (priv->monitor_manager, i); + if (phosh_monitor_is_builtin (tmp)) { + monitor = tmp; break; } } - g_assert (priv->primary_monitor && priv->primary_monitor != monitor); + return monitor; } @@ -593,11 +679,14 @@ G_OBJECT_CLASS (phosh_shell_parent_class)->constructed (object); /* We bind this early since a wl_display_roundtrip () would make us miss - exising toplevels */ + existing toplevels */ priv->toplevel_manager = phosh_toplevel_manager_new (); - priv->transform = -1; /* force initial update */ - priv->monitor_manager = phosh_monitor_manager_new (); + priv->monitor_manager = phosh_monitor_manager_new (NULL); + g_signal_connect_swapped (priv->monitor_manager, + "monitor-added", + G_CALLBACK (on_monitor_added), + self); g_signal_connect_swapped (priv->monitor_manager, "monitor-removed", G_CALLBACK (on_monitor_removed), @@ -606,27 +695,34 @@ /* Make sure all outputs are up to date */ phosh_wayland_roundtrip (phosh_wayland_get_default ()); - if (phosh_monitor_manager_get_num_monitors(priv->monitor_manager)) { - priv->builtin_monitor = phosh_shell_get_builtin_monitor (self); + if (phosh_monitor_manager_get_num_monitors (priv->monitor_manager)) { + PhoshMonitor *monitor = find_builtin_monitor (self); + + /* Setup builtin monitor */ + if (monitor) { + on_monitor_added (self, monitor); + g_debug ("Builtin monitor %p, configured: %d", + priv->builtin_monitor, + phosh_monitor_is_configured (priv->builtin_monitor)); + } - g_debug ("Builtin monitor is %s, %d", priv->builtin_monitor->name, - phosh_monitor_is_configured (priv->builtin_monitor)); + /* Setup primary monitor, prefer builtin */ /* Can't invoke phosh_shell_set_primary_monitor () since the shell object does not really exist yet but we need the primary monitor early for the panels */ - priv->primary_monitor = g_object_ref (priv->builtin_monitor); - g_signal_connect_swapped (priv->primary_monitor, - "configured", - G_CALLBACK (on_primary_monitor_configured), - self); + if (priv->builtin_monitor) + priv->primary_monitor = g_object_ref (priv->builtin_monitor); + else + priv->primary_monitor = g_object_ref (phosh_monitor_manager_get_monitor (priv->monitor_manager, 0)); + } else { + g_error ("Need at least one monitor"); } gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (), "/sm/puri/phosh/icons"); - css_setup (self); - type_setup (); - priv->lockscreen_manager = phosh_lockscreen_manager_new (); + priv->calls_manager = phosh_calls_manager_new (); + priv->lockscreen_manager = phosh_lockscreen_manager_new (priv->calls_manager); g_object_bind_property (priv->lockscreen_manager, "locked", self, "locked", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); @@ -639,16 +735,6 @@ priv->polkit_auth_agent = phosh_polkit_auth_agent_new (); priv->feedback_manager = phosh_feedback_manager_new (); - priv->gnome_shell_manager = phosh_gnome_shell_manager_get_default (); - - if (priv->builtin_monitor) { - g_signal_connect_swapped ( - priv->builtin_monitor, - "notify::power-mode", - G_CALLBACK(on_builtin_monitor_power_mode_changed), - self); - } - priv->keyboard_events = phosh_keyboard_events_new (); g_idle_add ((GSourceFunc) setup_idle_cb, self); @@ -666,71 +752,70 @@ object_class->set_property = phosh_shell_set_property; object_class->get_property = phosh_shell_get_property; - props[PHOSH_SHELL_PROP_TRANSFORM] = - g_param_spec_enum ("transform", - "Transform", - "Monitor transform of the primary monitor", - PHOSH_TYPE_MONITOR_TRANSFORM, - PHOSH_MONITOR_TRANSFORM_NORMAL, - G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY); + type_setup (); - props[PHOSH_SHELL_PROP_LOCKED] = + props[PROP_LOCKED] = g_param_spec_boolean ("locked", "Locked", "Whether the screen is locked", FALSE, - G_PARAM_READWRITE); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - props[PHOSH_SHELL_PROP_PRIMARY_MONITOR] = + /** + * PhoshShell:builtin-monitor: + * + * The built in monitor. This is a hardware property and hence can + * only be read. It can be %NULL when not present or disabled. + */ + props[PROP_BUILTIN_MONITOR] = + g_param_spec_object ("builtin-monitor", + "Built in monitor", + "The builtin monitor", + PHOSH_TYPE_MONITOR, + G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + /** + * PhoshShell:primary-monitor: + * + * The primary monitor that has the panels, lock screen etc. This can't be %NULL. + */ + props[PROP_PRIMARY_MONITOR] = g_param_spec_object ("primary-monitor", "Primary monitor", "The primary monitor", PHOSH_TYPE_MONITOR, - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); - g_object_class_install_properties (object_class, PHOSH_SHELL_PROP_LAST_PROP, props); + props[PROP_SHELL_STATE] = + g_param_spec_flags ("shell-state", + "Shell state", + "The state of the shell", + PHOSH_TYPE_SHELL_STATE_FLAGS, + PHOSH_STATE_NONE, + G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); + + signals[READY] = g_signal_new ("ready", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); } static void phosh_shell_init (PhoshShell *self) { + PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); GtkSettings *gtk_settings; gtk_settings = gtk_settings_get_default (); g_object_set (G_OBJECT (gtk_settings), "gtk-application-prefer-dark-theme", TRUE, NULL); -} - - -PhoshMonitorTransform -phosh_shell_get_transform (PhoshShell *self) -{ - PhoshShellPrivate *priv; - - g_return_val_if_fail (PHOSH_IS_SHELL (self), PHOSH_MONITOR_TRANSFORM_NORMAL); - priv = phosh_shell_get_instance_private (self); - g_return_val_if_fail (priv->primary_monitor, PHOSH_MONITOR_TRANSFORM_NORMAL); - return phosh_monitor_get_transform (priv->primary_monitor); -} - - -void -phosh_shell_set_transform (PhoshShell *self, - PhoshMonitorTransform transform) -{ - PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); - PhoshMonitorTransform current; - g_return_if_fail (priv->primary_monitor); - current = phosh_monitor_get_transform (priv->primary_monitor); - if (current == transform) - return; + g_signal_connect_swapped (gtk_settings, "notify::gtk-theme-name", G_CALLBACK (on_gtk_theme_name_changed), self); + on_gtk_theme_name_changed (self, NULL, gtk_settings); - phosh_monitor_manager_set_monitor_transform (priv->monitor_manager, - priv->primary_monitor, - transform); - phosh_monitor_manager_apply_monitor_config (priv->monitor_manager); - /* Notification change signalled in on_primary_monitor_configured */ + priv->shell_state = PHOSH_STATE_NONE; } @@ -739,7 +824,6 @@ { PhoshShellPrivate *priv; PhoshMonitor *m = NULL; - PhoshMonitorTransform transform; g_return_if_fail (monitor); g_return_if_fail (PHOSH_IS_SHELL (self)); @@ -755,25 +839,15 @@ } g_return_if_fail (monitor == m); - if (priv->primary_monitor) - g_signal_handlers_disconnect_by_data (priv->primary_monitor, self); g_clear_object (&priv->primary_monitor); priv->primary_monitor = g_object_ref (monitor); g_debug ("New primary monitor is %s", monitor->name); - g_signal_connect_swapped (priv->primary_monitor, - "configured", - G_CALLBACK (on_primary_monitor_configured), - self); - /* Catch up if old and new primary monitor's rotation are different */ - transform = phosh_monitor_get_transform (priv->primary_monitor); - if (transform != priv->transform) - on_primary_monitor_configured (self, priv->primary_monitor); /* Move panels to the new monitor by recreating the layer shell surfaces */ panels_dispose (self); panels_create (self); - g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_SHELL_PROP_PRIMARY_MONITOR]); + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PRIMARY_MONITOR]); } @@ -781,25 +855,12 @@ phosh_shell_get_builtin_monitor (PhoshShell *self) { PhoshShellPrivate *priv; - PhoshMonitor *monitor = NULL; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); + g_return_val_if_fail (PHOSH_IS_MONITOR (priv->builtin_monitor) || priv->builtin_monitor == NULL, NULL); - if (priv->builtin_monitor) - return priv->builtin_monitor; - - for (int i = 0; i < phosh_monitor_manager_get_num_monitors (priv->monitor_manager); i++) { - monitor = phosh_monitor_manager_get_monitor (priv->monitor_manager, i); - if (phosh_monitor_is_builtin (monitor)) - break; - } - - if (!monitor) - monitor = phosh_monitor_manager_get_monitor (priv->monitor_manager, 0); - g_return_val_if_fail (monitor, NULL); - - return monitor; + return priv->builtin_monitor; } @@ -822,6 +883,59 @@ return monitor; } +/* Manager getters */ + +PhoshBackgroundManager * +phosh_shell_get_background_manager (PhoshShell *self) +{ + PhoshShellPrivate *priv; + + g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); + priv = phosh_shell_get_instance_private (self); + g_return_val_if_fail (PHOSH_IS_BACKGROUND_MANAGER (priv->background_manager), NULL); + + return priv->background_manager; +} + + +PhoshCallsManager * +phosh_shell_get_calls_manager (PhoshShell *self) +{ + PhoshShellPrivate *priv; + + g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); + priv = phosh_shell_get_instance_private (self); + g_return_val_if_fail (PHOSH_IS_CALLS_MANAGER (priv->calls_manager), NULL); + + return priv->calls_manager; +} + + +PhoshFeedbackManager * +phosh_shell_get_feedback_manager (PhoshShell *self) +{ + PhoshShellPrivate *priv; + + g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); + priv = phosh_shell_get_instance_private (self); + g_return_val_if_fail (PHOSH_IS_FEEDBACK_MANAGER (priv->feedback_manager), NULL); + + return priv->feedback_manager; +} + + +PhoshGtkMountManager * +phosh_shell_get_gtk_mount_manager (PhoshShell *self) +{ + PhoshShellPrivate *priv; + + g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); + priv = phosh_shell_get_instance_private (self); + g_return_val_if_fail (PHOSH_IS_GTK_MOUNT_MANAGER (priv->gtk_mount_manager), NULL); + + return priv->gtk_mount_manager; +} + PhoshLockscreenManager * phosh_shell_get_lockscreen_manager (PhoshShell *self) @@ -862,21 +976,32 @@ } -PhoshWifiManager * -phosh_shell_get_wifi_manager (PhoshShell *self) +PhoshToplevelManager * +phosh_shell_get_toplevel_manager (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); - if (!priv->wifi_manager) - priv->wifi_manager = phosh_wifi_manager_new (); + g_return_val_if_fail (PHOSH_IS_TOPLEVEL_MANAGER (priv->toplevel_manager), NULL); + return priv->toplevel_manager; +} - g_return_val_if_fail (PHOSH_IS_WIFI_MANAGER (priv->wifi_manager), NULL); - return priv->wifi_manager; + +PhoshSessionManager * +phosh_shell_get_session_manager (PhoshShell *self) +{ + PhoshShellPrivate *priv; + + g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); + priv = phosh_shell_get_instance_private (self); + g_return_val_if_fail (PHOSH_IS_SESSION_MANAGER (priv->session_manager), NULL); + + return priv->session_manager; } +/* Manager getters that create them as needed */ PhoshBtManager * phosh_shell_get_bt_manager (PhoshShell *self) @@ -894,73 +1019,86 @@ } -PhoshOskManager * -phosh_shell_get_osk_manager (PhoshShell *self) +PhoshDockedManager * +phosh_shell_get_docked_manager (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); - if (!priv->osk_manager) - priv->osk_manager = phosh_osk_manager_new (); + if (!priv->docked_manager) + priv->docked_manager = phosh_docked_manager_new (priv->mode_manager); - g_return_val_if_fail (PHOSH_IS_OSK_MANAGER (priv->osk_manager), NULL); - return priv->osk_manager; + g_return_val_if_fail (PHOSH_IS_DOCKED_MANAGER (priv->docked_manager), NULL); + return priv->docked_manager; } -PhoshToplevelManager * -phosh_shell_get_toplevel_manager (PhoshShell *self) +PhoshHksManager * +phosh_shell_get_hks_manager (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); - g_return_val_if_fail (PHOSH_IS_TOPLEVEL_MANAGER (priv->toplevel_manager), NULL); - return priv->toplevel_manager; + if (!priv->hks_manager) + priv->hks_manager = phosh_hks_manager_new (); + + g_return_val_if_fail (PHOSH_IS_HKS_MANAGER (priv->hks_manager), NULL); + return priv->hks_manager; } -PhoshFeedbackManager * -phosh_shell_get_feedback_manager (PhoshShell *self) +PhoshLocationManager * +phosh_shell_get_location_manager (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); - g_return_val_if_fail (PHOSH_IS_FEEDBACK_MANAGER (priv->feedback_manager), NULL); - return priv->feedback_manager; + if (!priv->location_manager) + priv->location_manager = phosh_location_manager_new (); + + g_return_val_if_fail (PHOSH_IS_LOCATION_MANAGER (priv->location_manager), NULL); + return priv->location_manager; } -PhoshWWan * -phosh_shell_get_wwan (PhoshShell *self) +PhoshOskManager * +phosh_shell_get_osk_manager (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); - if (!priv->wwan) { - g_autoptr (GSettings) settings = g_settings_new ("sm.puri.phosh"); - PhoshWWanBackend backend = g_settings_get_enum (settings, WWAN_BACKEND_KEY); + if (!priv->osk_manager) + priv->osk_manager = phosh_osk_manager_new (); - switch (backend) { - default: - case PHOSH_WWAN_BACKEND_MM: - priv->wwan = PHOSH_WWAN (phosh_wwan_mm_new()); - break; - case PHOSH_WWAN_BACKEND_OFONO: - priv->wwan = PHOSH_WWAN (phosh_wwan_ofono_new()); - break; - } - } + g_return_val_if_fail (PHOSH_IS_OSK_MANAGER (priv->osk_manager), NULL); + return priv->osk_manager; +} - g_return_val_if_fail (PHOSH_IS_WWAN (priv->wwan), NULL); - return priv->wwan; + +PhoshRotationManager * +phosh_shell_get_rotation_manager (PhoshShell *self) +{ + PhoshShellPrivate *priv; + + g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); + priv = phosh_shell_get_instance_private (self); + + if (!priv->rotation_manager) + priv->rotation_manager = phosh_rotation_manager_new (priv->sensor_proxy_manager, + priv->lockscreen_manager, + priv->builtin_monitor); + + g_return_val_if_fail (PHOSH_IS_ROTATION_MANAGER (priv->rotation_manager), NULL); + + return priv->rotation_manager; } @@ -980,34 +1118,48 @@ } -PhoshDockedManager * -phosh_shell_get_docked_manager (PhoshShell *self) +PhoshWifiManager * +phosh_shell_get_wifi_manager (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); - if (!priv->docked_manager) - priv->docked_manager = phosh_docked_manager_new (priv->mode_manager); + if (!priv->wifi_manager) + priv->wifi_manager = phosh_wifi_manager_new (); - g_return_val_if_fail (PHOSH_IS_DOCKED_MANAGER (priv->docked_manager), NULL); - return priv->docked_manager; + g_return_val_if_fail (PHOSH_IS_WIFI_MANAGER (priv->wifi_manager), NULL); + return priv->wifi_manager; } -PhoshSessionManager * -phosh_shell_get_session_manager (PhoshShell *self) +PhoshWWan * +phosh_shell_get_wwan (PhoshShell *self) { PhoshShellPrivate *priv; g_return_val_if_fail (PHOSH_IS_SHELL (self), NULL); priv = phosh_shell_get_instance_private (self); - g_return_val_if_fail (PHOSH_IS_SESSION_MANAGER (priv->session_manager), NULL); - return priv->session_manager; -} + if (!priv->wwan) { + g_autoptr (GSettings) settings = g_settings_new ("sm.puri.phosh"); + PhoshWWanBackend backend = g_settings_get_enum (settings, WWAN_BACKEND_KEY); + + switch (backend) { + default: + case PHOSH_WWAN_BACKEND_MM: + priv->wwan = PHOSH_WWAN (phosh_wwan_mm_new()); + break; + case PHOSH_WWAN_BACKEND_OFONO: + priv->wwan = PHOSH_WWAN (phosh_wwan_ofono_new()); + break; + } + } + g_return_val_if_fail (PHOSH_IS_WWAN (priv->wwan), NULL); + return priv->wwan; +} /** * Returns the usable area in pixels usable by a client on the phone @@ -1019,7 +1171,7 @@ PhoshMonitor *monitor; PhoshMonitorMode *mode; int w, h; - int scale; + float scale; g_return_if_fail (PHOSH_IS_SHELL (self)); @@ -1028,11 +1180,11 @@ mode = phosh_monitor_get_current_mode (monitor); g_return_if_fail (mode != NULL); - scale = monitor->scale ? monitor->scale : 1; + scale = MAX(1.0, phosh_monitor_get_fractional_scale (monitor)); - g_debug ("Primary monitor %p scale is %d, transform is %d", + g_debug ("Primary monitor %p scale is %f, transform is %d", monitor, - monitor->scale, + scale, monitor->transform); switch (phosh_monitor_get_transform(monitor)) { @@ -1041,18 +1193,18 @@ case PHOSH_MONITOR_TRANSFORM_FLIPPED: case PHOSH_MONITOR_TRANSFORM_FLIPPED_180: w = mode->width / scale; - h = mode->height / scale - PHOSH_PANEL_HEIGHT - PHOSH_HOME_BUTTON_HEIGHT; + h = mode->height / scale - PHOSH_TOP_PANEL_HEIGHT - PHOSH_HOME_BUTTON_HEIGHT; break; default: w = mode->height / scale; - h = mode->width / scale - PHOSH_PANEL_HEIGHT - PHOSH_HOME_BUTTON_HEIGHT; + h = mode->width / scale - PHOSH_TOP_PANEL_HEIGHT - PHOSH_HOME_BUTTON_HEIGHT; break; } if (x) *x = 0; if (y) - *y = PHOSH_PANEL_HEIGHT; + *y = PHOSH_TOP_PANEL_HEIGHT; if (width) *width = w; if (height) @@ -1077,7 +1229,6 @@ phosh_shell_fade_out (PhoshShell *self, guint timeout) { PhoshShellPrivate *priv; - PhoshWayland *wl = phosh_wayland_get_default (); PhoshMonitorManager *monitor_manager; g_debug ("Fading out..."); @@ -1090,8 +1241,7 @@ PhoshFader *fader; PhoshMonitor *monitor = phosh_monitor_manager_get_monitor (monitor_manager, i); - fader = phosh_fader_new (phosh_wayland_get_zwlr_layer_shell_v1 (wl), - monitor->wl_output); + fader = phosh_fader_new (monitor); g_ptr_array_add (priv->faders, fader); gtk_widget_show (GTK_WIDGET (fader)); if (timeout > 0) @@ -1177,9 +1327,7 @@ void phosh_shell_remove_global_keyboard_action_entries (PhoshShell *self, - const GActionEntry *entries, - gint n_entries) - + GStrv action_names) { PhoshShellPrivate *priv; @@ -1187,9 +1335,9 @@ priv = phosh_shell_get_instance_private (self); g_return_if_fail (priv->keyboard_events); - for (int i = 0; i < n_entries; i++) { + for (int i = 0; i < g_strv_length (action_names); i++) { g_action_map_remove_action (G_ACTION_MAP (priv->keyboard_events), - entries[i].name); + action_names[i]); } } @@ -1216,7 +1364,7 @@ * phosh_get_app_launch_context: * @self: The shell * - * Returns: a an app launch context for the primary display + * Returns: an app launch context for the primary display */ GdkAppLaunchContext* phosh_shell_get_app_launch_context (PhoshShell *self) @@ -1228,3 +1376,120 @@ return gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (priv->panel))); } + +/** + * phosh_shell_get_state + * @self: The shell + * + * Returns: The current #PhoshShellStateFlags + */ +PhoshShellStateFlags +phosh_shell_get_state (PhoshShell *self) +{ + PhoshShellPrivate *priv; + + g_return_val_if_fail (PHOSH_IS_SHELL (self), PHOSH_STATE_NONE); + priv = phosh_shell_get_instance_private (self); + + return priv->shell_state; +} + +/** + * phosh_shell_set_state: + * @self: The shell + * @state: The #PhoshShellStateFlags to set + * @enabled: %TRUE to set a shell state, %FALSE to reset + * + * Set the shells state. + */ +void +phosh_shell_set_state (PhoshShell *self, + PhoshShellStateFlags state, + gboolean enabled) +{ + PhoshShellPrivate *priv; + PhoshShellStateFlags old_state; + g_autofree gchar *str_state = NULL; + g_autofree gchar *str_new_flags = NULL; + + g_return_if_fail (PHOSH_IS_SHELL (self)); + priv = phosh_shell_get_instance_private (self); + + old_state = priv->shell_state; + + if (enabled) + priv->shell_state = priv->shell_state | state; + else + priv->shell_state = priv->shell_state & ~state; + + if (old_state == priv->shell_state) + return; + + str_state = g_flags_to_string (PHOSH_TYPE_SHELL_STATE_FLAGS, + state); + str_new_flags = g_flags_to_string (PHOSH_TYPE_SHELL_STATE_FLAGS, + priv->shell_state); + + g_debug ("%s %s shells state. New state: %s", + enabled ? "Adding to" : "Removing from", + str_state, str_new_flags); + + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SHELL_STATE]); +} + +void +phosh_shell_lock (PhoshShell *self) +{ + g_return_if_fail (PHOSH_IS_SHELL (self)); + + phosh_shell_set_locked (self, TRUE); +} + + +void +phosh_shell_unlock (PhoshShell *self) +{ + g_return_if_fail (PHOSH_IS_SHELL (self)); + + phosh_shell_set_locked (self, FALSE); +} + +/** + * phosh_shell_get_locked: + * @self: The #PhoshShell singleton + * + * Returns: %TRUE if the shell is currently locked, otherwise %FALSE. + */ +gboolean +phosh_shell_get_locked (PhoshShell *self) +{ + PhoshShellPrivate *priv; + + g_return_val_if_fail (PHOSH_IS_SHELL (self), FALSE); + priv = phosh_shell_get_instance_private (self); + + return priv->locked; +} + +/** + * phosh_shell_set_locked: + * @self: The #PhoshShell singleton + * @locked: %TRUE to lock the shell + * + * Lock the shell. We proxy to lockscreen-manager to avoid + * that other parts of the shell need to care about this + * abstraction. + */ +void +phosh_shell_set_locked (PhoshShell *self, gboolean locked) +{ + PhoshShellPrivate *priv; + + g_return_if_fail (PHOSH_IS_SHELL (self)); + priv = phosh_shell_get_instance_private (self); + + if (locked == priv->locked) + return; + + phosh_lockscreen_manager_set_locked (priv->lockscreen_manager, locked); +} diff -Nru phosh-0.8.0/src/shell.h phosh-0.13.1/src/shell.h --- phosh-0.8.0/src/shell.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/shell.h 2021-08-31 09:15:52.000000000 +0000 @@ -8,13 +8,19 @@ #pragma once +#include "background-manager.h" #include "bt-manager.h" +#include "calls-manager.h" #include "docked-manager.h" #include "feedback-manager.h" +#include "gtk-mount-manager.h" +#include "hks-manager.h" +#include "location-manager.h" #include "lockscreen-manager.h" #include "monitor-manager.h" #include "monitor/monitor.h" #include "osk-manager.h" +#include "rotation-manager.h" #include "session-manager.h" #include "toplevel-manager.h" #include "torch-manager.h" @@ -23,6 +29,27 @@ #include +/** + * PhoshShellStateFlags: + * @PHOSH_STATE_NONE: No other state + * @PHOSH_STATE_MODAL_SYSTEM_PROMPT: any modal prompt shown + * @PHOSH_STATE_BLANKED: built-in display off + * @PHOSH_STATE_LOCKED: displays locked + * @PHOSH_STATE_SETTINGS: settings menu unfolded from top bar + * @PHOSH_STATE_OVERVIEW: overview unfolded from bottom bar + * + * These flags are used to keep track of the state + * the #PhoshShell is in. + */ +typedef enum { + PHOSH_STATE_NONE = 0, + PHOSH_STATE_MODAL_SYSTEM_PROMPT = 1 << 0, + PHOSH_STATE_BLANKED = 1 << 1, + PHOSH_STATE_LOCKED = 1 << 2, + PHOSH_STATE_SETTINGS = 1 << 3, + PHOSH_STATE_OVERVIEW = 1 << 4, +} PhoshShellStateFlags; + G_BEGIN_DECLS #define PHOSH_APP_ID "sm.puri.Phosh" @@ -33,8 +60,6 @@ G_DECLARE_FINAL_TYPE (PhoshShell, phosh_shell, PHOSH, SHELL, GObject) PhoshShell *phosh_shell_get_default (void); -void phosh_shell_set_transform (PhoshShell *self, PhoshMonitorTransform transform); -PhoshMonitorTransform phosh_shell_get_transform (PhoshShell *self); void phosh_shell_get_usable_area (PhoshShell *self, int *x, int *y, @@ -47,18 +72,28 @@ void phosh_shell_set_primary_monitor (PhoshShell *self, PhoshMonitor *monitor); PhoshMonitor *phosh_shell_get_primary_monitor (PhoshShell *self); PhoshMonitor *phosh_shell_get_builtin_monitor (PhoshShell *self); + +/* Created by the shell on startup */ +PhoshBackgroundManager *phosh_shell_get_background_manager (PhoshShell *self); +PhoshCallsManager *phosh_shell_get_calls_manager (PhoshShell *self); +PhoshFeedbackManager *phosh_shell_get_feedback_manager (PhoshShell *self); +PhoshGtkMountManager *phosh_shell_get_gtk_mount_manager (PhoshShell *self); PhoshLockscreenManager *phosh_shell_get_lockscreen_manager (PhoshShell *self); -PhoshModeManager *phosh_shell_get_mode_manager (PhoshShell *self); -PhoshMonitorManager *phosh_shell_get_monitor_manager (PhoshShell *self); -PhoshOskManager *phosh_shell_get_osk_manager (PhoshShell *self); -PhoshToplevelManager *phosh_shell_get_toplevel_manager (PhoshShell *self); -PhoshWifiManager *phosh_shell_get_wifi_manager (PhoshShell *self); -PhoshFeedbackManager *phosh_shell_get_feedback_manager (PhoshShell *self); -PhoshBtManager *phosh_shell_get_bt_manager (PhoshShell *self); -PhoshWWan *phosh_shell_get_wwan (PhoshShell *self); -PhoshTorchManager *phosh_shell_get_torch_manager (PhoshShell *self); -PhoshDockedManager *phosh_shell_get_docked_manager (PhoshShell *self); -PhoshSessionManager *phosh_shell_get_session_manager (PhoshShell *self); +PhoshModeManager *phosh_shell_get_mode_manager (PhoshShell *self); +PhoshMonitorManager *phosh_shell_get_monitor_manager (PhoshShell *self); +PhoshToplevelManager *phosh_shell_get_toplevel_manager (PhoshShell *self); +PhoshSessionManager *phosh_shell_get_session_manager (PhoshShell *self); +/* Created on the fly */ +PhoshBtManager *phosh_shell_get_bt_manager (PhoshShell *self); +PhoshDockedManager *phosh_shell_get_docked_manager (PhoshShell *self); +PhoshHksManager *phosh_shell_get_hks_manager (PhoshShell *self); +PhoshLocationManager *phosh_shell_get_location_manager (PhoshShell *self); +PhoshOskManager *phosh_shell_get_osk_manager (PhoshShell *self); +PhoshRotationManager *phosh_shell_get_rotation_manager (PhoshShell *self); +PhoshTorchManager *phosh_shell_get_torch_manager (PhoshShell *self); +PhoshWifiManager *phosh_shell_get_wifi_manager (PhoshShell *self); +PhoshWWan *phosh_shell_get_wwan (PhoshShell *self); + void phosh_shell_fade_out (PhoshShell *self, guint timeout); void phosh_shell_enable_power_save (PhoshShell *self, gboolean enable); gboolean phosh_shell_started_by_display_manager(PhoshShell *self); @@ -68,9 +103,10 @@ gint n_entries, gpointer user_data); void phosh_shell_remove_global_keyboard_action_entries (PhoshShell *self, - const GActionEntry *actions, - gint n_entries); + GStrv action_names); gboolean phosh_shell_is_session_active (PhoshShell *self); GdkAppLaunchContext *phosh_shell_get_app_launch_context (PhoshShell *self); +PhoshShellStateFlags phosh_shell_get_state (PhoshShell *self); +void phosh_shell_set_state (PhoshShell *self, PhoshShellStateFlags state, gboolean enabled); G_END_DECLS diff -Nru phosh-0.8.0/src/status-icon.c phosh-0.13.1/src/status-icon.c --- phosh-0.8.0/src/status-icon.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/status-icon.c 2021-08-31 09:15:52.000000000 +0000 @@ -30,10 +30,12 @@ typedef struct { - GtkWidget *image; - GtkWidget *extra_widget; - GtkIconSize icon_size; - char *info; + GtkWidget *image; + GtkWidget *extra_widget; + GtkIconSize icon_size; + char *info; + + guint idle_id; } PhoshStatusIconPrivate; G_DEFINE_TYPE_WITH_PRIVATE (PhoshStatusIcon, phosh_status_icon, GTK_TYPE_BIN); @@ -93,6 +95,46 @@ } +static gboolean +on_idle (PhoshStatusIcon *self) +{ + PhoshStatusIconClass *klass = PHOSH_STATUS_ICON_GET_CLASS (self); + PhoshStatusIconPrivate *priv = phosh_status_icon_get_instance_private (self); + + if (klass->idle_init) + (*klass->idle_init) (self); + + priv->idle_id = 0; + return G_SOURCE_REMOVE; +} + + +static void +phosh_status_icon_constructed (GObject *object) +{ + PhoshStatusIcon *self = PHOSH_STATUS_ICON (object); + PhoshStatusIconPrivate *priv = phosh_status_icon_get_instance_private (self); + PhoshStatusIconClass *klass = PHOSH_STATUS_ICON_GET_CLASS (self); + + G_OBJECT_CLASS (phosh_status_icon_parent_class)->constructed (object); + + if (klass->idle_init) + priv->idle_id = g_idle_add ((GSourceFunc) on_idle, self); +} + + +static void +phosh_status_icon_dispose (GObject *object) +{ + PhoshStatusIcon *self = PHOSH_STATUS_ICON (object); + PhoshStatusIconPrivate *priv = phosh_status_icon_get_instance_private (self); + + g_clear_handle_id (&priv->idle_id, g_source_remove); + + G_OBJECT_CLASS (phosh_status_icon_parent_class)->dispose (object); +} + + static void phosh_status_icon_finalize (GObject *gobject) { @@ -108,11 +150,16 @@ phosh_status_icon_class_init (PhoshStatusIconClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = phosh_status_icon_set_property; object_class->get_property = phosh_status_icon_get_property; + object_class->constructed = phosh_status_icon_constructed; + object_class->dispose = phosh_status_icon_dispose; object_class->finalize = phosh_status_icon_finalize; + gtk_widget_class_set_css_name (widget_class, "phosh-status-icon"); + props[PHOSH_STATUS_ICON_PROP_ICON_NAME] = g_param_spec_string ("icon-name", "icon name", @@ -312,4 +359,3 @@ g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_STATUS_ICON_PROP_INFO]); } - diff -Nru phosh-0.8.0/src/status-icon.h phosh-0.13.1/src/status-icon.h --- phosh-0.8.0/src/status-icon.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/status-icon.h 2021-08-31 09:15:52.000000000 +0000 @@ -14,9 +14,16 @@ G_DECLARE_DERIVABLE_TYPE (PhoshStatusIcon, phosh_status_icon, PHOSH, STATUS_ICON, GtkBin) +/** + * PhoshStatusIconClass: + * @parent_class: The parent class + * @idle_init: a callback to be invoked once on idle + */ struct _PhoshStatusIconClass { GtkBinClass parent_class; + + void (*idle_init) (PhoshStatusIcon *self); }; GtkWidget * phosh_status_icon_new (void); diff -Nru phosh-0.8.0/src/style.css phosh-0.13.1/src/style.css --- phosh-0.8.0/src/style.css 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/style.css 1970-01-01 00:00:00.000000000 +0000 @@ -1,367 +0,0 @@ -/* - * Top bar panel - */ -.phosh-panel { - font: 15px Cantarell; -} - -.phosh-panel-btn { - background-image: none; - border-width: 0; -} - -.phosh-topbar-clock { - font-weight: bold; -} - -.phosh-power-button { - padding-top: 0; - padding-bottom: 0; -} - -/* - * Home bar - */ -.phosh-osk-button { - border-radius: 50%; - min-width: 0; - min-height: 0; - padding: 6px; -} - -/* - * Settings menu - */ -.phosh-settings-menu { - background-color: black; - border-bottom-right-radius: 10px; - border-bottom-left-radius: 10px; -} - -.phosh-settings-listboxrow { - padding: 0; -} - -.phosh-settings-row { - box-shadow: none; - background-color: black; -} - -.phosh-settings-menu button.circular:not(:hover):not(:active) { - border: 2px solid @theme_bg_color; -} - -.phosh-notification-tray, .phosh-notification-tray list { - border-radius: 6px; - background-color: #282828; -} - -.phosh-quick-setting { - font-size: 9px; - padding: 9px; - border: 0; - box-shadow: 0 0; -} - -.phosh-quick-setting:not(:hover):not(:active) { - background: none; -} - -/* - * Overview (app grid with favories and, activities) - */ -phosh-activity > widget > button { - background: none; - box-shadow: none; - border: none; - border-radius: 0; - padding: 0; - margin: 0; -} - -phosh-activity box button { - background: white; - border: none; - border-radius: 0; - /* box-shadow: 0 2px 2px rgba(0,0,0,0.4), 0 3px 16px rgba(0,0,0,0.3); */ -} - -.phosh-activity-empty { - background: url('resource:///sm/puri/phosh/fake-app.svg'); - background-size: cover; -} - -phosh-activity box { - background: rgba(0, 0, 0, 0.7); - padding: 6px; - color: white; - font-weight: bold; -} - -phosh-activity:focus box { - background: rgba(38, 35, 83, 0.7); -} - -phosh-home, .phosh-panel { - background: black; - color: white; -} - -.phosh-activity-close-button { - border-radius: 50%; - min-width: 48px; - min-height: 48px; - padding: 0; -} - -.phosh-overview { - background: black; -} - -.phosh-favorite { - background: none; - border: none; - box-shadow: none; - padding: 0; -} - -.phosh-favorite:hover { - -gtk-icon-effect: none; -} - -.phosh-favorite:active { - -gtk-icon-effect: highlight; -} - -.phosh-search-bar { - border-radius: 9999px; - padding: 3px 18px 3px 14px; - margin: 0 10px 6px; -} - -phosh-app-grid { - background: black; -} - -phosh-app-grid separator { - background: rgba(51, 51, 51, 1); - min-height: 2px -} - -phosh-app-grid-button { - font-size: 0.8rem; -} - -phosh-app-grid-button button, phosh-app-grid-button button:hover { - background: none; - padding: 0; - margin: 0; - border: 1px solid transparent; -} - -phosh-app-grid-button button:hover, -phosh-app-grid-button button:focus, -.search-active phosh-app-grid-button:first-child button { - background: rgba(46, 45, 45, 0.6); - border-radius: 5px; -} - -phosh-app-grid-button button:focus { - border-color: @theme_selected_bg_color; -} - -phosh-app-grid-button image { - /* -gtk-icon-shadow: 0 1px 2px rgba(0,0,0,0.4), 0 1px 8px rgba(0,0,0,0.2); */ -} - -/* - * Lock screen - */ -phosh-lockscreen, .phosh-lockshield { - background-color: black; -} - -.phosh-lockscreen-clock { - font-size: 72px; - font-weight: 100; -} - -.phosh-lockscreen-arrow { - transition: 400ms linear; - animation: pulsate 1.8s ease-out; - animation-iteration-count: 15; -} - -.phosh-lockscreen-pin { - font-size: 20px; -} - -@keyframes pulsate { - 0% {-gtk-icon-transform: translateY(0); opacity: 0.7} - 35% {-gtk-icon-transform: translateY(-14px); opacity: 1} - 100% {-gtk-icon-transform: translateY(0); opacity: 0.7} -} - -/* Lockscreen keypad */ -keypad > grid > button { - border-radius: 9999px; - -gtk-outline-radius: 9999px; - background-origin: padding-box, border-box; - background-clip: padding-box, border-box; - font-size: 16px; - font-weight: bold; - padding: 16px; - border: 0; - box-shadow: none; - background: 0; - border: 0; -} - -keypad > grid > button:active { - background: rgba(255, 255, 255, 0.3); -} - -.text-only-button:active { - background: rgba(255, 255, 255, 0.5); -} - -keypad > grid > button:focus, .text-only-button:focus { - outline-style: none; -} - -.text-only-button { - font-size: 16px; - font-weight: bold; - padding: 16px 36px; - border: 0; - box-shadow: none; - background: rgba(255, 255, 255, 0.3); - border: 0; -} - -phosh-lockscreen phosh-media-player { - background: none; - border: solid 1px; - border-color: rgb(51,51,51); - border-radius: 0; -} - -phosh-lockscreen phosh-media-player button { - background: rgba(255, 255, 255, 0.3); - border: none; -} - -phosh-lockscreen phosh-media-player button:not(:hover):not(:active) { - background: none; -} - -/* - * System modal dialogs (polkit, gcr) - */ -.phosh-system-modal { - background-color: alpha(@theme_bg_color, 0.7); -} - -.phosh-system-modal-dialog { - background-color: black; - border: solid 2px; - border-color: white; - border-radius: 10px; - padding: 18px; -} - -/* - * Notifications - */ -phosh-notification-content { - background: transparent; -} - -phosh-notification-content .message-area { - padding: 12px; -} - -phosh-notification-content .message-area image { - border-radius: 50%; -} - -phosh-notification-content .actions-area button { - border-radius: 0; - box-shadow: none; - border-left: none; - border-right: none; -} - -phosh-notification-content:last-child .actions-area button:last-child { - border-radius: 0 0 6px 6px; - border-bottom: none; -} - -phosh-notification-frame { - border-radius: 6px; - background-color: #282828; - margin: 12px; -} - -phosh-notification-banner > phosh-notification-frame { - box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.33), - 0px 5px 6px 0px rgba(0, 0, 0, 0.07), - 0px 0px 0px 1px rgba(0, 0, 0, 0.2); -} - -phosh-notification-frame list { - background: transparent; -} - -phosh-notification-frame .header-area { - padding: 12px 12px 0 12px; -} - -phosh-notification-frame .header-area image { - -gtk-icon-style: symbolic; -} - -phosh-notification-banner { - border: none; - background: transparent; - padding: 12px; -} - -/* - * Output fader - */ -@keyframes phosh-fade-in { - from {background:rgba(0, 0, 0, 0);} - to {background:rgba(0, 0, 0, 1);} -} - -.phosh-fader-fade-in { - animation-name: phosh-fade-in; - animation-duration: 2s; - animation-timing-function: linear; - animation-iteration-count: 1; - animation-fill-mode: forwards; -} - -/* - * Media player - */ -phosh-media-player { - background: rgb(51,51,51); - border-radius: 5%; - padding: 9px; - border: 0; - box-shadow: 0 0; -} - -phosh-media-player > button { - border-radius: 0; - box-shadow: none; - outline-style: none; -} - -/* The details button should not look inactive even when disabled */ -phosh-media-player box *:disabled { - color: white; - -gtk-icon-effect: none; -} diff -Nru phosh-0.8.0/src/stylesheet/adwaita-dark.css phosh-0.13.1/src/stylesheet/adwaita-dark.css --- phosh-0.8.0/src/stylesheet/adwaita-dark.css 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/stylesheet/adwaita-dark.css 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,7 @@ +/* Adwaita dark them variant */ + +@define-color phosh_fg_color white; +@define-color phosh_bg_color black; +@define-color phosh_notification_bg_color #282828; + +@import url("resource:///sm/puri/phosh/stylesheet/common.css"); diff -Nru phosh-0.8.0/src/stylesheet/adwaita-hc-light.css phosh-0.13.1/src/stylesheet/adwaita-hc-light.css --- phosh-0.8.0/src/stylesheet/adwaita-hc-light.css 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/stylesheet/adwaita-hc-light.css 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,12 @@ +/* HighContrast theme variant */ + +@define-color phosh_fg_color black; +@define-color phosh_bg_color white; +@define-color phosh_notification_bg_color #e0e0e0; + +@import url("resource:///sm/puri/phosh/stylesheet/common.css"); + +.phosh-panel-btn { + border-width: 1px; + border-radius: 0; +} diff -Nru phosh-0.8.0/src/stylesheet/common.css phosh-0.13.1/src/stylesheet/common.css --- phosh-0.8.0/src/stylesheet/common.css 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/stylesheet/common.css 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,535 @@ +/* + * Top panel bar + */ +phosh-top-panel { + font: 15px Cantarell; +} + +.phosh-panel-btn { + background-image: none; + border-width: 0; +} + +phosh-top-panel .indicators { + font-weight: bold; + font-feature-settings: "tnum"; +} + +.phosh-topbar-clock { + font-weight: bold; + font-feature-settings: "tnum"; +} + +.phosh-power-button { + padding-top: 0; + padding-bottom: 0; +} + +/* + * Home bar + */ +.phosh-osk-button { + border-radius: 50%; + min-width: 0; + min-height: 0; + padding: 6px; +} + +/* + * Settings menu + */ +.phosh-settings-menu { + background-color: @phosh_bg_color; + border-bottom-right-radius: 10px; + border-bottom-left-radius: 10px; +} + +.phosh-settings-menu button.circular:not(:hover):not(:active) { + border: 2px solid @theme_bg_color; +} + +.phosh-notification-tray, .phosh-notification-tray list { + border-radius: 6px; + background-color: @phosh_notification_bg_color; +} + +.phosh-quick-setting { + font-size: 9px; + padding: 9px; + border: 0; + box-shadow: 0 0; +} + +.phosh-quick-setting:not(:hover):not(:active) { + background: none; +} + +/* + * Overview (app grid with favories and, activities) + */ +phosh-activity > widget > button { + background: none; + box-shadow: none; + border: none; + border-radius: 0; + padding: 0; + margin: 0; + transition: none; +} + +phosh-activity box button { + background: white; + border: none; + border-radius: 0; + /* box-shadow: 0 2px 2px rgba(0,0,0,0.4), 0 3px 16px rgba(0,0,0,0.3); */ +} + +.phosh-activity-empty { + background: url('resource:///sm/puri/phosh/fake-app.svg'); + background-size: cover; +} + +phosh-activity box { + background: rgba(0, 0, 0, 0.7); + padding: 6px; + color: white; + font-weight: bold; +} + +phosh-activity:focus box { + background: rgba(38, 35, 83, 0.7); +} + +phosh-home, phosh-top-panel { + background: @phosh_bg_color; + color: @phosh_fg_color; +} + +.phosh-activity-close-button { + border-radius: 50%; + min-width: 48px; + min-height: 48px; + padding: 0; +} + +.phosh-overview { + background: @phosh_bg_color; +} + +.phosh-favorite { + background: none; + border: none; + box-shadow: none; + padding: 0; +} + +.phosh-favorite:hover { + -gtk-icon-effect: none; +} + +.phosh-favorite:active { + -gtk-icon-effect: highlight; +} + +.phosh-search-bar-box { + margin: 6px 16px; +} + +.phosh-search-bar { + border-radius: 9999px; + padding: 3px 18px 3px 14px; +} + +.phosh-menu-button { + margin: 3px 0px 3px 10px; +} + +phosh-app-grid { + background: @phosh_bg_color; +} + +phosh-app-grid separator { + background: rgba(51, 51, 51, 1); + min-height: 2px +} + +phosh-app-grid-button { + font-size: 0.8rem; +} + +phosh-app-grid-button button, phosh-app-grid-button button:hover { + background: none; + padding: 0; + margin: 0; + border: 1px solid transparent; +} + +phosh-app-grid-button button:hover, +phosh-app-grid-button button:focus, +.search-active phosh-app-grid-button:first-child button { + background: rgba(46, 45, 45, 0.6); + border-radius: 5px; +} + +phosh-app-grid-button button:focus { + border-color: @theme_selected_bg_color; +} + +phosh-app-grid-button image { + /* -gtk-icon-shadow: 0 1px 2px rgba(0,0,0,0.4), 0 1px 8px rgba(0,0,0,0.2); */ +} + +/* + * Lock screen + */ +phosh-lockscreen, .phosh-lockshield { + background-color: @phosh_bg_color; +} + +.phosh-lockscreen-clock { + font-size: 72px; + font-weight: 100; + font-feature-settings: "tnum"; +} + +.phosh-lockscreen-arrow { + transition: 400ms linear; + animation: pulsate 1.8s ease-out; + animation-iteration-count: 15; +} + +.phosh-lockscreen-pin { + font-size: 20px; +} + +@keyframes pulsate { + 0% {-gtk-icon-transform: translateY(0); opacity: 0.7} + 35% {-gtk-icon-transform: translateY(-14px); opacity: 1} + 100% {-gtk-icon-transform: translateY(0); opacity: 0.7} +} + +/* Lockscreen keypad */ +keypad > grid > button { + border-radius: 9999px; + -gtk-outline-radius: 9999px; + background-origin: padding-box, border-box; + background-clip: padding-box, border-box; + font-size: 16px; + font-weight: bold; + padding: 16px; + border: 0; + box-shadow: none; + background: 0; +} + +keypad > grid > button:active { + background: rgba(255, 255, 255, 0.3); +} + +.text-only-button:active { + background: rgba(255, 255, 255, 0.5); +} + +keypad > grid > button:focus, .text-only-button:focus { + outline-style: none; +} + +.text-only-button { + font-size: 16px; + font-weight: bold; + padding: 16px 36px; + border: 0; + box-shadow: none; + background: rgba(255, 255, 255, 0.3); +} + +phosh-lockscreen phosh-media-player { + margin-left: 12px; + margin-right: 12px; +} + +phosh-lockscreen .phosh-notification-tray list { + background-color: @phosh_bg_color; +} + +phosh-lockscreen .phosh-notification-tray row { + background-color: @phosh_bg_color; + margin-left: 12px; + margin-right: 12px; +} + +phosh-lockscreen .phosh-notification-tray phosh-notification-frame { + background-color: @phosh_notification_bg_color; + margin: 3px 0px 0px 0px; +} + +phosh-lockscreen .phosh-notification-tray phosh-notification-content { + background-color: @phosh_notification_bg_color; +} + +phosh-lockscreen .phosh-notification-tray phosh-notification-content:last-child { + margin-bottom: 3px; + border-radius: 0px 0px 6px 6px; +} + +/* + * System modal dialogs (polkit, gcr, ...) + */ +.phosh-system-modal { + background-color: alpha(@theme_bg_color, 0.7); +} + +.phosh-system-modal-dialog { + background-color: @theme_bg_color; + border: none; + border-radius: 10px; + box-shadow: 0 0 0 1px alpha(black, .75); + padding: 0px; +} + +.phosh-system-modal-dialog-buttons label { + margin: 12px; +} + +.phosh-system-modal-dialog-buttons button { + padding: 0; + margin: 0; + border-top: 1px solid @borders; + border-right: 1px solid @borders; + border-left-width: 0; + border-bottom-width: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; + box-shadow: none; + text-shadow: none; +} + +.phosh-system-modal-dialog-buttons button:first-child { + border-bottom-left-radius: 11px; + border-bottom-right-radius: 0; +} + +.phosh-system-modal-dialog-buttons button:last-child { + border-bottom-left-radius: 0; + border-bottom-right-radius: 11px; + border-right: none; +} + +.phosh-system-modal-dialog-content { + padding-left: 18px; + padding-right: 18px; +} + +.phosh-system-modal-dialog-title { + padding-top: 18px; + font-weight: 800; + font-size: 120%; +} + +.phosh-end-session-dialog .phosh-end-session-subtitle { + font-feature-settings: "tnum"; +} + +.phosh-end-session-dialog .phosh-end-session-warning { + color: #ba5645; + font-weight: bold; +} + +.phosh-end-session-dialog list { + border-radius: 12px; +} + +.phosh-end-session-dialog list row { + margin-left: 6px; + margin-right: 6px; +} + +.phosh-end-session-dialog list row:first-child { + margin-top: 6px; +} + +.phosh-end-session-dialog list row:last-child { + margin-bottom: 6px; +} + +.phosh-end-session-dialog list row box box.vertical label:first-child { + font-weight: bold; +} + +/* Don't dim list of inhibited applications */ +.phosh-end-session-dialog list * { + color: @theme_text_color; + -gtk-icon-effect: none; +} + +phosh-gtk-mount-prompt .phosh-system-modal-dialog-content > image { + -gtk-icon-style: symbolic; +} + +/* + * Notifications + */ +phosh-notification-content { + background: transparent; +} + +phosh-notification-content .message-area { + padding: 12px; +} + +phosh-notification-content .message-area image { + border-radius: 50%; +} + +phosh-notification-content .actions-area button { + border-radius: 0; + box-shadow: none; + border-left: none; + border-right: none; +} + +phosh-notification-content:last-child .actions-area button:last-child { + border-radius: 0 0 6px 6px; + border-bottom: none; +} + +phosh-notification-frame { + border-radius: 6px; + background-color: @phosh_notification_bg_color; + margin: 12px; +} + +phosh-notification-banner > phosh-notification-frame { + box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.33), + 0px 5px 6px 0px rgba(0, 0, 0, 0.07), + 0px 0px 0px 1px rgba(0, 0, 0, 0.2); +} + +phosh-notification-frame list { + background: transparent; +} + +phosh-notification-frame .header-area { + padding: 12px 12px 0 12px; +} + +phosh-notification-frame .header-area image { + -gtk-icon-style: symbolic; +} + +phosh-notification-banner { + border: none; + background: transparent; + padding: 12px; +} + +/* + * Output fader + */ +@keyframes phosh-fader-default-keyframe { + from {background:rgba(0, 0, 0, 0);} + to {background:rgba(0, 0, 0, 1);} +} + +.phosh-fader-default-fade { + animation-name: phosh-fader-default-keyframe; + animation-duration: 2s; + animation-timing-function: linear; + animation-iteration-count: 1; + animation-fill-mode: forwards; +} + +/* Fader used for proximity dimming */ +.phosh-fader-proximity-fade { + animation-name: phosh-fader-default-keyframe; + animation-duration: 200ms; + animation-timing-function: linear; + animation-iteration-count: 1; + animation-fill-mode: forwards; +} + +/* Fader used for screenshot flash */ +@keyframes phosh-fader-flash-keyframe { + from {background:rgba(255, 255, 255, 1);} + to {background:rgba(255, 255, 255, 0);} +} + +.phosh-fader-flash-fade { + animation-name: phosh-fader-flash-keyframe; + animation-duration: 500ms; + animation-timing-function: linear; + animation-iteration-count: 1; + animation-fill-mode: forwards; +} + +.phosh-fader-screenshot-opaque { + background: rgba(255, 255, 255, 0); +} + +/* + * Media player + */ +phosh-media-player { + background: @phosh_notification_bg_color; + border-radius: 6px; + box-shadow: none; +} + +phosh-media-player button { + background: @phosh_notification_bg_color; + border-radius: 0; + box-shadow: none; + border: 0; + outline-style: none; +} + +phosh-media-player button:hover, +phosh-media-player button:active { + background-color: rgba(255, 255, 255, 0.3); +} + +phosh-media-player > box > button:first-child { + border-radius: 0 0 0 6px; +} + +phosh-media-player > box > button:last-child { + border-radius: 0 0 6px 0; +} + +phosh-media-player .media-player-details { + border-radius: 6px 6px 0 0; +} + +/* The details button should not look inactive even when disabled */ +phosh-media-player .media-player-details *:disabled { + color: @theme_fg_color; + -gtk-icon-effect: none; +} + +/* + * OSD + */ +phosh-osd-window levelbar block { + min-height: 16px; + box-shadow: none; + border-color: white; + border-radius: 5px; +} + +phosh-osd-window levelbar block.low { + background-color: white; +} + +phosh-osd-window levelbar block.high { + background-color: white; +} + +phosh-osd-window levelbar block.full { + background-color: white; +} + +phosh-osd-window levelbar trough { + box-shadow: none; + border-width: 0px; + padding: 0px; +} diff -Nru phosh-0.8.0/src/system-modal.c phosh-0.13.1/src/system-modal.c --- phosh-0.8.0/src/system-modal.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/system-modal.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-system-modal" + +#include "config.h" + +#include "shell.h" +#include "system-modal.h" + +/** + * SECTION:system-modal + * @short_description: A modal system component + * @Title: PhoshSystemModal + * + * The #PhoshSystemModal is used as a base class for other + * system components such as dialogs like #PhoshSystemPrompt or + * the OSD display. + */ + +enum { + PROP_0, + PROP_MONITOR, + PROP_LAST_PROP, +}; +static GParamSpec *props[PROP_LAST_PROP]; + +typedef struct { + PhoshMonitor *monitor; + +} PhoshSystemModalPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (PhoshSystemModal, phosh_system_modal, PHOSH_TYPE_LAYER_SURFACE); + +/* + * Keep track of opened modals + * Only reset PHOSH_STATE_MODAL_SYSTEM_PROMPT when there are no more modals + * see phosh_system_modal_map/unmap + */ +static int modal_count = 0; + + +static void +phosh_system_modal_map (GtkWidget *widget) +{ + g_return_if_fail (PHOSH_IS_SYSTEM_MODAL (widget)); + + modal_count++; + phosh_shell_set_state (phosh_shell_get_default (), PHOSH_STATE_MODAL_SYSTEM_PROMPT, TRUE); + + GTK_WIDGET_CLASS (phosh_system_modal_parent_class)->map (widget); +} + + +static void +phosh_system_modal_unmap (GtkWidget *widget) +{ + g_return_if_fail (PHOSH_IS_SYSTEM_MODAL (widget)); + + modal_count--; + + if (modal_count == 0) + phosh_shell_set_state (phosh_shell_get_default (), PHOSH_STATE_MODAL_SYSTEM_PROMPT, FALSE); + else if (modal_count < 0) + g_warning ("The modal counter is negative %d. This should never happen", + modal_count); + + GTK_WIDGET_CLASS (phosh_system_modal_parent_class)->unmap (widget); +} + +static void +phosh_system_modal_set_property (GObject *obj, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshSystemModal *self = PHOSH_SYSTEM_MODAL (obj); + PhoshSystemModalPrivate *priv = phosh_system_modal_get_instance_private (self); + + switch (prop_id) { + case PROP_MONITOR: + g_set_object (&priv->monitor, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + + +static void +phosh_system_modal_get_property (GObject *obj, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshSystemModal *self = PHOSH_SYSTEM_MODAL (obj); + PhoshSystemModalPrivate *priv = phosh_system_modal_get_instance_private (self); + + switch (prop_id) { + case PROP_MONITOR: + g_value_set_object (value, priv->monitor); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + + +static void +phosh_system_modal_dispose (GObject *obj) +{ + PhoshSystemModal *self = PHOSH_SYSTEM_MODAL (obj); + PhoshSystemModalPrivate *priv = phosh_system_modal_get_instance_private (self); + + g_clear_object (&priv->monitor); + + G_OBJECT_CLASS (phosh_system_modal_parent_class)->dispose (obj); +} + + +static void +phosh_system_modal_constructed (GObject *object) +{ + PhoshSystemModal *self = PHOSH_SYSTEM_MODAL (object); + PhoshSystemModalPrivate *priv = phosh_system_modal_get_instance_private (self); + PhoshWayland *wl = phosh_wayland_get_default (); + + if (priv->monitor == NULL) + priv->monitor = g_object_ref (phosh_shell_get_primary_monitor (phosh_shell_get_default ())); + + g_object_set (PHOSH_LAYER_SURFACE (self), + "layer-shell", phosh_wayland_get_zwlr_layer_shell_v1 (wl), + "wl-output", phosh_monitor_get_wl_output (priv->monitor), + "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, + "layer", ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, + "kbd-interactivity", TRUE, + "exclusive-zone", -1, + "namespace", "phosh system-modal", + NULL); + + gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (self)), + "phosh-system-modal"); + + G_OBJECT_CLASS (phosh_system_modal_parent_class)->constructed (object); +} + + +static void +phosh_system_modal_class_init (PhoshSystemModalClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + widget_class->map = phosh_system_modal_map; + widget_class->unmap = phosh_system_modal_unmap; + + object_class->get_property = phosh_system_modal_get_property; + object_class->set_property = phosh_system_modal_set_property; + object_class->constructed = phosh_system_modal_constructed; + object_class->dispose = phosh_system_modal_dispose; + + props[PROP_MONITOR] = g_param_spec_object ("monitor", + "Monitor", + "Monitor to put modal on", + PHOSH_TYPE_MONITOR, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); +} + + +static void +phosh_system_modal_init (PhoshSystemModal *self) +{ +} + +/** + * phosh_system_modal_new: + * @monitor: The #PhoshMonitor to put the modal surface on. If %NULL the primary monitor is used. + * + * Create a new system-modal surface. + */ +GtkWidget * +phosh_system_modal_new (PhoshMonitor *monitor) +{ + g_return_val_if_fail (PHOSH_IS_MONITOR (monitor) || monitor == NULL, NULL); + + return g_object_new (PHOSH_TYPE_SYSTEM_MODAL, "monitor", monitor, NULL); +} diff -Nru phosh-0.8.0/src/system-modal-dialog.c phosh-0.13.1/src/system-modal-dialog.c --- phosh-0.8.0/src/system-modal-dialog.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/system-modal-dialog.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-system-modal-dialog" + +#include "config.h" + +#include "shell.h" +#include "system-modal-dialog.h" +#include "swipe-away-bin.h" + +/** + * SECTION:system-modal-dialog + * @short_description: A modal system dialog + * @Title: PhoshSystemModalDialog + * + * The #PhoshSystemModalDialog is used as a base class for system modal dialogs + * such as #PhoshSystemPrompt or #PhoshNetworkAuthPrompt. It consists of a title + * at the top, a content widget below that and button are at the bottom. + * The content widget can be set via #phosh_system_modal_dialog_set_content() and buttons + * to the button area added via #phosh_system_modal_dialog_add_button(). + * + * # CSS Style classes + * + * A system modal dialog uses several style classes for consistent layout: + * ".phosh-system-modal-dialog" for the whole dialog area, + * ".phosh-system-modal-dialog-title" for the dialog title, + * ".phosh-system-modal-dialog-content" for the content area and + * ".phosh-system-modal-dialog-buttons" for the button area. + * + * # PhoshSystemModalDialog as #GtkBuildable + * + * The content widget and buttons can be specified using type + * <phosh-dialog-content> and <phosh-dialog-button> type attributes: + * + * |[ + * + * + * + * True + * vertical + * + * ... + * + * + * + * + * + * Ok + * ... + * + * + * + * + * Cancel + * ... + * + * + * + * ]| + */ + +enum { + PROP_0, + PROP_TITLE, + PROP_LAST_PROP, +}; +static GParamSpec *props[PROP_LAST_PROP]; + +enum { + DIALOG_CANCELED, + N_SIGNALS +}; +static guint signals[N_SIGNALS] = { 0 }; + +typedef struct { + gchar *title; + + GtkWidget *lbl_title; + GtkWidget *box_dialog; + GtkWidget *box_buttons; +} PhoshSystemModalDialogPrivate; + +static void phosh_system_modal_dialog_buildable_init (GtkBuildableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (PhoshSystemModalDialog, phosh_system_modal_dialog, + PHOSH_TYPE_SYSTEM_MODAL, + G_ADD_PRIVATE (PhoshSystemModalDialog) + G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, + phosh_system_modal_dialog_buildable_init)) + +static void +phosh_system_modal_dialog_set_property (GObject *obj, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshSystemModalDialog *self = PHOSH_SYSTEM_MODAL_DIALOG (obj); + + switch (prop_id) { + case PROP_TITLE: + phosh_system_modal_dialog_set_title (self, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + + +static void +phosh_system_modal_dialog_get_property (GObject *obj, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshSystemModalDialog *self = PHOSH_SYSTEM_MODAL_DIALOG (obj); + PhoshSystemModalDialogPrivate *priv = phosh_system_modal_dialog_get_instance_private (self); + + switch (prop_id) { + case PROP_TITLE: + g_value_set_string (value, priv->title); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + + +static void +on_removed_by_swipe (PhoshSystemModalDialog *self) +{ + g_signal_emit (self, signals[DIALOG_CANCELED], 0); +} + + +static gboolean +on_key_press_event (PhoshSystemModalDialog *self, GdkEventKey *event, gpointer data) +{ + gboolean handled = FALSE; + + g_return_val_if_fail (PHOSH_IS_SYSTEM_MODAL_DIALOG (self), FALSE); + + switch (event->keyval) { + case GDK_KEY_Escape: + g_signal_emit (self, signals[DIALOG_CANCELED], 0); + handled = TRUE; + break; + default: + /* nothing to do */ + break; + } + + return handled; +} + + +static void +phosh_system_modal_dialog_finalize (GObject *obj) +{ + PhoshSystemModalDialog *self = PHOSH_SYSTEM_MODAL_DIALOG (obj); + PhoshSystemModalDialogPrivate *priv = phosh_system_modal_dialog_get_instance_private (self); + + g_clear_pointer (&priv->title, g_free); + + G_OBJECT_CLASS (phosh_system_modal_dialog_parent_class)->finalize (obj); +} + + +static void +phosh_system_modal_dialog_constructed (GObject *object) +{ + PhoshSystemModalDialog *self = PHOSH_SYSTEM_MODAL_DIALOG (object); + PhoshSystemModalDialogPrivate *priv = phosh_system_modal_dialog_get_instance_private (self); + + G_OBJECT_CLASS (phosh_system_modal_dialog_parent_class)->constructed (object); + + g_object_bind_property (self, "title", priv->lbl_title, "label", G_BINDING_DEFAULT); + + gtk_widget_add_events (GTK_WIDGET (self), GDK_KEY_PRESS_MASK); + g_signal_connect (G_OBJECT (self), + "key_press_event", + G_CALLBACK (on_key_press_event), + NULL); +} + + +static void +phosh_system_modal_dialog_class_init (PhoshSystemModalDialogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->get_property = phosh_system_modal_dialog_get_property; + object_class->set_property = phosh_system_modal_dialog_set_property; + object_class->constructed = phosh_system_modal_dialog_constructed; + object_class->finalize = phosh_system_modal_dialog_finalize; + + props[PROP_TITLE] = g_param_spec_string ("title", + "Title", + "The dialogs title", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); + + /** + * PhoshSystemModalDialog::dialog-canceled: + * + * The ::dialog-done signal is emitted when the dialog was canceled and should be + * hidden or destroyed. + */ + signals[DIALOG_CANCELED] = g_signal_new ("dialog-canceled", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, + NULL, G_TYPE_NONE, 0); + + g_type_ensure (PHOSH_TYPE_SWIPE_AWAY_BIN); + gtk_widget_class_set_template_from_resource (widget_class, + "/sm/puri/phosh/ui/system-modal-dialog.ui"); + gtk_widget_class_bind_template_child_private (widget_class, PhoshSystemModalDialog, lbl_title); + gtk_widget_class_bind_template_child_private (widget_class, PhoshSystemModalDialog, box_dialog); + gtk_widget_class_bind_template_child_private (widget_class, PhoshSystemModalDialog, box_buttons); + gtk_widget_class_bind_template_callback (widget_class, on_removed_by_swipe); +} + + +static GtkBuildableIface *parent_buildable_iface; + + +static void +phosh_system_modal_dialog_buildable_add_child (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *type) +{ + PhoshSystemModalDialog *self = PHOSH_SYSTEM_MODAL_DIALOG (buildable); + + if (g_strcmp0 (type, "phosh-dialog-content") == 0) { + phosh_system_modal_dialog_set_content (self, GTK_WIDGET (child)); + return; + } + + if (g_strcmp0 (type, "phosh-dialog-button") == 0) { + phosh_system_modal_dialog_add_button (self, GTK_WIDGET (child), -1); + return; + } + + /* The parent is a container itself so chain up */ + parent_buildable_iface->add_child (buildable, builder, child, type); +} + + +static void +phosh_system_modal_dialog_buildable_init (GtkBuildableIface *iface) +{ + parent_buildable_iface = g_type_interface_peek_parent (iface); + iface->add_child = phosh_system_modal_dialog_buildable_add_child; +} + + + +static void +phosh_system_modal_dialog_init (PhoshSystemModalDialog *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} + +/** + * phosh_system_modal_dialog_new: + * + * Create a new system-modal dialog. + * + * Returns: A new system modal dialog + */ +GtkWidget * +phosh_system_modal_dialog_new (void) +{ + return g_object_new (PHOSH_TYPE_SYSTEM_MODAL_DIALOG, NULL); +} + + +/** + * phosh_system_modal_dialog_set_content: + * @self: The #PhoshSystemModalDialog + * @content: The widget for the dialog's content area + * + * Adds the given widget as the dialog's content area. It is a programming error + * to set the content more than once. + */ +void +phosh_system_modal_dialog_set_content (PhoshSystemModalDialog *self, GtkWidget *content) +{ + PhoshSystemModalDialogPrivate *priv; + + g_return_if_fail (PHOSH_IS_SYSTEM_MODAL_DIALOG (self)); + g_return_if_fail (GTK_IS_WIDGET (content)); + + priv = phosh_system_modal_dialog_get_instance_private (PHOSH_SYSTEM_MODAL_DIALOG (self)); + + gtk_box_pack_start (GTK_BOX (priv->box_dialog), GTK_WIDGET (content), FALSE, FALSE, 0); + gtk_box_reorder_child (GTK_BOX (priv->box_dialog), GTK_WIDGET (content), 1); + gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (content)), + "phosh-system-modal-dialog-content"); +} + + +/** + * phosh_system_modal_dialog_add_button: + * @self: The #PhoshSystemModalDialog + * @button: The button for the dialog's button area + * @position: The buttons position in the box or -1 + * + * Adds the given button to the dialog's content area at the given position. If + * the posiion is `-1` the button is appended at the end. + */ +void +phosh_system_modal_dialog_add_button (PhoshSystemModalDialog *self, GtkWidget *button, gint position) +{ + PhoshSystemModalDialogPrivate *priv; + + g_return_if_fail (PHOSH_IS_SYSTEM_MODAL_DIALOG (self)); + g_return_if_fail (GTK_IS_BUTTON (button)); + + priv = phosh_system_modal_dialog_get_instance_private (PHOSH_SYSTEM_MODAL_DIALOG (self)); + + gtk_box_pack_start (GTK_BOX (priv->box_buttons), GTK_WIDGET (button), TRUE, TRUE, 0); + if (position >= 0) + gtk_box_reorder_child (GTK_BOX (priv->box_dialog), GTK_WIDGET (button), position); +} + + +void +phosh_system_modal_dialog_remove_button (PhoshSystemModalDialog *self, GtkWidget *button) +{ + PhoshSystemModalDialogPrivate *priv; + + g_return_if_fail (PHOSH_IS_SYSTEM_MODAL_DIALOG (self)); + g_return_if_fail (GTK_IS_BUTTON (button)); + priv = phosh_system_modal_dialog_get_instance_private (PHOSH_SYSTEM_MODAL_DIALOG (self)); + + gtk_container_remove (GTK_CONTAINER (priv->box_buttons), button); +} + + +GList * +phosh_system_modal_dialog_get_buttons (PhoshSystemModalDialog *self) +{ + PhoshSystemModalDialogPrivate *priv; + + g_return_val_if_fail (PHOSH_IS_SYSTEM_MODAL_DIALOG (self), NULL); + priv = phosh_system_modal_dialog_get_instance_private (PHOSH_SYSTEM_MODAL_DIALOG (self)); + + return gtk_container_get_children (GTK_CONTAINER (priv->box_buttons)); +} + + +void +phosh_system_modal_dialog_set_title (PhoshSystemModalDialog *self, const gchar *title) +{ + PhoshSystemModalDialogPrivate *priv; + + g_return_if_fail (PHOSH_IS_SYSTEM_MODAL_DIALOG (self)); + + priv = phosh_system_modal_dialog_get_instance_private (PHOSH_SYSTEM_MODAL_DIALOG (self)); + g_free (priv->title); + priv->title = g_strdup (title); + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TITLE]); +} diff -Nru phosh-0.8.0/src/system-modal-dialog.h phosh-0.13.1/src/system-modal-dialog.h --- phosh-0.8.0/src/system-modal-dialog.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/system-modal-dialog.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "system-modal.h" + +#include + +#define PHOSH_TYPE_SYSTEM_MODAL_DIALOG (phosh_system_modal_dialog_get_type ()) + +G_DECLARE_DERIVABLE_TYPE (PhoshSystemModalDialog, phosh_system_modal_dialog, PHOSH, SYSTEM_MODAL_DIALOG, PhoshSystemModal) + +/** + * PhoshSystemModalDialogClass + * @parent_class: The parent class + */ +struct _PhoshSystemModalDialogClass { + PhoshSystemModalClass parent_class; +}; + + +GtkWidget *phosh_system_modal_dialog_new (void); +void phosh_system_modal_dialog_set_content (PhoshSystemModalDialog *self, GtkWidget *content); +void phosh_system_modal_dialog_add_button (PhoshSystemModalDialog *self, GtkWidget *button, gint position); +void phosh_system_modal_dialog_set_title (PhoshSystemModalDialog *self, const gchar *title); +void phosh_system_modal_dialog_remove_button (PhoshSystemModalDialog *self, GtkWidget *button); +GList *phosh_system_modal_dialog_get_buttons (PhoshSystemModalDialog *self); diff -Nru phosh-0.8.0/src/system-modal.h phosh-0.13.1/src/system-modal.h --- phosh-0.8.0/src/system-modal.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/system-modal.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2018 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include +#include "layersurface.h" +#include "monitor/monitor.h" + +#define PHOSH_TYPE_SYSTEM_MODAL (phosh_system_modal_get_type ()) + +G_DECLARE_DERIVABLE_TYPE (PhoshSystemModal, phosh_system_modal, PHOSH, SYSTEM_MODAL, PhoshLayerSurface) + +/** + * PhoshSystemModalClass + * @parent_class: The parent class + */ +struct _PhoshSystemModalClass { + PhoshLayerSurfaceClass parent_class; +}; + + +GtkWidget *phosh_system_modal_new (PhoshMonitor *monitor); diff -Nru phosh-0.8.0/src/system-prompt.c phosh-0.13.1/src/system-prompt.c --- phosh-0.8.0/src/system-prompt.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/system-prompt.c 2021-08-31 09:15:52.000000000 +0000 @@ -32,7 +32,6 @@ PROP_0, /* GcrPromptIface */ - PROP_TITLE, PROP_MESSAGE, PROP_DESCRIPTION, PROP_WARNING, @@ -62,7 +61,6 @@ typedef struct { - char *title; char *message; char *description; char *warning; @@ -81,7 +79,6 @@ GtkWidget *grid; GtkWidget *lbl_confirm; GtkWidget *lbl_description; - GtkWidget *lbl_message; GtkWidget *lbl_password; GtkWidget *lbl_warning; GtkWidget *pbar_quality; @@ -98,12 +95,12 @@ struct _PhoshSystemPrompt { - PhoshLayerSurface parent; + PhoshSystemModalDialog parent; }; static void phosh_system_prompt_iface_init (GcrPromptIface *iface); -G_DEFINE_TYPE_WITH_CODE(PhoshSystemPrompt, phosh_system_prompt, PHOSH_TYPE_LAYER_SURFACE, +G_DEFINE_TYPE_WITH_CODE(PhoshSystemPrompt, phosh_system_prompt, PHOSH_TYPE_SYSTEM_MODAL_DIALOG, G_IMPLEMENT_INTERFACE (GCR_TYPE_PROMPT, phosh_system_prompt_iface_init) G_ADD_PRIVATE (PhoshSystemPrompt)); @@ -119,11 +116,6 @@ PhoshSystemPromptPrivate *priv = phosh_system_prompt_get_instance_private (self); switch (prop_id) { - case PROP_TITLE: - g_free (priv->title); - priv->title = g_value_dup_string (value); - g_object_notify (obj, "title"); - break; case PROP_MESSAGE: g_free (priv->message); priv->message = g_value_dup_string (value); @@ -185,9 +177,6 @@ PhoshSystemPromptPrivate *priv = phosh_system_prompt_get_instance_private (self); switch (prop_id) { - case PROP_TITLE: - g_value_set_string (value, priv->title ? priv->title : ""); - break; case PROP_MESSAGE: g_value_set_string (value, priv->message ? priv->message : ""); break; @@ -506,14 +495,14 @@ static void -btn_continue_clicked_cb (PhoshSystemPrompt *self, GtkButton *btn) +on_btn_continue_clicked (PhoshSystemPrompt *self, GtkButton *btn) { prompt_complete (self); } static void -btn_cancel_clicked_cb (PhoshSystemPrompt *self, GtkButton *btn) +on_dialog_canceled (PhoshSystemPrompt *self) { prompt_cancel (self); } @@ -529,26 +518,6 @@ } -static gboolean -on_key_press_event (PhoshSystemPrompt *self, GdkEventKey *event, gpointer data) -{ - gboolean handled = FALSE; - g_return_val_if_fail (PHOSH_IS_SYSTEM_PROMPT (self), FALSE); - - switch (event->keyval) { - case GDK_KEY_Escape: - prompt_cancel (self); - handled = TRUE; - break; - default: - /* nothing to do */ - break; - } - - return handled; -} - - static void phosh_system_prompt_dispose (GObject *obj) { @@ -572,7 +541,6 @@ PhoshSystemPrompt *self = PHOSH_SYSTEM_PROMPT (obj); PhoshSystemPromptPrivate *priv = phosh_system_prompt_get_instance_private (self); - g_free (priv->title); g_free (priv->message); g_free (priv->description); g_free (priv->warning); @@ -592,7 +560,7 @@ G_OBJECT_CLASS (phosh_system_prompt_parent_class)->constructed (object); - g_object_bind_property (self, "message", priv->lbl_message, "label", G_BINDING_DEFAULT); + g_object_bind_property (self, "message", self, "title", G_BINDING_DEFAULT); g_object_bind_property (self, "description", priv->lbl_description, "label", G_BINDING_DEFAULT); g_object_bind_property (self, "password-visible", priv->lbl_password, "visible", G_BINDING_DEFAULT); @@ -622,25 +590,9 @@ "active", G_BINDING_BIDIRECTIONAL); g_object_bind_property (self, "cancel-label", priv->btn_cancel, "label", G_BINDING_DEFAULT); - g_signal_connect_object (priv->btn_cancel, - "clicked", - G_CALLBACK (btn_cancel_clicked_cb), - self, - G_CONNECT_SWAPPED); - g_object_bind_property (self, "continue-label", priv->btn_continue, "label", G_BINDING_DEFAULT); - g_signal_connect_object (priv->btn_continue, - "clicked", - G_CALLBACK (btn_continue_clicked_cb), - self, - G_CONNECT_SWAPPED); - gtk_widget_grab_default (priv->btn_continue); - gtk_widget_add_events (GTK_WIDGET (self), GDK_KEY_PRESS_MASK); - g_signal_connect (G_OBJECT (self), - "key_press_event", - G_CALLBACK (on_key_press_event), - NULL); + gtk_widget_grab_default (priv->btn_continue); } @@ -656,7 +608,6 @@ object_class->dispose = phosh_system_prompt_dispose; object_class->finalize = phosh_system_prompt_finalize; - g_object_class_override_property (object_class, PROP_TITLE, "title"); g_object_class_override_property (object_class, PROP_MESSAGE, "message"); g_object_class_override_property (object_class, PROP_DESCRIPTION, "description"); g_object_class_override_property (object_class, PROP_WARNING, "warning"); @@ -674,7 +625,7 @@ * Whether the password entry is visible or not. */ g_object_class_install_property (object_class, PROP_PASSWORD_VISIBLE, - g_param_spec_boolean ("password-visible", "Password visible", "Password field is visible", + g_param_spec_boolean ("password-visible", "", "", FALSE, G_PARAM_READABLE)); /** @@ -683,7 +634,7 @@ * Whether the password confirm entry is visible or not. */ g_object_class_install_property (object_class, PROP_CONFIRM_VISIBLE, - g_param_spec_boolean ("confirm-visible", "Confirm visible", "Confirm field is visible", + g_param_spec_boolean ("confirm-visible", "", "", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** @@ -692,7 +643,7 @@ * Whether the warning label is visible or not. */ g_object_class_install_property (object_class, PROP_WARNING_VISIBLE, - g_param_spec_boolean ("warning-visible", "Warning visible", "Warning is visible", + g_param_spec_boolean ("warning-visible", "", "", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** @@ -701,13 +652,12 @@ * Whether the choice check box is visible or not. */ g_object_class_install_property (object_class, PROP_CHOICE_VISIBLE, - g_param_spec_boolean ("choice-visible", "Choice visible", "Choice is visible", + g_param_spec_boolean ("choice-visible", "", "", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); gtk_widget_class_set_template_from_resource (widget_class, "/sm/puri/phosh/ui/system-prompt.ui"); gtk_widget_class_bind_template_child_private (widget_class, PhoshSystemPrompt, grid); - gtk_widget_class_bind_template_child_private (widget_class, PhoshSystemPrompt, lbl_message); gtk_widget_class_bind_template_child_private (widget_class, PhoshSystemPrompt, lbl_description); gtk_widget_class_bind_template_child_private (widget_class, PhoshSystemPrompt, lbl_password); gtk_widget_class_bind_template_child_private (widget_class, PhoshSystemPrompt, entry_password); @@ -718,7 +668,8 @@ gtk_widget_class_bind_template_child_private (widget_class, PhoshSystemPrompt, checkbtn_choice); gtk_widget_class_bind_template_child_private (widget_class, PhoshSystemPrompt, btn_cancel); gtk_widget_class_bind_template_child_private (widget_class, PhoshSystemPrompt, btn_continue); - + gtk_widget_class_bind_template_callback (widget_class, on_dialog_canceled); + gtk_widget_class_bind_template_callback (widget_class, on_btn_continue_clicked); } @@ -738,19 +689,7 @@ GtkWidget * -phosh_system_prompt_new (gpointer layer_shell, - gpointer wl_output) +phosh_system_prompt_new (void) { - return g_object_new (PHOSH_TYPE_SYSTEM_PROMPT, - "layer-shell", layer_shell, - "wl-output", wl_output, - "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, - "layer", ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, - "kbd-interactivity", TRUE, - "exclusive-zone", -1, - "namespace", "phosh prompter", - NULL); + return g_object_new (PHOSH_TYPE_SYSTEM_PROMPT, NULL); } diff -Nru phosh-0.8.0/src/system-prompter.c phosh-0.13.1/src/system-prompter.c --- phosh-0.8.0/src/system-prompter.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/system-prompter.c 2021-08-31 09:15:52.000000000 +0000 @@ -33,15 +33,12 @@ new_prompt_cb (GcrSystemPrompter *prompter, gpointer user_data) { - PhoshWayland *wl = phosh_wayland_get_default (); - PhoshShell *shell = phosh_shell_get_default (); GtkWidget *prompt; g_debug ("Building new system prompt"); g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (prompter), NULL); - prompt = phosh_system_prompt_new (phosh_wayland_get_zwlr_layer_shell_v1 (wl), - phosh_shell_get_primary_monitor (shell)->wl_output); + prompt = phosh_system_prompt_new (); /* Show widget when not locked and keep that in sync */ g_object_bind_property (phosh_shell_get_default (), "locked", @@ -78,6 +75,7 @@ if (connection == NULL) { g_warning ("couldn't connect to session bus"); phosh_system_prompter_unregister (); + registered_prompter = FALSE; } } @@ -116,13 +114,17 @@ phosh_system_prompter_unregister(void) { if (_prompter) { - gcr_system_prompter_unregister (_prompter, TRUE); - _prompter = NULL; + if (registered_prompter) { + gcr_system_prompter_unregister (_prompter, TRUE); + registered_prompter = FALSE; + } + g_clear_object (&_prompter); } - if (acquired_prompter) { + if (owner_id) { g_bus_unown_name (owner_id); owner_id = 0; - acquired_prompter = FALSE; } + + acquired_prompter = FALSE; } diff -Nru phosh-0.8.0/src/system-prompt.h phosh-0.13.1/src/system-prompt.h --- phosh-0.8.0/src/system-prompt.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/system-prompt.h 2021-08-31 09:15:52.000000000 +0000 @@ -7,11 +7,14 @@ #pragma once #include -#include "layersurface.h" +#include "system-modal-dialog.h" + +G_BEGIN_DECLS #define PHOSH_TYPE_SYSTEM_PROMPT (phosh_system_prompt_get_type()) -G_DECLARE_FINAL_TYPE (PhoshSystemPrompt, phosh_system_prompt, PHOSH, SYSTEM_PROMPT, PhoshLayerSurface) +G_DECLARE_FINAL_TYPE (PhoshSystemPrompt, phosh_system_prompt, PHOSH, SYSTEM_PROMPT, PhoshSystemModalDialog) + +GtkWidget *phosh_system_prompt_new (void); -GtkWidget *phosh_system_prompt_new (gpointer layer_shell, - gpointer wl_output); +G_END_DECLS diff -Nru phosh-0.8.0/src/toplevel-manager.c phosh-0.13.1/src/toplevel-manager.c --- phosh-0.8.0/src/toplevel-manager.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/toplevel-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -41,6 +41,7 @@ struct _PhoshToplevelManager { GObject parent; GPtrArray *toplevels; + GPtrArray *toplevels_pending; }; G_DEFINE_TYPE (PhoshToplevelManager, phosh_toplevel_manager, G_TYPE_OBJECT); @@ -79,6 +80,16 @@ g_return_if_fail (PHOSH_IS_TOPLEVEL_MANAGER (self)); g_return_if_fail (PHOSH_IS_TOPLEVEL (toplevel)); g_return_if_fail (self->toplevels); + g_return_if_fail (self->toplevels_pending); + + /* Check if toplevel exists in toplevels_pending, in that case it is + * not yet configured and we just remove it from toplevels_pending + * without touching the regular toplevels array. */ + if (g_ptr_array_find (self->toplevels_pending, toplevel, NULL)) { + g_assert_true (g_ptr_array_remove (self->toplevels_pending, toplevel)); + g_object_unref (toplevel); + return; + } g_assert_true(g_ptr_array_remove (self->toplevels, toplevel)); @@ -93,6 +104,7 @@ g_return_if_fail (PHOSH_IS_TOPLEVEL_MANAGER (self)); g_return_if_fail (PHOSH_IS_TOPLEVEL (toplevel)); g_return_if_fail (self->toplevels); + g_return_if_fail (self->toplevels_pending); configured = phosh_toplevel_is_configured (toplevel); @@ -102,6 +114,7 @@ if (g_ptr_array_find (self->toplevels, toplevel, NULL)) { g_signal_emit (self, signals[SIGNAL_TOPLEVEL_CHANGED], 0, toplevel); } else { + g_assert_true (g_ptr_array_remove (self->toplevels_pending, toplevel)); g_ptr_array_add (self->toplevels, toplevel); g_signal_emit (self, signals[SIGNAL_TOPLEVEL_ADDED], 0, toplevel); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NUM_TOPLEVELS]); @@ -120,6 +133,8 @@ g_return_if_fail (PHOSH_IS_TOPLEVEL_MANAGER (self)); toplevel = phosh_toplevel_new_from_handle (handle); + g_ptr_array_add (self->toplevels_pending, toplevel); + g_signal_connect_swapped (toplevel, "closed", G_CALLBACK (on_toplevel_closed), self); g_signal_connect_swapped (toplevel, "notify::configured", G_CALLBACK (on_toplevel_configured), self); @@ -150,6 +165,10 @@ g_ptr_array_free(self->toplevels, TRUE); self->toplevels = NULL; } + if (self->toplevels_pending) { + g_ptr_array_free (self->toplevels_pending, TRUE); + self->toplevels_pending = NULL; + } G_OBJECT_CLASS (phosh_toplevel_manager_parent_class)->dispose (object); } @@ -208,6 +227,7 @@ phosh_wayland_get_default ()); self->toplevels = g_ptr_array_new_with_free_func ((GDestroyNotify) (g_object_unref)); + self->toplevels_pending = g_ptr_array_new (); if (!toplevel_manager) { g_warning ("Skipping app list due to missing wlr-foreign-toplevel-management protocol extension"); diff -Nru phosh-0.8.0/src/top-panel.c phosh-0.13.1/src/top-panel.c --- phosh-0.8.0/src/top-panel.c 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/top-panel.c 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,486 @@ +/* + * Copyright (C) 2018 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + * + * Somewhat based on maynard's panel which is + * Copyright (C) 2014 Collabora Ltd. * + * Author: Jonny Lamb + */ + +#define G_LOG_DOMAIN "phosh-top-panel" + +#include "config.h" + +#include "shell.h" +#include "session-manager.h" +#include "settings.h" +#include "top-panel.h" +#include "util.h" + +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include +#include + +#include + +/** + * SECTION:top-panel + * @short_description: The top panel + * @Title: PhoshTopPanel + * + * The top panel containing the clock and status indicators. When activated + * int unfolds the #PhoshSettings. + */ + +enum { + SETTINGS_ACTIVATED, + N_SIGNALS +}; +static guint signals[N_SIGNALS] = { 0 }; + +typedef struct _PhoshTopPanel { + PhoshLayerSurface parent; + + PhoshTopPanelState state; + + GtkWidget *btn_power; + GtkWidget *menu_power; + GtkWidget *stack; + GtkWidget *box; /* main content box */ + GtkWidget *btn_top_panel; + GtkWidget *lbl_clock; + GtkWidget *lbl_lang; + GtkWidget *settings; /* settings menu */ + GtkWidget *batteryinfo; + + GnomeWallClock *wall_clock; + GnomeXkbInfo *xkbinfo; + GSettings *input_settings; + GSettings *interface_settings; + GdkSeat *seat; + + GSimpleActionGroup *actions; +} PhoshTopPanel; + +G_DEFINE_TYPE (PhoshTopPanel, phosh_top_panel, PHOSH_TYPE_LAYER_SURFACE) + + +static void +on_shutdown_action (GSimpleAction *action, + GVariant *parameter, + gpointer data) +{ + PhoshTopPanel *self = PHOSH_TOP_PANEL(data); + PhoshSessionManager *sm = phosh_shell_get_session_manager (phosh_shell_get_default ()); + + g_return_if_fail (PHOSH_IS_TOP_PANEL (self)); + phosh_session_manager_shutdown (sm); + phosh_top_panel_fold (self); +} + + +static void +on_restart_action (GSimpleAction *action, + GVariant *parameter, + gpointer data) +{ + PhoshTopPanel *self = PHOSH_TOP_PANEL(data); + PhoshSessionManager *sm = phosh_shell_get_session_manager (phosh_shell_get_default ()); + + g_return_if_fail (PHOSH_IS_TOP_PANEL (self)); + g_return_if_fail (PHOSH_IS_SESSION_MANAGER (sm)); + + phosh_session_manager_reboot (sm); + phosh_top_panel_fold (self); +} + + +static void +on_lockscreen_action (GSimpleAction *action, + GVariant *parameter, + gpointer data) +{ + PhoshTopPanel *self = PHOSH_TOP_PANEL(data); + + g_return_if_fail (PHOSH_IS_TOP_PANEL (self)); + phosh_shell_lock (phosh_shell_get_default ()); + phosh_top_panel_fold (self); +} + + +static void +on_logout_action (GSimpleAction *action, + GVariant *parameter, + gpointer data) +{ + PhoshTopPanel *self = PHOSH_TOP_PANEL(data); + PhoshSessionManager *sm = phosh_shell_get_session_manager (phosh_shell_get_default ()); + + g_return_if_fail (PHOSH_IS_TOP_PANEL (self)); + g_return_if_fail (PHOSH_IS_SESSION_MANAGER (sm)); + phosh_session_manager_logout (sm); + phosh_top_panel_fold (self); +} + + +static void +top_panel_clicked_cb (PhoshTopPanel *self, GtkButton *btn) +{ + g_return_if_fail (PHOSH_IS_TOP_PANEL (self)); + g_return_if_fail (GTK_IS_BUTTON (btn)); + g_signal_emit(self, signals[SETTINGS_ACTIVATED], 0); +} + + +static void +wall_clock_notify_cb (PhoshTopPanel *self, + GParamSpec *pspec, + GnomeWallClock *wall_clock) +{ + const char *str; + + g_return_if_fail (PHOSH_IS_TOP_PANEL (self)); + g_return_if_fail (GNOME_IS_WALL_CLOCK (wall_clock)); + + str = gnome_wall_clock_get_clock(wall_clock); + gtk_label_set_text (GTK_LABEL (self->lbl_clock), str); +} + + +static gboolean +needs_keyboard_label (PhoshTopPanel *self) +{ + GList *slaves; + g_autoptr(GVariant) sources = NULL; + + g_return_val_if_fail (GDK_IS_SEAT (self->seat), FALSE); + g_return_val_if_fail (G_IS_SETTINGS (self->input_settings), FALSE); + + sources = g_settings_get_value(self->input_settings, "sources"); + if (g_variant_n_children (sources) < 2) + return FALSE; + + slaves = gdk_seat_get_slaves (self->seat, GDK_SEAT_CAPABILITY_KEYBOARD); + if (!slaves) + return FALSE; + + g_list_free (slaves); + return TRUE; +} + + +static void +on_seat_device_changed (PhoshTopPanel *self, GdkDevice *device, GdkSeat *seat) +{ + gboolean visible; + + g_return_if_fail (PHOSH_IS_TOP_PANEL (self)); + g_return_if_fail (GDK_IS_SEAT (seat)); + + visible = needs_keyboard_label (self); + gtk_widget_set_visible (self->lbl_lang, visible); +} + + +static void +on_input_setting_changed (PhoshTopPanel *self, + const char *key, + GSettings *settings) +{ + g_autoptr(GVariant) sources = NULL; + GVariantIter iter; + g_autofree char *id = NULL; + g_autofree char *type = NULL; + const char *name; + + if (!needs_keyboard_label (self)) { + gtk_widget_hide (self->lbl_lang); + return; + } + + sources = g_settings_get_value(settings, "sources"); + g_variant_iter_init (&iter, sources); + g_variant_iter_next (&iter, "(ss)", &type, &id); + + if (g_strcmp0 (type, "xkb")) { + g_debug ("Not a xkb layout: '%s' - ignoring", id); + return; + } + + if (!gnome_xkb_info_get_layout_info (self->xkbinfo, id, + NULL, &name, NULL, NULL)) { + g_debug ("Failed to get layout info for %s", id); + name = id; + } + g_debug ("Layout is %s", name); + gtk_label_set_text (GTK_LABEL (self->lbl_lang), name); + gtk_widget_show (self->lbl_lang); +} + + +static gboolean +on_key_press_event (PhoshTopPanel *self, GdkEventKey *event, gpointer data) +{ + gboolean handled = FALSE; + + g_return_val_if_fail (PHOSH_IS_TOP_PANEL (self), FALSE); + + if (!self->settings) + return handled; + + switch (event->keyval) { + case GDK_KEY_Escape: + phosh_top_panel_fold (self); + handled = TRUE; + break; + default: + /* nothing to do */ + break; + } + return handled; +} + + +static gboolean +on_button_press_event (PhoshTopPanel *self, GdkEventButton *event, gpointer data) +{ + phosh_trigger_feedback ("button-pressed"); + + /* + * The popover has to be popdown manually as it doesn't happen + * automatically when the power button is tapped with touch + */ + if (gtk_widget_is_visible (self->menu_power)) + gtk_popover_popdown (GTK_POPOVER (self->menu_power)); + else + phosh_top_panel_fold (self); + + return GDK_EVENT_PROPAGATE; +} + + +static GActionEntry entries[] = { + { "poweroff", on_shutdown_action, NULL, NULL, NULL }, + { "restart", on_restart_action, NULL, NULL, NULL }, + { "lockscreen", on_lockscreen_action, NULL, NULL, NULL }, + { "logout", on_logout_action, NULL, NULL, NULL }, +}; + + +static void +phosh_top_panel_constructed (GObject *object) +{ + PhoshTopPanel *self = PHOSH_TOP_PANEL (object); + GdkDisplay *display = gdk_display_get_default (); + + G_OBJECT_CLASS (phosh_top_panel_parent_class)->constructed (object); + + self->state = PHOSH_TOP_PANEL_STATE_FOLDED; + self->wall_clock = gnome_wall_clock_new (); + + g_signal_connect_object (self->wall_clock, + "notify::clock", + G_CALLBACK (wall_clock_notify_cb), + self, + G_CONNECT_SWAPPED); + + g_signal_connect_object (self->btn_top_panel, + "clicked", + G_CALLBACK (top_panel_clicked_cb), + self, + G_CONNECT_SWAPPED); + + phosh_connect_feedback (self->btn_top_panel); + + gtk_window_set_title (GTK_WINDOW (self), "phosh panel"); + + /* Button properites */ + gtk_style_context_remove_class (gtk_widget_get_style_context (self->btn_top_panel), + "button"); + gtk_style_context_remove_class (gtk_widget_get_style_context (self->btn_top_panel), + "image-button"); + + wall_clock_notify_cb (self, NULL, self->wall_clock); + + /* language indicator */ + if (display) { + self->input_settings = g_settings_new ("org.gnome.desktop.input-sources"); + self->xkbinfo = gnome_xkb_info_new (); + self->seat = gdk_display_get_default_seat (display); + g_object_connect (self->seat, + "swapped_signal::device-added", G_CALLBACK (on_seat_device_changed), self, + "swapped_signal::device-removed", G_CALLBACK (on_seat_device_changed), self, + NULL); + g_signal_connect_swapped (self->input_settings, + "changed::sources", G_CALLBACK (on_input_setting_changed), + self); + on_input_setting_changed (self, NULL, self->input_settings); + } + + /* Settings menu and it's top-bar / menu */ + gtk_widget_add_events (GTK_WIDGET (self), GDK_KEY_PRESS_MASK); + g_signal_connect (G_OBJECT (self), + "key-press-event", + G_CALLBACK (on_key_press_event), + NULL); + g_signal_connect (G_OBJECT (self), + "button-press-event", + G_CALLBACK (on_button_press_event), + NULL); + g_signal_connect_swapped (self->settings, + "setting-done", + G_CALLBACK (phosh_top_panel_fold), + self); + + self->actions = g_simple_action_group_new (); + gtk_widget_insert_action_group (GTK_WIDGET (self), "panel", + G_ACTION_GROUP (self->actions)); + g_action_map_add_action_entries (G_ACTION_MAP (self->actions), + entries, G_N_ELEMENTS (entries), + self); + if (!phosh_shell_started_by_display_manager (phosh_shell_get_default ())) { + GAction *action = g_action_map_lookup_action (G_ACTION_MAP (self->actions), + "logout"); + g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE); + } + + self->interface_settings = g_settings_new ("org.gnome.desktop.interface"); + g_settings_bind (self->interface_settings, + "show-battery-percentage", + self->batteryinfo, + "show-detail", + G_SETTINGS_BIND_GET); +} + + +static void +phosh_top_panel_dispose (GObject *object) +{ + PhoshTopPanel *self = PHOSH_TOP_PANEL (object); + + g_clear_object (&self->wall_clock); + g_clear_object (&self->xkbinfo); + g_clear_object (&self->input_settings); + g_clear_object (&self->interface_settings); + g_clear_object (&self->actions); + self->seat = NULL; + + G_OBJECT_CLASS (phosh_top_panel_parent_class)->dispose (object); +} + + +static void +phosh_top_panel_class_init (PhoshTopPanelClass *klass) +{ + GObjectClass *object_class = (GObjectClass *)klass; + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->constructed = phosh_top_panel_constructed; + object_class->dispose = phosh_top_panel_dispose; + + gtk_widget_class_set_css_name (widget_class, "phosh-top-panel"); + + signals[SETTINGS_ACTIVATED] = g_signal_new ("settings-activated", + G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, + NULL, G_TYPE_NONE, 0); + + gtk_widget_class_set_template_from_resource (widget_class, + "/sm/puri/phosh/ui/top-panel.ui"); + gtk_widget_class_bind_template_child (widget_class, PhoshTopPanel, btn_power); + gtk_widget_class_bind_template_child (widget_class, PhoshTopPanel, menu_power); + gtk_widget_class_bind_template_child (widget_class, PhoshTopPanel, btn_top_panel); + gtk_widget_class_bind_template_child (widget_class, PhoshTopPanel, batteryinfo); + gtk_widget_class_bind_template_child (widget_class, PhoshTopPanel, lbl_clock); + gtk_widget_class_bind_template_child (widget_class, PhoshTopPanel, lbl_lang); + gtk_widget_class_bind_template_child (widget_class, PhoshTopPanel, box); + gtk_widget_class_bind_template_child (widget_class, PhoshTopPanel, stack); + gtk_widget_class_bind_template_child (widget_class, PhoshTopPanel, settings); +} + + +static void +phosh_top_panel_init (PhoshTopPanel *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} + + +GtkWidget * +phosh_top_panel_new (struct zwlr_layer_shell_v1 *layer_shell, + struct wl_output *wl_output) +{ + return g_object_new (PHOSH_TYPE_TOP_PANEL, + "layer-shell", layer_shell, + "wl-output", wl_output, + "height", PHOSH_TOP_PANEL_HEIGHT, + "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, + "layer", ZWLR_LAYER_SHELL_V1_LAYER_TOP, + "kbd-interactivity", FALSE, + "exclusive-zone", PHOSH_TOP_PANEL_HEIGHT, + "namespace", "phosh", + NULL); +} + + +void +phosh_top_panel_fold (PhoshTopPanel *self) +{ + int width; + + g_return_if_fail (PHOSH_IS_TOP_PANEL (self)); + + if (self->state == PHOSH_TOP_PANEL_STATE_FOLDED) + return; + + gtk_widget_hide (self->menu_power); + gtk_stack_set_transition_type (GTK_STACK (self->stack), GTK_STACK_TRANSITION_TYPE_SLIDE_UP); + gtk_stack_set_visible_child_name (GTK_STACK (self->stack), "topbar"); + gtk_widget_hide (self->settings); + phosh_layer_surface_set_kbd_interactivity (PHOSH_LAYER_SURFACE (self), FALSE); + gtk_window_get_size (GTK_WINDOW (self), &width, NULL); + gtk_window_resize (GTK_WINDOW (self), width, PHOSH_TOP_PANEL_HEIGHT); + self->state = PHOSH_TOP_PANEL_STATE_FOLDED; +} + + +void +phosh_top_panel_unfold (PhoshTopPanel *self) +{ + g_return_if_fail (PHOSH_IS_TOP_PANEL (self)); + + if (self->state == PHOSH_TOP_PANEL_STATE_UNFOLDED) + return; + + phosh_layer_surface_set_kbd_interactivity (PHOSH_LAYER_SURFACE (self), TRUE); + gtk_widget_show (self->settings); + gtk_stack_set_transition_type (GTK_STACK (self->stack), GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN); + gtk_stack_set_visible_child_name(GTK_STACK (self->stack), "settings"); + self->state =PHOSH_TOP_PANEL_STATE_UNFOLDED; +} + + +void +phosh_top_panel_toggle_fold (PhoshTopPanel *self) +{ + g_return_if_fail (PHOSH_IS_TOP_PANEL (self)); + + if (self->state == PHOSH_TOP_PANEL_STATE_UNFOLDED) { + phosh_top_panel_fold (self); + } else { + phosh_top_panel_unfold (self); + } +} + + +PhoshTopPanelState +phosh_top_panel_get_state (PhoshTopPanel *self) +{ + g_return_val_if_fail (PHOSH_IS_TOP_PANEL (self), PHOSH_TOP_PANEL_STATE_FOLDED); + + return self->state; +} diff -Nru phosh-0.8.0/src/top-panel.h phosh-0.13.1/src/top-panel.h --- phosh-0.8.0/src/top-panel.h 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/top-panel.h 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "layersurface.h" + +#define PHOSH_TYPE_TOP_PANEL (phosh_top_panel_get_type ()) + +G_DECLARE_FINAL_TYPE (PhoshTopPanel, phosh_top_panel, PHOSH, TOP_PANEL, PhoshLayerSurface) + +#define PHOSH_TOP_PANEL_HEIGHT 32 + +/** + * PhoshTopPanelState: + * @PHOSH_TOP_PANEL_STATE_FOLDED: Only top-bar is visible + * @PHOSH_TOP_PANEL_STATE_UNFOLDED: Settings menu is unfolded + */ +typedef enum { + PHOSH_TOP_PANEL_STATE_FOLDED, + PHOSH_TOP_PANEL_STATE_UNFOLDED, +} PhoshTopPanelState; + +GtkWidget *phosh_top_panel_new (struct zwlr_layer_shell_v1 *layer_shell, + struct wl_output *wl_output); +void phosh_top_panel_toggle_fold (PhoshTopPanel *self); +void phosh_top_panel_fold (PhoshTopPanel *self); +void phosh_top_panel_unfold (PhoshTopPanel *self); +PhoshTopPanelState phosh_top_panel_get_state (PhoshTopPanel *self); diff -Nru phosh-0.8.0/src/torch-info.c phosh-0.13.1/src/torch-info.c --- phosh-0.8.0/src/torch-info.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/torch-info.c 2021-08-31 09:15:52.000000000 +0000 @@ -87,7 +87,6 @@ { gboolean enabled; - g_debug ("Updating torch status"); g_return_if_fail (PHOSH_IS_TORCH_INFO (self)); g_return_if_fail (PHOSH_IS_TORCH_MANAGER (torch)); @@ -96,6 +95,8 @@ return; self->enabled = enabled; + g_debug ("Updating torch enabled: %d", enabled); + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ENABLED]); } @@ -117,9 +118,11 @@ } -static gboolean -on_idle (PhoshTorchInfo *self) +static void +phosh_torch_info_idle_init (PhoshStatusIcon *icon) { + PhoshTorchInfo *self = PHOSH_TORCH_INFO (icon); + g_object_bind_property (self->torch, "icon-name", self, "icon-name", G_BINDING_SYNC_CREATE); @@ -142,8 +145,6 @@ G_CALLBACK (on_torch_present), self); on_torch_present (self, NULL, self->torch); - - return FALSE; } @@ -162,8 +163,6 @@ g_warning ("Failed to get torch manager"); return; } - - g_idle_add ((GSourceFunc) on_idle, self); } @@ -185,11 +184,17 @@ phosh_torch_info_class_init (PhoshTorchInfoClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + PhoshStatusIconClass *status_icon_class = PHOSH_STATUS_ICON_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->constructed = phosh_torch_info_constructed; object_class->dispose = phosh_torch_info_dispose; object_class->get_property = phosh_torch_info_get_property; + status_icon_class->idle_init = phosh_torch_info_idle_init; + + gtk_widget_class_set_css_name (widget_class, "phosh-torch-info"); + props[PROP_ENABLED] = g_param_spec_boolean ("enabled", "enabled", diff -Nru phosh-0.8.0/src/torch-manager.c phosh-0.13.1/src/torch-manager.c --- phosh-0.8.0/src/torch-manager.c 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/torch-manager.c 2021-08-31 09:15:52.000000000 +0000 @@ -10,12 +10,17 @@ #include "config.h" +#include + #include "torch-manager.h" #include "shell.h" -#include "dbus/upower-torch-dbus.h" +#include "util.h" +#include "dbus/login1-session-dbus.h" + +#define BUS_NAME "org.freedesktop.login1" +#define OBJECT_PATH "/org/freedesktop/login1/session/auto" -#define BUS_NAME "org.freedesktop.UPower" -#define OBJECT_PATH "/org/freedesktop/UPower/Torch" +#define TORCH_SUBSYSTEM "leds" #define TORCH_DISABLED_ICON "torch-disabled-symbolic" #define TORCH_ENABLED_ICON "torch-enabled-symbolic" @@ -40,41 +45,84 @@ static GParamSpec *props[PROP_LAST_PROP]; struct _PhoshTorchManager { - GObject parent; + PhoshManager parent; + + /* Whether we found a torch device */ + gboolean present; + const char *icon_name; + int brightness; + int max_brightness; + int last_brightness; - /* Whether upower sees a torch device */ - gboolean present; - const char *icon_name; - int brightness; - int max_brightness; - int last_brightness; + GUdevClient *udev_client; + GUdevDevice *udev_device; - PhoshUPowerDBusTorch *proxy; + PhoshLogin1SessionDBusLoginSession *proxy; + GCancellable *cancel; }; -G_DEFINE_TYPE (PhoshTorchManager, phosh_torch_manager, G_TYPE_OBJECT); +G_DEFINE_TYPE (PhoshTorchManager, phosh_torch_manager, PHOSH_TYPE_MANAGER); static void -on_brightness_set (PhoshUPowerDBusTorch *proxy, - GAsyncResult *res, - PhoshTorchManager *self) +apply_brightness (PhoshTorchManager *self) +{ + const char *icon_name; + + g_return_if_fail (PHOSH_IS_TORCH_MANAGER (self)); + g_return_if_fail (G_UDEV_IS_DEVICE (self->udev_device)); + + g_object_freeze_notify (G_OBJECT (self)); + + self->brightness = g_udev_device_get_sysfs_attr_as_int_uncached (self->udev_device, + "brightness"); + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_BRIGHTNESS]); + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ENABLED]); + + icon_name = self->brightness ? TORCH_ENABLED_ICON : TORCH_DISABLED_ICON; + if (icon_name != self->icon_name) { + self->icon_name = icon_name; + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ICON_NAME]); + } + + g_object_thaw_notify (G_OBJECT (self)); +} + +static void +on_brightness_set (PhoshLogin1SessionDBusLoginSession *proxy, + GAsyncResult *res, + PhoshTorchManager *self) { g_autoptr (GError) err = NULL; - if (!phosh_upower_dbus_torch_call_set_brightness_finish (proxy, res, &err)) { - g_warning ("Failed to set torch brighness: %s", err->message); + g_return_if_fail (PHOSH_IS_TORCH_MANAGER (self)); + g_return_if_fail (PHOSH_LOGIN1_SESSION_DBUS_IS_LOGIN_SESSION (proxy)); + + if (!phosh_login1_session_dbus_login_session_call_set_brightness_finish (proxy, res, &err)) { + g_warning ("Failed to set torch brigthness: %s", err->message); + return; } - g_object_unref (self); + + apply_brightness (self); } static void set_brightness (PhoshTorchManager *self, int brightness) { - phosh_upower_dbus_torch_call_set_brightness (self->proxy, brightness, - NULL, - (GAsyncReadyCallback) on_brightness_set, - g_object_ref (self)); + g_return_if_fail (G_UDEV_IS_DEVICE (self->udev_device)); + + if (self->brightness == brightness) + return; + + g_debug("Setting brightness to %d", brightness); + + phosh_login1_session_dbus_login_session_call_set_brightness (self->proxy, + TORCH_SUBSYSTEM, + g_udev_device_get_name (self->udev_device), + (guint) brightness, + NULL, + (GAsyncReadyCallback) on_brightness_set, + self); } static void @@ -106,92 +154,96 @@ static void -on_torch_brightness_changed (PhoshTorchManager *self, - GParamSpec *pspec, - PhoshUPowerDBusTorch *proxy) +get_first_torch_device (gpointer data, gpointer manager) { - int brightness; - const char *icon_name; + PhoshTorchManager *self = PHOSH_TORCH_MANAGER (manager); + GUdevDevice *device = G_UDEV_DEVICE (data); - g_autoptr (GError) err = NULL; - - g_return_if_fail (PHOSH_IS_TORCH_MANAGER (self)); - g_return_if_fail (PHOSH_UPOWER_DBUS_IS_TORCH (proxy)); + /* Keep only the first torch device found */ + if (!self->udev_device) + self->udev_device = g_object_ref (device); +} - brightness = phosh_upower_dbus_torch_get_brightness (proxy); - if (brightness == self->brightness) - return; +static gboolean +find_torch_device (PhoshTorchManager *self) +{ + g_autoptr (GUdevEnumerator) udev_enumerator = NULL; + g_autolist (GUdevDevice) device_list = NULL; - g_debug ("Torch brightness: %d", brightness); + self->udev_device = NULL; - g_object_freeze_notify (G_OBJECT (self)); - g_object_notify_by_pspec (G_OBJECT (self), props[PROP_BRIGHTNESS]); + udev_enumerator = g_udev_enumerator_new (self->udev_client); + g_udev_enumerator_add_match_subsystem (udev_enumerator, TORCH_SUBSYSTEM); + g_udev_enumerator_add_match_name (udev_enumerator, "*:torch"); + g_udev_enumerator_add_match_name (udev_enumerator, "*:flash"); + + device_list = g_udev_enumerator_execute (udev_enumerator); + if (!device_list) { + g_warning ("Failed to find a torch device"); + return FALSE; + } - if (!!self->brightness != !!brightness) - g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ENABLED]); - self->brightness = brightness; + g_list_foreach (device_list, get_first_torch_device, self); - icon_name = self->brightness ? TORCH_ENABLED_ICON : TORCH_DISABLED_ICON; - if (icon_name != self->icon_name) { - self->icon_name = icon_name; - g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ICON_NAME]); + if (!self->udev_device) { + g_warning ("Failed to find a usable torch device"); + return FALSE; } - g_object_thaw_notify (G_OBJECT (self)); + self->max_brightness = g_udev_device_get_sysfs_attr_as_int (self->udev_device, + "max_brightness"); + g_debug("Found torch device '%s' with max brightness %d", + g_udev_device_get_name (self->udev_device), self->max_brightness); + return TRUE; } static void -on_get_max_brightness_finished (PhoshUPowerDBusTorch *proxy, - GAsyncResult *res, - PhoshTorchManager *self) +on_proxy_new_for_bus_finish (GObject *source_object, + GAsyncResult *res, + PhoshTorchManager *self) { g_autoptr (GError) err = NULL; - gboolean present = TRUE; - int value; + PhoshLogin1SessionDBusLoginSession *proxy; - if (phosh_upower_dbus_torch_call_get_max_brightness_finish (proxy, &value, res, &err)) { - self->max_brightness = value; - } else { - g_debug ("Failed to get torch brightness: %s", err->message); - present = FALSE; + proxy = phosh_login1_session_dbus_login_session_proxy_new_for_bus_finish (res, &err); + if (!proxy) { + phosh_async_error_warn (err, "Failed to get login1 session proxy"); + return; } - if (self->present != present) { - self->present = present; + g_return_if_fail (PHOSH_IS_TORCH_MANAGER (self)); + self->proxy = proxy; + + self->present = find_torch_device (self); + if (self->present) { + g_object_freeze_notify (G_OBJECT (self)); + + apply_brightness (self); + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PRESENT]); + g_object_thaw_notify (G_OBJECT (self)); } - - g_debug ("Torch present: %d", self->present); - g_object_unref (self); } static void -on_name_owner_changed (PhoshTorchManager *self, - GParamSpec *pspec, - PhoshUPowerDBusTorch *proxy) +phosh_torch_manager_idle_init (PhoshManager *manager) { - g_autofree char *owner = NULL; - gboolean present; - - g_return_if_fail (PHOSH_IS_TORCH_MANAGER (self)); - g_return_if_fail (G_IS_DBUS_PROXY (proxy)); + PhoshTorchManager *self = PHOSH_TORCH_MANAGER (manager); + const char * const subsystems[] = { TORCH_SUBSYSTEM, NULL }; - owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (proxy)); - present = owner ? TRUE : FALSE; - /* Name owner went away */ - if (!present && self->present) { - self->present = present; - g_debug ("Torch present: %d", self->present); - g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PRESENT]); - return; - } + self->udev_client = g_udev_client_new (subsystems); + g_return_if_fail (self->udev_client != NULL); - /* Check max brightness as indicator if we can drive that DBus interface */ - phosh_upower_dbus_torch_call_get_max_brightness ( - proxy, NULL, (GAsyncReadyCallback)on_get_max_brightness_finished, - g_object_ref (self)); + self->cancel = g_cancellable_new (); + phosh_login1_session_dbus_login_session_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + BUS_NAME, + OBJECT_PATH, + self->cancel, + (GAsyncReadyCallback) on_proxy_new_for_bus_finish, + self); } @@ -200,8 +252,14 @@ { PhoshTorchManager *self = PHOSH_TORCH_MANAGER(object); + g_cancellable_cancel (self->cancel); + g_clear_object (&self->cancel); + g_clear_object (&self->proxy); + g_clear_object (&self->udev_client); + g_clear_object (&self->udev_device); + G_OBJECT_CLASS (phosh_torch_manager_parent_class)->dispose (object); } @@ -210,10 +268,13 @@ phosh_torch_manager_class_init (PhoshTorchManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + PhoshManagerClass *manager_class = PHOSH_MANAGER_CLASS (klass); object_class->get_property = phosh_torch_manager_get_property; object_class->dispose = phosh_torch_manager_dispose; + manager_class->idle_init = phosh_torch_manager_idle_init; + props[PROP_ICON_NAME] = g_param_spec_string ("icon-name", "icon name", @@ -255,61 +316,10 @@ static void -on_proxy_new_for_bus_finish (GObject *source_object, - GAsyncResult *res, - PhoshTorchManager *self) -{ - g_autoptr (GError) err = NULL; - - g_return_if_fail (PHOSH_IS_TORCH_MANAGER (self)); - - self->proxy = phosh_upower_dbus_torch_proxy_new_for_bus_finish (res, &err); - - if (!self->proxy) { - g_warning ("Failed to get upower torch proxy: %s", err->message); - goto out; - } - - g_signal_connect_object (self->proxy, - "notify::g-name-owner", - G_CALLBACK (on_name_owner_changed), - self, - G_CONNECT_SWAPPED); - on_name_owner_changed (self, NULL, self->proxy); - g_signal_connect_object (self->proxy, - "notify::brightness", - G_CALLBACK (on_torch_brightness_changed), - self, - G_CONNECT_SWAPPED); - on_torch_brightness_changed (self, NULL, self->proxy); - - g_debug ("Torch manager initialized"); -out: - g_object_unref (self); -} - - -static gboolean -on_idle (PhoshTorchManager *self) -{ - phosh_upower_dbus_torch_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - BUS_NAME, - OBJECT_PATH, - NULL, - (GAsyncReadyCallback) on_proxy_new_for_bus_finish, - g_object_ref (self)); - return G_SOURCE_REMOVE; -} - - -static void phosh_torch_manager_init (PhoshTorchManager *self) { self->icon_name = TORCH_DISABLED_ICON; self->max_brightness = 1; - /* Perform DBus setup when idle */ - g_idle_add ((GSourceFunc)on_idle, self); } @@ -405,7 +415,7 @@ phosh_torch_manager_toggle (PhoshTorchManager *self) { g_return_if_fail (PHOSH_IS_TORCH_MANAGER (self)); - g_return_if_fail (PHOSH_UPOWER_DBUS_IS_TORCH (self->proxy)); + g_return_if_fail (PHOSH_LOGIN1_SESSION_DBUS_IS_LOGIN_SESSION (self->proxy)); if (self->brightness) { g_debug ("Disabling torch"); diff -Nru phosh-0.8.0/src/torch-manager.h phosh-0.13.1/src/torch-manager.h --- phosh-0.8.0/src/torch-manager.h 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/torch-manager.h 2021-08-31 09:15:52.000000000 +0000 @@ -6,13 +6,15 @@ #pragma once +#include "manager.h" + #include G_BEGIN_DECLS #define PHOSH_TYPE_TORCH_MANAGER (phosh_torch_manager_get_type ()) -G_DECLARE_FINAL_TYPE (PhoshTorchManager, phosh_torch_manager, PHOSH, TORCH_MANAGER, GObject) +G_DECLARE_FINAL_TYPE (PhoshTorchManager, phosh_torch_manager, PHOSH, TORCH_MANAGER, PhoshManager) PhoshTorchManager *phosh_torch_manager_new (void); const char *phosh_torch_manager_get_icon_name (PhoshTorchManager *self); diff -Nru phosh-0.8.0/src/ui/app-auth-prompt.ui phosh-0.13.1/src/ui/app-auth-prompt.ui --- phosh-0.8.0/src/ui/app-auth-prompt.ui 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/ui/app-auth-prompt.ui 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,79 @@ + + + + + + diff -Nru phosh-0.8.0/src/ui/app-grid.ui phosh-0.13.1/src/ui/app-grid.ui --- phosh-0.8.0/src/ui/app-grid.ui 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/ui/app-grid.ui 2021-08-31 09:15:52.000000000 +0000 @@ -9,30 +9,60 @@ True vertical - + True - True - 6 - 6 - 6 - edit-find-symbolic - False - False - Search apps… - - - - - + False + + + True + True + edit-find-symbolic + False + False + Search apps… + + + + + + + + + True + True + 0 + + + + + True + True + False + True + menu_filter + + + True + False + open-menu + + + + + + False + True + 1 + + - - False - True - 0 - @@ -125,4 +155,21 @@ + + + + True + 10 + 6 + vertical + + + True + app-grid.filter-adaptive + Show only adaptive apps + + + + + diff -Nru phosh-0.8.0/src/ui/end-session-dialog.ui phosh-0.13.1/src/ui/end-session-dialog.ui --- phosh-0.8.0/src/ui/end-session-dialog.ui 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/ui/end-session-dialog.ui 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,80 @@ + + + + + + diff -Nru phosh-0.8.0/src/ui/gtk-mount-prompt.ui phosh-0.13.1/src/ui/gtk-mount-prompt.ui --- phosh-0.8.0/src/ui/gtk-mount-prompt.ui 1970-01-01 00:00:00.000000000 +0000 +++ phosh-0.13.1/src/ui/gtk-mount-prompt.ui 2021-08-31 09:15:52.000000000 +0000 @@ -0,0 +1,167 @@ + + + + + + + + diff -Nru phosh-0.8.0/src/ui/home.ui phosh-0.13.1/src/ui/home.ui --- phosh-0.8.0/src/ui/home.ui 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/ui/home.ui 2021-08-31 09:15:52.000000000 +0000 @@ -4,6 +4,7 @@ diff -Nru phosh-0.8.0/src/ui/media-player.ui phosh-0.13.1/src/ui/media-player.ui --- phosh-0.8.0/src/ui/media-player.ui 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/ui/media-player.ui 2021-08-31 09:15:52.000000000 +0000 @@ -4,60 +4,58 @@ diff -Nru phosh-0.8.0/src/ui/network-auth-prompt.ui phosh-0.13.1/src/ui/network-auth-prompt.ui --- phosh-0.8.0/src/ui/network-auth-prompt.ui 2021-01-17 16:49:25.000000000 +0000 +++ phosh-0.13.1/src/ui/network-auth-prompt.ui 2021-08-31 09:15:52.000000000 +0000 @@ -1,41 +1,23 @@ -