diff --git a/.gitignore b/.gitignore index 4e8b63b00..4e401aeda 100644 --- a/.gitignore +++ b/.gitignore @@ -11,24 +11,24 @@ _* grub2/grub2 grub2/testdata/tmp_* themes/themes -network/network -accounts/accounts -audio/audio +network1/network +accounts1/accounts +audio1/audio datetime/datetime deepin-daemon/deepin-daemon desktop-toggle/desktop-toggle display/display dock-apps-builder/dock-apps-builder dock-daemon/dock-daemon -inputdevices/inputdevices -keybinding/keybinding +inputdevices1/inputdevices +keybinding1/keybinding launcher-daemon/launcher-daemon mime/mime mounts/mounts power/power system-info/system-info zone-settings/zone-settings -bluetooth/bluetooth +bluetooth1/bluetooth main_network.go bin/default-terminal/default-terminal bin/default-file-manager/default-file-manager diff --git a/.obs/workflows.yml b/.obs/workflows.yml new file mode 100644 index 000000000..9a3e95dab --- /dev/null +++ b/.obs/workflows.yml @@ -0,0 +1,44 @@ +test_build: + steps: + - link_package: + source_project: deepin:Develop:dde + source_package: %{SCM_REPOSITORY_NAME} + target_project: deepin:CI + + - configure_repositories: + project: deepin:CI + repositories: + - name: deepin_develop + paths: + - target_project: deepin:CI + target_repository: deepin_develop + architectures: + - x86_64 + - aarch64 + + - name: debian + paths: + - target_project: deepin:CI + target_repository: debian_sid + architectures: + - x86_64 + + filters: + event: pull_request + +tag_build: + steps: + - branch_package: + source_project: deepin:Develop:dde + source_package: %{SCM_REPOSITORY_NAME} + target_project: deepin:Unstable:dde + filters: + event: tag_push + +commit_build: + steps: + - trigger_services: + project: deepin:Develop:dde + package: %{SCM_REPOSITORY_NAME} + filters: + event: push diff --git a/.reuse/dep5 b/.reuse/dep5 index 1e4bb1506..0c78405d4 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -9,7 +9,7 @@ Copyright: None License: CC0-1.0 # ci -Files: .github/* .gitlab-ci.yml +Files: .github/* .obs/* .gitlab-ci.yml Copyright: None License: CC0-1.0 diff --git a/.tx/config b/.tx/config index 40e38f06d..575a77a50 100644 --- a/.tx/config +++ b/.tx/config @@ -10,19 +10,19 @@ source_lang = en type = PO [o:linuxdeepin:p:deepin-desktop-environment:r:dde-daemon-grub2-policyts] -file_filter = misc/ts/com.deepin.daemon.Grub2.policy/policy_.ts -source_file = misc/ts/com.deepin.daemon.Grub2.policy/policy.ts +file_filter = misc/ts/org.deepin.dde.grub2.policy/policy_.ts +source_file = misc/ts/org.deepin.dde.grub2.policy/policy.ts source_lang = en type = QT [o:linuxdeepin:p:deepin-desktop-environment:r:dde-daemon-accounts-policyts] -file_filter = misc/ts/com.deepin.daemon.accounts.policy/policy_.ts -source_file = misc/ts/com.deepin.daemon.accounts.policy/policy.ts +file_filter = misc/ts/org.deepin.dde.accounts.policy/policy_.ts +source_file = misc/ts/org.deepin.dde.accounts.policy/policy.ts source_lang = en type = QT [o:linuxdeepin:p:deepin-desktop-environment:r:dde-daemon-fprintd-policyts] -file_filter = misc/ts/com.deepin.daemon.Fprintd.policy/policy_.ts -source_file = misc/ts/com.deepin.daemon.Fprintd.policy/policy.ts +file_filter = misc/ts/org.deepin.dde.fprintd.policy/policy_.ts +source_file = misc/ts/org.deepin.dde.fprintd.policy/policy.ts source_lang = en type = QT diff --git a/.tx/deepin.conf b/.tx/deepin.conf index 45cd054c3..2d7ce1709 100644 --- a/.tx/deepin.conf +++ b/.tx/deepin.conf @@ -1,2 +1,2 @@ [transifex] -branch = m20 \ No newline at end of file +branch = m23 diff --git a/CHANGELOG.md b/CHANGELOG.md index 71ce79216..470d16b16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,7 +47,7 @@ * feat(dde-session-daemon): sync login sound config after all module started * fix(soundeffect): still play login sound even if sound effect switch is off * chore: auto pull translation files from transifex -* change(api): com.deepin.daemon.Greeter add method UpdateGreeterQtTheme +* change(api): org.deepin.dde.Greeter1 add method UpdateGreeterQtTheme * fix: ScreenScaleFactors cannot be easily parsed by greeter * feat: also set the screen scale factors of the greeter * fix(accounts): user was not added to some groups when creating user @@ -68,7 +68,7 @@ * chore(langselector): remove failed test * fix(audio): trySelectBestPort do not work * change(api): sound effect add more functions -* change(api): add sytem service com.deepin.system.Network +* change(api): add sytem service org.deepin.dde.Network1 [3.23.1] 2019-03-01 * feat(bluetooth): when disconnected quickly after connecting, automatically try to connect @@ -531,7 +531,7 @@ ## [3.2.4] - 2017-11-09 #### Features -* add com.deepin.daemon.ImageBlur interface +* add org.deepin.dde.ImageBlur1 interface #### Bug Fixes * not show newly installed wechat in launcher diff --git a/Makefile b/Makefile index a2b13cddb..1533906fc 100644 --- a/Makefile +++ b/Makefile @@ -2,22 +2,110 @@ PREFIX = /usr GOPATH_DIR = gopath GOPKG_PREFIX = github.com/linuxdeepin/dde-daemon GOBUILD = go build $(GO_BUILD_FLAGS) -export GO111MODULE=off export GOPATH=$(shell go env GOPATH) +ifneq (${shell uname -m}, mips64el) + GOBUILD_OPTIONS = -ldflags '-linkmode=external -extldflags "-pie"' +endif + +TEST = \ + ${GOPKG_PREFIX}/accounts1 \ + ${GOPKG_PREFIX}/accounts1/checkers \ + ${GOPKG_PREFIX}/accounts1/logined \ + ${GOPKG_PREFIX}/accounts1/users \ + ${GOPKG_PREFIX}/appinfo \ + ${GOPKG_PREFIX}/apps1 \ + ${GOPKG_PREFIX}/audio1 \ + ${GOPKG_PREFIX}/bin/backlight_helper \ + ${GOPKG_PREFIX}/bin/backlight_helper/ddcci \ + ${GOPKG_PREFIX}/bin/dde-authority \ + ${GOPKG_PREFIX}/bin/dde-greeter-setter \ + ${GOPKG_PREFIX}/bin/dde-lockservice \ + ${GOPKG_PREFIX}/bin/dde-session-daemon \ + ${GOPKG_PREFIX}/bin/dde-system-daemon \ + ${GOPKG_PREFIX}/bin/default-terminal \ + ${GOPKG_PREFIX}/bin/grub2 \ + ${GOPKG_PREFIX}/bin/langselector \ + ${GOPKG_PREFIX}/bin/search \ + ${GOPKG_PREFIX}/bin/soundeffect \ + ${GOPKG_PREFIX}/bin/user-config \ + ${GOPKG_PREFIX}/bluetooth1 \ + ${GOPKG_PREFIX}/calltrace \ + ${GOPKG_PREFIX}/clipboard1 \ + ${GOPKG_PREFIX}/clipboard1/mocks \ + ${GOPKG_PREFIX}/common/bluetooth \ + ${GOPKG_PREFIX}/common/dsync \ + ${GOPKG_PREFIX}/common/sessionmsg \ + ${GOPKG_PREFIX}/dbus \ + ${GOPKG_PREFIX}/debug \ + ${GOPKG_PREFIX}/fprintd1 \ + ${GOPKG_PREFIX}/fprintd1/common \ + ${GOPKG_PREFIX}/gesture1 \ + ${GOPKG_PREFIX}/graph \ + ${GOPKG_PREFIX}/grub2 \ + ${GOPKG_PREFIX}/grub_common \ + ${GOPKG_PREFIX}/grub_gfx \ + ${GOPKG_PREFIX}/housekeeping \ + ${GOPKG_PREFIX}/image_effect1 \ + ${GOPKG_PREFIX}/inputdevices1 \ + ${GOPKG_PREFIX}/inputdevices1/iso639 \ + ${GOPKG_PREFIX}/iw \ + ${GOPKG_PREFIX}/keybinding1 \ + ${GOPKG_PREFIX}/keybinding1/shortcuts \ + ${GOPKG_PREFIX}/keybinding1/util \ + ${GOPKG_PREFIX}/langselector1 \ + ${GOPKG_PREFIX}/lastore1 \ + ${GOPKG_PREFIX}/loader \ + ${GOPKG_PREFIX}/network1 \ + ${GOPKG_PREFIX}/network1/nm \ + ${GOPKG_PREFIX}/network1/nm_generator \ + ${GOPKG_PREFIX}/network1/proxychains \ + ${GOPKG_PREFIX}/screenedge1 \ + ${GOPKG_PREFIX}/screensaver1 \ + ${GOPKG_PREFIX}/service_trigger \ + ${GOPKG_PREFIX}/session/common \ + ${GOPKG_PREFIX}/session/eventlog \ + ${GOPKG_PREFIX}/session/power1 \ + ${GOPKG_PREFIX}/session/uadpagent1 \ + ${GOPKG_PREFIX}/sessionwatcher1 \ + ${GOPKG_PREFIX}/soundeffect1 \ + ${GOPKG_PREFIX}/system/airplane_mode1 \ + ${GOPKG_PREFIX}/system/bluetooth1 \ + ${GOPKG_PREFIX}/system/display1 \ + ${GOPKG_PREFIX}/system/gesture1 \ + ${GOPKG_PREFIX}/system/hostname \ + ${GOPKG_PREFIX}/system/inputdevices1 \ + ${GOPKG_PREFIX}/system/keyevent1 \ + ${GOPKG_PREFIX}/system/lang \ + ${GOPKG_PREFIX}/system/network1 \ + ${GOPKG_PREFIX}/system/power1 \ + ${GOPKG_PREFIX}/system/power_manager1 \ + ${GOPKG_PREFIX}/system/resource_ctl \ + ${GOPKG_PREFIX}/system/scheduler \ + ${GOPKG_PREFIX}/system/swapsched1 \ + ${GOPKG_PREFIX}/system/systeminfo1 \ + ${GOPKG_PREFIX}/system/timedate1 \ + ${GOPKG_PREFIX}/system/uadp1 \ + ${GOPKG_PREFIX}/systeminfo1 \ + ${GOPKG_PREFIX}/timedate1 \ + ${GOPKG_PREFIX}/trayicon1 \ + ${GOPKG_PREFIX}/x_event_monitor1 \ + ${GOPKG_PREFIX}/bin/default-file-manager + #${GOPKG_PREFIX}/timedate1/zoneinfo \ + BINARIES = \ dde-session-daemon \ dde-system-daemon \ grub2 \ search \ - theme-thumb-tool \ backlight_helper \ langselector \ soundeffect \ dde-lockservice \ dde-authority \ default-terminal \ - dde-greeter-setter + dde-greeter-setter \ + default-file-manager LANGUAGES = $(basename $(notdir $(wildcard misc/po/*.po))) @@ -33,9 +121,6 @@ prepare: out/bin/%: prepare env GOPATH="${CURDIR}/${GOPATH_DIR}:${GOPATH}" ${GOBUILD} -o $@ ${GOBUILD_OPTIONS} ${GOPKG_PREFIX}/bin/${@F} -out/bin/default-file-manager: bin/default-file-manager/main.c - gcc $^ $(shell pkg-config --cflags --libs gio-unix-2.0) $(CFLAGS) -o $@ - out/bin/desktop-toggle: bin/desktop-toggle/main.c gcc $^ $(shell pkg-config --cflags --libs x11) $(CFLAGS) -o $@ @@ -48,22 +133,21 @@ translate: $(addsuffix /LC_MESSAGES/dde-daemon.mo, $(addprefix out/locale/, ${LA pot: deepin-update-pot misc/po/locale_config.ini -POLICIES=accounts Grub2 Fprintd +POLICIES=accounts1 Grub2 Fprintd1 ts: for i in $(POLICIES); do \ - deepin-policy-ts-convert policy2ts misc/polkit-action/com.deepin.daemon.$$i.policy.in misc/ts/com.deepin.daemon.$$i.policy; \ + deepin-policy-ts-convert policy2ts misc/polkit-action/org.deepin.dde.$$i.policy.in misc/ts/org.deepin.dde.$$i.policy; \ done ts_to_policy: for i in $(POLICIES); do \ - deepin-policy-ts-convert ts2policy misc/polkit-action/com.deepin.daemon.$$i.policy.in misc/ts/com.deepin.daemon.$$i.policy misc/polkit-action/com.deepin.daemon.$$i.policy; \ + deepin-policy-ts-convert ts2policy misc/polkit-action/org.deepin.dde.$$i.policy.in misc/ts/org.deepin.dde.$$i.policy misc/polkit-action/org.deepin.dde.$$i.policy; \ done build: prepare out/bin/default-terminal out/bin/default-file-manager out/bin/desktop-toggle $(addprefix out/bin/, ${BINARIES}) ts_to_policy icons translate test: prepare - env GOPATH="${CURDIR}/${GOPATH_DIR}:${GOPATH}" go test -v ./... - + env GOPATH="${CURDIR}/${GOPATH_DIR}:${GOPATH}" go test -v ${TEST} test-coverage: prepare env GOPATH="${CURDIR}/${GOPATH_DIR}:${GOPATH}" go test -cover -v ./... | awk '$$2 ~ "_${CURDIR}" {print $$2","$$5}' | sed "s:${CURDIR}::g" | sed 's/files\]/0\.0%/g' > coverage.csv @@ -94,8 +178,17 @@ install: build install-dde-data install-icons cp -r misc/dde-daemon/* ${DESTDIR}${PREFIX}/share/dde-daemon/ cp -r misc/usr/share/deepin ${DESTDIR}${PREFIX}/share/ + mkdir -pv ${DESTDIR}/lib/systemd/user/ + cp -f misc/systemd/services/user/* ${DESTDIR}/lib/systemd/user/ + + mkdir -pv ${DESTDIR}/lib/systemd/system/ + cp -f misc/systemd/services/system/* ${DESTDIR}/lib/systemd/system/ + + mkdir -p $(DESTDIR)$(PREFIX)/lib/systemd/user/dde-session-initialized.target.wants/ + ln -s $(PREFIX)/lib/systemd/user/org.dde.session.Daemon1.service $(DESTDIR)$(PREFIX)/lib/systemd/user/dde-session-initialized.target.wants/org.dde.session.Daemon1.service + mkdir -pv ${DESTDIR}/lib/systemd/system/ - cp -f misc/systemd/services/* ${DESTDIR}/lib/systemd/system/ + cp -f misc/systemd/system-services/* ${DESTDIR}/lib/systemd/system/ mkdir -pv ${DESTDIR}/etc/pam.d/ cp -f misc/etc/pam.d/* ${DESTDIR}/etc/pam.d/ @@ -118,9 +211,8 @@ install: build install-dde-data install-icons mkdir -pv ${DESTDIR}/lib/udev/rules.d cp -f misc/udev-rules/*.rules ${DESTDIR}/lib/udev/rules.d/ - mkdir -pv ${DESTDIR}/usr/lib/deepin-daemon/service-trigger - cp -f misc/service-trigger/*.json ${DESTDIR}/usr/lib/deepin-daemon/service-trigger/ - cp -f misc/service-trigger/*.sh ${DESTDIR}/usr/lib/deepin-daemon/service-trigger/ + mkdir -pv ${DESTDIR}${PREFIX}/lib/deepin-daemon/service-trigger + cp -f misc/service-trigger/*.json ${DESTDIR}${PREFIX}/lib/deepin-daemon/service-trigger/ mkdir -pv ${DESTDIR}/etc/NetworkManager/conf.d cp -f misc/etc/NetworkManager/conf.d/* ${DESTDIR}/etc/NetworkManager/conf.d/ @@ -130,9 +222,8 @@ install: build install-dde-data install-icons mkdir -pv ${DESTDIR}${PREFIX}/share/dsg/configs/org.deepin.dde.daemon/ cp -r misc/dsg-configs/*.json ${DESTDIR}${PREFIX}/share/dsg/configs/org.deepin.dde.daemon/ - mkdir -pv ${DESTDIR}${PREFIX}/share/dsg/configs/org.deepin.dde.lightdm-deepin-greeter - cp -r misc/dsg-configs/org.deepin.dde.lightdm-deepin-greeter/*.json ${DESTDIR}${PREFIX}/share/dsg/configs/org.deepin.dde.lightdm-deepin-greeter/ + cp -f misc/scripts/dde-lock.sh ${DESTDIR}${PREFIX}/lib/deepin-daemon/ install-dde-data: mkdir -pv ${DESTDIR}${PREFIX}/share/dde/ cp -r misc/data ${DESTDIR}${PREFIX}/share/dde/ diff --git a/accounts/exported_methods_auto.go b/accounts/exported_methods_auto.go deleted file mode 100644 index cf9dc8369..000000000 --- a/accounts/exported_methods_auto.go +++ /dev/null @@ -1,309 +0,0 @@ -// Code generated by "dbusutil-gen em -type Manager,User,ImageBlur"; DO NOT EDIT. - -package accounts - -import ( - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (v *ImageBlur) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "Delete", - Fn: v.Delete, - InArgs: []string{"file"}, - }, - { - Name: "Get", - Fn: v.Get, - InArgs: []string{"file"}, - OutArgs: []string{"blurred"}, - }, - } -} -func (v *Manager) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "AllowGuestAccount", - Fn: v.AllowGuestAccount, - InArgs: []string{"allow"}, - }, - { - Name: "CreateGroup", - Fn: v.CreateGroup, - InArgs: []string{"groupName", "gid", "isSystem"}, - }, - { - Name: "CreateGuestAccount", - Fn: v.CreateGuestAccount, - OutArgs: []string{"user"}, - }, - { - Name: "CreateUser", - Fn: v.CreateUser, - InArgs: []string{"name", "fullName", "accountType"}, - OutArgs: []string{"userPath"}, - }, - { - Name: "DeleteGroup", - Fn: v.DeleteGroup, - InArgs: []string{"groupName", "force"}, - }, - { - Name: "DeleteUser", - Fn: v.DeleteUser, - InArgs: []string{"name", "rmFiles"}, - }, - { - Name: "EnablePasswdChangedHandler", - Fn: v.EnablePasswdChangedHandler, - InArgs: []string{"enable"}, - }, - { - Name: "FindUserById", - Fn: v.FindUserById, - InArgs: []string{"uid"}, - OutArgs: []string{"user"}, - }, - { - Name: "FindUserByName", - Fn: v.FindUserByName, - InArgs: []string{"name"}, - OutArgs: []string{"user"}, - }, - { - Name: "GetGroupInfoByName", - Fn: v.GetGroupInfoByName, - InArgs: []string{"name"}, - OutArgs: []string{"groupInfo"}, - }, - { - Name: "GetGroups", - Fn: v.GetGroups, - OutArgs: []string{"groups"}, - }, - { - Name: "GetPresetGroups", - Fn: v.GetPresetGroups, - InArgs: []string{"accountType"}, - OutArgs: []string{"groups"}, - }, - { - Name: "IsPasswordValid", - Fn: v.IsPasswordValid, - InArgs: []string{"password"}, - OutArgs: []string{"valid", "msg", "code"}, - }, - { - Name: "IsUsernameValid", - Fn: v.IsUsernameValid, - InArgs: []string{"name"}, - OutArgs: []string{"valid", "msg", "code"}, - }, - { - Name: "ModifyGroup", - Fn: v.ModifyGroup, - InArgs: []string{"currentGroupName", "newGroupName", "newGID"}, - }, - { - Name: "RandUserIcon", - Fn: v.RandUserIcon, - OutArgs: []string{"iconFile"}, - }, - { - Name: "SetTerminalLocked", - Fn: v.SetTerminalLocked, - InArgs: []string{"locked"}, - }, - } -} -func (v *User) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "AddGroup", - Fn: v.AddGroup, - InArgs: []string{"group"}, - }, - { - Name: "DeleteGroup", - Fn: v.DeleteGroup, - InArgs: []string{"group"}, - }, - { - Name: "DeleteIconFile", - Fn: v.DeleteIconFile, - InArgs: []string{"icon"}, - }, - { - Name: "DeleteSecretKey", - Fn: v.DeleteSecretKey, - }, - { - Name: "EnableNoPasswdLogin", - Fn: v.EnableNoPasswdLogin, - InArgs: []string{"enabled"}, - }, - { - Name: "GetReminderInfo", - Fn: v.GetReminderInfo, - OutArgs: []string{"info"}, - }, - { - Name: "GetSecretKey", - Fn: v.GetSecretKey, - InArgs: []string{"username"}, - OutArgs: []string{"outArg0"}, - }, - { - Name: "GetSecretQuestions", - Fn: v.GetSecretQuestions, - OutArgs: []string{"list"}, - }, - { - Name: "IsPasswordExpired", - Fn: v.IsPasswordExpired, - OutArgs: []string{"outArg0"}, - }, - { - Name: "PasswordExpiredInfo", - Fn: v.PasswordExpiredInfo, - OutArgs: []string{"expiredStatus", "dayLeft"}, - }, - { - Name: "SetAutomaticLogin", - Fn: v.SetAutomaticLogin, - InArgs: []string{"enabled"}, - }, - { - Name: "SetCurrentWorkspace", - Fn: v.SetCurrentWorkspace, - InArgs: []string{"currentWorkspace"}, - }, - { - Name: "SetDesktopBackgrounds", - Fn: v.SetDesktopBackgrounds, - InArgs: []string{"val"}, - }, - { - Name: "SetFullName", - Fn: v.SetFullName, - InArgs: []string{"name"}, - }, - { - Name: "SetGreeterBackground", - Fn: v.SetGreeterBackground, - InArgs: []string{"bg"}, - }, - { - Name: "SetGroups", - Fn: v.SetGroups, - InArgs: []string{"groups"}, - }, - { - Name: "SetHistoryLayout", - Fn: v.SetHistoryLayout, - InArgs: []string{"list"}, - }, - { - Name: "SetHomeDir", - Fn: v.SetHomeDir, - InArgs: []string{"home"}, - }, - { - Name: "SetIconFile", - Fn: v.SetIconFile, - InArgs: []string{"iconURI"}, - }, - { - Name: "SetLayout", - Fn: v.SetLayout, - InArgs: []string{"layout"}, - }, - { - Name: "SetLocale", - Fn: v.SetLocale, - InArgs: []string{"locale"}, - }, - { - Name: "SetLocked", - Fn: v.SetLocked, - InArgs: []string{"locked"}, - }, - { - Name: "SetLongDateFormat", - Fn: v.SetLongDateFormat, - InArgs: []string{"value"}, - }, - { - Name: "SetLongTimeFormat", - Fn: v.SetLongTimeFormat, - InArgs: []string{"value"}, - }, - { - Name: "SetMaxPasswordAge", - Fn: v.SetMaxPasswordAge, - InArgs: []string{"nDays"}, - }, - { - Name: "SetPassword", - Fn: v.SetPassword, - InArgs: []string{"password"}, - }, - { - Name: "SetPasswordHint", - Fn: v.SetPasswordHint, - InArgs: []string{"hint"}, - }, - { - Name: "SetQuickLogin", - Fn: v.SetQuickLogin, - InArgs: []string{"enabled"}, - }, - { - Name: "SetSecretKey", - Fn: v.SetSecretKey, - InArgs: []string{"secretKey"}, - }, - { - Name: "SetSecretQuestions", - Fn: v.SetSecretQuestions, - InArgs: []string{"list"}, - }, - { - Name: "SetShell", - Fn: v.SetShell, - InArgs: []string{"shell"}, - }, - { - Name: "SetShortDateFormat", - Fn: v.SetShortDateFormat, - InArgs: []string{"value"}, - }, - { - Name: "SetShortTimeFormat", - Fn: v.SetShortTimeFormat, - InArgs: []string{"value"}, - }, - { - Name: "SetUse24HourFormat", - Fn: v.SetUse24HourFormat, - InArgs: []string{"value"}, - }, - { - Name: "SetWeekBegins", - Fn: v.SetWeekBegins, - InArgs: []string{"value"}, - }, - { - Name: "SetWeekdayFormat", - Fn: v.SetWeekdayFormat, - InArgs: []string{"value"}, - }, - { - Name: "VerifySecretQuestions", - Fn: v.VerifySecretQuestions, - InArgs: []string{"answers"}, - OutArgs: []string{"failed"}, - }, - } -} diff --git a/accounts/manager.go b/accounts/manager.go deleted file mode 100644 index 474962fbd..000000000 --- a/accounts/manager.go +++ /dev/null @@ -1,820 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package accounts - -import ( - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "sort" - "strconv" - "sync" - "syscall" - "time" - - dbus "github.com/godbus/dbus" - udcp "github.com/linuxdeepin/go-dbus-factory/com.deepin.udcp.iam" - configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/tasker" - dutils "github.com/linuxdeepin/go-lib/utils" - - "github.com/linuxdeepin/dde-daemon/accounts/users" - "github.com/linuxdeepin/dde-daemon/common/sessionmsg" -) - -const ( - actConfigDir = "/var/lib/AccountsService" - userConfigDir = actConfigDir + "/deepin/users" - userIconsDir = actConfigDir + "/icons" - userCustomIconsDir = actConfigDir + "/icons/local" - - userIconGuest = actConfigDir + "/icons/guest.png" - actConfigFile = actConfigDir + "/accounts.ini" - actConfigGroupGroup = "Accounts" - actConfigKeyGuest = "AllowGuest" - - interfacesFile = "/usr/share/dde-daemon/accounts/dbus-udcp.json" -) - -var configFile = filepath.Join(actConfigDir, "domainUser.json") - -type domainUserConfig struct { - Name string - Uid string - IsLogined bool -} - -type DefaultDomainUserConfig map[string]*domainUserConfig - -type InterfaceConfig struct { - Service string `json:"service"` - Path string `json:"path"` - Interface string `json:"interface"` -} - -const ( - dsettingsAppID = "org.deepin.dde.daemon" - dsettingsAccountName = "org.deepin.dde.daemon.account" - dsettingsIsTerminalLocked = "isTerminalLocked" - gsSchemaDdeControlCenter = "com.deepin.dde.control-center" - settingKeyAutoLoginVisable = "auto-login-visable" -) - -//go:generate dbusutil-gen -type Manager,User manager.go user.go -//go:generate dbusutil-gen em -type Manager,User,ImageBlur - -type Manager struct { - service *dbusutil.Service - sysSigLoop *dbusutil.SignalLoop - login1Manager login1.Manager - PropsMu sync.RWMutex - - UserList []string - UserListMu sync.RWMutex - - // dbusutil-gen: ignore - GuestIcon string - AllowGuest bool - // dbusutil-gen: equal=isStrvEqual - GroupList []string - - watcher *dutils.WatchProxy - usersMap map[string]*User - usersMapMu sync.Mutex - - enablePasswdChangedHandler bool - enablePasswdChangedHandlerMu sync.Mutex - - delayTaskManager *tasker.DelayTaskManager - userAddedChanMap map[string]chan string - udcpCache udcp.UdcpCache - userConfig DefaultDomainUserConfig - domainUserMapMu sync.Mutex - cfgManager configManager.ConfigManager - dsAccount configManager.Manager - // greeter 的 dconfig 配置 - dsGreeterAccounts configManager.Manager - - dbusDaemon ofdbus.DBus - IsTerminalLocked bool - // 快速登录总开关 - QuickLoginEnabled bool - - //nolint - signals *struct { - UserAdded struct { - objPath string - } - - UserDeleted struct { - objPath string - } - } -} - -func NewManager(service *dbusutil.Service) *Manager { - systemBus, err := dbus.SystemBus() - if err != nil { - return nil - } - login1Manager := login1.NewManager(systemBus) - sysSigLoop := dbusutil.NewSignalLoop(systemBus, 10) - sysSigLoop.Start() - - var m = &Manager{ - service: service, - login1Manager: login1Manager, - sysSigLoop: sysSigLoop, - enablePasswdChangedHandler: true, - } - m.usersMap = make(map[string]*User) - m.userAddedChanMap = make(map[string]chan string) - - m.GuestIcon = userIconGuest - m.AllowGuest = isGuestUserEnabled() - - m.initUsers(getUserPaths()) - m.initUdcpUsers() - m.initAccountDSettings() - - // 检测到系统加入LDAP域后,才去初始化域用户信息 - ret, err := m.isJoinLDAPDoamin() - if err == nil { - if ret { - m.initDomainUsers() - } - } - - if m.IsTerminalLocked { - for _, u := range m.usersMap { - if u.AutomaticLogin { - u.setAutomaticLogin(false) - } - } - } - - m.GroupList, _ = m.GetGroups() - m.watcher = dutils.NewWatchProxy() - if m.watcher != nil { - m.delayTaskManager = tasker.NewDelayTaskManager() - _ = m.delayTaskManager.AddTask(taskNamePasswd, fileEventDelay, m.handleFilePasswdChanged) - _ = m.delayTaskManager.AddTask(taskNameGroup, fileEventDelay, m.handleFileGroupChanged) - _ = m.delayTaskManager.AddTask(taskNameShadow, fileEventDelay, m.handleFileShadowChanged) - _ = m.delayTaskManager.AddTask(taskNameDM, fileEventDelay, m.handleDMConfigChanged) - _ = m.delayTaskManager.AddTask(taskNameGreeterState, fileEventDelay, m.handleGreeterStateChanged) - - m.watcher.SetFileList(m.getWatchFiles()) - m.watcher.SetEventHandler(m.handleFileChanged) - go m.watcher.StartWatch() - } - - m.login1Manager.InitSignalExt(m.sysSigLoop, true) - _, _ = m.login1Manager.ConnectSessionNew(func(id string, sessionPath dbus.ObjectPath) { - core, err := login1.NewSession(systemBus, sessionPath) - if err != nil { - logger.Warningf("new login1 session failed:%v", err) - return - } - - userInfo, err := core.User().Get(0) - if err != nil { - logger.Warningf("get user info failed:%v", err) - return - } - - if userInfo.UID < 10000 { - return - } - - err = m.addDomainUser(userInfo.UID) - if err != nil { - logger.Warningf("add login session failed:%v", err) - } - }) - - _, _ = m.login1Manager.ConnectPrepareForSleep(func(before bool) { - if before { - return - } - - pwdChangerLock.Lock() - defer pwdChangerLock.Unlock() - - if pwdChangerProcess != nil { - err := syscall.Kill(-pwdChangerProcess.Pid, syscall.SIGTERM) - if err != nil { - logger.Warning(err) - } - } - }) - - return m -} - -func (m *Manager) destroy() { - if m.watcher != nil { - m.watcher.EndWatch() - m.watcher = nil - } - - m.sysSigLoop.Stop() - m.stopExportUsers(m.UserList) - _ = m.service.StopExport(m) -} - -func (m *Manager) initUsers(list []string) { - var userList []string - for _, p := range list { - u, err := NewUser(p, m.service, false) - if err != nil { - logger.Errorf("New user '%s' failed: %v", p, err) - continue - } - - userList = append(userList, p) - - m.usersMapMu.Lock() - m.usersMap[p] = u - m.usersMapMu.Unlock() - } - sort.Strings(userList) - m.UserList = userList -} - -func (m *Manager) initUdcpCache() error { - // 解析json文件 新建udcp-cache对象 - var ifcCfg InterfaceConfig - content, err := ioutil.ReadFile(interfacesFile) - if err != nil { - return err - } - err = json.Unmarshal(content, &ifcCfg) - if err != nil { - logger.Warning(err) - return err - } - if !dbus.ObjectPath(ifcCfg.Path).IsValid() { - logger.Warningf("interface config file %q, path %q is invalid", interfacesFile, ifcCfg.Path) - return err - } - - sysBus, err := dbus.SystemBus() - if err != nil { - return err - } - - udcpCache, err := udcp.NewUdcpCache(sysBus, ifcCfg.Service, dbus.ObjectPath(ifcCfg.Path)) - if err != nil { - return err - } - - udcpCache.SetInterfaceName_(ifcCfg.Interface) - - m.udcpCache = udcpCache - return nil - -} - -func (m *Manager) initUdcpUsers() { - // 解析json文件 新建udcp-cache对象,获取所有加域账户ID - err := m.initUdcpCache() - if err != nil { - logger.Warningf("New udcp cache object failed: %v", err) - return - } - - userIdList, err := m.udcpCache.GetUserIdList(0) - if err != nil { - logger.Warningf("Udcp cache getUserIdList failed: %v", err) - return - } - - isJoinUdcp, err := m.udcpCache.Enable().Get(0) - if err != nil { - logger.Warningf("Udcp cache get Enable failed: %v", err) - return - } - - if !isJoinUdcp { - return - } - - // 构造User服务对象 - var userList = m.UserList - for _, uId := range userIdList { - if users.ExistPwUid(uId) != 0 { - continue - } - userGroups, err := m.udcpCache.GetUserGroups(0, users.GetPwName(uId)) - if err != nil { - logger.Warningf("Udcp cache getUserGroups failed: %v", err) - continue - } - - u, err := NewDomainUser(uId, m.service, userGroups) - if err != nil { - logger.Warningf("New udcp user '%d' failed: %v", uId, err) - continue - } - userDBusPath := userDBusPathPrefix + strconv.FormatUint(uint64(uId), 10) - userList = append(userList, userDBusPath) - m.usersMapMu.Lock() - m.usersMap[userDBusPath] = u - m.usersMapMu.Unlock() - } - sort.Strings(userList) - m.UserList = userList -} - -func (m *Manager) initDomainUsers() { - var domainUserList []string - // 解析json文件,获取所有之前登录过的域账号 - err := m.loadDomainUserConfig() - - if err != nil { - logger.Warningf("init domain user config failed: %v", err) - return - } - - for _, v := range m.userConfig { - if users.IsLDAPDomainUserID(v.Uid) && (v.IsLogined == true) { - domainUserList = append(domainUserList, v.Uid) - } - } - - // 构造User服务对象 - var userList = m.UserList - for _, uId := range domainUserList { - id, _ := strconv.Atoi(uId) - domainUserGroups, err := users.GetADUserGroupsByUID(uint32(id)) - if err != nil { - logger.Warningf("get domain user groups failed: %v", err) - return - } - - u, err := NewDomainUser(uint32(id), m.service, domainUserGroups) - if err != nil { - logger.Errorf("New domain user '%s' failed: %v", uId, err) - continue - } - - userDBusPath := userDBusPathPrefix + uId - userList = append(userList, userDBusPath) - m.usersMapMu.Lock() - m.usersMap[userDBusPath] = u - m.usersMapMu.Unlock() - } - sort.Strings(userList) - m.UserList = userList -} - -func (m *Manager) exportUsers() { - m.usersMapMu.Lock() - - for _, u := range m.usersMap { - err := m.service.Export(dbus.ObjectPath(userDBusPathPrefix+u.Uid), u) - if err != nil { - logger.Errorf("failed to export user %q: %v", - u.Uid, err) - continue - } - - } - - m.usersMapMu.Unlock() -} - -func (m *Manager) stopExportUsers(list []string) { - for _, p := range list { - m.stopExportUser(p) - } -} - -func (m *Manager) exportUserByUid(uId string) error { - var err error - var u *User - var userGroups []string - userPath := userDBusPathPrefix + uId - id, _ := strconv.Atoi(uId) - - if /*m.isUserJoinUdcp()*/ id > 10000 { - if users.ExistPwUid(uint32(id)) != 0 { - return errors.New("no such user id") - } - - // 域管用户 - if m.udcpCache != nil { - userGroups, err = m.udcpCache.GetUserGroups(0, users.GetPwName(uint32(id))) - if err != nil { - logger.Warningf("Udcp cache getUserGroups failed: %v", err) - } - } - - // LDAP 域用户 - if users.IsLDAPDomainUserID(uId) { - userGroups, err = users.GetADUserGroupsByUID(uint32(id)) - if err != nil { - logger.Warningf("get domain user groups failed: %v", err) - } - } - - if err != nil { - return err - } - - u, err = NewDomainUser(uint32(id), m.service, userGroups) - - if users.IsLDAPDomainUserID(uId) { - var config = &domainUserConfig{ - Name: u.UserName, - Uid: u.Uid, - IsLogined: true, - } - - m.domainUserMapMu.Lock() - m.userConfig[userPath] = config - m.saveDomainUserConfig(m.userConfig) - m.domainUserMapMu.Unlock() - } - } else { - u, err = NewUser(userPath, m.service, true) - } - if err != nil { - return err - } - - var stat = &syscall.Stat_t{} - if err := syscall.Stat(u.HomeDir, stat); err != nil { - logger.Warning(err) - } else if strconv.Itoa(int(stat.Uid)) != u.Uid { - logger.Debug("incorrect ownership") - err = recoverOwnership(u) - if err != nil { - logger.Warning(err) - } - } - - m.usersMapMu.Lock() - ch := m.userAddedChanMap[u.UserName] - m.usersMapMu.Unlock() - - err = m.service.Export(dbus.ObjectPath(userPath), u) - logger.Debugf("export user %q err: %v", userPath, err) - if ch != nil { - if err != nil { - ch <- "" - } else { - ch <- userPath - } - logger.Debug("after ch <- userPath") - } - - if err != nil { - return err - } - - m.usersMapMu.Lock() - m.usersMap[userPath] = u - m.usersMapMu.Unlock() - - return nil -} - -func (m *Manager) stopExportUser(userPath string) { - m.usersMapMu.Lock() - defer m.usersMapMu.Unlock() - u, ok := m.usersMap[userPath] - if !ok { - logger.Debug("Invalid user path:", userPath) - return - } - - delete(m.usersMap, userPath) - _ = m.service.StopExport(u) -} - -func (m *Manager) getUserByName(name string) *User { - m.usersMapMu.Lock() - defer m.usersMapMu.Unlock() - - for _, user := range m.usersMap { - if user.UserName == name { - return user - } - } - return nil -} - -func (m *Manager) getUserByUid(uid string) *User { - m.usersMapMu.Lock() - defer m.usersMapMu.Unlock() - - for _, user := range m.usersMap { - if user.Uid == uid { - return user - } - } - return nil -} - -func getUserPaths() []string { - infos, err := users.GetHumanUserInfos() - if err != nil { - return nil - } - - var paths []string - for _, info := range infos { - paths = append(paths, userDBusPathPrefix+info.Uid) - } - - return paths -} - -func isGuestUserEnabled() bool { - v, exist := dutils.ReadKeyFromKeyFile(actConfigFile, - actConfigGroupGroup, actConfigKeyGuest, true) - if !exist { - return false - } - - ret, ok := v.(bool) - if !ok { - return false - } - - return ret -} - -func (m *Manager) checkAuth(sender dbus.Sender) error { - return checkAuth(polkitActionUserAdministration, string(sender)) -} - -func chownHomeDir(homeDir string, username string) { - logger.Debug("change owner for dir:", homeDir) - err := exec.Command("chown", "-hR", username+":"+username, homeDir).Run() - if err != nil { - logger.Warningf("change owner for dir %v failed: %v", homeDir, err) - return - } - err = sessionmsg.SendMessage(sessionmsg.NewMessage(true, &sessionmsg.BodyNotify{ - Icon: "preferences-system", - Body: &sessionmsg.LocalizeStr{ - Format: Tr("User \"%s\" existed before and its data is synced"), - Args: []string{username}, - }, - ExpireTimeout: -1, - })) - if err != nil { - logger.Warning("send session msg failed:", err) - } -} - -func Tr(text string) string { - return text -} - -func (m *Manager) loadDomainUserConfig() error { - logger.Debug("loadDomainUserConfig") - - m.userConfig = make(DefaultDomainUserConfig) - if !dutils.IsFileExist(configFile) { - err := dutils.CreateFile(configFile) - if err != nil { - return err - } - } else { - data, err := ioutil.ReadFile(configFile) - if err != nil { - return err - } - - if len(data) == 0 { - return errors.New("domain user config file is empty") - } - - err = json.Unmarshal(data, &m.userConfig) - if err != nil { - return err - } - } - - return nil -} - -func (m *Manager) saveDomainUserConfig(config DefaultDomainUserConfig) error { - data, err := json.Marshal(config) - if err != nil { - return err - } - - dir := filepath.Dir(configFile) - err = os.MkdirAll(dir, 0755) - if err != nil { - return err - } - - err = ioutil.WriteFile(configFile, data, 0644) - return err -} - -func (m *Manager) isJoinLDAPDoamin() (bool, error) { - out, err := exec.Command("realm", "list").CombinedOutput() - if err != nil { - logger.Debugf("failed to execute %s, error: %v", "realm list", err) - return false, err - } - - if len(out) == 0 { - return false, nil - } - - return true, nil -} - -func (m *Manager) modifyUserConfig(path string) error { - m.usersMapMu.Lock() - root, ok := m.usersMap[path] - m.usersMapMu.Unlock() - if ok { - loadUserConfigInfo(root) - } - - return nil -} - -func (m *Manager) checkGroupCanChange(name string) bool { - groupInfoMap, err := users.GetGroupInfoWithCacheLock() - if err != nil { - logger.Warning(err) - return false - } - info, ok := groupInfoMap[name] - if !ok { - return false - } - gid, err := strconv.Atoi(info.Gid) - if err != nil { - logger.Warning(err) - return false - } - return gid >= 1000 -} - -func (m *Manager) initAccountDSettings() { - m.cfgManager = configManager.NewConfigManager(m.sysSigLoop.Conn()) - - accountPath, err := m.cfgManager.AcquireManager(0, dsettingsAppID, dsettingsAccountName, "") - if err != nil { - logger.Warning(err) - return - } - - m.dsAccount, err = configManager.NewManager(m.sysSigLoop.Conn(), accountPath) - if err != nil { - logger.Warning(err) - return - } - - v, err := m.dsAccount.Value(0, dsettingsIsTerminalLocked) - if err != nil { - logger.Warning(err) - return - } - - if data, ok := v.Value().(bool); ok { - m.IsTerminalLocked = data - } -} - -const ( - greeterAppId = "org.deepin.dde.lightdm-deepin-greeter" - daemonAccountsResourceId = "org.deepin.dde.daemon.accounts" - keyEnableQuickLogin = "enableQuickLogin" -) - -// 在 dconfig 设置 quick login (总开关) -func (m *Manager) setDConfigQuickLoginEnabled(enabled bool) error { - if m.dsGreeterAccounts == nil { - return errors.New("get greeter accounts dconfig failed") - } - err := m.dsGreeterAccounts.SetValue(0, keyEnableQuickLogin, dbus.MakeVariant(enabled)) - if err != nil { - return fmt.Errorf("set greeter dconfig enableQuickLogin failed, err: %v", err) - } - return nil -} - -// 从 dconfig 获取 quick login (总开关)的配置 -func (m *Manager) getDConfigQuickLoginEnabled() (bool, error) { - if m.dsGreeterAccounts == nil { - return false, errors.New("get greeter accounts dconfig failed") - } - enabledVar, err := m.dsGreeterAccounts.Value(0, keyEnableQuickLogin) - if err != nil { - return false, fmt.Errorf("get greeter accounts dconfig enableQuickLogin failed, err: %v", err) - } - - enabled, ok := enabledVar.Value().(bool) - if !ok { - return false, errors.New("enabledVar.Value() is not bool type") - } - return enabled, nil -} - -func (m *Manager) initDConfigGreeterWatch() error { - greeterAccountsPath, err := m.cfgManager.AcquireManager(0, greeterAppId, daemonAccountsResourceId, "") - if err != nil { - return err - } - - m.dsGreeterAccounts, err = configManager.NewManager(m.sysSigLoop.Conn(), greeterAccountsPath) - if err != nil { - return err - } - - enabled, err := m.getDConfigQuickLoginEnabled() - if err != nil { - logger.Warning("getDConfigQuickLoginEnabled failed, err:", err) - } else { - // 从 dconfig 获取值,然后同步到 /etc/lightdm/lightdm.conf 配置文件中。 - err = users.SetLightDMQuickLoginEnabled(enabled) - if err != nil { - logger.Warning("SetLightDMQuickLoginEnabled failed, error:", err) - } - m.setPropQuickLoginEnabled(enabled) - } - - m.dsGreeterAccounts.InitSignalExt(m.sysSigLoop, true) - m.dsGreeterAccounts.ConnectValueChanged(func(key string) { - // dconfig 配置改变 - if key != keyEnableQuickLogin { - return - } - - enabled, err := m.getDConfigQuickLoginEnabled() - if err != nil { - logger.Warning("getDConfigQuickLoginEnabled failed, err:", err) - return - } - - logger.Debug("handle dconfig quick login enabled changed", enabled) - err = users.SetLightDMQuickLoginEnabled(enabled) - if err != nil { - logger.Warning("SetLightDMQuickLoginEnabled failed, error:", err) - } - }) - return nil -} - -func (m *Manager) removeGreeterDConfigWatch() { - if m.dsGreeterAccounts != nil { - m.dsGreeterAccounts.RemoveAllHandlers() - } -} - -// 监控 dconfig-daemon 服务是否重新启动, 如果重新启动了,需要重新注册监控器。 -func (m *Manager) initDBusDaemonWatch() { - systemBus, err := dbus.SystemBus() - if err != nil { - logger.Warning("get system bus failed, err:", err) - return - } - - m.dbusDaemon = ofdbus.NewDBus(systemBus) - m.dbusDaemon.InitSignalExt(m.sysSigLoop, false) - - // 手工构建匹配规则 - rule := dbusutil.NewMatchRuleBuilder().Sender(m.dbusDaemon.ServiceName_()). - Path(string(m.dbusDaemon.Path_())).Member("NameOwnerChanged"). - Arg(0, m.cfgManager.ServiceName_()). - Build() - logger.Debug("rule:", rule.Str) - err = rule.AddTo(systemBus) - if err != nil { - logger.Warning("add match rule failed, err:", err) - return - } - - _, err = m.dbusDaemon.ConnectNameOwnerChanged(func(name, oldOwner, newOwner string) { - if name == m.cfgManager.ServiceName_() && oldOwner == "" && newOwner != "" { - // 检测到 dconfig-daemon 服务启动后,重新初始化相关配置 - logger.Debug("monitored that the dconfig-daemon service has restarted") - time.Sleep(2 * time.Second) - m.removeGreeterDConfigWatch() - m.initDConfigGreeterWatch() - } - }) - if err != nil { - logger.Warning("connect NameOwnerChanged signal failed, err:", err) - } -} diff --git a/accounts/manager_ifc.go b/accounts/manager_ifc.go deleted file mode 100644 index 95a585792..000000000 --- a/accounts/manager_ifc.go +++ /dev/null @@ -1,566 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package accounts - -import ( - "encoding/json" - "errors" - "fmt" - "math/rand" - "os" - "os/exec" - "strconv" - "time" - - "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/accounts/checkers" - "github.com/linuxdeepin/dde-daemon/accounts/users" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/gettext" - "github.com/linuxdeepin/go-lib/procfs" - "github.com/linuxdeepin/go-lib/users/passwd" - dutils "github.com/linuxdeepin/go-lib/utils" -) - -const ( - nilObjPath = dbus.ObjectPath("/") - dbusServiceName = "com.deepin.daemon.Accounts" - dbusPath = "/com/deepin/daemon/Accounts" - dbusInterface = "com.deepin.daemon.Accounts" -) - -func (*Manager) GetInterfaceName() string { - return dbusInterface -} - -// Create new user. -// -// 如果收到 Error 信号,则创建失败。 -// -// name: 用户名 -// -// fullName: 全名,可以为空 -// -// ty: 用户类型,0 为普通用户,1 为管理员 - -func (m *Manager) CreateUser(sender dbus.Sender, - name, fullName string, accountType int32) (userPath dbus.ObjectPath, busErr *dbus.Error) { - - logger.Debug("[CreateUser] new user:", name, fullName, accountType) - - err := checkAccountType(int(accountType)) - if err != nil { - return nilObjPath, dbusutil.ToError(err) - } - - err = m.checkAuth(sender) - if err != nil { - logger.Debug("[CreateUser] access denied:", err) - return nilObjPath, dbusutil.ToError(err) - } - - ch := make(chan string) - m.usersMapMu.Lock() - m.userAddedChanMap[name] = ch - m.usersMapMu.Unlock() - defer func() { - m.usersMapMu.Lock() - delete(m.userAddedChanMap, name) - m.usersMapMu.Unlock() - close(ch) - }() - - homeDir := "/home/" + name - _, err = os.Stat(homeDir) - homeDirExist := err == nil - - if err := users.CreateUser(name, fullName, ""); err != nil { - logger.Warningf("DoAction: create user '%s' failed: %v\n", - name, err) - return nilObjPath, dbusutil.ToError(err) - } - - groups := users.GetPresetGroups(int(accountType)) - logger.Debug("groups:", groups) - err = users.SetGroupsForUser(groups, name) - if err != nil { - logger.Warningf("failed to set groups for user %s: %v", name, err) - } - // create user success - select { - case userPath, ok := <-ch: - if !ok { - return nilObjPath, dbusutil.ToError(errors.New("invalid user path event")) - } - - logger.Debug("receive user path", userPath) - if userPath == "" { - return nilObjPath, dbusutil.ToError(errors.New("failed to install user on session bus")) - } - if homeDirExist { - go chownHomeDir(homeDir, name) - } - return dbus.ObjectPath(userPath), nil - case <-time.After(time.Second * 60): - err := errors.New("wait timeout exceeded") - logger.Warning(err) - return nilObjPath, dbusutil.ToError(err) - } -} - -// Delete a exist user. -// -// name: 用户名 -// -// rmFiles: 是否删除用户数据 -func (m *Manager) DeleteUser(sender dbus.Sender, - name string, rmFiles bool) *dbus.Error { - - logger.Debug("[DeleteUser] user:", name, rmFiles) - - err := m.checkAuth(sender) - if err != nil { - logger.Debug("[DeleteUser] access denied:", err) - return dbusutil.ToError(err) - } - - user := m.getUserByName(name) - if user == nil { - err := fmt.Errorf("user %q not found", name) - logger.Warning(err) - return dbusutil.ToError(err) - } - - if m.isDomainUser(user.Uid) { - id, _ := strconv.Atoi(user.Uid) - - if m.udcpCache != nil && m.isUdcpUserID(user.Uid) { - result, err := m.udcpCache.RemoveCacheFile(0, uint32(id)) - if err != nil { - logger.Errorf("Udcp cache RemoveCacheFile failed: %v", err) - return dbusutil.ToError(err) - } - - if !result { - return dbusutil.ToError(errors.New("failed to remove user cache files")) - } - } - - // 删除账户前先删除生物特征,避免删除账户后,用户数据找不到 - if rmFiles { - user.clearBiometricChara() - // 删除域用户家目录 - os.RemoveAll(user.HomeDir) - } - - // 删除服务,更新UserList - userPath := userDBusPathPrefix + user.Uid - // 删除对应AD域账户配置 - if len(m.userConfig) != 0 { - delete(m.userConfig, userPath) - m.domainUserMapMu.Lock() - m.saveDomainUserConfig(m.userConfig) - m.domainUserMapMu.Unlock() - } - - m.stopExportUser(userPath) - m.updatePropUserList() - - // 清楚域账户本地缓存 - if rmFiles { - user.clearData() - } - - err = m.service.Emit(m, "UserDeleted", userPath) - if err != nil { - logger.Warning(err) - } - return dbusutil.ToError(err) - } - - // 清除用户快速登录设置 - err = users.SetQuickLogin(name, false) - if err != nil { - // 仅警告错误 - logger.Warningf("disable quick login for user %q failed: %v", name, err) - } - - // 删除账户前先删除生物特征,避免删除账户后,用户数据找不到 - if rmFiles { - user.clearBiometricChara() - } - if err := users.DeleteUser(rmFiles, name); err != nil { - logger.Warningf("DoAction: delete user '%s' failed: %v\n", - name, err) - return dbusutil.ToError(err) - } - - //delete user config and icons - if rmFiles { - user.clearData() - } - - return nil -} - -func (m *Manager) FindUserById(uid string) (user string, busErr *dbus.Error) { - userPath := userDBusPathPrefix + uid - for _, v := range m.UserList { - if v == userPath { - return v, nil - } - } - - return "", dbusutil.ToError(fmt.Errorf("invalid uid: %s", uid)) -} - -func (m *Manager) FindUserByName(name string) (user string, busErr *dbus.Error) { - pwd, err := passwd.GetPasswdByName(name) - if err != nil { - logger.Warning(err) - pwd = &passwd.Passwd{ - Name: name, - } - } - - m.usersMapMu.Lock() - defer m.usersMapMu.Unlock() - - for p, u := range m.usersMap { - if u.UserName == pwd.Name { - return p, nil - } - } - - return "", dbusutil.ToError(fmt.Errorf("invalid username: %s", pwd.Name)) -} - -// 随机得到一个用户头像 -// -// ret0:头像路径,为空则表示获取失败 -func (m *Manager) RandUserIcon() (iconFile string, busErr *dbus.Error) { - icons := getUserStandardIcons() - if len(icons) == 0 { - return "", dbusutil.ToError(errors.New("Did not find any user icons")) - } - - rand.Seed(time.Now().UnixNano()) - idx := rand.Intn(len(icons)) // #nosec G404 - return icons[idx], nil -} - -func (m *Manager) isDomainUserExist(name string) bool { - pwd, err := passwd.GetPasswdByName(name) - if err != nil { - return false - } - - id := strconv.FormatUint(uint64(pwd.Uid), 10) - - return m.isUdcpUserExists(name) || users.IsLDAPDomainUserID(id) -} - -// 检查用户名是否有效 -// -// ret0: 是否合法 -// -// ret1: 不合法原因 -// -// ret2: 不合法代码 -func (m *Manager) IsUsernameValid(sender dbus.Sender, name string) (valid bool, - msg string, code int32, busErr *dbus.Error) { - var err error - var info *checkers.ErrorInfo - - defer func() { - busErr = dbusutil.ToError(err) - }() - - pid, err := m.service.GetConnPID(string(sender)) - if err != nil { - return - } - - p := procfs.Process(pid) - environ, err := p.Environ() - if err != nil { - return - } - - locale := environ.Get("LANG") - - // 如果新建用户使用的用户名和域用户名一致,提示用户该用户已经存在 - if m.isDomainUserExist(name) { - info = checkers.ErrCodeExist.Error() - } else { - info = checkers.CheckUsernameValid(name) - if info == nil { - valid = true - return - } - } - - msg = info.Error.Error() - logger.Debug("locale:", locale) - if locale != "" { - gettext.SetLocale(gettext.LcAll, locale) - msg = gettext.Tr(msg) - } - code = int32(info.Code) - return -} - -// 检测密码是否有效 -// -// ret0: 是否合法 -// -// ret1: 提示信息 -// -// ret2: 不合法代码 -func (m *Manager) IsPasswordValid(password string) (valid bool, msg string, code int32, busErr *dbus.Error) { - releaseType := getDeepinReleaseType() - logger.Infof("release type %q", releaseType) - errCode := checkers.CheckPasswordValid(releaseType, password) - return errCode.IsOk(), errCode.Prompt(), int32(errCode), nil -} - -func (m *Manager) AllowGuestAccount(sender dbus.Sender, allow bool) *dbus.Error { - err := m.checkAuth(sender) - if err != nil { - return dbusutil.ToError(err) - } - - m.PropsMu.Lock() - defer m.PropsMu.Unlock() - - if m.AllowGuest == allow { - return nil - } - - success := dutils.WriteKeyToKeyFile(actConfigFile, - actConfigGroupGroup, actConfigKeyGuest, allow) - if !success { - return dbusutil.ToError(errors.New("enable guest user failed")) - } - - m.AllowGuest = allow - _ = m.emitPropChangedAllowGuest(allow) - return nil -} - -func (m *Manager) CreateGuestAccount(sender dbus.Sender) (user string, busErr *dbus.Error) { - err := m.checkAuth(sender) - if err != nil { - return "", dbusutil.ToError(err) - } - - name, err := users.CreateGuestUser() - if err != nil { - return "", dbusutil.ToError(err) - } - - info, err := users.GetUserInfoByName(name) - if err != nil { - return "", dbusutil.ToError(err) - } - - return userDBusPathPrefix + info.Uid, nil -} - -func (m *Manager) GetGroups() (groups []string, busErr *dbus.Error) { - groups, err := users.GetAllGroups() - return groups, dbusutil.ToError(err) -} - -func (m *Manager) GetGroupInfoByName(name string) (groupInfo string, busErr *dbus.Error) { - info, err := users.GetGroupByName(name) - if err != nil { - logger.Warning(err) - return "", dbusutil.ToError(err) - } - infoJson, err := json.Marshal(info) - if err != nil { - logger.Warning(err) - return "", dbusutil.ToError(err) - } - return string(infoJson), nil -} - -func (m *Manager) GetPresetGroups(accountType int32) (groups []string, busErr *dbus.Error) { - err := checkAccountType(int(accountType)) - if err != nil { - return nil, dbusutil.ToError(err) - } - - groups = users.GetPresetGroups(int(accountType)) - return groups, nil -} - -// 是否使能accounts服务在监听到/etc/passwd文件变化后,执行对应的属性更新和服务导出,只允许root用户操作该接口 -func (m *Manager) EnablePasswdChangedHandler(sender dbus.Sender, enable bool) *dbus.Error { - const rootUid = "0" - uid, err := m.service.GetConnUID(string(sender)) - if err != nil { - return dbusutil.ToError(err) - } - if uid != 0 { - return dbusutil.ToError(fmt.Errorf("not allow %v call this method", sender)) - } - m.enablePasswdChangedHandlerMu.Lock() - defer m.enablePasswdChangedHandlerMu.Unlock() - if m.enablePasswdChangedHandler == enable { - return nil - } - m.enablePasswdChangedHandler = enable - if enable { - m.handleFilePasswdChanged() - m.modifyUserConfig(userDBusPathPrefix + rootUid) // root账户的信息需要更新(deepin安装器会在后配置界面修改语言) - } - return nil -} - -func (m *Manager) CreateGroup(sender dbus.Sender, groupName string, gid uint32, isSystem bool) *dbus.Error { - logger.Debug("[CreateGroup] new group:", groupName) - - err := m.checkAuth(sender) - if err != nil { - logger.Debug("[CreateGroup] access denied:", err) - return dbusutil.ToError(err) - } - args := []string{ - groupName, - "-f", - } - if gid > 0 { - args = append(args, []string{ - "-g", fmt.Sprint(gid), "-o", - }...) - } - if isSystem { - args = append(args, "-r") - } - cmd := exec.Command("groupadd", args...) - logger.Debug("[CreateGroup] exec cmd is:", cmd.String()) - err = cmd.Run() - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - groupList, _ := m.GetGroups() - m.setPropGroupList(groupList) - return nil -} - -func (m *Manager) DeleteGroup(sender dbus.Sender, groupName string, force bool) *dbus.Error { - logger.Debug("[DeleteGroup] del group:", groupName) - if !m.checkGroupCanChange(groupName) { - return dbusutil.ToError(fmt.Errorf("can not delete %v", groupName)) - } - err := m.checkAuth(sender) - if err != nil { - logger.Debug("[DeleteGroup] access denied:", err) - return dbusutil.ToError(err) - } - args := []string{ - groupName, - } - if force { - args = append(args, "-f") - } - cmd := exec.Command("groupdel", args...) - logger.Debug("[DeleteGroup] exec cmd is:", cmd.String()) - err = cmd.Run() - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - groupList, _ := m.GetGroups() - m.setPropGroupList(groupList) - return nil -} - -func (m *Manager) ModifyGroup(sender dbus.Sender, currentGroupName string, newGroupName string, newGID uint32) *dbus.Error { - logger.Debug("[ModifyGroup] modify group :", currentGroupName) - if newGroupName == "" && newGID <= 0 { - return dbusutil.ToError(errors.New("invalid modify,need new name or gid")) - } - if !m.checkGroupCanChange(currentGroupName) { - return dbusutil.ToError(fmt.Errorf("can not modify %v", currentGroupName)) - } - err := m.checkAuth(sender) - if err != nil { - logger.Debug("[ModifyGroup] access denied:", err) - return dbusutil.ToError(err) - } - args := []string{ - currentGroupName, - } - if newGroupName != "" { - args = append(args, []string{ - "-n", newGroupName, - }...) - } - if newGID > 0 { - args = append(args, []string{ - "-g", fmt.Sprint(newGID), "-o", - }...) - } - cmd := exec.Command("groupmod", args...) - logger.Debug("[ModifyGroup] exec cmd is:", cmd.String()) - err = cmd.Run() - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - groupList, _ := m.GetGroups() - m.setPropGroupList(groupList) - return nil -} - -func (m *Manager) SetTerminalLocked(sender dbus.Sender, locked bool) *dbus.Error { - logger.Infof("SetTerminalLocked snder: %s, locked: %t", sender, locked) - if m.IsTerminalLocked == locked { - return dbusutil.ToError(fmt.Errorf("current terminal lock is equal set locked: %t", locked)) - } - - if locked { - sessions, err := m.login1Manager.ListSessions(0) - if err != nil { - logger.Warning("Failed to list sessions:", err) - return dbusutil.ToError(err) - } - - for _, session := range sessions { - core, err := login1.NewSession(m.service.Conn(), session.Path) - if err != nil { - logger.Warningf("new login1 session failed:%v", err) - return dbusutil.ToError(err) - } - - err = core.Terminate(0) - if err != nil { - logger.Warningf("new login1 session failed:%v", err) - } - } - } - - err := m.dsAccount.SetValue(0, dsettingsIsTerminalLocked, dbus.MakeVariant(locked)) - if err != nil { - logger.Warningf("setDsgData key : %s ,value : %t err : %s", dsettingsIsTerminalLocked, locked, err) - return dbusutil.ToError(err) - } - - if locked { - for _, u := range m.usersMap { - if u.AutomaticLogin { - u.setAutomaticLogin(false) - } - } - } - - m.setPropIsTerminalLocked(locked) - return nil -} diff --git a/accounts/utils.go b/accounts/utils.go deleted file mode 100644 index 5347a4b65..000000000 --- a/accounts/utils.go +++ /dev/null @@ -1,326 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package accounts - -import ( - "bufio" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "regexp" - "sort" - "strconv" - "strings" - "time" - - "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/accounts/users" - polkit "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.policykit1" - "github.com/linuxdeepin/go-lib/encoding/kv" - "github.com/linuxdeepin/go-lib/graphic" - "github.com/linuxdeepin/go-lib/utils" -) - -// #nosec G101 -const ( - polkitActionUserAdministration = "com.deepin.daemon.accounts.user-administration" - polkitActionChangeOwnData = "com.deepin.daemon.accounts.change-own-user-data" - polkitActionEnableAutoLogin = "com.deepin.daemon.accounts.enable-auto-login" - polkitActionDisableAutoLogin = "com.deepin.daemon.accounts.disable-auto-login" - polkitActionEnableQuickLogin = "com.deepin.daemon.accounts.enable-quick-login" - polkitActionDisableQuickLogin = "com.deepin.daemon.accounts.disable-quick-login" - polkitActionEnableNoPasswordLogin = "com.deepin.daemon.accounts.enable-nopass-login" - polkitActionDisableNoPasswordLogin = "com.deepin.daemon.accounts.disable-nopass-login" - polkitActionSetKeyboardLayout = "com.deepin.daemon.accounts.set-keyboard-layout" - - systemLocaleFile = "/etc/default/locale" - systemdLocaleFile = "/etc/locale.conf" - defaultLocale = "en_US.UTF-8" - - layoutDelimiter = ";" - defaultLayout = "us" + layoutDelimiter - defaultLayoutFile = "/etc/default/keyboard" -) - -type ErrCodeType int32 - -const ( - // 未知错误 - ErrCodeUnkown ErrCodeType = iota - // 权限认证失败 - ErrCodeAuthFailed - // 执行命令失败 - ErrCodeExecFailed - // 传入的参数不合法 - ErrCodeParamInvalid -) - -func (code ErrCodeType) String() string { - switch code { - case ErrCodeUnkown: - return "Unkown error" - case ErrCodeAuthFailed: - return "Policykit authentication failed" - case ErrCodeExecFailed: - return "Exec command failed" - case ErrCodeParamInvalid: - return "Invalid parameters" - } - - return "Unkown error" -} - -// return icons uris -func getUserStandardIcons() []string { - imgs, err := graphic.GetImagesInDir(userIconsDir) - if err != nil { - return nil - } - - var icons []string - for _, img := range imgs { - img = utils.EncodeURI(img, utils.SCHEME_FILE) - if strings.Contains(img, "guest") || img == defaultUserIcon { - continue - } - - icons = append(icons, img) - } - - return icons -} - -func getNewUserCustomIconDest(username string) string { - ns := time.Now().UnixNano() - base := username + "-" + strconv.FormatInt(ns, 36) - return filepath.Join(userCustomIconsDir, base) -} - -func isStrInArray(str string, array []string) bool { - for _, v := range array { - if v == str { - return true - } - } - - return false -} - -func isStrvEqual(l1, l2 []string) bool { - if len(l1) != len(l2) { - return false - } - - sort.Strings(l1) - sort.Strings(l2) - for i, v := range l1 { - if v != l2[i] { - return false - } - } - return true -} - -func checkAccountType(accountType int) error { - switch accountType { - case users.UserTypeStandard, users.UserTypeAdmin: - return nil - default: - return fmt.Errorf("invalid account type %d", accountType) - } -} - -func checkAuth(actionId string, sysBusName string) error { - ret, err := checkAuthByPolkit(actionId, sysBusName) - if err != nil { - return err - } - if !ret.IsAuthorized { - inf, err := getDetailsKey(ret.Details, "polkit.dismissed") - if err == nil { - if dismiss, ok := inf.(string); ok { - if dismiss != "" { - return errors.New("") - } - } - } - return fmt.Errorf(ErrCodeAuthFailed.String()) - } - return nil -} - -func checkAuthByPolkit(actionId string, sysBusName string) (ret polkit.AuthorizationResult, err error) { - systemBus, err := dbus.SystemBus() - if err != nil { - return - } - authority := polkit.NewAuthority(systemBus) - subject := polkit.MakeSubject(polkit.SubjectKindSystemBusName) - subject.SetDetail("name", sysBusName) - - ret, err = authority.CheckAuthorization(0, subject, - actionId, nil, - polkit.CheckAuthorizationFlagsAllowUserInteraction, "") - if err != nil { - logger.Warningf("call check auth failed, err: %v", err) - return - } - logger.Debugf("call check auth success, ret: %v", ret) - return -} - -func getDetailsKey(details map[string]dbus.Variant, key string) (interface{}, error) { - result, ok := details[key] - if !ok { - return nil, errors.New("key dont exist in details") - } - if utils.IsInterfaceNil(result) { - return nil, errors.New("result is nil") - } - return result.Value(), nil -} - -func getDefaultLocale() (locale string) { - files := [...]string{ - systemLocaleFile, - systemdLocaleFile, - } - for _, file := range files { - locale = getLocaleFromFile(file) - if locale != "" { - // get locale success - break - } - } - if locale == "" { - return defaultLocale - } - - return strings.Trim(locale, "\"'") -} - -func getLocaleFromFile(file string) string { - f, err := os.Open(file) - if err != nil { - return "" - } - defer f.Close() - - r := kv.NewReader(f) - r.Delim = '=' - r.Comment = '#' - r.TrimSpace = kv.TrimLeadingTailingSpace - for { - pair, err := r.Read() - if err == io.EOF { - break - } else if err != nil { - return "" - } - - if pair.Key == "LANG" { - return pair.Value - } - } - return "" -} - -func getDefaultLayout() string { - layout, err := getSystemLayout(defaultLayoutFile) - if err != nil { - logger.Warning("failed to get system default layout:", err) - return defaultLayout - } - return layout -} - -func getSystemLayout(file string) (string, error) { - fr, err := os.Open(file) - if err != nil { - return "", err - } - defer fr.Close() - - var ( - found int - layout string - variant string - - regLayout = regexp.MustCompile(`^XKBLAYOUT=`) - regVariant = regexp.MustCompile(`^XKBVARIANT=`) - - scanner = bufio.NewScanner(fr) - ) - for scanner.Scan() { - if found == 2 { - break - } - - var line = scanner.Text() - if regLayout.MatchString(line) { - layout = strings.Trim(getValueFromLine(line, "="), "\"") - found += 1 - continue - } - - if regVariant.MatchString(line) { - variant = strings.Trim(getValueFromLine(line, "="), "\"") - found += 1 - } - } - - if len(layout) == 0 { - return "", fmt.Errorf("not found default layout") - } - - return layout + layoutDelimiter + variant, nil -} - -func getValueFromLine(line, delim string) string { - array := strings.Split(line, delim) - if len(array) != 2 { - return "" - } - - return strings.TrimSpace(array[1]) -} - -// Get available shells from '/etc/shells' -func getAvailableShells(file string) []string { - contents, err := ioutil.ReadFile(file) - if err != nil || len(contents) == 0 { - return nil - } - var shells []string - lines := strings.Split(string(contents), "\n") - for _, line := range lines { - if line == "" || line[0] == '#' { - continue - } - shells = append(shells, line) - } - return shells -} - -// 修复目录 ownership -func recoverOwnership(u *User) error { - uid, err := strconv.Atoi(u.Uid) - if err != nil { - return err - } - gid, err := strconv.Atoi(u.Gid) - if err != nil { - return err - } - return filepath.Walk(u.HomeDir, func(name string, info os.FileInfo, err error) error { - if err == nil { - err = os.Chown(name, uid, gid) - } - return err - }) -} diff --git a/accounts/utils_test.go b/accounts/utils_test.go deleted file mode 100644 index 344ffda51..000000000 --- a/accounts/utils_test.go +++ /dev/null @@ -1,109 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package accounts - -import ( - "testing" - - "github.com/godbus/dbus" - "github.com/stretchr/testify/assert" -) - -var str = []string{"/bin/sh", "/bin/bash", - "/bin/zsh", "/usr/bin/zsh", - "/usr/bin/fish", -} - -func Test_GetLocaleFromFile(t *testing.T) { - assert.Equal(t, getLocaleFromFile("testdata/locale"), "zh_CN.UTF-8") -} - -func Test_SystemLayout(t *testing.T) { - layout, err := getSystemLayout("testdata/keyboard_us") - assert.NoError(t, err) - assert.Equal(t, layout, "us;") - layout, _ = getSystemLayout("testdata/keyboard_us_chr") - assert.Equal(t, layout, "us;chr") -} - -func TestAvailableShells(t *testing.T) { - var ret = []string{"/bin/sh", "/bin/bash", - "/bin/zsh", "/usr/bin/zsh", - "/usr/bin/fish", - } - shells := getAvailableShells("testdata/shells") - assert.ElementsMatch(t, shells, ret) -} - -func TestIsStrInArray(t *testing.T) { - ret := isStrInArray("testdata/shells", str) - assert.Equal(t, ret, false) - ret = isStrInArray("/bin/sh", str) - assert.Equal(t, ret, true) -} - -func TestIsStrvEqual(t *testing.T) { - var str1 = []string{"/bin/sh", "/bin/bash", - "/bin/zsh", "/usr/bin/zsh", - "/usr/bin/fish", - } - var str2 = []string{"/bin/sh", "/bin/bash"} - ret := isStrvEqual(str, str1) - assert.Equal(t, ret, true) - ret = isStrvEqual(str, str2) - assert.Equal(t, ret, false) -} - -func TestGetValueFromLine(t *testing.T) { - ret := getValueFromLine("testdata/shells", "/") - assert.Equal(t, ret, "shells") -} - -func Test_getDetailsKey(t *testing.T) { - type args struct { - details map[string]dbus.Variant - key string - } - tests := []struct { - name string - args args - want interface{} - wantErr bool - }{ - { - name: "getDetailsKey", - args: args{ - details: map[string]dbus.Variant{ - "te": dbus.MakeVariant(true), - }, - key: "te", - }, - want: true, - wantErr: false, - }, - { - name: "getDetailsKey not found", - args: args{ - details: map[string]dbus.Variant{ - "te": dbus.MakeVariant(true), - }, - key: "te1", - }, - want: nil, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := getDetailsKey(tt.args.details, tt.args.key) - if tt.wantErr { - assert.Error(t, err) - return - } - - assert.Equal(t, tt.want, got) - }) - } -} diff --git a/accounts/accounts.go b/accounts1/accounts.go similarity index 97% rename from accounts/accounts.go rename to accounts1/accounts.go index 6df2b13be..b261209bd 100644 --- a/accounts/accounts.go +++ b/accounts1/accounts.go @@ -5,7 +5,7 @@ package accounts import ( - "github.com/linuxdeepin/dde-daemon/accounts/logined" + "github.com/linuxdeepin/dde-daemon/accounts1/logined" "github.com/linuxdeepin/dde-daemon/loader" "github.com/linuxdeepin/go-lib/log" ) diff --git a/accounts/accounts_dbusutil.go b/accounts1/accounts_dbusutil.go similarity index 97% rename from accounts/accounts_dbusutil.go rename to accounts1/accounts_dbusutil.go index 6735bf92a..c1b1301e8 100644 --- a/accounts/accounts_dbusutil.go +++ b/accounts1/accounts_dbusutil.go @@ -2,6 +2,58 @@ package accounts +func (v *Manager) setPropAllowGuest(value bool) (changed bool) { + if v.AllowGuest != value { + v.AllowGuest = value + v.emitPropChangedAllowGuest(value) + return true + } + return false +} + +func (v *Manager) emitPropChangedAllowGuest(value bool) error { + return v.service.EmitPropertyChanged(v, "AllowGuest", value) +} + +func (v *Manager) setPropGroupList(value []string) (changed bool) { + if !isStrvEqual(v.GroupList, value) { + v.GroupList = value + v.emitPropChangedGroupList(value) + return true + } + return false +} + +func (v *Manager) emitPropChangedGroupList(value []string) error { + return v.service.EmitPropertyChanged(v, "GroupList", value) +} + +func (v *Manager) setPropIsTerminalLocked(value bool) (changed bool) { + if v.IsTerminalLocked != value { + v.IsTerminalLocked = value + v.emitPropChangedIsTerminalLocked(value) + return true + } + return false +} + +func (v *Manager) emitPropChangedIsTerminalLocked(value bool) error { + return v.service.EmitPropertyChanged(v, "IsTerminalLocked", value) +} + +func (v *Manager) setPropQuickLoginEnabled(value bool) (changed bool) { + if v.QuickLoginEnabled != value { + v.QuickLoginEnabled = value + v.emitPropChangedQuickLoginEnabled(value) + return true + } + return false +} + +func (v *Manager) emitPropChangedQuickLoginEnabled(value bool) error { + return v.service.EmitPropertyChanged(v, "QuickLoginEnabled", value) +} + func (v *User) setPropUserName(value string) (changed bool) { if v.UserName != value { v.UserName = value @@ -458,54 +510,15 @@ func (v *User) emitPropChangedHistoryLayout(value []string) error { return v.service.EmitPropertyChanged(v, "HistoryLayout", value) } -func (v *Manager) setPropAllowGuest(value bool) (changed bool) { - if v.AllowGuest != value { - v.AllowGuest = value - v.emitPropChangedAllowGuest(value) - return true - } - return false -} - -func (v *Manager) emitPropChangedAllowGuest(value bool) error { - return v.service.EmitPropertyChanged(v, "AllowGuest", value) -} - -func (v *Manager) setPropGroupList(value []string) (changed bool) { - if !isStrvEqual(v.GroupList, value) { - v.GroupList = value - v.emitPropChangedGroupList(value) - return true - } - return false -} - -func (v *Manager) emitPropChangedGroupList(value []string) error { - return v.service.EmitPropertyChanged(v, "GroupList", value) -} - -func (v *Manager) setPropIsTerminalLocked(value bool) (changed bool) { - if v.IsTerminalLocked != value { - v.IsTerminalLocked = value - v.emitPropChangedIsTerminalLocked(value) - return true - } - return false -} - -func (v *Manager) emitPropChangedIsTerminalLocked(value bool) error { - return v.service.EmitPropertyChanged(v, "IsTerminalLocked", value) -} - -func (v *Manager) setPropQuickLoginEnabled(value bool) (changed bool) { - if v.QuickLoginEnabled != value { - v.QuickLoginEnabled = value - v.emitPropChangedQuickLoginEnabled(value) +func (v *User) setPropWechatAuthEnabled(value bool) (changed bool) { + if v.WechatAuthEnabled != value { + v.WechatAuthEnabled = value + v.emitPropChangedWechatAuthEnabled(value) return true } return false } -func (v *Manager) emitPropChangedQuickLoginEnabled(value bool) error { - return v.service.EmitPropertyChanged(v, "QuickLoginEnabled", value) +func (v *User) emitPropChangedWechatAuthEnabled(value bool) error { + return v.service.EmitPropertyChanged(v, "WechatAuthEnabled", value) } diff --git a/accounts/checkers/checkers_test.go b/accounts1/checkers/checkers_test.go similarity index 100% rename from accounts/checkers/checkers_test.go rename to accounts1/checkers/checkers_test.go diff --git a/accounts/checkers/common.go b/accounts1/checkers/common.go similarity index 100% rename from accounts/checkers/common.go rename to accounts1/checkers/common.go diff --git a/accounts/checkers/common_test.go b/accounts1/checkers/common_test.go similarity index 100% rename from accounts/checkers/common_test.go rename to accounts1/checkers/common_test.go diff --git a/accounts/checkers/password.go b/accounts1/checkers/password.go similarity index 100% rename from accounts/checkers/password.go rename to accounts1/checkers/password.go diff --git a/accounts/checkers/testdata/passwd b/accounts1/checkers/testdata/passwd similarity index 100% rename from accounts/checkers/testdata/passwd rename to accounts1/checkers/testdata/passwd diff --git a/accounts/checkers/username.go b/accounts1/checkers/username.go similarity index 100% rename from accounts/checkers/username.go rename to accounts1/checkers/username.go diff --git a/accounts/deepinversion.go b/accounts1/deepinversion.go similarity index 100% rename from accounts/deepinversion.go rename to accounts1/deepinversion.go diff --git a/accounts/deepinversion_test.go b/accounts1/deepinversion_test.go similarity index 100% rename from accounts/deepinversion_test.go rename to accounts1/deepinversion_test.go diff --git a/accounts1/exported_methods_auto.go b/accounts1/exported_methods_auto.go new file mode 100644 index 000000000..75eecf5fb --- /dev/null +++ b/accounts1/exported_methods_auto.go @@ -0,0 +1,318 @@ +// Code generated by "dbusutil-gen em -type Manager,User,ImageBlur"; DO NOT EDIT. + +package accounts + +import ( + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (v *ImageBlur) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "Delete", + Fn: v.Delete, + InArgs: []string{"file"}, + }, + { + Name: "Get", + Fn: v.Get, + InArgs: []string{"file"}, + OutArgs: []string{"blurred"}, + }, + } +} +func (v *Manager) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "AllowGuestAccount", + Fn: v.AllowGuestAccount, + InArgs: []string{"allow"}, + }, + { + Name: "CreateGroup", + Fn: v.CreateGroup, + InArgs: []string{"groupName", "gid", "isSystem"}, + }, + { + Name: "CreateGuestAccount", + Fn: v.CreateGuestAccount, + OutArgs: []string{"user"}, + }, + { + Name: "CreateUser", + Fn: v.CreateUser, + InArgs: []string{"name", "fullName", "accountType"}, + OutArgs: []string{"userPath"}, + }, + { + Name: "DeleteGroup", + Fn: v.DeleteGroup, + InArgs: []string{"groupName", "force"}, + }, + { + Name: "DeleteUser", + Fn: v.DeleteUser, + InArgs: []string{"name", "rmFiles"}, + }, + { + Name: "EnablePasswdChangedHandler", + Fn: v.EnablePasswdChangedHandler, + InArgs: []string{"enable"}, + }, + { + Name: "FindUserById", + Fn: v.FindUserById, + InArgs: []string{"uid"}, + OutArgs: []string{"user"}, + }, + { + Name: "FindUserByName", + Fn: v.FindUserByName, + InArgs: []string{"name"}, + OutArgs: []string{"user"}, + }, + { + Name: "GetGroupInfoByName", + Fn: v.GetGroupInfoByName, + InArgs: []string{"name"}, + OutArgs: []string{"groupInfo"}, + }, + { + Name: "GetGroups", + Fn: v.GetGroups, + OutArgs: []string{"groups"}, + }, + { + Name: "GetPresetGroups", + Fn: v.GetPresetGroups, + InArgs: []string{"accountType"}, + OutArgs: []string{"groups"}, + }, + { + Name: "IsPasswordValid", + Fn: v.IsPasswordValid, + InArgs: []string{"password"}, + OutArgs: []string{"valid", "msg", "code"}, + }, + { + Name: "IsUsernameValid", + Fn: v.IsUsernameValid, + InArgs: []string{"name"}, + OutArgs: []string{"valid", "msg", "code"}, + }, + { + Name: "ModifyGroup", + Fn: v.ModifyGroup, + InArgs: []string{"currentGroupName", "newGroupName", "newGID"}, + }, + { + Name: "RandUserIcon", + Fn: v.RandUserIcon, + OutArgs: []string{"iconFile"}, + }, + { + Name: "SetTerminalLocked", + Fn: v.SetTerminalLocked, + InArgs: []string{"locked"}, + }, + } +} +func (v *User) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "AddGroup", + Fn: v.AddGroup, + InArgs: []string{"group"}, + }, + { + Name: "DeleteGroup", + Fn: v.DeleteGroup, + InArgs: []string{"group"}, + }, + { + Name: "DeleteIconFile", + Fn: v.DeleteIconFile, + InArgs: []string{"icon"}, + }, + { + Name: "DeleteSecretKey", + Fn: v.DeleteSecretKey, + }, + { + Name: "EnableNoPasswdLogin", + Fn: v.EnableNoPasswdLogin, + InArgs: []string{"enabled"}, + }, + { + Name: "EnableWechatAuth", + Fn: v.EnableWechatAuth, + InArgs: []string{"value"}, + }, + { + Name: "GetReminderInfo", + Fn: v.GetReminderInfo, + OutArgs: []string{"info"}, + }, + { + Name: "GetSecretKey", + Fn: v.GetSecretKey, + InArgs: []string{"username"}, + OutArgs: []string{"outArg0"}, + }, + { + Name: "GetSecretQuestions", + Fn: v.GetSecretQuestions, + OutArgs: []string{"list"}, + }, + { + Name: "IsPasswordExpired", + Fn: v.IsPasswordExpired, + OutArgs: []string{"outArg0"}, + }, + { + Name: "PasswordExpiredInfo", + Fn: v.PasswordExpiredInfo, + OutArgs: []string{"expiredStatus", "dayLeft"}, + }, + { + Name: "SetAutomaticLogin", + Fn: v.SetAutomaticLogin, + InArgs: []string{"enabled"}, + }, + { + Name: "SetCurrentWorkspace", + Fn: v.SetCurrentWorkspace, + InArgs: []string{"currentWorkspace"}, + }, + { + Name: "SetDesktopBackgrounds", + Fn: v.SetDesktopBackgrounds, + InArgs: []string{"val"}, + }, + { + Name: "SetFullName", + Fn: v.SetFullName, + InArgs: []string{"name"}, + }, + { + Name: "SetGreeterBackground", + Fn: v.SetGreeterBackground, + InArgs: []string{"bg"}, + }, + { + Name: "SetGroups", + Fn: v.SetGroups, + InArgs: []string{"groups"}, + }, + { + Name: "SetHistoryLayout", + Fn: v.SetHistoryLayout, + InArgs: []string{"list"}, + }, + { + Name: "SetHomeDir", + Fn: v.SetHomeDir, + InArgs: []string{"home"}, + }, + { + Name: "SetIconFile", + Fn: v.SetIconFile, + InArgs: []string{"iconURI"}, + }, + { + Name: "SetLayout", + Fn: v.SetLayout, + InArgs: []string{"layout"}, + }, + { + Name: "SetLocale", + Fn: v.SetLocale, + InArgs: []string{"locale"}, + }, + { + Name: "SetLocked", + Fn: v.SetLocked, + InArgs: []string{"locked"}, + }, + { + Name: "SetLongDateFormat", + Fn: v.SetLongDateFormat, + InArgs: []string{"value"}, + }, + { + Name: "SetLongTimeFormat", + Fn: v.SetLongTimeFormat, + InArgs: []string{"value"}, + }, + { + Name: "SetMaxPasswordAge", + Fn: v.SetMaxPasswordAge, + InArgs: []string{"nDays"}, + }, + { + Name: "SetPassword", + Fn: v.SetPassword, + InArgs: []string{"password"}, + }, + { + Name: "SetPasswordHint", + Fn: v.SetPasswordHint, + InArgs: []string{"hint"}, + }, + { + Name: "SetQuickLogin", + Fn: v.SetQuickLogin, + InArgs: []string{"enabled"}, + }, + { + Name: "SetSecretKey", + Fn: v.SetSecretKey, + InArgs: []string{"secretKey"}, + }, + { + Name: "SetSecretQuestions", + Fn: v.SetSecretQuestions, + InArgs: []string{"list"}, + }, + { + Name: "SetShell", + Fn: v.SetShell, + InArgs: []string{"shell"}, + }, + { + Name: "SetShortDateFormat", + Fn: v.SetShortDateFormat, + InArgs: []string{"value"}, + }, + { + Name: "SetShortTimeFormat", + Fn: v.SetShortTimeFormat, + InArgs: []string{"value"}, + }, + { + Name: "SetUse24HourFormat", + Fn: v.SetUse24HourFormat, + InArgs: []string{"value"}, + }, + { + Name: "SetWeekBegins", + Fn: v.SetWeekBegins, + InArgs: []string{"value"}, + }, + { + Name: "SetWeekdayFormat", + Fn: v.SetWeekdayFormat, + InArgs: []string{"value"}, + }, + { + Name: "UpdateWechatAuthState", + Fn: v.UpdateWechatAuthState, + }, + { + Name: "VerifySecretQuestions", + Fn: v.VerifySecretQuestions, + InArgs: []string{"answers"}, + OutArgs: []string{"failed"}, + }, + } +} diff --git a/accounts/handle_event.go b/accounts1/handle_event.go similarity index 99% rename from accounts/handle_event.go rename to accounts1/handle_event.go index 331539d8f..a47949797 100644 --- a/accounts/handle_event.go +++ b/accounts1/handle_event.go @@ -11,7 +11,7 @@ import ( "time" "github.com/fsnotify/fsnotify" - "github.com/linuxdeepin/dde-daemon/accounts/users" + "github.com/linuxdeepin/dde-daemon/accounts1/users" "github.com/linuxdeepin/go-lib/strv" ) diff --git a/accounts/image_blur.go b/accounts1/image_blur.go similarity index 96% rename from accounts/image_blur.go rename to accounts1/image_blur.go index b45030139..30d1bb3f2 100644 --- a/accounts/image_blur.go +++ b/accounts1/image_blur.go @@ -11,14 +11,14 @@ import ( "path/filepath" "sync" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" dutils "github.com/linuxdeepin/go-lib/utils" ) const ( - imageBlurDBusPath = "/com/deepin/daemon/ImageBlur" - imageBlurDBusInterface = "com.deepin.daemon.ImageBlur" + imageBlurDBusPath = "/org/deepin/dde/ImageBlur1" + imageBlurDBusInterface = "org.deepin.dde.ImageBlur1" ) type ImageBlur struct { diff --git a/accounts/left_space.go b/accounts1/left_space.go similarity index 100% rename from accounts/left_space.go rename to accounts1/left_space.go diff --git a/accounts/logined/exported_methods_auto.go b/accounts1/logined/exported_methods_auto.go similarity index 100% rename from accounts/logined/exported_methods_auto.go rename to accounts1/logined/exported_methods_auto.go diff --git a/accounts/logined/login.go b/accounts1/logined/login.go similarity index 96% rename from accounts/logined/login.go rename to accounts1/logined/login.go index 3196ffec9..11a62d5dd 100644 --- a/accounts/logined/login.go +++ b/accounts1/logined/login.go @@ -9,8 +9,8 @@ import ( "fmt" "sync" - "github.com/godbus/dbus" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" + "github.com/godbus/dbus/v5" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/dbusutil/proxy" "github.com/linuxdeepin/go-lib/log" @@ -33,7 +33,7 @@ type Manager struct { } const ( - DBusPath = "/com/deepin/daemon/Logined" + DBusPath = "/org/deepin/dde/Logined" ) // Register register and install loginedManager on dbus @@ -201,5 +201,5 @@ func (m *Manager) marshalUserSessions() string { } func (*Manager) GetInterfaceName() string { - return "com.deepin.daemon.Logined" + return "org.deepin.dde.Logined" } diff --git a/accounts/logined/user_info.go b/accounts1/logined/user_info.go similarity index 95% rename from accounts/logined/user_info.go rename to accounts1/logined/user_info.go index 68e91c434..286d337cb 100644 --- a/accounts/logined/user_info.go +++ b/accounts1/logined/user_info.go @@ -5,8 +5,8 @@ package logined import ( - "github.com/godbus/dbus" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" + "github.com/godbus/dbus/v5" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" ) // SessionInfo Show logined session info, if type is tty or ssh, no desktop and display diff --git a/accounts/logined/user_info_test.go b/accounts1/logined/user_info_test.go similarity index 100% rename from accounts/logined/user_info_test.go rename to accounts1/logined/user_info_test.go diff --git a/accounts1/manager.go b/accounts1/manager.go new file mode 100644 index 000000000..9a1e0e9a7 --- /dev/null +++ b/accounts1/manager.go @@ -0,0 +1,820 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package accounts + +import ( + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "sort" + "strconv" + "sync" + "syscall" + "time" + + dbus "github.com/godbus/dbus/v5" + configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" + udcp "github.com/linuxdeepin/go-dbus-factory/system/com.deepin.udcp.iam" + ofdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.dbus" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/tasker" + dutils "github.com/linuxdeepin/go-lib/utils" + + "github.com/linuxdeepin/dde-daemon/accounts1/users" + "github.com/linuxdeepin/dde-daemon/common/sessionmsg" +) + +const ( + actConfigDir = "/var/lib/AccountsService" + userConfigDir = actConfigDir + "/deepin/users" + userIconsDir = actConfigDir + "/icons" + userCustomIconsDir = actConfigDir + "/icons/local" + + userIconGuest = actConfigDir + "/icons/guest.png" + actConfigFile = actConfigDir + "/accounts.ini" + actConfigGroupGroup = "Accounts" + actConfigKeyGuest = "AllowGuest" + + interfacesFile = "/usr/share/dde-daemon/accounts/dbus-udcp.json" +) + +var configFile = filepath.Join(actConfigDir, "domainUser.json") + +type domainUserConfig struct { + Name string + Uid string + IsLogined bool +} + +type DefaultDomainUserConfig map[string]*domainUserConfig + +type InterfaceConfig struct { + Service string `json:"service"` + Path string `json:"path"` + Interface string `json:"interface"` +} + +const ( + dsettingsAppID = "org.deepin.dde.daemon" + dsettingsAccountName = "org.deepin.dde.daemon.account" + dsettingsIsTerminalLocked = "isTerminalLocked" + gsSchemaDdeControlCenter = "com.deepin.dde.control-center" + settingKeyAutoLoginVisable = "auto-login-visable" +) + +//go:generate dbusutil-gen -type Manager,User manager.go user.go +//go:generate dbusutil-gen em -type Manager,User,ImageBlur + +type Manager struct { + service *dbusutil.Service + sysSigLoop *dbusutil.SignalLoop + login1Manager login1.Manager + PropsMu sync.RWMutex + + UserList []string + UserListMu sync.RWMutex + + // dbusutil-gen: ignore + GuestIcon string + AllowGuest bool + // dbusutil-gen: equal=isStrvEqual + GroupList []string + + watcher *dutils.WatchProxy + usersMap map[string]*User + usersMapMu sync.Mutex + + enablePasswdChangedHandler bool + enablePasswdChangedHandlerMu sync.Mutex + + delayTaskManager *tasker.DelayTaskManager + userAddedChanMap map[string]chan string + udcpCache udcp.UdcpCache + userConfig DefaultDomainUserConfig + domainUserMapMu sync.Mutex + cfgManager configManager.ConfigManager + dsAccount configManager.Manager + // greeter 的 dconfig 配置 + dsGreeterAccounts configManager.Manager + + dbusDaemon ofdbus.DBus + IsTerminalLocked bool + // 快速登录总开关 + QuickLoginEnabled bool + + //nolint + signals *struct { + UserAdded struct { + objPath string + } + + UserDeleted struct { + objPath string + } + } +} + +func NewManager(service *dbusutil.Service) *Manager { + systemBus, err := dbus.SystemBus() + if err != nil { + return nil + } + login1Manager := login1.NewManager(systemBus) + sysSigLoop := dbusutil.NewSignalLoop(systemBus, 10) + sysSigLoop.Start() + + var m = &Manager{ + service: service, + login1Manager: login1Manager, + sysSigLoop: sysSigLoop, + enablePasswdChangedHandler: true, + } + m.usersMap = make(map[string]*User) + m.userAddedChanMap = make(map[string]chan string) + + m.GuestIcon = userIconGuest + m.AllowGuest = isGuestUserEnabled() + + m.initUsers(getUserPaths()) + m.initUdcpUsers() + m.initAccountDSettings() + + // 检测到系统加入LDAP域后,才去初始化域用户信息 + ret, err := m.isJoinLDAPDoamin() + if err == nil { + if ret { + m.initDomainUsers() + } + } + + if m.IsTerminalLocked { + for _, u := range m.usersMap { + if u.AutomaticLogin { + u.setAutomaticLogin(false) + } + } + } + + m.GroupList, _ = m.GetGroups() + m.watcher = dutils.NewWatchProxy() + if m.watcher != nil { + m.delayTaskManager = tasker.NewDelayTaskManager() + _ = m.delayTaskManager.AddTask(taskNamePasswd, fileEventDelay, m.handleFilePasswdChanged) + _ = m.delayTaskManager.AddTask(taskNameGroup, fileEventDelay, m.handleFileGroupChanged) + _ = m.delayTaskManager.AddTask(taskNameShadow, fileEventDelay, m.handleFileShadowChanged) + _ = m.delayTaskManager.AddTask(taskNameDM, fileEventDelay, m.handleDMConfigChanged) + _ = m.delayTaskManager.AddTask(taskNameGreeterState, fileEventDelay, m.handleGreeterStateChanged) + + m.watcher.SetFileList(m.getWatchFiles()) + m.watcher.SetEventHandler(m.handleFileChanged) + go m.watcher.StartWatch() + } + + m.login1Manager.InitSignalExt(m.sysSigLoop, true) + _, _ = m.login1Manager.ConnectSessionNew(func(id string, sessionPath dbus.ObjectPath) { + core, err := login1.NewSession(systemBus, sessionPath) + if err != nil { + logger.Warningf("new login1 session failed:%v", err) + return + } + + userInfo, err := core.User().Get(0) + if err != nil { + logger.Warningf("get user info failed:%v", err) + return + } + + if userInfo.UID < 10000 { + return + } + + err = m.addDomainUser(userInfo.UID) + if err != nil { + logger.Warningf("add login session failed:%v", err) + } + }) + + _, _ = m.login1Manager.ConnectPrepareForSleep(func(before bool) { + if before { + return + } + + pwdChangerLock.Lock() + defer pwdChangerLock.Unlock() + + if pwdChangerProcess != nil { + err := syscall.Kill(-pwdChangerProcess.Pid, syscall.SIGTERM) + if err != nil { + logger.Warning(err) + } + } + }) + + return m +} + +func (m *Manager) destroy() { + if m.watcher != nil { + m.watcher.EndWatch() + m.watcher = nil + } + + m.sysSigLoop.Stop() + m.stopExportUsers(m.UserList) + _ = m.service.StopExport(m) +} + +func (m *Manager) initUsers(list []string) { + var userList []string + for _, p := range list { + u, err := NewUser(p, m.service, false) + if err != nil { + logger.Errorf("New user '%s' failed: %v", p, err) + continue + } + + userList = append(userList, p) + + m.usersMapMu.Lock() + m.usersMap[p] = u + m.usersMapMu.Unlock() + } + sort.Strings(userList) + m.UserList = userList +} + +func (m *Manager) initUdcpCache() error { + // 解析json文件 新建udcp-cache对象 + var ifcCfg InterfaceConfig + content, err := ioutil.ReadFile(interfacesFile) + if err != nil { + return err + } + err = json.Unmarshal(content, &ifcCfg) + if err != nil { + logger.Warning(err) + return err + } + if !dbus.ObjectPath(ifcCfg.Path).IsValid() { + logger.Warningf("interface config file %q, path %q is invalid", interfacesFile, ifcCfg.Path) + return err + } + + sysBus, err := dbus.SystemBus() + if err != nil { + return err + } + + udcpCache, err := udcp.NewUdcpCache(sysBus, ifcCfg.Service, dbus.ObjectPath(ifcCfg.Path)) + if err != nil { + return err + } + + udcpCache.SetInterfaceName_(ifcCfg.Interface) + + m.udcpCache = udcpCache + return nil + +} + +func (m *Manager) initUdcpUsers() { + // 解析json文件 新建udcp-cache对象,获取所有加域账户ID + err := m.initUdcpCache() + if err != nil { + logger.Warningf("New udcp cache object failed: %v", err) + return + } + + userIdList, err := m.udcpCache.GetUserIdList(0) + if err != nil { + logger.Warningf("Udcp cache getUserIdList failed: %v", err) + return + } + + isJoinUdcp, err := m.udcpCache.Enable().Get(0) + if err != nil { + logger.Warningf("Udcp cache get Enable failed: %v", err) + return + } + + if !isJoinUdcp { + return + } + + // 构造User服务对象 + var userList = m.UserList + for _, uId := range userIdList { + if users.ExistPwUid(uId) != 0 { + continue + } + userGroups, err := m.udcpCache.GetUserGroups(0, users.GetPwName(uId)) + if err != nil { + logger.Warningf("Udcp cache getUserGroups failed: %v", err) + continue + } + + u, err := NewDomainUser(uId, m.service, userGroups) + if err != nil { + logger.Warningf("New udcp user '%d' failed: %v", uId, err) + continue + } + userDBusPath := userDBusPathPrefix + strconv.FormatUint(uint64(uId), 10) + userList = append(userList, userDBusPath) + m.usersMapMu.Lock() + m.usersMap[userDBusPath] = u + m.usersMapMu.Unlock() + } + sort.Strings(userList) + m.UserList = userList +} + +func (m *Manager) initDomainUsers() { + var domainUserList []string + // 解析json文件,获取所有之前登录过的域账号 + err := m.loadDomainUserConfig() + + if err != nil { + logger.Warningf("init domain user config failed: %v", err) + return + } + + for _, v := range m.userConfig { + if users.IsLDAPDomainUserID(v.Uid) && (v.IsLogined == true) { + domainUserList = append(domainUserList, v.Uid) + } + } + + // 构造User服务对象 + var userList = m.UserList + for _, uId := range domainUserList { + id, _ := strconv.Atoi(uId) + domainUserGroups, err := users.GetADUserGroupsByUID(uint32(id)) + if err != nil { + logger.Warningf("get domain user groups failed: %v", err) + return + } + + u, err := NewDomainUser(uint32(id), m.service, domainUserGroups) + if err != nil { + logger.Errorf("New domain user '%s' failed: %v", uId, err) + continue + } + + userDBusPath := userDBusPathPrefix + uId + userList = append(userList, userDBusPath) + m.usersMapMu.Lock() + m.usersMap[userDBusPath] = u + m.usersMapMu.Unlock() + } + sort.Strings(userList) + m.UserList = userList +} + +func (m *Manager) exportUsers() { + m.usersMapMu.Lock() + + for _, u := range m.usersMap { + err := m.service.Export(dbus.ObjectPath(userDBusPathPrefix+u.Uid), u) + if err != nil { + logger.Errorf("failed to export user %q: %v", + u.Uid, err) + continue + } + + } + + m.usersMapMu.Unlock() +} + +func (m *Manager) stopExportUsers(list []string) { + for _, p := range list { + m.stopExportUser(p) + } +} + +func (m *Manager) exportUserByUid(uId string) error { + var err error + var u *User + var userGroups []string + userPath := userDBusPathPrefix + uId + id, _ := strconv.Atoi(uId) + + if /*m.isUserJoinUdcp()*/ id > 10000 { + if users.ExistPwUid(uint32(id)) != 0 { + return errors.New("no such user id") + } + + // 域管用户 + if m.udcpCache != nil { + userGroups, err = m.udcpCache.GetUserGroups(0, users.GetPwName(uint32(id))) + if err != nil { + logger.Warningf("Udcp cache getUserGroups failed: %v", err) + } + } + + // LDAP 域用户 + if users.IsLDAPDomainUserID(uId) { + userGroups, err = users.GetADUserGroupsByUID(uint32(id)) + if err != nil { + logger.Warningf("get domain user groups failed: %v", err) + } + } + + if err != nil { + return err + } + + u, err = NewDomainUser(uint32(id), m.service, userGroups) + + if users.IsLDAPDomainUserID(uId) { + var config = &domainUserConfig{ + Name: u.UserName, + Uid: u.Uid, + IsLogined: true, + } + + m.domainUserMapMu.Lock() + m.userConfig[userPath] = config + m.saveDomainUserConfig(m.userConfig) + m.domainUserMapMu.Unlock() + } + } else { + u, err = NewUser(userPath, m.service, true) + } + if err != nil { + return err + } + + var stat = &syscall.Stat_t{} + if err := syscall.Stat(u.HomeDir, stat); err != nil { + logger.Warning(err) + } else if strconv.Itoa(int(stat.Uid)) != u.Uid { + logger.Debug("incorrect ownership") + err = recoverOwnership(u) + if err != nil { + logger.Warning(err) + } + } + + m.usersMapMu.Lock() + ch := m.userAddedChanMap[u.UserName] + m.usersMapMu.Unlock() + + err = m.service.Export(dbus.ObjectPath(userPath), u) + logger.Debugf("export user %q err: %v", userPath, err) + if ch != nil { + if err != nil { + ch <- "" + } else { + ch <- userPath + } + logger.Debug("after ch <- userPath") + } + + if err != nil { + return err + } + + m.usersMapMu.Lock() + m.usersMap[userPath] = u + m.usersMapMu.Unlock() + + return nil +} + +func (m *Manager) stopExportUser(userPath string) { + m.usersMapMu.Lock() + defer m.usersMapMu.Unlock() + u, ok := m.usersMap[userPath] + if !ok { + logger.Debug("Invalid user path:", userPath) + return + } + + delete(m.usersMap, userPath) + _ = m.service.StopExport(u) +} + +func (m *Manager) getUserByName(name string) *User { + m.usersMapMu.Lock() + defer m.usersMapMu.Unlock() + + for _, user := range m.usersMap { + if user.UserName == name { + return user + } + } + return nil +} + +func (m *Manager) getUserByUid(uid string) *User { + m.usersMapMu.Lock() + defer m.usersMapMu.Unlock() + + for _, user := range m.usersMap { + if user.Uid == uid { + return user + } + } + return nil +} + +func getUserPaths() []string { + infos, err := users.GetHumanUserInfos() + if err != nil { + return nil + } + + var paths []string + for _, info := range infos { + paths = append(paths, userDBusPathPrefix+info.Uid) + } + + return paths +} + +func isGuestUserEnabled() bool { + v, exist := dutils.ReadKeyFromKeyFile(actConfigFile, + actConfigGroupGroup, actConfigKeyGuest, true) + if !exist { + return false + } + + ret, ok := v.(bool) + if !ok { + return false + } + + return ret +} + +func (m *Manager) checkAuth(sender dbus.Sender) error { + return checkAuth(polkitActionUserAdministration, string(sender)) +} + +func chownHomeDir(homeDir string, username string) { + logger.Debug("change owner for dir:", homeDir) + err := exec.Command("chown", "-hR", username+":"+username, homeDir).Run() + if err != nil { + logger.Warningf("change owner for dir %v failed: %v", homeDir, err) + return + } + err = sessionmsg.SendMessage(sessionmsg.NewMessage(true, &sessionmsg.BodyNotify{ + Icon: "preferences-system", + Body: &sessionmsg.LocalizeStr{ + Format: Tr("User \"%s\" existed before and its data is synced"), + Args: []string{username}, + }, + ExpireTimeout: -1, + })) + if err != nil { + logger.Warning("send session msg failed:", err) + } +} + +func Tr(text string) string { + return text +} + +func (m *Manager) loadDomainUserConfig() error { + logger.Debug("loadDomainUserConfig") + + m.userConfig = make(DefaultDomainUserConfig) + if !dutils.IsFileExist(configFile) { + err := dutils.CreateFile(configFile) + if err != nil { + return err + } + } else { + data, err := ioutil.ReadFile(configFile) + if err != nil { + return err + } + + if len(data) == 0 { + return errors.New("domain user config file is empty") + } + + err = json.Unmarshal(data, &m.userConfig) + if err != nil { + return err + } + } + + return nil +} + +func (m *Manager) saveDomainUserConfig(config DefaultDomainUserConfig) error { + data, err := json.Marshal(config) + if err != nil { + return err + } + + dir := filepath.Dir(configFile) + err = os.MkdirAll(dir, 0755) + if err != nil { + return err + } + + err = ioutil.WriteFile(configFile, data, 0644) + return err +} + +func (m *Manager) isJoinLDAPDoamin() (bool, error) { + out, err := exec.Command("realm", "list").CombinedOutput() + if err != nil { + logger.Debugf("failed to execute %s, error: %v", "realm list", err) + return false, err + } + + if len(out) == 0 { + return false, nil + } + + return true, nil +} + +func (m *Manager) modifyUserConfig(path string) error { + m.usersMapMu.Lock() + root, ok := m.usersMap[path] + m.usersMapMu.Unlock() + if ok { + loadUserConfigInfo(root) + } + + return nil +} + +func (m *Manager) checkGroupCanChange(name string) bool { + groupInfoMap, err := users.GetGroupInfoWithCacheLock() + if err != nil { + logger.Warning(err) + return false + } + info, ok := groupInfoMap[name] + if !ok { + return false + } + gid, err := strconv.Atoi(info.Gid) + if err != nil { + logger.Warning(err) + return false + } + return gid >= 1000 +} + +func (m *Manager) initAccountDSettings() { + m.cfgManager = configManager.NewConfigManager(m.sysSigLoop.Conn()) + + accountPath, err := m.cfgManager.AcquireManager(0, dsettingsAppID, dsettingsAccountName, "") + if err != nil { + logger.Warning(err) + return + } + + m.dsAccount, err = configManager.NewManager(m.sysSigLoop.Conn(), accountPath) + if err != nil { + logger.Warning(err) + return + } + + v, err := m.dsAccount.Value(0, dsettingsIsTerminalLocked) + if err != nil { + logger.Warning(err) + return + } + + if data, ok := v.Value().(bool); ok { + m.IsTerminalLocked = data + } +} + +const ( + greeterAppId = "org.deepin.dde.lightdm-deepin-greeter" + daemonAccountsResourceId = "org.deepin.dde.daemon.accounts" + keyEnableQuickLogin = "enableQuickLogin" +) + +// 在 dconfig 设置 quick login (总开关) +func (m *Manager) setDConfigQuickLoginEnabled(enabled bool) error { + if m.dsGreeterAccounts == nil { + return errors.New("get greeter accounts dconfig failed") + } + err := m.dsGreeterAccounts.SetValue(0, keyEnableQuickLogin, dbus.MakeVariant(enabled)) + if err != nil { + return fmt.Errorf("set greeter dconfig enableQuickLogin failed, err: %v", err) + } + return nil +} + +// 从 dconfig 获取 quick login (总开关)的配置 +func (m *Manager) getDConfigQuickLoginEnabled() (bool, error) { + if m.dsGreeterAccounts == nil { + return false, errors.New("get greeter accounts dconfig failed") + } + enabledVar, err := m.dsGreeterAccounts.Value(0, keyEnableQuickLogin) + if err != nil { + return false, fmt.Errorf("get greeter accounts dconfig enableQuickLogin failed, err: %v", err) + } + + enabled, ok := enabledVar.Value().(bool) + if !ok { + return false, errors.New("enabledVar.Value() is not bool type") + } + return enabled, nil +} + +func (m *Manager) initDConfigGreeterWatch() error { + greeterAccountsPath, err := m.cfgManager.AcquireManager(0, greeterAppId, daemonAccountsResourceId, "") + if err != nil { + return err + } + + m.dsGreeterAccounts, err = configManager.NewManager(m.sysSigLoop.Conn(), greeterAccountsPath) + if err != nil { + return err + } + + enabled, err := m.getDConfigQuickLoginEnabled() + if err != nil { + logger.Warning("getDConfigQuickLoginEnabled failed, err:", err) + } else { + // 从 dconfig 获取值,然后同步到 /etc/lightdm/lightdm.conf 配置文件中。 + err = users.SetLightDMQuickLoginEnabled(enabled) + if err != nil { + logger.Warning("SetLightDMQuickLoginEnabled failed, error:", err) + } + m.setPropQuickLoginEnabled(enabled) + } + + m.dsGreeterAccounts.InitSignalExt(m.sysSigLoop, true) + m.dsGreeterAccounts.ConnectValueChanged(func(key string) { + // dconfig 配置改变 + if key != keyEnableQuickLogin { + return + } + + enabled, err := m.getDConfigQuickLoginEnabled() + if err != nil { + logger.Warning("getDConfigQuickLoginEnabled failed, err:", err) + return + } + + logger.Debug("handle dconfig quick login enabled changed", enabled) + err = users.SetLightDMQuickLoginEnabled(enabled) + if err != nil { + logger.Warning("SetLightDMQuickLoginEnabled failed, error:", err) + } + }) + return nil +} + +func (m *Manager) removeGreeterDConfigWatch() { + if m.dsGreeterAccounts != nil { + m.dsGreeterAccounts.RemoveAllHandlers() + } +} + +// 监控 dconfig-daemon 服务是否重新启动, 如果重新启动了,需要重新注册监控器。 +func (m *Manager) initDBusDaemonWatch() { + systemBus, err := dbus.SystemBus() + if err != nil { + logger.Warning("get system bus failed, err:", err) + return + } + + m.dbusDaemon = ofdbus.NewDBus(systemBus) + m.dbusDaemon.InitSignalExt(m.sysSigLoop, false) + + // 手工构建匹配规则 + rule := dbusutil.NewMatchRuleBuilder().Sender(m.dbusDaemon.ServiceName_()). + Path(string(m.dbusDaemon.Path_())).Member("NameOwnerChanged"). + Arg(0, m.cfgManager.ServiceName_()). + Build() + logger.Debug("rule:", rule.Str) + err = rule.AddTo(systemBus) + if err != nil { + logger.Warning("add match rule failed, err:", err) + return + } + + _, err = m.dbusDaemon.ConnectNameOwnerChanged(func(name, oldOwner, newOwner string) { + if name == m.cfgManager.ServiceName_() && oldOwner == "" && newOwner != "" { + // 检测到 dconfig-daemon 服务启动后,重新初始化相关配置 + logger.Debug("monitored that the dconfig-daemon service has restarted") + time.Sleep(2 * time.Second) + m.removeGreeterDConfigWatch() + m.initDConfigGreeterWatch() + } + }) + if err != nil { + logger.Warning("connect NameOwnerChanged signal failed, err:", err) + } +} diff --git a/accounts1/manager_ifc.go b/accounts1/manager_ifc.go new file mode 100644 index 000000000..bcd0f3829 --- /dev/null +++ b/accounts1/manager_ifc.go @@ -0,0 +1,596 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package accounts + +import ( + "encoding/json" + "errors" + "fmt" + "math/rand" + "os" + "os/exec" + "strconv" + "strings" + "time" + + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/accounts1/checkers" + "github.com/linuxdeepin/dde-daemon/accounts1/users" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/gettext" + "github.com/linuxdeepin/go-lib/procfs" + "github.com/linuxdeepin/go-lib/users/passwd" + dutils "github.com/linuxdeepin/go-lib/utils" +) + +const ( + nilObjPath = dbus.ObjectPath("/") + dbusServiceName = "org.deepin.dde.Accounts1" + dbusPath = "/org/deepin/dde/Accounts1" + dbusInterface = "org.deepin.dde.Accounts1" +) + +func (*Manager) GetInterfaceName() string { + return dbusInterface +} + +// Create new user. +// +// 如果收到 Error 信号,则创建失败。 +// +// name: 用户名 +// +// fullName: 全名,可以为空 +// +// ty: 用户类型,0 为普通用户,1 为管理员 + +func (m *Manager) CreateUser(sender dbus.Sender, + name, fullName string, accountType int32) (userPath dbus.ObjectPath, busErr *dbus.Error) { + + logger.Debug("[CreateUser] new user:", name, fullName, accountType) + + // 判断用户名字符串长度,大于2小于32 + if len(name) < 3 || len(name) > 32 { + return nilObjPath, dbusutil.ToError(errors.New("Username must be between 3 and 32 characters")) + } + + // 用户名必需以数字或字母开始 + compStr := "1234567890" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + if !strings.Contains(compStr, string(name[0])) { + return nilObjPath, dbusutil.ToError(errors.New("The first character must be a letter or number")) + } + + // 用户名必需是数字、字母和_-@字符组成 + compStr = compStr + "-_@" + for _, ch := range name { + if !strings.Contains(compStr, string(ch)) { + return nilObjPath, dbusutil.ToError(errors.New("Invalid user name")) + } + } + err := checkAccountType(int(accountType)) + if err != nil { + return nilObjPath, dbusutil.ToError(err) + } + + err = m.checkAuth(sender) + if err != nil { + logger.Debug("[CreateUser] access denied:", err) + return nilObjPath, dbusutil.ToError(err) + } + + ch := make(chan string) + m.usersMapMu.Lock() + m.userAddedChanMap[name] = ch + m.usersMapMu.Unlock() + defer func() { + m.usersMapMu.Lock() + delete(m.userAddedChanMap, name) + m.usersMapMu.Unlock() + close(ch) + }() + + homeDir := "/home/" + name + _, err = os.Stat(homeDir) + homeDirExist := err == nil + + if err := users.CreateUser(name, fullName, ""); err != nil { + logger.Warningf("DoAction: create user '%s' failed: %v\n", + name, err) + return nilObjPath, dbusutil.ToError(err) + } + + groups := users.GetPresetGroups(int(accountType)) + logger.Debug("groups:", groups) + err = users.SetGroupsForUser(groups, name) + if err != nil { + logger.Warningf("failed to set groups for user %s: %v", name, err) + } + // create user success + select { + case userPath, ok := <-ch: + if !ok { + return nilObjPath, dbusutil.ToError(errors.New("invalid user path event")) + } + + logger.Debug("receive user path", userPath) + if userPath == "" { + return nilObjPath, dbusutil.ToError(errors.New("failed to install user on session bus")) + } + if homeDirExist { + go chownHomeDir(homeDir, name) + } + return dbus.ObjectPath(userPath), nil + case <-time.After(time.Second * 60): + err := errors.New("wait timeout exceeded") + logger.Warning(err) + return nilObjPath, dbusutil.ToError(err) + } +} + +// Delete a exist user. +// +// name: 用户名 +// +// rmFiles: 是否删除用户数据 +func (m *Manager) DeleteUser(sender dbus.Sender, + name string, rmFiles bool) *dbus.Error { + + logger.Debug("[DeleteUser] user:", name, rmFiles) + + err := m.checkAuth(sender) + if err != nil { + logger.Debug("[DeleteUser] access denied:", err) + return dbusutil.ToError(err) + } + + user := m.getUserByName(name) + if user == nil { + err := fmt.Errorf("user %q not found", name) + logger.Warning(err) + return dbusutil.ToError(err) + } + + if m.isDomainUser(user.Uid) { + id, _ := strconv.Atoi(user.Uid) + + if m.udcpCache != nil && m.isUdcpUserID(user.Uid) { + result, err := m.udcpCache.RemoveCacheFile(0, uint32(id)) + if err != nil { + logger.Errorf("Udcp cache RemoveCacheFile failed: %v", err) + return dbusutil.ToError(err) + } + + if !result { + return dbusutil.ToError(errors.New("failed to remove user cache files")) + } + } + + // 删除账户前先删除生物特征,避免删除账户后,用户数据找不到 + if rmFiles { + user.clearBiometricChara() + // 删除域用户家目录 + os.RemoveAll(user.HomeDir) + } + + // 删除服务,更新UserList + userPath := userDBusPathPrefix + user.Uid + // 删除对应AD域账户配置 + if len(m.userConfig) != 0 { + delete(m.userConfig, userPath) + m.domainUserMapMu.Lock() + m.saveDomainUserConfig(m.userConfig) + m.domainUserMapMu.Unlock() + } + + m.stopExportUser(userPath) + m.updatePropUserList() + + // 清楚域账户本地缓存 + if rmFiles { + user.clearData() + } + + err = m.service.Emit(m, "UserDeleted", userPath) + if err != nil { + logger.Warning(err) + } + return dbusutil.ToError(err) + } + + // 清除用户快速登录设置 + err = users.SetQuickLogin(name, false) + if err != nil { + // 仅警告错误 + logger.Warningf("disable quick login for user %q failed: %v", name, err) + } + + // 删除用户前,清空用户的安全密钥 + err = user.deleteSecretKey() + if err != nil { + logger.Warning("Delete secret key failed") + } + // 删除账户前先删除生物特征,避免删除账户后,用户数据找不到 + if rmFiles { + user.clearBiometricChara() + } + if err := users.DeleteUser(rmFiles, name); err != nil { + logger.Warningf("DoAction: delete user '%s' failed: %v\n", + name, err) + return dbusutil.ToError(err) + } + + //delete user config and icons + if rmFiles { + user.clearData() + } + + return nil +} + +func (m *Manager) FindUserById(uid string) (user string, busErr *dbus.Error) { + userPath := userDBusPathPrefix + uid + for _, v := range m.UserList { + if v == userPath { + return v, nil + } + } + + return "", dbusutil.ToError(fmt.Errorf("invalid uid: %s", uid)) +} + +func (m *Manager) FindUserByName(name string) (user string, busErr *dbus.Error) { + pwd, err := passwd.GetPasswdByName(name) + if err != nil { + logger.Warning(err) + pwd = &passwd.Passwd{ + Name: name, + } + } + + m.usersMapMu.Lock() + defer m.usersMapMu.Unlock() + + for p, u := range m.usersMap { + if u.UserName == pwd.Name { + return p, nil + } + } + + return "", dbusutil.ToError(fmt.Errorf("invalid username: %s", pwd.Name)) +} + +// 随机得到一个用户头像 +// +// ret0:头像路径,为空则表示获取失败 +func (m *Manager) RandUserIcon() (iconFile string, busErr *dbus.Error) { + icons := getUserStandardIcons() + if len(icons) == 0 { + return "", dbusutil.ToError(errors.New("Did not find any user icons")) + } + + rand.Seed(time.Now().UnixNano()) + idx := rand.Intn(len(icons)) // #nosec G404 + return icons[idx], nil +} + +func (m *Manager) isDomainUserExist(name string) bool { + pwd, err := passwd.GetPasswdByName(name) + if err != nil { + return false + } + + id := strconv.FormatUint(uint64(pwd.Uid), 10) + + return m.isUdcpUserExists(name) || users.IsLDAPDomainUserID(id) +} + +// 检查用户名是否有效 +// +// ret0: 是否合法 +// +// ret1: 不合法原因 +// +// ret2: 不合法代码 +func (m *Manager) IsUsernameValid(sender dbus.Sender, name string) (valid bool, + msg string, code int32, busErr *dbus.Error) { + var err error + var info *checkers.ErrorInfo + + defer func() { + busErr = dbusutil.ToError(err) + }() + + pid, err := m.service.GetConnPID(string(sender)) + if err != nil { + return + } + + p := procfs.Process(pid) + environ, err := p.Environ() + if err != nil { + return + } + + locale := environ.Get("LANG") + + // 如果新建用户使用的用户名和域用户名一致,提示用户该用户已经存在 + if m.isDomainUserExist(name) { + info = checkers.ErrCodeExist.Error() + } else { + info = checkers.CheckUsernameValid(name) + if info == nil { + valid = true + return + } + } + + msg = info.Error.Error() + logger.Debug("locale:", locale) + if locale != "" { + gettext.SetLocale(gettext.LcAll, locale) + msg = gettext.Tr(msg) + } + code = int32(info.Code) + return +} + +// 检测密码是否有效 +// +// ret0: 是否合法 +// +// ret1: 提示信息 +// +// ret2: 不合法代码 +func (m *Manager) IsPasswordValid(password string) (valid bool, msg string, code int32, busErr *dbus.Error) { + releaseType := getDeepinReleaseType() + logger.Infof("release type %q", releaseType) + errCode := checkers.CheckPasswordValid(releaseType, password) + return errCode.IsOk(), errCode.Prompt(), int32(errCode), nil +} + +func (m *Manager) AllowGuestAccount(sender dbus.Sender, allow bool) *dbus.Error { + err := m.checkAuth(sender) + if err != nil { + return dbusutil.ToError(err) + } + + m.PropsMu.Lock() + defer m.PropsMu.Unlock() + + if m.AllowGuest == allow { + return nil + } + + success := dutils.WriteKeyToKeyFile(actConfigFile, + actConfigGroupGroup, actConfigKeyGuest, allow) + if !success { + return dbusutil.ToError(errors.New("enable guest user failed")) + } + + m.AllowGuest = allow + _ = m.emitPropChangedAllowGuest(allow) + return nil +} + +func (m *Manager) CreateGuestAccount(sender dbus.Sender) (user string, busErr *dbus.Error) { + err := m.checkAuth(sender) + if err != nil { + return "", dbusutil.ToError(err) + } + + name, err := users.CreateGuestUser() + if err != nil { + return "", dbusutil.ToError(err) + } + + info, err := users.GetUserInfoByName(name) + if err != nil { + return "", dbusutil.ToError(err) + } + + return userDBusPathPrefix + info.Uid, nil +} + +func (m *Manager) GetGroups() (groups []string, busErr *dbus.Error) { + groups, err := users.GetAllGroups() + return groups, dbusutil.ToError(err) +} + +func (m *Manager) GetGroupInfoByName(name string) (groupInfo string, busErr *dbus.Error) { + info, err := users.GetGroupByName(name) + if err != nil { + logger.Warning(err) + return "", dbusutil.ToError(err) + } + infoJson, err := json.Marshal(info) + if err != nil { + logger.Warning(err) + return "", dbusutil.ToError(err) + } + return string(infoJson), nil +} + +func (m *Manager) GetPresetGroups(accountType int32) (groups []string, busErr *dbus.Error) { + err := checkAccountType(int(accountType)) + if err != nil { + return nil, dbusutil.ToError(err) + } + + groups = users.GetPresetGroups(int(accountType)) + return groups, nil +} + +// 是否使能accounts服务在监听到/etc/passwd文件变化后,执行对应的属性更新和服务导出,只允许root用户操作该接口 +func (m *Manager) EnablePasswdChangedHandler(sender dbus.Sender, enable bool) *dbus.Error { + const rootUid = "0" + uid, err := m.service.GetConnUID(string(sender)) + if err != nil { + return dbusutil.ToError(err) + } + if uid != 0 { + return dbusutil.ToError(fmt.Errorf("not allow %v call this method", sender)) + } + m.enablePasswdChangedHandlerMu.Lock() + defer m.enablePasswdChangedHandlerMu.Unlock() + if m.enablePasswdChangedHandler == enable { + return nil + } + m.enablePasswdChangedHandler = enable + if enable { + m.handleFilePasswdChanged() + m.modifyUserConfig(userDBusPathPrefix + rootUid) // root账户的信息需要更新(deepin安装器会在后配置界面修改语言) + } + return nil +} + +func (m *Manager) CreateGroup(sender dbus.Sender, groupName string, gid uint32, isSystem bool) *dbus.Error { + logger.Debug("[CreateGroup] new group:", groupName) + + err := m.checkAuth(sender) + if err != nil { + logger.Debug("[CreateGroup] access denied:", err) + return dbusutil.ToError(err) + } + args := []string{ + groupName, + "-f", + } + if gid > 0 { + args = append(args, []string{ + "-g", fmt.Sprint(gid), "-o", + }...) + } + if isSystem { + args = append(args, "-r") + } + cmd := exec.Command("groupadd", args...) + logger.Debug("[CreateGroup] exec cmd is:", cmd.String()) + err = cmd.Run() + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + groupList, _ := m.GetGroups() + m.setPropGroupList(groupList) + return nil +} + +func (m *Manager) DeleteGroup(sender dbus.Sender, groupName string, force bool) *dbus.Error { + logger.Debug("[DeleteGroup] del group:", groupName) + if !m.checkGroupCanChange(groupName) { + return dbusutil.ToError(fmt.Errorf("can not delete %v", groupName)) + } + err := m.checkAuth(sender) + if err != nil { + logger.Debug("[DeleteGroup] access denied:", err) + return dbusutil.ToError(err) + } + args := []string{ + groupName, + } + if force { + args = append(args, "-f") + } + cmd := exec.Command("groupdel", args...) + logger.Debug("[DeleteGroup] exec cmd is:", cmd.String()) + err = cmd.Run() + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + groupList, _ := m.GetGroups() + m.setPropGroupList(groupList) + return nil +} + +func (m *Manager) ModifyGroup(sender dbus.Sender, currentGroupName string, newGroupName string, newGID uint32) *dbus.Error { + logger.Debug("[ModifyGroup] modify group :", currentGroupName) + if newGroupName == "" && newGID <= 0 { + return dbusutil.ToError(errors.New("invalid modify,need new name or gid")) + } + if !m.checkGroupCanChange(currentGroupName) { + return dbusutil.ToError(fmt.Errorf("can not modify %v", currentGroupName)) + } + err := m.checkAuth(sender) + if err != nil { + logger.Debug("[ModifyGroup] access denied:", err) + return dbusutil.ToError(err) + } + args := []string{ + currentGroupName, + } + if newGroupName != "" { + args = append(args, []string{ + "-n", newGroupName, + }...) + } + if newGID > 0 { + args = append(args, []string{ + "-g", fmt.Sprint(newGID), "-o", + }...) + } + cmd := exec.Command("groupmod", args...) + logger.Debug("[ModifyGroup] exec cmd is:", cmd.String()) + err = cmd.Run() + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + groupList, _ := m.GetGroups() + m.setPropGroupList(groupList) + return nil +} + +func (m *Manager) SetTerminalLocked(sender dbus.Sender, locked bool) *dbus.Error { + logger.Infof("SetTerminalLocked snder: %s, locked: %t", sender, locked) + if m.IsTerminalLocked == locked { + return dbusutil.ToError(fmt.Errorf("current terminal lock is equal set locked: %t", locked)) + } + + err := m.checkAuth(sender) + if err != nil { + logger.Warning("[SetTerminalLocked] access denied:", err) + return dbusutil.ToError(err) + } + + if locked { + sessions, err := m.login1Manager.ListSessions(0) + if err != nil { + logger.Warning("Failed to list sessions:", err) + return dbusutil.ToError(err) + } + + for _, session := range sessions { + core, err := login1.NewSession(m.service.Conn(), session.Path) + if err != nil { + logger.Warningf("new login1 session failed:%v", err) + return dbusutil.ToError(err) + } + + err = core.Terminate(0) + if err != nil { + logger.Warningf("new login1 session failed:%v", err) + } + } + } + + err = m.dsAccount.SetValue(0, dsettingsIsTerminalLocked, dbus.MakeVariant(locked)) + if err != nil { + logger.Warningf("setDsgData key : %s ,value : %t err : %s", dsettingsIsTerminalLocked, locked, err) + return dbusutil.ToError(err) + } + + if locked { + for _, u := range m.usersMap { + if u.AutomaticLogin { + u.setAutomaticLogin(false) + } + } + } + + m.setPropIsTerminalLocked(locked) + return nil +} diff --git a/accounts/reminder_info.c b/accounts1/reminder_info.c similarity index 100% rename from accounts/reminder_info.c rename to accounts1/reminder_info.c diff --git a/accounts/reminder_info.go b/accounts1/reminder_info.go similarity index 100% rename from accounts/reminder_info.go rename to accounts1/reminder_info.go diff --git a/accounts/reminder_info.h b/accounts1/reminder_info.h similarity index 100% rename from accounts/reminder_info.h rename to accounts1/reminder_info.h diff --git a/accounts/testdata/keyboard_us b/accounts1/testdata/keyboard_us similarity index 100% rename from accounts/testdata/keyboard_us rename to accounts1/testdata/keyboard_us diff --git a/accounts/testdata/keyboard_us_chr b/accounts1/testdata/keyboard_us_chr similarity index 100% rename from accounts/testdata/keyboard_us_chr rename to accounts1/testdata/keyboard_us_chr diff --git a/accounts/testdata/locale b/accounts1/testdata/locale similarity index 100% rename from accounts/testdata/locale rename to accounts1/testdata/locale diff --git a/accounts/testdata/shells b/accounts1/testdata/shells similarity index 100% rename from accounts/testdata/shells rename to accounts1/testdata/shells diff --git a/accounts/user.go b/accounts1/user.go similarity index 96% rename from accounts/user.go rename to accounts1/user.go index 67539d5eb..46d33899e 100644 --- a/accounts/user.go +++ b/accounts1/user.go @@ -16,10 +16,10 @@ import ( "strings" "sync" - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/accounts/users" - authenticate "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.authenticate" - uadp "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.uadp" + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/accounts1/users" + authenticate "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.authenticate1" + uadp "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.uadp1" glib "github.com/linuxdeepin/go-gir/glib-2.0" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/gdkpixbuf" @@ -51,6 +51,7 @@ const ( confKeyGreeterBackground = "GreeterBackground" confKeyHistoryLayout = "HistoryLayout" confKeyUse24HourFormat = "Use24HourFormat" + confKeyWechatAuthEnabled = "WechatAuthEnabled" confKeyUUID = "UUID" confKeyWorkspace = "Workspace" confKeyWeekdayFormat = "WeekdayFormat" @@ -61,14 +62,15 @@ const ( confKeyWeekBegins = "WeekBegins" confKeyPasswordHint = "PasswordHint" - defaultUse24HourFormat = true - defaultWeekdayFormat = 0 - defaultShortDateFormat = 3 - defaultLongDateFormat = 1 - defaultShortTimeFormat = 0 - defaultLongTimeFormat = 0 - defaultWeekBegins = 0 - defaultWorkspace = 1 + defaultWechatAuthEnabled = false + defaultUse24HourFormat = true + defaultWeekdayFormat = 0 + defaultShortDateFormat = 3 + defaultLongDateFormat = 1 + defaultShortTimeFormat = 0 + defaultLongTimeFormat = 0 + defaultWeekBegins = 0 + defaultWorkspace = 1 ) func getDefaultUserBackground() string { @@ -140,7 +142,8 @@ type User struct { // dbusutil-gen: equal=nil HistoryLayout []string - configLocker sync.Mutex + WechatAuthEnabled bool + configLocker sync.Mutex } func NewUser(userPath string, service *dbusutil.Service, ignoreErr bool) (*User, error) { @@ -834,6 +837,12 @@ func loadUserConfigInfo(u *User) { isSave = true } + u.WechatAuthEnabled, err = kf.GetBoolean(confGroupUser, confKeyWechatAuthEnabled) + if err != nil { + u.WechatAuthEnabled = defaultWechatAuthEnabled + isSave = true + } + u.WeekdayFormat, err = kf.GetInteger(confGroupUser, confKeyWeekdayFormat) if err != nil { u.WeekdayFormat = defaultWeekdayFormat diff --git a/accounts/user_chpwd_union_id.go b/accounts1/user_chpwd_union_id.go similarity index 98% rename from accounts/user_chpwd_union_id.go rename to accounts1/user_chpwd_union_id.go index 44da6e397..3eab230a3 100644 --- a/accounts/user_chpwd_union_id.go +++ b/accounts1/user_chpwd_union_id.go @@ -22,10 +22,10 @@ import ( "syscall" "time" - "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/accounts/users" - authenticate "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.authenticate" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/accounts1/users" + authenticate "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.authenticate1" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/procfs" dutils "github.com/linuxdeepin/go-lib/utils" diff --git a/accounts/user_created_time.go b/accounts1/user_created_time.go similarity index 100% rename from accounts/user_created_time.go rename to accounts1/user_created_time.go diff --git a/accounts/user_ifc.go b/accounts1/user_ifc.go similarity index 93% rename from accounts/user_ifc.go rename to accounts1/user_ifc.go index 3bea4e95a..9af6ead57 100644 --- a/accounts/user_ifc.go +++ b/accounts1/user_ifc.go @@ -31,9 +31,9 @@ import ( "time" "unsafe" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-api/lang_info" - "github.com/linuxdeepin/dde-daemon/accounts/users" + "github.com/linuxdeepin/dde-daemon/accounts1/users" "github.com/linuxdeepin/dde-daemon/common/sessionmsg" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/gdkpixbuf" @@ -44,8 +44,8 @@ import ( ) const ( - userDBusPathPrefix = "/com/deepin/daemon/Accounts/User" - userDBusInterface = "com.deepin.daemon.Accounts.User" + userDBusPathPrefix = "/org/deepin/dde/Accounts1/User" + userDBusInterface = "org.deepin.dde.Accounts1.User" controlCenter = "dde-control-center" resetPasswordDia = "reset-password-dialog" ) @@ -581,6 +581,62 @@ func (u *User) DeleteIconFile(sender dbus.Sender, icon string) *dbus.Error { return nil } +func (u *User) EnableWechatAuth(sender dbus.Sender, value bool) *dbus.Error { + logger.Infof("DBus call EnableWechatAuth sender %v, enabled %t", sender, value) + // 验证调用者权限 + if !u.checkIsControlCenter(sender) { + return dbusutil.ToError(fmt.Errorf("not allow %v call this method", sender)) + } + return u.enableWechatAuth(value) +} +func (u *User) UpdateWechatAuthState() *dbus.Error { + logger.Infof("DBus call UpdateWechatAuthState") + // 通过synchelper检查本地账户是否有绑定的UOS ID + syncObj := u.service.Conn().Object("com.deepin.sync.Helper", "/com/deepin/sync/Helper") + var uosid string + err := syncObj.Call("com.deepin.sync.Helper.UOSID", 0).Store(&uosid) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + var ubid string + err = syncObj.Call("com.deepin.sync.Helper.LocalBindCheck", 0, uosid, u.UUID).Store(&ubid) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + var isBindWechat bool + var wechatNickName string + err = syncObj.Call("com.deepin.sync.Helper.LocalBindCheckWechat", 0, uosid, u.UUID).Store(&isBindWechat, &wechatNickName) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + logger.Infof("DBus call UpdateWechatAuthState ubid %v, wechatNickName %v", ubid, wechatNickName) + if (ubid == "" || !isBindWechat) && u.WechatAuthEnabled { + return u.enableWechatAuth(false) + } + + return nil +} + +func (u *User) enableWechatAuth(value bool) *dbus.Error { + u.PropsMu.Lock() + defer u.PropsMu.Unlock() + + if value == u.WechatAuthEnabled { + return nil + } + + err := u.writeUserConfigWithChange(confKeyWechatAuthEnabled, value) + if err != nil { + return dbusutil.ToError(err) + } + + u.setPropWechatAuthEnabled(value) + return nil +} + func (u *User) SetDesktopBackgrounds(sender dbus.Sender, val []string) *dbus.Error { logger.Debugf("[SetDesktopBackgrounds] val: %#v", val) @@ -1226,3 +1282,12 @@ func (u *User) DeleteSecretKey(sender dbus.Sender) *dbus.Error { } return nil } + +func (u *User) deleteSecretKey() error { + if u.uadpInterface == nil { + logger.Warning("uadpInterface is nil") + return nil + } + + return u.uadpInterface.Delete(0, u.UserName) +} diff --git a/accounts/user_test.go b/accounts1/user_test.go similarity index 91% rename from accounts/user_test.go rename to accounts1/user_test.go index 369dbc83f..9c62fa68d 100644 --- a/accounts/user_test.go +++ b/accounts1/user_test.go @@ -17,7 +17,7 @@ func Test_getUidFromUserPath(t *testing.T) { }{ { name: "getUidFromUserPath", - userPath: "/com/deepin/daemon/Accounts/User1000", + userPath: "/org/deepin/dde/Accounts1/User1000", want: "1000", }, } diff --git a/accounts/users/common.go b/accounts1/users/common.go similarity index 100% rename from accounts/users/common.go rename to accounts1/users/common.go diff --git a/accounts/users/common_test.go b/accounts1/users/common_test.go similarity index 100% rename from accounts/users/common_test.go rename to accounts1/users/common_test.go diff --git a/accounts/users/display_manager.go b/accounts1/users/display_manager.go similarity index 99% rename from accounts/users/display_manager.go rename to accounts1/users/display_manager.go index ded2ecff5..fd3d5015b 100644 --- a/accounts/users/display_manager.go +++ b/accounts1/users/display_manager.go @@ -432,7 +432,7 @@ func setIniKeys(filename, group string, keys, values []string) error { return err } -//Default config: /etc/X11/default-display-manager +// Default config: /etc/X11/default-display-manager func getDefaultDM(file string) (string, error) { if !dutils.IsFileExist(file) { return "", fmt.Errorf("Not found this file: %s", file) diff --git a/accounts/users/display_manager.org b/accounts1/users/display_manager.org similarity index 100% rename from accounts/users/display_manager.org rename to accounts1/users/display_manager.org diff --git a/accounts/users/guest.go b/accounts1/users/guest.go similarity index 100% rename from accounts/users/guest.go rename to accounts1/users/guest.go diff --git a/accounts/users/list.go b/accounts1/users/list.go similarity index 100% rename from accounts/users/list.go rename to accounts1/users/list.go diff --git a/accounts/users/manager.go b/accounts1/users/manager.go similarity index 100% rename from accounts/users/manager.go rename to accounts1/users/manager.go diff --git a/accounts/users/passwd.c b/accounts1/users/passwd.c similarity index 100% rename from accounts/users/passwd.c rename to accounts1/users/passwd.c diff --git a/accounts/users/passwd.go b/accounts1/users/passwd.go similarity index 100% rename from accounts/users/passwd.go rename to accounts1/users/passwd.go diff --git a/accounts/users/passwd.h b/accounts1/users/passwd.h similarity index 100% rename from accounts/users/passwd.h rename to accounts1/users/passwd.h diff --git a/accounts/users/prop.go b/accounts1/users/prop.go similarity index 100% rename from accounts/users/prop.go rename to accounts1/users/prop.go diff --git a/accounts/users/testdata/adduser.conf b/accounts1/users/testdata/adduser.conf similarity index 100% rename from accounts/users/testdata/adduser.conf rename to accounts1/users/testdata/adduser.conf diff --git a/accounts/users/testdata/adduser1.conf b/accounts1/users/testdata/adduser1.conf similarity index 100% rename from accounts/users/testdata/adduser1.conf rename to accounts1/users/testdata/adduser1.conf diff --git a/accounts/users/testdata/autologin/custom.conf b/accounts1/users/testdata/autologin/custom.conf similarity index 100% rename from accounts/users/testdata/autologin/custom.conf rename to accounts1/users/testdata/autologin/custom.conf diff --git a/accounts/users/testdata/autologin/custom_autologin.conf b/accounts1/users/testdata/autologin/custom_autologin.conf similarity index 100% rename from accounts/users/testdata/autologin/custom_autologin.conf rename to accounts1/users/testdata/autologin/custom_autologin.conf diff --git a/accounts/users/testdata/autologin/default-display-manager b/accounts1/users/testdata/autologin/default-display-manager similarity index 100% rename from accounts/users/testdata/autologin/default-display-manager rename to accounts1/users/testdata/autologin/default-display-manager diff --git a/accounts/users/testdata/autologin/display-manager.service b/accounts1/users/testdata/autologin/display-manager.service similarity index 100% rename from accounts/users/testdata/autologin/display-manager.service rename to accounts1/users/testdata/autologin/display-manager.service diff --git a/accounts/users/testdata/autologin/kdmrc b/accounts1/users/testdata/autologin/kdmrc similarity index 100% rename from accounts/users/testdata/autologin/kdmrc rename to accounts1/users/testdata/autologin/kdmrc diff --git a/accounts/users/testdata/autologin/kdmrc_autologin b/accounts1/users/testdata/autologin/kdmrc_autologin similarity index 100% rename from accounts/users/testdata/autologin/kdmrc_autologin rename to accounts1/users/testdata/autologin/kdmrc_autologin diff --git a/accounts/users/testdata/autologin/lightdm.conf b/accounts1/users/testdata/autologin/lightdm.conf similarity index 100% rename from accounts/users/testdata/autologin/lightdm.conf rename to accounts1/users/testdata/autologin/lightdm.conf diff --git a/accounts/users/testdata/autologin/lightdm.service b/accounts1/users/testdata/autologin/lightdm.service similarity index 100% rename from accounts/users/testdata/autologin/lightdm.service rename to accounts1/users/testdata/autologin/lightdm.service diff --git a/accounts/users/testdata/autologin/lightdm_autologin.conf b/accounts1/users/testdata/autologin/lightdm_autologin.conf similarity index 100% rename from accounts/users/testdata/autologin/lightdm_autologin.conf rename to accounts1/users/testdata/autologin/lightdm_autologin.conf diff --git a/accounts/users/testdata/autologin/lxdm.conf b/accounts1/users/testdata/autologin/lxdm.conf similarity index 100% rename from accounts/users/testdata/autologin/lxdm.conf rename to accounts1/users/testdata/autologin/lxdm.conf diff --git a/accounts/users/testdata/autologin/lxdm_autologin.conf b/accounts1/users/testdata/autologin/lxdm_autologin.conf similarity index 100% rename from accounts/users/testdata/autologin/lxdm_autologin.conf rename to accounts1/users/testdata/autologin/lxdm_autologin.conf diff --git a/accounts/users/testdata/autologin/sddm.conf b/accounts1/users/testdata/autologin/sddm.conf similarity index 100% rename from accounts/users/testdata/autologin/sddm.conf rename to accounts1/users/testdata/autologin/sddm.conf diff --git a/accounts/users/testdata/autologin/sddm_autologin.conf b/accounts1/users/testdata/autologin/sddm_autologin.conf similarity index 100% rename from accounts/users/testdata/autologin/sddm_autologin.conf rename to accounts1/users/testdata/autologin/sddm_autologin.conf diff --git a/accounts/users/testdata/autologin/slim.conf b/accounts1/users/testdata/autologin/slim.conf similarity index 100% rename from accounts/users/testdata/autologin/slim.conf rename to accounts1/users/testdata/autologin/slim.conf diff --git a/accounts/users/testdata/autologin/slim_autologin.conf b/accounts1/users/testdata/autologin/slim_autologin.conf similarity index 100% rename from accounts/users/testdata/autologin/slim_autologin.conf rename to accounts1/users/testdata/autologin/slim_autologin.conf diff --git a/accounts/users/testdata/group b/accounts1/users/testdata/group similarity index 100% rename from accounts/users/testdata/group rename to accounts1/users/testdata/group diff --git a/accounts/users/testdata/login.defs b/accounts1/users/testdata/login.defs similarity index 100% rename from accounts/users/testdata/login.defs rename to accounts1/users/testdata/login.defs diff --git a/accounts/users/testdata/passwd b/accounts1/users/testdata/passwd similarity index 100% rename from accounts/users/testdata/passwd rename to accounts1/users/testdata/passwd diff --git a/accounts/users/testdata/shadow b/accounts1/users/testdata/shadow similarity index 100% rename from accounts/users/testdata/shadow rename to accounts1/users/testdata/shadow diff --git a/accounts/users/testdata/sudoers_arch b/accounts1/users/testdata/sudoers_arch similarity index 100% rename from accounts/users/testdata/sudoers_arch rename to accounts1/users/testdata/sudoers_arch diff --git a/accounts/users/testdata/sudoers_deepin b/accounts1/users/testdata/sudoers_deepin similarity index 100% rename from accounts/users/testdata/sudoers_deepin rename to accounts1/users/testdata/sudoers_deepin diff --git a/accounts/users/users_test.go b/accounts1/users/users_test.go similarity index 100% rename from accounts/users/users_test.go rename to accounts1/users/users_test.go diff --git a/accounts1/utils.go b/accounts1/utils.go new file mode 100644 index 000000000..e31582bf6 --- /dev/null +++ b/accounts1/utils.go @@ -0,0 +1,328 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package accounts + +import ( + "bufio" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "regexp" + "sort" + "strconv" + "strings" + "time" + + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/accounts1/users" + polkit "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.policykit1" + "github.com/linuxdeepin/go-lib/encoding/kv" + "github.com/linuxdeepin/go-lib/graphic" + "github.com/linuxdeepin/go-lib/utils" +) + +// #nosec G101 +const ( + polkitActionUserAdministration = "org.deepin.dde.accounts.user-administration" + polkitActionChangeOwnData = "org.deepin.dde.accounts.change-own-user-data" + polkitActionEnableAutoLogin = "org.deepin.dde.accounts.enable-auto-login" + polkitActionDisableAutoLogin = "org.deepin.dde.accounts.disable-auto-login" + polkitActionEnableNoPasswordLogin = "org.deepin.dde.accounts.enable-nopass-login" + polkitActionDisableNoPasswordLogin = "org.deepin.dde.accounts.disable-nopass-login" + polkitActionEnableWechatAuth = "org.deepin.dde.accounts.enable-wechat-auth" + polkitActionDisableWechatAuth = "org.deepin.dde.accounts.disable-wechat-auth" + polkitActionSetKeyboardLayout = "org.deepin.dde.accounts.set-keyboard-layout" + polkitActionEnableQuickLogin = "org.deepin.dde.accounts.enable-quick-login" + polkitActionDisableQuickLogin = "org.deepin.dde.accounts.disable-quick-login" + + systemLocaleFile = "/etc/default/locale" + systemdLocaleFile = "/etc/locale.conf" + defaultLocale = "en_US.UTF-8" + + layoutDelimiter = ";" + defaultLayout = "us" + layoutDelimiter + defaultLayoutFile = "/etc/default/keyboard" +) + +type ErrCodeType int32 + +const ( + // 未知错误 + ErrCodeUnkown ErrCodeType = iota + // 权限认证失败 + ErrCodeAuthFailed + // 执行命令失败 + ErrCodeExecFailed + // 传入的参数不合法 + ErrCodeParamInvalid +) + +func (code ErrCodeType) String() string { + switch code { + case ErrCodeUnkown: + return "Unkown error" + case ErrCodeAuthFailed: + return "Policykit authentication failed" + case ErrCodeExecFailed: + return "Exec command failed" + case ErrCodeParamInvalid: + return "Invalid parameters" + } + + return "Unkown error" +} + +// return icons uris +func getUserStandardIcons() []string { + imgs, err := graphic.GetImagesInDir(userIconsDir) + if err != nil { + return nil + } + + var icons []string + for _, img := range imgs { + img = utils.EncodeURI(img, utils.SCHEME_FILE) + if strings.Contains(img, "guest") || img == defaultUserIcon { + continue + } + + icons = append(icons, img) + } + + return icons +} + +func getNewUserCustomIconDest(username string) string { + ns := time.Now().UnixNano() + base := username + "-" + strconv.FormatInt(ns, 36) + return filepath.Join(userCustomIconsDir, base) +} + +func isStrInArray(str string, array []string) bool { + for _, v := range array { + if v == str { + return true + } + } + + return false +} + +func isStrvEqual(l1, l2 []string) bool { + if len(l1) != len(l2) { + return false + } + + sort.Strings(l1) + sort.Strings(l2) + for i, v := range l1 { + if v != l2[i] { + return false + } + } + return true +} + +func checkAccountType(accountType int) error { + switch accountType { + case users.UserTypeStandard, users.UserTypeAdmin: + return nil + default: + return fmt.Errorf("invalid account type %d", accountType) + } +} + +func checkAuth(actionId string, sysBusName string) error { + ret, err := checkAuthByPolkit(actionId, sysBusName) + if err != nil { + return err + } + if !ret.IsAuthorized { + inf, err := getDetailsKey(ret.Details, "polkit.dismissed") + if err == nil { + if dismiss, ok := inf.(string); ok { + if dismiss != "" { + return errors.New("") + } + } + } + return fmt.Errorf(ErrCodeAuthFailed.String()) + } + return nil +} + +func checkAuthByPolkit(actionId string, sysBusName string) (ret polkit.AuthorizationResult, err error) { + systemBus, err := dbus.SystemBus() + if err != nil { + return + } + authority := polkit.NewAuthority(systemBus) + subject := polkit.MakeSubject(polkit.SubjectKindSystemBusName) + subject.SetDetail("name", sysBusName) + + ret, err = authority.CheckAuthorization(0, subject, + actionId, nil, + polkit.CheckAuthorizationFlagsAllowUserInteraction, "") + if err != nil { + logger.Warningf("call check auth failed, err: %v", err) + return + } + logger.Debugf("call check auth success, ret: %v", ret) + return +} + +func getDetailsKey(details map[string]dbus.Variant, key string) (interface{}, error) { + result, ok := details[key] + if !ok { + return nil, errors.New("key dont exist in details") + } + if utils.IsInterfaceNil(result) { + return nil, errors.New("result is nil") + } + return result.Value(), nil +} + +func getDefaultLocale() (locale string) { + files := [...]string{ + systemLocaleFile, + systemdLocaleFile, + } + for _, file := range files { + locale = getLocaleFromFile(file) + if locale != "" { + // get locale success + break + } + } + if locale == "" { + return defaultLocale + } + + return strings.Trim(locale, "\"'") +} + +func getLocaleFromFile(file string) string { + f, err := os.Open(file) + if err != nil { + return "" + } + defer f.Close() + + r := kv.NewReader(f) + r.Delim = '=' + r.Comment = '#' + r.TrimSpace = kv.TrimLeadingTailingSpace + for { + pair, err := r.Read() + if err == io.EOF { + break + } else if err != nil { + return "" + } + + if pair.Key == "LANG" { + return pair.Value + } + } + return "" +} + +func getDefaultLayout() string { + layout, err := getSystemLayout(defaultLayoutFile) + if err != nil { + logger.Warning("failed to get system default layout:", err) + return defaultLayout + } + return layout +} + +func getSystemLayout(file string) (string, error) { + fr, err := os.Open(file) + if err != nil { + return "", err + } + defer fr.Close() + + var ( + found int + layout string + variant string + + regLayout = regexp.MustCompile(`^XKBLAYOUT=`) + regVariant = regexp.MustCompile(`^XKBVARIANT=`) + + scanner = bufio.NewScanner(fr) + ) + for scanner.Scan() { + if found == 2 { + break + } + + var line = scanner.Text() + if regLayout.MatchString(line) { + layout = strings.Trim(getValueFromLine(line, "="), "\"") + found += 1 + continue + } + + if regVariant.MatchString(line) { + variant = strings.Trim(getValueFromLine(line, "="), "\"") + found += 1 + } + } + + if len(layout) == 0 { + return "", fmt.Errorf("not found default layout") + } + + return layout + layoutDelimiter + variant, nil +} + +func getValueFromLine(line, delim string) string { + array := strings.Split(line, delim) + if len(array) != 2 { + return "" + } + + return strings.TrimSpace(array[1]) +} + +// Get available shells from '/etc/shells' +func getAvailableShells(file string) []string { + contents, err := ioutil.ReadFile(file) + if err != nil || len(contents) == 0 { + return nil + } + var shells []string + lines := strings.Split(string(contents), "\n") + for _, line := range lines { + if line == "" || line[0] == '#' { + continue + } + shells = append(shells, line) + } + return shells +} + +// 修复目录 ownership +func recoverOwnership(u *User) error { + uid, err := strconv.Atoi(u.Uid) + if err != nil { + return err + } + gid, err := strconv.Atoi(u.Gid) + if err != nil { + return err + } + return filepath.Walk(u.HomeDir, func(name string, info os.FileInfo, err error) error { + if err == nil { + err = os.Chown(name, uid, gid) + } + return err + }) +} diff --git a/accounts1/utils_test.go b/accounts1/utils_test.go new file mode 100644 index 000000000..419b24901 --- /dev/null +++ b/accounts1/utils_test.go @@ -0,0 +1,109 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package accounts + +import ( + "testing" + + "github.com/godbus/dbus/v5" + "github.com/stretchr/testify/assert" +) + +var str = []string{"/bin/sh", "/bin/bash", + "/bin/zsh", "/usr/bin/zsh", + "/usr/bin/fish", +} + +func Test_GetLocaleFromFile(t *testing.T) { + assert.Equal(t, getLocaleFromFile("testdata/locale"), "zh_CN.UTF-8") +} + +func Test_SystemLayout(t *testing.T) { + layout, err := getSystemLayout("testdata/keyboard_us") + assert.NoError(t, err) + assert.Equal(t, layout, "us;") + layout, _ = getSystemLayout("testdata/keyboard_us_chr") + assert.Equal(t, layout, "us;chr") +} + +func TestAvailableShells(t *testing.T) { + var ret = []string{"/bin/sh", "/bin/bash", + "/bin/zsh", "/usr/bin/zsh", + "/usr/bin/fish", + } + shells := getAvailableShells("testdata/shells") + assert.ElementsMatch(t, shells, ret) +} + +func TestIsStrInArray(t *testing.T) { + ret := isStrInArray("testdata/shells", str) + assert.Equal(t, ret, false) + ret = isStrInArray("/bin/sh", str) + assert.Equal(t, ret, true) +} + +func TestIsStrvEqual(t *testing.T) { + var str1 = []string{"/bin/sh", "/bin/bash", + "/bin/zsh", "/usr/bin/zsh", + "/usr/bin/fish", + } + var str2 = []string{"/bin/sh", "/bin/bash"} + ret := isStrvEqual(str, str1) + assert.Equal(t, ret, true) + ret = isStrvEqual(str, str2) + assert.Equal(t, ret, false) +} + +func TestGetValueFromLine(t *testing.T) { + ret := getValueFromLine("testdata/shells", "/") + assert.Equal(t, ret, "shells") +} + +func Test_getDetailsKey(t *testing.T) { + type args struct { + details map[string]dbus.Variant + key string + } + tests := []struct { + name string + args args + want interface{} + wantErr bool + }{ + { + name: "getDetailsKey", + args: args{ + details: map[string]dbus.Variant{ + "te": dbus.MakeVariant(true), + }, + key: "te", + }, + want: true, + wantErr: false, + }, + { + name: "getDetailsKey not found", + args: args{ + details: map[string]dbus.Variant{ + "te": dbus.MakeVariant(true), + }, + key: "te1", + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := getDetailsKey(tt.args.details, tt.args.key) + if tt.wantErr { + assert.Error(t, err) + return + } + + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/appearance/README.md b/appearance/README.md deleted file mode 100644 index 3ca210193..000000000 --- a/appearance/README.md +++ /dev/null @@ -1,88 +0,0 @@ -## 描述 - -deepin 个性化后端, 提供了GTK主题,Icon 主题,Cursor 主题, 背景和字体的管理功能。 - - -## 功能实现简介 - -首先Gtk, Icon, Cursor和字体都需要先设置对应的 xsettings 属性(xsettings 的实现见 startdde),部分还需要设置 xresources , 使用的接口见 dde-api - -Cursor 还需要单独监听 `gtk-cursor-theme-name` 的改变,来让 Gtk 程序实时生效,对于 Qt 程序则需要在设置时更改下一些光标的映射关系,具体见 dde-api - -背景的绘制和设置接口都是由 deepin-wm 提供的,只需要调用接口就可以了。 - -字体使用了 fontconfig 来获取字体列表,并更改了它的配置问题来实现实时生效的。 - -而主题列表的获取都是遍历相关的安装目录而的到的(字体除外),然后会监听这些目录的变化来刷新列表。 - - -## 目录结构 - -+ *subthemes, fsnotify.go*: 管理 GTK, Icon, Cursor 主题, 并监听列表的改变,发出 `Refreshed` 信号 -+ *background, bg_wrapper.go*: 管理桌面背景 -+ *fonts, default_font_config.go*: 管理字体,包括标准字体,等款字体及字体大小 -+ *listener.go, cursor.c, cursor.h*: 处理 `gtk cursor` 的改变事件,让改变实时生效 -+ *handle_gsetting.go*: 监听 `gsettings` 的改变,并应用 -+ *manager.go, stup.go, ifc.go*: 个性化后端的接口 -+ *appearance.go*: 个性化模块的入口 - - -## DBus 接口简介 - -*Dest*: com.deepin.daemon.Appearance -*Path*: /com/deepin/daemon/Appearance -*Interface*: com.deepin.daemon.Appearance - - -### 支持的主题类型 - -+ TypeGtkTheme ("gtk") -+ TypeIconTheme ("icon") -+ TypeCursorTheme ("cursor") -+ TypeBackground ("background") -+ TypeGreeterBackground ("greeterbackground") -+ TypeStandardFont ("standardfont") -+ TypeMonospaceFont ("monospacefont") -+ TypeFontSize ("fontsize") - - -### Methods - -+ List(type string) (string, error) - 获取指定类型的主题列表,返回的是json格式的字符串。如果类型错误将返回错误。 -+ Show(type, name string) (string, error) - 获取指定类型主题的详细信息,包含主题名称,路径,是否可删除。如果类型错误或者主题不存在将返回错误。 -+ Set(type, name string) error - 这是指定类型的主题,如果类型错误或者主题不存在将返回错误。 -+ Delete(type, name string) error - 删除指定类型主题,注意只可删除用户目录下的。如果类型错误或者主题不存在将返回错误。 -+ Thumbnail(type, name string) (string, error) - 获取指定类型主题的缩略图,返回的是缩略图的路径。如果类型错误或者主题不存在将返回错误。 -+ Reset() - 重置所有的设置为默认值 - - -### Properties - -+ GtkTheme - 显示当前窗口主题 -+ IconTheme - 显示当前图标主题 -+ CursorTheme - 显示当前光标主题 -+ Background - 显示当前桌面背景 -+ StandardFont - 显示当前标准字体 -+ MonospaceFont - 显示当前等宽字体 -+ FontSize - 显示当前字体大小 - - -### Signals - -+ Changed(type, name string) - 当上面的属性改变时,会发送此信号,包含改变的属性类型及改变后的值 -+ Refreshed(type string) - 当 gtk, icon, cursor, background 的安装目录改变后,有主题或壁纸被添加或删除后,就会发出此信号 diff --git a/appearance/appearance.go b/appearance/appearance.go deleted file mode 100644 index e21277ac4..000000000 --- a/appearance/appearance.go +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -// Manage desktop appearance -package appearance - -import ( - "errors" - "time" - - "github.com/godbus/dbus" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/log" - - "github.com/linuxdeepin/dde-daemon/appearance/background" - "github.com/linuxdeepin/dde-daemon/loader" -) - -var ( - _m *Manager - logger = log.NewLogger("daemon/appearance") -) - -type Module struct { - *loader.ModuleBase -} - -func init() { - background.SetLogger(logger) - loader.Register(NewModule(logger)) -} - -func NewModule(logger *log.Logger) *Module { - var d = new(Module) - d.ModuleBase = loader.NewModuleBase("appearance", d, logger) - return d -} - -func HandlePrepareForSleep(sleep bool) { - if _m == nil { - return - } - if sleep { - return - } - cfg, err := doUnmarshalWallpaperSlideshow(_m.WallpaperSlideShow.Get()) - if err == nil { - for monitorSpace := range cfg { - if cfg[monitorSpace] == wsPolicyWakeup { - _m.autoChangeBg(monitorSpace, time.Now()) - } - } - } -} - -func (*Module) GetDependencies() []string { - return []string{} -} - -func (*Module) start() error { - service := loader.GetService() - - _m = newManager(service) - err := _m.init() - if err != nil { - logger.Warning(err) - return err - } - - err = service.Export(dbusPath, _m, _m.syncConfig) - if err != nil { - _m.destroy() - return err - } - - err = service.Export(backgroundDBusPath, _m.bgSyncConfig) - if err != nil { - return err - } - - so := service.GetServerObject(_m) - err = so.SetWriteCallback(_m, propQtActiveColor, func(write *dbusutil.PropertyWrite) *dbus.Error { - value, ok := write.Value.(string) - if !ok { - return dbusutil.ToError(errors.New("type is not string")) - } - err = _m.setQtActiveColor(value) - return dbusutil.ToError(err) - }) - if err != nil { - return err - } - - err = service.RequestName(dbusServiceName) - if err != nil { - _m.destroy() - err = service.StopExport(_m) - if err != nil { - return err - } - return err - } - - err = _m.syncConfig.Register() - if err != nil { - logger.Warning("failed to register for deepin sync", err) - } - - err = _m.bgSyncConfig.Register() - if err != nil { - logger.Warning("failed to register for deepin sync", err) - } - - go _m.listenCursorChanged() - go _m.handleThemeChanged() - _m.listenGSettingChanged() - _m.initFont() - return nil -} - -func (m *Module) Start() error { - if _m != nil { - return nil - } - return m.start() -} - -func (*Module) Stop() error { - if _m == nil { - return nil - } - - _m.destroy() - service := loader.GetService() - err := service.StopExport(_m) - if err != nil { - return err - } - _m = nil - return nil -} diff --git a/appearance/appearance_test.go b/appearance/appearance_test.go deleted file mode 100644 index 1b0e50597..000000000 --- a/appearance/appearance_test.go +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package appearance - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_hexColorToXsColor(t *testing.T) { - var tests = []struct { - hex string - xs string - err bool - }{ - {"#ffffff", "65535,65535,65535,65535", false}, - {"#ffffffff", "65535,65535,65535,65535", false}, - {"#ff69b4", "65535,26985,46260,65535", false}, - {"#00000000", "0,0,0,0", false}, - {"abc", "", true}, - {"#FfFff", "", true}, - {"", "", true}, - } - - for _, test := range tests { - xsColor, err := hexColorToXsColor(test.hex) - assert.Equal(t, err != nil, test.err) - assert.Equal(t, xsColor, test.xs) - } -} - -func Test_xsColorToHexColor(t *testing.T) { - var tests = []struct { - hex string - xs string - err bool - }{ - {"#FFFFFF", "65535,65535,65535,65535", false}, - {"#FF69B4", "65535,26985,46260,65535", false}, - {"", "", true}, - {"", "123,456,678", true}, - {"", "-1,-2,03,45", true}, - {"", "65535,26985,46260,65535,", true}, - {"", "65535,26985,46260,165535", true}, - } - - for _, test := range tests { - hexColor, err := xsColorToHexColor(test.xs) - assert.Equal(t, err != nil, test.err) - assert.Equal(t, hexColor, test.hex) - } -} - -func Test_byteArrayToHexColor(t *testing.T) { - var tests = []struct { - byteArray [4]byte - hex string - }{ - {[4]byte{0xff, 0xff, 0xff}, "#FFFFFF00"}, - {[4]byte{0xff, 0xff, 0xff, 0xff}, "#FFFFFF"}, - {[4]byte{0xff, 0x69, 0xb4}, "#FF69B400"}, - {[4]byte{0xff, 0x69, 0xb4, 0xff}, "#FF69B4"}, - } - - for _, test := range tests { - hexColor := byteArrayToHexColor(test.byteArray) - assert.Equal(t, hexColor, test.hex) - } -} - -func Test_parseHexColor(t *testing.T) { - var tests = []struct { - byteArray [4]byte - hex string - }{ - {[4]byte{0xff, 0xff, 0xff}, "#FFFFFF00"}, - {[4]byte{0xff, 0xff, 0xff, 0xff}, "#FFFFFF"}, - {[4]byte{0xff, 0x69, 0xb4}, "#FF69B400"}, - {[4]byte{0xff, 0x69, 0xb4, 0xff}, "#FF69B4"}, - } - - for _, test := range tests { - byteArray, err := parseHexColor(test.hex) - assert.NoError(t, err) - assert.Equal(t, byteArray, test.byteArray) - } -} diff --git a/appearance/background/background.go b/appearance/background/background.go deleted file mode 100644 index 6f2ac3712..000000000 --- a/appearance/background/background.go +++ /dev/null @@ -1,325 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package background - -import ( - "errors" - "fmt" - "os" - "os/user" - "path/filepath" - "strings" - "sync" - - "github.com/godbus/dbus" - daemon "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.daemon" - "github.com/linuxdeepin/go-lib/imgutil" - - "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/go-lib/strv" - dutils "github.com/linuxdeepin/go-lib/utils" - "github.com/linuxdeepin/go-lib/xdg/basedir" -) - -var ( - backgroundsCache Backgrounds - backgroundsCacheMu sync.Mutex - - CustomWallpapersConfigDir string - customWallpaperDeleteCallback func(file string) - logger *log.Logger -) - -const customWallpapersLimit = 10 - -//0:专业版 1: 政务授权 2: 企业授权 -const ( - Professional uint32 = iota - Government - Enterprise - Count -) - -const ( - Unknown uint32 = iota - Normal - Solid -) - -const ( - solidPrefix = "solid::" - solidWallPaperPath = "/usr/share/wallpapers/custom-solidwallpapers" - sysSolidWallPaperPath = "/usr/share/wallpapers/deepin-solidwallpapers" -) - -var NotifyFunc func(string, string) - -var _licenseAuthorizationProperty uint32 = 0 - -var _wallpapersPathMap = make(map[uint32]string) - -func SetLogger(value *log.Logger) { - logger = value -} - -func SetCustomWallpaperDeleteCallback(fn func(file string)) { - customWallpaperDeleteCallback = fn -} - -func LicenseAuthorizationProperty() uint32 { - return _licenseAuthorizationProperty -} - -func SetLicenseAuthorizationProperty(value uint32) { - if value != _licenseAuthorizationProperty { - _licenseAuthorizationProperty = value - } -} - -func UpdateLicenseAuthorizationProperty() { - refreshBackground(true) -} - -func init() { - logger = log.NewLogger("background") - SetLogger(logger) - CustomWallpapersConfigDir = filepath.Join(basedir.GetUserConfigDir(), - "deepin/dde-daemon/appearance/custom-wallpapers") - err := os.MkdirAll(CustomWallpapersConfigDir, 0755) - if err != nil { - _, _ = fmt.Fprintln(os.Stderr, err) - } - - _wallpapersPathMap[Professional] = "/usr/share/wallpapers/deepin" - _wallpapersPathMap[Government] = "/usr/share/wallpapers/deepin/deepin-government" - _wallpapersPathMap[Enterprise] = "/usr/share/wallpapers/deepin/deepin-enterprise" -} - -type Background struct { - Id string - Deletable bool -} - -type Backgrounds []*Background - -func refreshBackground(notify bool) { - if logger != nil { - logger.Debug("refresh background") - } - var bgs Backgrounds - // add custom - for _, file := range getCustomBgFiles() { - logger.Debugf("custom: %s", file) - bgs = append(bgs, &Background{ - Id: dutils.EncodeURI(file, dutils.SCHEME_FILE), - Deletable: true, - }) - } - - // add system, get default systemWallpapers - var systemWallpapersDir = []string{ - _wallpapersPathMap[Professional], - sysSolidWallPaperPath, - } - for _, file := range getSysBgFiles(systemWallpapersDir) { - logger.Debugf("system: %s", file) - bgs = append(bgs, &Background{ - Id: dutils.EncodeURI(file, dutils.SCHEME_FILE), - Deletable: false, - }) - } - - logger.Debug("[refreshBackground] _licenseAuthorizationProperty : ", _licenseAuthorizationProperty) - // add system, get enterprise or government systemWallpapers - if _licenseAuthorizationProperty > Professional && _licenseAuthorizationProperty < uint32(len(_wallpapersPathMap)) { - for _, file := range getSysBgFiles([]string{_wallpapersPathMap[_licenseAuthorizationProperty]}) { - logger.Debugf("system: %s", file) - bgs = append(bgs, &Background{ - Id: dutils.EncodeURI(file, dutils.SCHEME_FILE), - Deletable: false, - }) - } - } - // 对比差异,发送壁纸新增和删除的信号 - if notify && NotifyFunc != nil { - diff := diffBackgroundCache(bgs, backgroundsCache) - // TODO: 不在此处理壁纸添加信号。用户添加壁纸时,只要路径不是/usr/share/wallpaper,即认为是新壁纸,不管底层是否已经存在 - // if diff["added"] != nil { - // logger.Debug("new wallpapper added!", diff["added"]) - // NotifyFunc("background-add", strings.Join(diff["added"], ";")) - // } - if diff["deleted"] != nil { - logger.Debug("new wallpapper deleted!", diff["deleted"]) - NotifyFunc("background-delete", strings.Join(diff["deleted"], ";")) - } - } - backgroundsCache = bgs -} - -func diffBackgroundCache(newCache Backgrounds, oldCache Backgrounds) map[string][]string { - tmp := make(map[string]string) - for _, newBg := range newCache { - tmp[newBg.Id] = "added" - for _, oldBg := range oldCache { - if tmp[oldBg.Id] == "existed" { - continue - } - if newBg.Id == oldBg.Id { - tmp[oldBg.Id] = "existed" - } - if tmp[oldBg.Id] == "" { - tmp[oldBg.Id] = "deleted" - } - } - } - diff := make(map[string][]string) - for file, stat := range tmp { - diff[stat] = append(diff[stat], file) - } - return diff -} - -func ListBackground() Backgrounds { - backgroundsCacheMu.Lock() - defer backgroundsCacheMu.Unlock() - - if len(backgroundsCache) == 0 { - refreshBackground(false) - } - return backgroundsCache -} - -func NotifyChanged() { - backgroundsCacheMu.Lock() - refreshBackground(true) - backgroundsCacheMu.Unlock() -} - -var uiSupportedFormats = strv.Strv([]string{"jpeg", "png", "bmp", "tiff", "gif"}) - -func IsBackgroundFile(file string) bool { - file = dutils.DecodeURI(file) - format, err := imgutil.SniffFormat(file) - if err != nil { - return false - } - - if uiSupportedFormats.Contains(format) { - return true - } - return false -} - -func (bgs Backgrounds) Get(uri string) *Background { - uri = dutils.EncodeURI(uri, dutils.SCHEME_FILE) - for _, info := range bgs { - if uri == info.Id { - return info - } - } - return nil -} - -func (bgs Backgrounds) ListGet(uris []string) Backgrounds { - var ret Backgrounds - for _, uri := range uris { - v := bgs.Get(uri) - if v == nil { - continue - } - ret = append(ret, v) - } - return ret -} - -func (bgs Backgrounds) Delete(uri string) error { - info := bgs.Get(uri) - if info == nil { - return fmt.Errorf("not found '%s'", uri) - } - - return info.Delete() -} - -func (bgs Backgrounds) Thumbnail(uri string) (string, error) { - return "", errors.New("not supported") -} - -func (info *Background) Delete() error { - if !info.Deletable { - return fmt.Errorf("not custom") - } - - bus, err := dbus.SystemBus() - if err != nil { - logger.Warning(err) - return err - } - - dm := daemon.NewDaemon(bus) - cur, err := user.Current() - if err != nil { - logger.Warning(err) - return err - } - - file := dutils.DecodeURI(info.Id) - err = dm.DeleteCustomWallPaper(0, cur.Username, file) - if err != nil { - logger.Warning(err) - return err - } - - if customWallpaperDeleteCallback != nil { - customWallpaperDeleteCallback(file) - } - - NotifyChanged() - return err -} - -func (info *Background) Thumbnail() (string, error) { - return "", errors.New("not supported") -} - -func Prepare(file string, t uint32) (string, error) { - var systemWallpapersDir = []string{ - _wallpapersPathMap[Professional], - sysSolidWallPaperPath, - } - if _licenseAuthorizationProperty > Professional && _licenseAuthorizationProperty < uint32(len(_wallpapersPathMap)) { - systemWallpapersDir = append(systemWallpapersDir, _wallpapersPathMap[_licenseAuthorizationProperty]) - } - - if isFileInDirs(file, systemWallpapersDir) { - logger.Debug("is system") - return file, nil - } - - logger.Debug("is custom") - return prepare(file, t) - -} - -func GetWallpaperType(file string) (string, uint32) { - t := Normal - - if strings.HasPrefix(file, solidPrefix) { - file = strings.TrimPrefix(file, solidPrefix) - t = Solid - } - if !IsBackgroundFile(file) { - t = Unknown - } - file = dutils.DecodeURI(file) - if file == "" { - t = Unknown - } - if strings.HasPrefix(file, sysSolidWallPaperPath) || - strings.HasPrefix(file, solidWallPaperPath) { - t = Solid - } - return file, t -} diff --git a/appearance/background/background_test.go b/appearance/background/background_test.go deleted file mode 100644 index 650c9d2f8..000000000 --- a/appearance/background/background_test.go +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package background - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_LicenseAuthorizationProperty(t *testing.T) { - t.Log(LicenseAuthorizationProperty()) -} - -func Test_SetLicenseAuthorizationProperty(t *testing.T) { - SetLicenseAuthorizationProperty(30) - t.Log(_licenseAuthorizationProperty) - assert.Equal(t, _licenseAuthorizationProperty, uint32(30)) -} - -func Test_Scanner(t *testing.T) { - assert.ElementsMatch(t, getBgFilesInDir("testdata/Theme1/wallpapers"), - []string{ - "testdata/Theme1/wallpapers/desktop.jpg", - }) - assert.Nil(t, getBgFilesInDir("testdata/Theme2/wallpapers")) -} - -func Test_FileInDirs(t *testing.T) { - var dirs = []string{ - "/tmp/backgrounds", - "/tmp/wallpapers", - } - - assert.Equal(t, isFileInDirs("/tmp/backgrounds/1.jpg", dirs), - true) - assert.Equal(t, isFileInDirs("/tmp/wallpapers/1.jpg", dirs), - true) - assert.Equal(t, isFileInDirs("/tmp/background/1.jpg", dirs), - false) -} - -func Test_GetBgFiles(t *testing.T) { - files := getSysBgFiles([]string{"/usr/share/wallpapers/deepin"}) - t.Log(files) -} diff --git a/appearance/background/custom_wallpapers.go b/appearance/background/custom_wallpapers.go deleted file mode 100644 index 234aead77..000000000 --- a/appearance/background/custom_wallpapers.go +++ /dev/null @@ -1,206 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package background - -import ( - "crypto/md5" - "fmt" - "io" - "io/ioutil" - "os" - "os/user" - "path/filepath" - "sort" - "strings" - "time" - - "github.com/godbus/dbus" - daemon "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.daemon" - "github.com/linuxdeepin/go-gir/gio-2.0" - "github.com/linuxdeepin/go-lib/graphic" - "github.com/linuxdeepin/go-lib/imgutil" - "github.com/linuxdeepin/go-lib/strv" - dutils "github.com/linuxdeepin/go-lib/utils" - "github.com/nfnt/resize" -) - -func sumFileMd5(filename string) (string, error) { - f, err := os.Open(filename) - if err != nil { - return "", err - } - defer f.Close() - h := md5.New() - _, err = io.Copy(h, f) - if err != nil { - return "", err - } - return fmt.Sprintf("%x", h.Sum(nil)), nil -} - -func updateModTime(file string) { - now := time.Now() - err := os.Chtimes(file, now, now) - if err != nil { - logger.Warning("failed to update cache file modify time:", err) - } -} - -func resizeImage(filename, cacheDir string) (outFilename, ext string, isResized bool) { - img, err := imgutil.Load(filename) - if err != nil { - _, _ = fmt.Fprintf(os.Stderr, "failed to load image file %q: %v\n", filename, err) - outFilename = filename - return - } - - const ( - stdWidth = 3840 - stdHeight = 2400 - ) - - imgWidth := img.Bounds().Dx() - imgHeight := img.Bounds().Dy() - - if imgWidth <= stdWidth && imgHeight <= stdHeight { - // no need to resize - outFilename = filename - return - } - - ext = "jpg" - format := graphic.FormatJpeg - _, err = os.Stat("/usr/share/wallpapers/deepin/desktop.bmp") - if err == nil { - ext = "bmp" - format = graphic.FormatBmp - } - - fh, err := ioutil.TempFile(cacheDir, "tmp-") - if err != nil { - _, _ = fmt.Fprintln(os.Stderr, "failed to create temp file:", err) - outFilename = filename - return - } - - // tmp-### - outFilename = fh.Name() + "." + ext - err = fh.Close() - if err != nil { - _, _ = fmt.Fprintln(os.Stderr, "failed to close temp file:", err) - } - // 删除临时文件 - err = os.Remove(fh.Name()) - if err != nil { - _, _ = fmt.Fprintln(os.Stderr, "failed to remove temp file:", err) - } - - if float64(imgWidth)/float64(imgHeight) > float64(stdWidth)/float64(stdHeight) { - // use std width - imgWidth = stdWidth - imgHeight = 0 - } else { - // use std height - imgWidth = 0 - imgHeight = stdHeight - } - - img = resize.Resize(uint(imgWidth), uint(imgHeight), img, resize.Lanczos3) - err = graphic.SaveImage(outFilename, img, format) - if err != nil { - _, _ = fmt.Fprintf(os.Stderr, "failed to save image file %q: %v\n", - outFilename, err) - outFilename = filename - return - } - - isResized = true - return -} - -func prepare(filename string, t uint32) (string, error) { - bus, err := dbus.SystemBus() - if err != nil { - return "", err - } - - file, _, _ := resizeImage(filename, CustomWallpapersConfigDir) - - dm := daemon.NewDaemon(bus) - cur, err := user.Current() - if err != nil { - return "", err - } - - if t == Solid { - file = solidPrefix + file - } - return dm.SaveCustomWallPaper(0, cur.Username, file) -} - -func shrinkCache(cacheFileBaseName string) { - gs := gio.NewSettings("com.deepin.dde.appearance") - defer gs.Unref() - - workspaceBackgrounds := gs.GetStrv("background-uris") - var notDeleteFiles strv.Strv - notDeleteFiles = append(notDeleteFiles, cacheFileBaseName) - for _, uri := range workspaceBackgrounds { - wbFile := dutils.DecodeURI(uri) - if strings.HasPrefix(wbFile, CustomWallpapersConfigDir) { - // is custom wallpaper - basename := filepath.Base(wbFile) - if basename != cacheFileBaseName { - notDeleteFiles = append(notDeleteFiles, basename) - } - } - } - deleteOld(notDeleteFiles) -} - -func deleteOld(notDeleteFiles strv.Strv) { - fileInfos, _ := ioutil.ReadDir(CustomWallpapersConfigDir) - count := len(fileInfos) - customWallpapersLimit - if count <= 0 { - return - } - logger.Debugf("need delete %d file(s)", count) - - sort.Sort(byModTime(fileInfos)) - for _, fileInfo := range fileInfos { - if count == 0 { - break - } - - // traverse from old to new - fileBaseName := fileInfo.Name() - if !notDeleteFiles.Contains(fileBaseName) { - logger.Debug("delete", fileBaseName) - fullPath := filepath.Join(CustomWallpapersConfigDir, fileBaseName) - err := os.Remove(fullPath) - if os.IsNotExist(err) { - err = nil - } - - if err == nil { - count-- - - if customWallpaperDeleteCallback != nil { - customWallpaperDeleteCallback(fullPath) - } - } else { - logger.Warning(err) - } - } - } -} - -type byModTime []os.FileInfo - -func (a byModTime) Len() int { return len(a) } -func (a byModTime) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a byModTime) Less(i, j int) bool { - return a[i].ModTime().Unix() < a[j].ModTime().Unix() -} diff --git a/appearance/background/custom_wallpapers_test.go b/appearance/background/custom_wallpapers_test.go deleted file mode 100644 index 17a8c7f1c..000000000 --- a/appearance/background/custom_wallpapers_test.go +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package background - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_sumFileMd5(t *testing.T) { - type args struct { - filename string - } - tests := []struct { - name string - args args - want string - wantErr bool - }{ - { - name: "sumFileMd5", - args: args{ - filename: "./testdata/Theme1/wallpapers/desktop.jpg", - }, - want: "fafa2baf6dba60d3e47b8c7fe4eea9e9", - wantErr: false, - }, - { - name: "sumFileMd5 not found", - args: args{ - filename: "./testdata/Theme1/wallpapers/desktop.jpxg", - }, - want: "", - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := sumFileMd5(tt.args.filename) - if tt.wantErr { - assert.Error(t, err) - return - } - - assert.Equal(t, tt.want, got) - }) - } -} diff --git a/appearance/background/list.go b/appearance/background/list.go deleted file mode 100644 index 2ae1770bd..000000000 --- a/appearance/background/list.go +++ /dev/null @@ -1,136 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package background - -import ( - "io/ioutil" - "os" - "os/user" - "path/filepath" - "sort" - - "github.com/godbus/dbus" - daemon "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.daemon" - dutils "github.com/linuxdeepin/go-lib/utils" -) - -// ListDirs list all background dirs -func ListDirs() []string { - var result []string - result = append(result, _wallpapersPathMap[Professional]) - if _licenseAuthorizationProperty > Professional && _licenseAuthorizationProperty < uint32(len(_wallpapersPathMap)) { - result = append(result, _wallpapersPathMap[_licenseAuthorizationProperty]) - } - result = append(result, CustomWallpapersConfigDir) - return result -} - -// 根据时间排序文件 -func sortByTime(fileInfoList []os.FileInfo) []os.FileInfo { - sort.Slice(fileInfoList, func(i, j int) bool { - fileInfoI := fileInfoList[i] - fileInfoJ := fileInfoList[j] - if fileInfoI.ModTime().After(fileInfoJ.ModTime()) { - return true - } else if fileInfoI.ModTime().Equal(fileInfoJ.ModTime()) { - if fileInfoI.Name() < fileInfoJ.Name() { - return true - } - } - return false - }) - - return fileInfoList -} - -func getSysBgFiles(paths []string) []string { - var files []string - - for _, path := range paths { - if dutils.IsFileExist(path) { - files = append(files, getBgFilesInDir(path)...) - } - } - return files -} - -func getCustomBgFiles() []string { - bus, err := dbus.SystemBus() - if err != nil { - logger.Warning(err) - return []string{} - } - - dm := daemon.NewDaemon(bus) - cur, err := user.Current() - if err != nil { - logger.Warning(err) - return []string{} - } - - files, err := dm.GetCustomWallPapers(0, cur.Username) - if err != nil { - logger.Warning(err) - } - - return files -} - -func getCustomBgFilesInDir(dir string) []string { - fileInfoList, err := ioutil.ReadDir(dir) - if err != nil { - logger.Warning(err) - return nil - } - - sortByTime(fileInfoList) - - var wallpapers []string - for _, info := range fileInfoList { - // 只处理custom-wallpapers目录下的壁纸图片文件 - if info.IsDir() { - continue - } - path := filepath.Join(dir, info.Name()) - if !IsBackgroundFile(path) { - continue - } - wallpapers = append(wallpapers, path) - } - - return wallpapers -} - -func getBgFilesInDir(dir string) []string { - fr, err := os.Open(dir) - if err != nil { - return []string{} - } - defer fr.Close() - - names, err := fr.Readdirnames(0) - if err != nil { - return []string{} - } - - var walls []string - for _, name := range names { - path := filepath.Join(dir, name) - if !IsBackgroundFile(path) { - continue - } - walls = append(walls, path) - } - return walls -} - -func isFileInDirs(file string, dirs []string) bool { - for _, dir := range dirs { - if filepath.Dir(file) == dir { - return true - } - } - return false -} diff --git a/appearance/background/list_test.go b/appearance/background/list_test.go deleted file mode 100644 index de5cd92ee..000000000 --- a/appearance/background/list_test.go +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package background - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_getSysBgFiles(t *testing.T) { - type args struct { - dir []string - } - tests := []struct { - name string - args args - want []string - }{ - { - name: "getSysBgFiles", - args: args{ - dir: []string{"./testdata/fakeimages"}, - }, - want: []string{"testdata/fakeimages/fakeimage1.jpg", "testdata/fakeimages/fakeimage2.jpg"}, - }, - { - name: "getCustomBgFilesInDir empty", - args: args{ - dir: []string{"./testdata/fakeimages/empty"}, - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := getSysBgFiles(tt.args.dir) - assert.ElementsMatch(t, tt.want, got) - }) - } -} - -func Test_getCustomBgFilesInDir(t *testing.T) { - type args struct { - dir string - } - tests := []struct { - name string - args args - want []string - }{ - { - name: "getCustomBgFilesInDir", - args: args{ - dir: "./testdata/fakeimages", - }, - want: []string{"testdata/fakeimages/fakeimage1.jpg", "testdata/fakeimages/fakeimage2.jpg"}, - }, - { - name: "getCustomBgFilesInDir empty", - args: args{ - dir: "./testdata/fakeimages/empty", - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := getCustomBgFilesInDir(tt.args.dir) - assert.ElementsMatch(t, tt.want, got) - }) - } -} diff --git a/appearance/background/testdata/Theme1/wallpapers/desktop.jpg b/appearance/background/testdata/Theme1/wallpapers/desktop.jpg deleted file mode 100644 index 4b16c3805..000000000 Binary files a/appearance/background/testdata/Theme1/wallpapers/desktop.jpg and /dev/null differ diff --git a/appearance/background/testdata/Theme2/wallpapers/README.md b/appearance/background/testdata/Theme2/wallpapers/README.md deleted file mode 100644 index 39528fb72..000000000 --- a/appearance/background/testdata/Theme2/wallpapers/README.md +++ /dev/null @@ -1 +0,0 @@ -#Test diff --git a/appearance/background/testdata/fakeimages/empty/notimage.jpg b/appearance/background/testdata/fakeimages/empty/notimage.jpg deleted file mode 100644 index e69de29bb..000000000 diff --git a/appearance/background/testdata/fakeimages/fakeimage1.jpg b/appearance/background/testdata/fakeimages/fakeimage1.jpg deleted file mode 100644 index 63666c252..000000000 --- a/appearance/background/testdata/fakeimages/fakeimage1.jpg +++ /dev/null @@ -1 +0,0 @@ -FAKE JPEG1 \ No newline at end of file diff --git a/appearance/background/testdata/fakeimages/fakeimage2.jpg b/appearance/background/testdata/fakeimages/fakeimage2.jpg deleted file mode 100644 index bff0f8747..000000000 --- a/appearance/background/testdata/fakeimages/fakeimage2.jpg +++ /dev/null @@ -1 +0,0 @@ -FAKE JPEG2 \ No newline at end of file diff --git a/appearance/cursor.c b/appearance/cursor.c deleted file mode 100644 index e7a0a3685..000000000 --- a/appearance/cursor.c +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include - -#include "cursor.h" - -static gboolean end_flag = FALSE; -static void update_gtk_cursor(); - -void -handle_gtk_cursor_changed() -{ - static int sig_id = 0; - if (sig_id > 0) { - end_flag = FALSE; - g_debug("Cursor changed handler has running\n"); - return; - } - - gtk_init(NULL, NULL); - GtkSettings* s = gtk_settings_get_default(); - sig_id = g_signal_connect(s, "notify::gtk-cursor-theme-name", - update_gtk_cursor, NULL); - if (sig_id <= 0) { - g_warning("Connect gtk cursor changed failed!"); - return; - } - - gtk_main(); -} - -void -end_cursor_changed_handler() -{ - end_flag = TRUE; -} - -static void -update_gtk_cursor() -{ - if (end_flag) { - return ; - } - - GdkCursor* cursor = gdk_cursor_new_for_display( - gdk_display_get_default(), - GDK_LEFT_PTR); - gdk_window_set_cursor(gdk_get_default_root_window(), cursor); - g_object_unref(G_OBJECT(cursor)); -} diff --git a/appearance/cursor.h b/appearance/cursor.h deleted file mode 100644 index 615cef4ab..000000000 --- a/appearance/cursor.h +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef __CURSOR_H__ -#define __CURSOR_H__ - -void handle_gtk_cursor_changed(); -void end_cursor_changed_handler(); - -#endif diff --git a/appearance/deepin_qt_theme.go b/appearance/deepin_qt_theme.go deleted file mode 100644 index 21e0c1474..000000000 --- a/appearance/deepin_qt_theme.go +++ /dev/null @@ -1,99 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package appearance - -import ( - "fmt" - "path" - "sync" - - "github.com/linuxdeepin/go-lib/keyfile" - "github.com/linuxdeepin/go-lib/utils" - "github.com/linuxdeepin/go-lib/xdg/basedir" -) - -const ( - dQtSectionTheme = "Theme" - dQtKeyIcon = "IconThemeName" - dQtKeyFont = "Font" - dQtKeyMonoFont = "MonoFont" - dQtKeyFontSize = "FontSize" -) - -var dQtFile = path.Join(basedir.GetUserConfigDir(), "deepin", "qt-theme.ini") - -func setDQtTheme(file, section string, keys, values []string) error { - _dQtLocker.Lock() - defer _dQtLocker.Unlock() - - keyLen := len(keys) - if keyLen != len(values) { - return fmt.Errorf("keys - values not match: %d - %d", keyLen, len(values)) - } - - _, err := getDQtHandler(file) - if err != nil { - return err - } - - for i := 0; i < keyLen; i++ { - v, _ := _dQtHandler.GetString(section, keys[i]) - if v == values[i] { - continue - } - _dQtHandler.SetString(section, keys[i], values[i]) - _needSave = true - } - return nil -} - -func saveDQtTheme(file string) error { - _dQtLocker.Lock() - defer _dQtLocker.Unlock() - - if !_needSave { - _dQtHandler = nil - return nil - } - _needSave = false - - _, err := getDQtHandler(file) - if err != nil { - return err - } - - err = _dQtHandler.SaveToFile(file) - _dQtHandler = nil - return err -} - -var ( - _dQtHandler *keyfile.KeyFile - _dQtLocker sync.Mutex - _needSave bool = false -) - -func getDQtHandler(file string) (*keyfile.KeyFile, error) { - if _dQtHandler != nil { - return _dQtHandler, nil - } - - if !utils.IsFileExist(file) { - err := utils.CreateFile(file) - if err != nil { - logger.Debug("Failed to create qt theme file:", file, err) - return nil, err - } - } - - kf := keyfile.NewKeyFile() - err := kf.LoadFromFile(file) - if err != nil { - logger.Debug("Failed to load qt theme file:", file, err) - return nil, err - } - _dQtHandler = kf - return _dQtHandler, nil -} diff --git a/appearance/exported_methods_auto.go b/appearance/exported_methods_auto.go deleted file mode 100644 index 5850198c1..000000000 --- a/appearance/exported_methods_auto.go +++ /dev/null @@ -1,80 +0,0 @@ -// Code generated by "dbusutil-gen em -type Manager"; DO NOT EDIT. - -package appearance - -import ( - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (v *Manager) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "Delete", - Fn: v.Delete, - InArgs: []string{"ty", "name"}, - }, - { - Name: "GetScaleFactor", - Fn: v.GetScaleFactor, - OutArgs: []string{"scaleFactor"}, - }, - { - Name: "GetScreenScaleFactors", - Fn: v.GetScreenScaleFactors, - OutArgs: []string{"scaleFactors"}, - }, - { - Name: "GetWallpaperSlideShow", - Fn: v.GetWallpaperSlideShow, - InArgs: []string{"monitorName"}, - OutArgs: []string{"slideShow"}, - }, - { - Name: "List", - Fn: v.List, - InArgs: []string{"ty"}, - OutArgs: []string{"list"}, - }, - { - Name: "Reset", - Fn: v.Reset, - }, - { - Name: "Set", - Fn: v.Set, - InArgs: []string{"ty", "value"}, - }, - { - Name: "SetMonitorBackground", - Fn: v.SetMonitorBackground, - InArgs: []string{"monitorName", "imageFile"}, - }, - { - Name: "SetScaleFactor", - Fn: v.SetScaleFactor, - InArgs: []string{"scale"}, - }, - { - Name: "SetScreenScaleFactors", - Fn: v.SetScreenScaleFactors, - InArgs: []string{"v"}, - }, - { - Name: "SetWallpaperSlideShow", - Fn: v.SetWallpaperSlideShow, - InArgs: []string{"monitorName", "wallpaperSlideShow"}, - }, - { - Name: "Show", - Fn: v.Show, - InArgs: []string{"ty", "names"}, - OutArgs: []string{"detail"}, - }, - { - Name: "Thumbnail", - Fn: v.Thumbnail, - InArgs: []string{"ty", "name"}, - OutArgs: []string{"file"}, - }, - } -} diff --git a/appearance/font_conf_version.go b/appearance/font_conf_version.go deleted file mode 100644 index de49df707..000000000 --- a/appearance/font_conf_version.go +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package appearance - -import ( - "io/ioutil" - "os" - "path" -) - -const _fontConfVersion = "1.4" - -var _fontVersionConf = os.Getenv("HOME") + "/.config/fontconfig/conf.d/deepin_conf.version" - -func (m *Manager) checkFontConfVersion() bool { - if isVersionRight(_fontConfVersion, _fontVersionConf) { - return true - } - - logger.Debug("Font config version not same, will delete config and create") - err := os.Remove(_fontVersionConf) - if err != nil { - logger.Warning("Failed to remove font version:", err) - } - - err = os.MkdirAll(path.Dir(_fontVersionConf), 0755) - if err != nil { - logger.Warning("Failed to create font version directory:", err) - return false - } - - err = ioutil.WriteFile(_fontVersionConf, - []byte(_fontConfVersion), 0644) - if err != nil { - logger.Warning("Failed to write font version:", err) - return false - } - return false -} - -func isVersionRight(version, file string) bool { - data, err := ioutil.ReadFile(file) - if err != nil { - return false - } - - return string(data) == version -} diff --git a/appearance/font_conf_version_test.go b/appearance/font_conf_version_test.go deleted file mode 100644 index 989352b33..000000000 --- a/appearance/font_conf_version_test.go +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package appearance - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_isVersionRight(t *testing.T) { - assert.True(t, isVersionRight("1.4", "testdata/fontVersionConf")) -} diff --git a/appearance/fonts/family.go b/appearance/fonts/family.go deleted file mode 100644 index 1658c3862..000000000 --- a/appearance/fonts/family.go +++ /dev/null @@ -1,199 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package fonts - -import ( - "crypto/md5" - "fmt" - "path" - "sort" - "strconv" - "strings" - "sync" - - "github.com/linuxdeepin/go-gir/gio-2.0" - "github.com/linuxdeepin/go-lib/xdg/basedir" -) - -type Family struct { - Id string - Name string - - Styles []string - - Monospace bool - Show bool -} - -type FamilyHashTable map[string]*Family - -const ( - fallbackStandard = "Noto Sans" - fallbackMonospace = "Noto Mono" - - xsettingsSchema = "com.deepin.xsettings" - gsKeyFontName = "gtk-font-name" -) - -var ( - locker sync.Mutex - xsSetting = gio.NewSettings(xsettingsSchema) - - DeepinFontConfig = path.Join(basedir.GetUserConfigDir(), "fontconfig", "conf.d", "99-deepin.conf") -) - -func Reset() error { - err := removeAll(DeepinFontConfig) - if err != nil { - return err - } - xsSetting.Reset(gsKeyFontName) - return nil -} - -func IsFontFamily(value string) bool { - if isVirtualFont(value) { - return true - } - - info := GetFamilyTable().GetFamily(value) - return info != nil -} - -func IsFontSizeValid(size float64) bool { - if size >= 7.0 && size <= 22.0 { - return true - } - return false -} - -func SetFamily(standard, monospace string, size float64) error { - locker.Lock() - defer locker.Unlock() - - if isVirtualFont(standard) { - standard = FcFont_Match(standard) - } - if isVirtualFont(monospace) { - monospace = FcFont_Match(monospace) - } - - table := GetFamilyTable() - standInfo := table.GetFamily(standard) - if standInfo == nil { - return fmt.Errorf("Invalid standard id '%s'", standard) - } - // standard += " " + standInfo.preferredStyle() - monoInfo := table.GetFamily(monospace) - if monoInfo == nil { - return fmt.Errorf("Invalid monospace id '%s'", monospace) - } - // monospace += " " + monoInfo.preferredStyle() - - // fc-match can not real time update - /* - curStand := FcFont_Match("sans-serif") - curMono := FcFont_Match("monospace") - if (standInfo.Id == curStand || standInfo.Name == curStand) && - (monoInfo.Id == curMono || monoInfo.Name == curMono) { - return nil - } - */ - - err := writeFontConfig(configContent(standInfo.Id, monoInfo.Id), DeepinFontConfig) - if err != nil { - return err - } - return setFontByXSettings(standard, size) -} - -func GetFontSize() float64 { - return getFontSize(xsSetting) -} - -func (table FamilyHashTable) ListMonospace() []string { - var ids []string - for _, info := range table { - if !info.Monospace { - continue - } - ids = append(ids, info.Id) - } - sort.Strings(ids) - return ids -} - -func (table FamilyHashTable) ListStandard() []string { - var ids []string - for _, info := range table { - if info.Monospace || !info.Show { - continue - } - ids = append(ids, info.Id) - } - sort.Strings(ids) - return ids -} - -func (table FamilyHashTable) Get(key string) *Family { - info := table[key] - return info -} - -func (table FamilyHashTable) GetFamily(id string) *Family { - info, ok := table[sumStrHash(id)] - if !ok { - return nil - } - return info -} - -func (table FamilyHashTable) GetFamilies(ids []string) []*Family { - var infos []*Family - for _, id := range ids { - info, ok := table[sumStrHash(id)] - if !ok { - continue - } - infos = append(infos, info) - } - return infos -} - -func setFontByXSettings(name string, size float64) error { - if size == -1 { - size = getFontSize(xsSetting) - } - v := fmt.Sprintf("%s %v", name, size) - if v == xsSetting.GetString(gsKeyFontName) { - return nil - } - - xsSetting.SetString(gsKeyFontName, v) - return nil -} - -func getFontSize(setting *gio.Settings) float64 { - value := setting.GetString(gsKeyFontName) - if len(value) == 0 { - return 0 - } - - array := strings.Split(value, " ") - size, _ := strconv.ParseFloat(array[len(array)-1], 64) - return size -} - -func isVirtualFont(name string) bool { - switch name { - case "monospace", "mono", "sans-serif", "sans", "serif": - return true - } - return false -} - -func sumStrHash(v string) string { - return fmt.Sprintf("%x", md5.Sum([]byte(v))) -} diff --git a/appearance/fonts/family_cache.go b/appearance/fonts/family_cache.go deleted file mode 100644 index 9222b041d..000000000 --- a/appearance/fonts/family_cache.go +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package fonts - -import ( - "bytes" - "encoding/gob" - "fmt" - "io/ioutil" - "os" - "path" -) - -var ( - familyHashCacheFile = path.Join(home, ".cache", "deepin", "dde-daemon", "fonts", "family_hash") -) - -func (table FamilyHashTable) saveToFile() error { - return doSaveObject(familyHashCacheFile, &table) -} - -func loadCacheFromFile(file string, obj interface{}) error { - data, err := ioutil.ReadFile(file) - if err != nil { - return err - } - - var r = bytes.NewBuffer(data) - decoder := gob.NewDecoder(r) - err = decoder.Decode(obj) - if err != nil { - return err - } - return nil -} - -func doSaveObject(file string, obj interface{}) error { - var w bytes.Buffer - encoder := gob.NewEncoder(&w) - err := encoder.Encode(obj) - if err != nil { - return err - } - - err = os.MkdirAll(path.Dir(file), 0755) - if err != nil { - return err - } - return ioutil.WriteFile(file, w.Bytes(), 0644) -} - -func writeFontConfig(content, file string) error { - err := os.MkdirAll(path.Dir(file), 0755) - if err != nil { - return err - } - - return ioutil.WriteFile(file, []byte(content), 0644) -} - -func removeAll(path string) error { - return os.RemoveAll(path) -} - -// If set pixelsize, wps-office-wps will not show some text. -// -//func configContent(standard, mono string, pixel float64) string { -func configContent(standard, mono string) string { - return fmt.Sprintf(` - - - - - serif - - - %s - %s - - - - - - sans-serif - - - %s - %s - - - - - - monospace - - - %s - %s - %s - - - - - rgb - -`, standard, fallbackStandard, - standard, fallbackStandard, - mono, fallbackMonospace, standard) -} diff --git a/appearance/fonts/font_list.c b/appearance/fonts/font_list.c deleted file mode 100644 index db175b6bb..000000000 --- a/appearance/fonts/font_list.c +++ /dev/null @@ -1,184 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include -#include -#include -#include -#include - -#include "font_list.h" - -static int append_font_info(FcInfo** list, FcPattern* pat, int idx); -static void free_font_info(FcInfo *info); - -int -fc_cache_update () -{ - static int first = 0; - if (first == 0) { - FcInit(); - first = 1; - return 1; - } - - return !FcConfigUptoDate (NULL) && FcInitReinitialize (); -} - -FcInfo * -list_font_info (int *num) -{ - *num = -1; - FcPattern *pat = FcPatternCreate(); - if (!pat) { - fprintf(stderr, "Create FcPattern Failed\n"); - return NULL; - } - - FcObjectSet *os = FcObjectSetBuild( - FC_FAMILY, - FC_FAMILYLANG, - /* FC_FULLNAME, */ - /* FC_FULLNAMELANG, */ - FC_STYLE, - /* FC_FILE, */ - FC_LANG, - FC_SPACING, - FC_CHARSET, - NULL); - if (!os) { - fprintf(stderr, "Build FcObjectSet Failed\n"); - FcPatternDestroy(pat); - return NULL; - } - - FcFontSet *fs = FcFontList(0, pat, os); - FcObjectSetDestroy(os); - FcPatternDestroy(pat); - if (!fs) { - fprintf(stderr, "List Font Failed\n"); - return NULL; - } - - int i; - int cnt = 0; - FcInfo *list = NULL; - for (i = 0; i < fs->nfont; i++) { - char *charset = (char*)FcPatternFormat(fs->fonts[i], (FcChar8*)"%{charset}"); - if (charset == NULL || strlen(charset) == 0) { - free(charset); - continue; - } - free(charset); - - if (append_font_info(&list, fs->fonts[i], cnt) == -1) { - continue; - } - cnt++; - } - FcFontSetDestroy(fs); - //FcFini(); // SIGABRT: FcCacheFini 'assert fcCacheChains[i] == NULL failed' - - *num = cnt; - - return list; -} - -void -free_font_info_list(FcInfo *list, int num) -{ - if (!list) { - return; - } - - int i; - for (i = 0; i < num; i++) { - free_font_info(list+i); - } - - free(list); -} - -char* -font_match(char* family) -{ - // configure the search pattern - FcPattern* pat = FcNameParse((FcChar8*)family); - if (!pat) { - return NULL; - } - - FcConfigSubstitute(NULL, pat, FcMatchPattern); - FcDefaultSubstitute(pat); - - FcResult result; - FcPattern* match = FcFontMatch(NULL, pat, &result); - FcPatternDestroy(pat); - if (!match) { - return NULL; - } - - FcFontSet* fs = FcFontSetCreate(); - if (!fs) { - FcPatternDestroy(match); - return NULL; - } - - FcFontSetAdd(fs, match); - FcPattern* font = FcPatternFilter(fs->fonts[0], NULL); - FcChar8* ret = FcPatternFormat(font, (const FcChar8*)"%{=fcmatch}\n"); - - FcPatternDestroy(font); - FcFontSetDestroy(fs); - FcPatternDestroy(match); - //FcFini(); // SIGABRT: FcCacheFini 'assert fcCacheChains[i] == NULL failed' - - if (!ret) { - return NULL; - } - - return (char*)ret; -} - -static int -append_font_info(FcInfo** list, FcPattern* pat, int idx) -{ - // realloc equals to malloc if the first argument is NULL. - // realloc will auto free old memory chunk. - FcInfo* tmp = (FcInfo*)realloc(*list, (idx+1)*sizeof(FcInfo)); - if (!tmp) { - fprintf(stderr, "Alloc memory at append %d font info failed\n", idx+1); - return -1; - } - - *list = tmp; - - tmp[idx].family = (char*)FcPatternFormat(pat, (FcChar8*)"%{family}"); - tmp[idx].familylang = (char*)FcPatternFormat(pat, (FcChar8*)"%{familylang}"); - /* tmp[idx].fullname = (char*)FcPatternFormat(pat, (FcChar8*)"%{fullname}"); */ - /* tmp[idx].fullnamelang = (char*)FcPatternFormat(pat, (FcChar8*)"%{fullnamelang}"); */ - tmp[idx].style = (char*)FcPatternFormat(pat, (FcChar8*)"%{style}"); - /* tmp[idx].filename = (char*)FcPatternFormat(pat, (FcChar8*)"%{file}"); */ - tmp[idx].lang = (char*)FcPatternFormat(pat, (FcChar8*)"%{lang}"); - tmp[idx].spacing = (char*)FcPatternFormat(pat, (FcChar8*)"%{spacing}"); - - return 0; -} - -static void -free_font_info(FcInfo *info) -{ - if (info == NULL) { - return; - } - - free(info->family); - free(info->familylang); - /* free(info->fullname); */ - /* free(info->fullnamelang); */ - free(info->style); - free(info->lang); - free(info->spacing); - /* free(info->filename); */ -} diff --git a/appearance/fonts/font_list.h b/appearance/fonts/font_list.h deleted file mode 100644 index 2a6bb9b1f..000000000 --- a/appearance/fonts/font_list.h +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef __FONT_LIST_H__ -#define __FONT_LIST_H__ - -typedef struct _FcInfo { - char *family; - char *familylang; - /* char *fullname; */ - /* char *fullnamelang; */ - char *style; - char *lang; - char *spacing; - /* char *filename; */ -} FcInfo; - -int fc_cache_update (); -FcInfo *list_font_info (int *num); -void free_font_info_list(FcInfo *list, int num); - -char* font_match(char* family); - -#endif diff --git a/appearance/fonts/wrapper.go b/appearance/fonts/wrapper.go deleted file mode 100644 index d73dab23b..000000000 --- a/appearance/fonts/wrapper.go +++ /dev/null @@ -1,257 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package fonts - -// #cgo pkg-config: fontconfig -// #cgo CFLAGS: -W -Wall -fstack-protector-all -fPIC -// #include -// #include "font_list.h" -import "C" - -import ( - "fmt" - "os" - "regexp" - "strings" - "sync" - "unsafe" - - "github.com/linuxdeepin/go-lib/strv" -) - -const ( - defaultLang = "en" - defaultLangDelim = "|" - defaultNameDelim = "," - spaceTypeMono = "100" -) - -var ( - curLang string - home = os.Getenv("HOME") - langReg = regexp.MustCompile("_") -) - -type fontOverrideProp struct { - AppendLang []string -} -type IrregularFontOverrideMap map[string]*fontOverrideProp - -var ( - _irregularFontOverrideMap IrregularFontOverrideMap - _irregularFontOverrideMapMu sync.Mutex -) - -var familyBlacklist = strv.Strv([]string{ - // font family names of Deepin Open Symbol Fonts: - "Symbol", - "webdings", - "MT Extra", - "Wingdings", - "Wingdings 2", - "Wingdings 3", -}) - -// family ex: 'sans', 'serif', 'monospace' -// cRet: `SourceCodePro-Medium.otf: "Source Code Pro" "Medium"` -func FcFont_Match(family string) string { - cFamily := C.CString(family) - defer C.free(unsafe.Pointer(cFamily)) - cRet := C.font_match(cFamily) - defer C.free(unsafe.Pointer(cRet)) - - ret := C.GoString(cRet) - if len(ret) == 0 { - return "" - } - - tmp := strings.Split(ret, ":") - if len(tmp) != 2 { - return "" - } - - // return font family id - name := strings.Split(tmp[1], "\"")[1] - table := GetFamilyTable() - key := sumStrHash(name) - info, ok := table[key] - if ok { - return info.Id - } - - for _, info := range table { - if info.Name == name { - return info.Id - } - } - return name -} - -func isFcCacheUpdate() bool { - ret := C.fc_cache_update() - return (ret == 1) -} - -func GetFamilyTable() FamilyHashTable { - var ( - table FamilyHashTable - err error - ) - if !isFcCacheUpdate() { - table = make(FamilyHashTable) - err = loadCacheFromFile(familyHashCacheFile, &table) - if err == nil { - return table - } - fmt.Println("Failed to load families cache:", err) - } - - table = fcInfosToFamilyTable() - err = table.saveToFile() - if err != nil { - fmt.Println("Failed to save families cache:", err) - } - return table -} - -func fcInfosToFamilyTable() FamilyHashTable { - var table = make(FamilyHashTable) - var num = C.int(0) - list := C.list_font_info(&num) - if num < 1 { - return nil - } - defer C.free_font_info_list(list, num) - - itemSize := unsafe.Sizeof(*list) - - for i := C.int(0); i < num; i++ { - cItem := (*C.FcInfo)(unsafe.Pointer(uintptr(unsafe.Pointer(list)) + uintptr(i)*itemSize)) - - info := fcInfoToFamily(cItem) - if info == nil { - continue - } - - key := sumStrHash(info.Id) - _, ok := table[key] - if !ok { - table[key] = info - } - } - return table -} - -func fcInfoToFamily(cInfo *C.FcInfo) *Family { - // var fullname = C.GoString(cInfo.fullname) - var familyname = C.GoString(cInfo.family) - if len(familyname) == 0 { - return nil - } - // names := strings.Split(fullname, defaultNameDelim) - // nameLang := strings.Split(C.GoString(cInfo.fullnamelang), - // defaultNameDelim) - families := strings.Split(familyname, defaultNameDelim) - familyLang := strings.Split(C.GoString(cInfo.familylang), - defaultNameDelim) - family := getItemByIndex(indexOf(defaultLang, familyLang), families) - if familyBlacklist.Contains(family) { - return nil - } - // info.Deletable = isDeletable(info.File) - langs := strings.Split(C.GoString(cInfo.lang), defaultLangDelim) - _irregularFontOverrideMapMu.Lock() - overrideProp, ok := _irregularFontOverrideMap[family] - if ok { - langs = append(langs, overrideProp.AppendLang...) - } - _irregularFontOverrideMapMu.Unlock() - return &Family{ - Id: family, - Name: getItemByIndex(indexOf(getCurLang(), familyLang), families), - Styles: strings.Split(C.GoString(cInfo.style), defaultNameDelim), - Monospace: isMonospace(family, C.GoString(cInfo.spacing)), - Show: strv.Strv(langs).Contains(getCurLang()), - } -} - -func isMonospace(name, spacing string) bool { - if spacing == spaceTypeMono || - strings.Contains(strings.ToLower(name), "mono") { - return true - } - - return false -} - -func getItemByIndex(idx int, list []string) string { - if len(list) == 0 { - return "" - } - - if idx < 0 || len(list) <= idx { - return list[0] - } - - return list[idx] -} - -func indexOf(item string, list []string) int { - for i, v := range list { - if item == v { - return i - } - } - return -1 -} - -func getCurLang() string { - if len(curLang) != 0 { - return curLang - } - - locale := os.Getenv("LANGUAGE") - if len(locale) == 0 { - locale = os.Getenv("LANG") - } - - lang := getLangFromLocale(locale) - if len(lang) == 0 { - return defaultLang - } - - curLang = lang - return lang -} - -func getLangFromLocale(locale string) string { - if len(locale) == 0 { - return "" - } - - locale = strings.ToLower(locale) - if strings.Contains(locale, ".") { - locale = strings.Split(locale, ".")[0] - } - if strings.Contains(locale, ":") { - locale = strings.Split(locale, ":")[0] - } - var lang string - switch locale { - case "zh_hk": - lang = "zh-tw" - case "zh_cn", "zh_tw", "zh_sg", "ku_tr", "mn_mn", "pap_an", "pap_aw": - lang = langReg.ReplaceAllString(locale, "-") - default: - lang = strings.Split(locale, "_")[0] - } - return lang -} - -func SetIrregularFontWhiteList(overrideMap IrregularFontOverrideMap) { - _irregularFontOverrideMapMu.Lock() - _irregularFontOverrideMap = overrideMap - _irregularFontOverrideMapMu.Unlock() -} diff --git a/appearance/fsnotify.go b/appearance/fsnotify.go deleted file mode 100644 index f0cb48c1b..000000000 --- a/appearance/fsnotify.go +++ /dev/null @@ -1,169 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package appearance - -import ( - "os" - "path" - "path/filepath" - "strings" - "time" - - "github.com/fsnotify/fsnotify" - "github.com/linuxdeepin/dde-daemon/appearance/background" - "github.com/linuxdeepin/dde-daemon/appearance/subthemes" - dutils "github.com/linuxdeepin/go-lib/utils" -) - -var ( - gtkDirs []string - iconDirs []string - bgDirs []string -) - -var prevTimestamp int64 - -func (m *Manager) handleThemeChanged() { - if m.watcher == nil { - return - } - - m.watchGtkDirs() - m.watchIconDirs() - m.watchBgDirs() - - tmpFilePrefix := filepath.Join(background.CustomWallpapersConfigDir, "tmp-") - - for { - select { - case <-m.endWatcher: - logger.Debug("[Fsnotify] quit watch") - return - case err := <-m.watcher.Errors: - logger.Warning("Receive file watcher error:", err) - return - case ev, ok := <-m.watcher.Events: - if !ok { - logger.Error("Invalid event:", ev) - return - } - - if strings.HasPrefix(ev.Name, tmpFilePrefix) { - continue - } - if (ev.Op == fsnotify.Create || ev.Op == fsnotify.Remove) && hasEventOccurred(ev.Name, iconDirs) && dutils.IsDir(ev.Name) { - upDir := filepath.Join(ev.Name, "../") - for _, v := range iconDirs { - if upDir == v { - if ev.Op == fsnotify.Create { - m.watcher.Add(ev.Name) - } else { - m.watcher.Remove(ev.Name) - } - break - } - } - } - - timestamp := time.Now().UnixNano() - tmp := timestamp - prevTimestamp - logger.Debug("[Fsnotify] timestamp:", prevTimestamp, timestamp, tmp, ev) - prevTimestamp = timestamp - // Filter time duration < 100ms's event - if tmp > 100000000 { - <-time.After(time.Millisecond * 100) - file := ev.Name - logger.Debug("[Fsnotify] changed file:", file) - switch { - case hasEventOccurred(file, bgDirs): - logger.Debug("fs event in bgDirs") - - if ev.Op&fsnotify.Chmod != 0 { - continue - } - - background.NotifyChanged() - for iloop := range m.wsLoopMap { - m.wsLoopMap[iloop].NotifyFsChanged() - } - - case hasEventOccurred(file, gtkDirs): - logger.Debug("fs event in gtkDirs") - // Wait for theme copy finished - <-time.After(time.Millisecond * 700) - subthemes.RefreshGtkThemes() - m.emitSignalRefreshed(TypeGtkTheme) - case hasEventOccurred(file, iconDirs): - // Wait for theme copy finished - logger.Debug("fs event in iconDirs") - <-time.After(time.Millisecond * 700) - subthemes.RefreshIconThemes() - subthemes.RefreshCursorThemes() - m.emitSignalRefreshed(TypeIconTheme) - m.emitSignalRefreshed(TypeCursorTheme) - } - } - } - } -} - -func (m *Manager) watchGtkDirs() { - var home = os.Getenv("HOME") - gtkDirs = []string{ - path.Join(home, ".local/share/themes"), - path.Join(home, ".themes"), - "/usr/local/share/themes", - "/usr/share/themes", - } - - m.watchDirs(gtkDirs) -} - -func (m *Manager) watchIconDirs() { - var home = os.Getenv("HOME") - iconDirs = []string{ - path.Join(home, ".local/share/icons"), - path.Join(home, ".icons"), - "/usr/local/share/icons", - "/usr/share/icons", - } - - m.watchDirs(iconDirs) -} - -func (m *Manager) watchBgDirs() { - bgDirs = background.ListDirs() - m.watchDirs(bgDirs) -} - -func (m *Manager) watchDirs(dirs []string) { - for _, dir := range dirs { - err := os.MkdirAll(dir, 0755) - if err != nil { - logger.Debugf("Mkdir '%s' failed: %v", dir, err) - } - - err = m.watcher.Add(dir) - if err != nil { - logger.Debugf("Watch dir '%s' failed: %v", dir, err) - } - } -} - -func hasEventOccurred(ev string, list []string) bool { - for _, v := range list { - if strings.Contains(ev, v) { - return true - } - } - return false -} - -func (m *Manager) emitSignalRefreshed(type0 string) { - err := m.service.Emit(m, "Refreshed", type0) - if err != nil { - logger.Warning("emit signal Refreshed failed:", err) - } -} diff --git a/appearance/fsnotify_test.go b/appearance/fsnotify_test.go deleted file mode 100644 index 6512a66aa..000000000 --- a/appearance/fsnotify_test.go +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package appearance - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_hasEventOccurred(t *testing.T) { - var shellStr = []string{"/bin/sh", "/bin/bash", - "/bin/zsh", "/usr/bin/zsh", - "/usr/bin/fish", - } - - assert.Equal(t, hasEventOccurred("/usr/bin/sh", shellStr), true) - assert.Equal(t, hasEventOccurred("/usr/lib/deepin", shellStr), false) -} diff --git a/appearance/handle_gsetting.go b/appearance/handle_gsetting.go deleted file mode 100644 index c283e29e3..000000000 --- a/appearance/handle_gsetting.go +++ /dev/null @@ -1,166 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package appearance - -import ( - "fmt" - "strings" - - "github.com/linuxdeepin/go-lib/gsettings" -) - -func (m *Manager) listenGSettingChanged() { - gsettings.ConnectChanged(xSettingsSchema, gsKeyQtActiveColor, func(key string) { - value, err := m.getQtActiveColor() - if err != nil { - logger.Warning(err) - return - } - if m.QtActiveColor != value { - m.QtActiveColor = value - err = m.service.EmitPropertyChanged(m, propQtActiveColor, value) - if err != nil { - logger.Warning(err) - } - } - }) - - gsettings.ConnectChanged(appearanceSchema, "*", func(key string) { - if m.setting == nil { - return - } - - var ( - ty string - value string - err error - ) - switch key { - case gsKeyGtkTheme: - ty = TypeGtkTheme - value = m.setting.GetString(key) - err = m.doSetGtkTheme(value) - m.updateThemeAuto(value == autoGtkTheme) - case gsKeyIconTheme: - ty = TypeIconTheme - value = m.setting.GetString(key) - err = m.doSetIconTheme(value) - case gsKeyCursorTheme: - ty = TypeCursorTheme - value = m.setting.GetString(key) - err = m.doSetCursorTheme(value) - case gsKeyFontStandard: - ty = TypeStandardFont - value = m.setting.GetString(key) - // 如果值相同,可能是dde设置导致的gsetting变化,不做变更 - if m.StandardFont.Get() != value { - err = m.doSetStandardFont(value) - } - case gsKeyFontMonospace: - ty = TypeMonospaceFont - value = m.setting.GetString(key) - // 如果值相同,可能是dde设置导致的gsetting变化,不做变更 - if m.MonospaceFont.Get() != value { - err = m.doSetMonospaceFont(value) - } - case gsKeyDTKSizeMode: - ty = TypeDTKSizeMode - enabled := m.setting.GetInt(key) - value = fmt.Sprint(enabled) - err = m.doSetDTKSizeMode(enabled) - if err == nil { - fontSizeKey := gsKeyFontSize - if m.DTKSizeMode.Get() == 1 { - fontSizeKey = gsKeyCompactFontSize - } - m.FontSize.Bind(m.setting, fontSizeKey) - _ = m.service.EmitPropertyChanged(m, propFontSize, m.FontSize.Get()) - err = m.doSetFontSize(m.FontSize.Get()) - } - case gsKeyFontSize: - ty = TypeFontSize - size := m.setting.GetDouble(key) - value = fmt.Sprint(size) - if m.isHasDTKSizeModeKey() && (m.DTKSizeMode.Get() == 0) { - err = m.doSetFontSize(size) - } else { - err = m.doSetFontSize(size) - } - case gsKeyCompactFontSize: - ty = TypeCompactFontSize - size := m.setting.GetDouble(key) - value = fmt.Sprint(size) - if m.isHasDTKSizeModeKey() && (m.DTKSizeMode.Get() == 1) { - err = m.doSetFontSize(size) - } - case gsKeyBackgroundURIs: - ty = TypeBackground - bgs := m.setting.GetStrv(key) - m.desktopBgs = bgs - m.setDesktopBackgrounds(bgs) - value = strings.Join(bgs, ";") - case gsKeyWallpaperSlideshow: - policy := m.setting.GetString(key) - m.updateWSPolicy(policy) - default: - return - } - if err != nil { - logger.Warningf("Set %v failed: %v", key, err) - return - } - if ty != "" { - m.emitSignalChanged(ty, value) - } - }) - - m.listenBgGSettings() -} - -func (m *Manager) emitSignalChanged(type0, value string) { - err := m.service.Emit(m, "Changed", type0, value) - if err != nil { - logger.Warning("emit emitSignalChanged Failed:", err) - } -} - -func (m *Manager) listenBgGSettings() { - gsettings.ConnectChanged(wrapBgSchema, "picture-uri", func(key string) { - if m.wrapBgSetting == nil { - return - } - - logger.Debug(wrapBgSchema, "changed") - value := m.wrapBgSetting.GetString(key) - file, err := m.doSetBackground(value) - if err != nil { - logger.Warning(err) - return - } - if m.wsLoopMap[m.curMonitorSpace] != nil { - m.wsLoopMap[m.curMonitorSpace].AddToShowed(file) - } - }) - - if m.gnomeBgSetting == nil { - return - } - gsettings.ConnectChanged(gnomeBgSchema, "picture-uri", func(key string) { - if m.gnomeBgSetting == nil { - return - } - - logger.Debug(gnomeBgSchema, "changed") - value := m.gnomeBgSetting.GetString(gsKeyBackground) - file, err := m.doSetBackground(value) - if err != nil { - logger.Warning(err) - return - } - if m.wsLoopMap[m.curMonitorSpace] != nil { - m.wsLoopMap[m.curMonitorSpace].AddToShowed(file) - } - }) -} diff --git a/appearance/ifc.go b/appearance/ifc.go deleted file mode 100644 index 025e1dd56..000000000 --- a/appearance/ifc.go +++ /dev/null @@ -1,319 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package appearance - -import ( - "fmt" - "path/filepath" - "strconv" - "strings" - - "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/appearance/fonts" - "github.com/linuxdeepin/dde-daemon/appearance/subthemes" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/strv" -) - -// Reset reset all themes and fonts settings to default values -func (m *Manager) Reset() *dbus.Error { - logger.Debug("Reset settings") - - var settingKeys = []string{ - gsKeyGtkTheme, - gsKeyIconTheme, - gsKeyCursorTheme, - gsKeyFontSize, - gsKeyCompactFontSize, - } - for _, key := range settingKeys { - userVal := m.setting.GetUserValue(key) - if userVal != nil { - logger.Debug("reset setting", key) - m.setting.Reset(key) - } - } - - m.resetFonts() - return nil -} - -// List list all available for the special type, return a json format list -func (m *Manager) List(ty string) (list string, busErr *dbus.Error) { - logger.Debug("List for type:", ty) - jsonStr, err := m.list(ty) - if err != nil { - return "", dbusutil.ToError(err) - } - return jsonStr, nil -} - -func (m *Manager) list(ty string) (string, error) { - switch strings.ToLower(ty) { - case TypeGtkTheme: - themes := subthemes.ListGtkTheme() - var gtkThemes subthemes.Themes - for _, theme := range themes { - if !strings.HasPrefix(theme.Id, "deepin") { - continue - } - gtkThemes = append(gtkThemes, theme) - } - gtkThemes = append(gtkThemes, &subthemes.Theme{ - Id: autoGtkTheme, - Path: "", - Deletable: false, - }) - return m.doShow(gtkThemes) - case TypeIconTheme: - return m.doShow(subthemes.ListIconTheme()) - case TypeCursorTheme: - return m.doShow(subthemes.ListCursorTheme()) - case TypeBackground: - return m.doShow(m.listBackground()) - case TypeStandardFont: - return m.doShow(fonts.GetFamilyTable().ListStandard()) - case TypeMonospaceFont: - return m.doShow(fonts.GetFamilyTable().ListMonospace()) - } - return "", fmt.Errorf("invalid type: %v", ty) - -} - -// Show show detail infos for the special type -// ret0: detail info, json format -func (m *Manager) Show(ty string, names []string) (detail string, busErr *dbus.Error) { - logger.Debugf("Show '%s' type '%s'", names, ty) - jsonStr, err := m.show(ty, names) - if err != nil { - return "", dbusutil.ToError(err) - } - return jsonStr, nil -} - -func (m *Manager) show(ty string, names []string) (string, error) { - switch strings.ToLower(ty) { - case TypeGtkTheme: - gtkThemes := subthemes.ListGtkTheme().ListGet(names) - if strv.Strv(names).Contains(autoGtkTheme) { - gtkThemes = append(gtkThemes, &subthemes.Theme{ - Id: autoGtkTheme, - Path: "", - Deletable: false, - }) - } - return m.doShow(gtkThemes) - case TypeIconTheme: - return m.doShow(subthemes.ListIconTheme().ListGet(names)) - case TypeCursorTheme: - return m.doShow(subthemes.ListCursorTheme().ListGet(names)) - case TypeBackground: - return m.doShow(m.listBackground().ListGet(names)) - case TypeStandardFont, TypeMonospaceFont: - return m.doShow(fonts.GetFamilyTable().GetFamilies(names)) - } - return "", fmt.Errorf("invalid type: %v", ty) -} - -// Set set to the special 'value' -func (m *Manager) Set(ty, value string) *dbus.Error { - logger.Debugf("Set '%s' for type '%s'", value, ty) - err := m.set(ty, value) - return dbusutil.ToError(err) -} - -func (m *Manager) set(ty, value string) error { - var err error - switch strings.ToLower(ty) { - case TypeGtkTheme: - if m.GtkTheme.Get() == value { - return nil - } - - err = m.doSetGtkTheme(value) - if err == nil { - m.GtkTheme.Set(value) - } - case TypeIconTheme: - if m.IconTheme.Get() == value { - return nil - } - err = m.doSetIconTheme(value) - if err == nil { - m.IconTheme.Set(value) - } - case TypeCursorTheme: - if m.CursorTheme.Get() == value { - return nil - } - err = m.doSetCursorTheme(value) - if err == nil { - m.CursorTheme.Set(value) - } - case TypeBackground: //old change wallpaple interface (no used) - file, err := m.doSetBackground(value) - if err == nil && m.wsLoopMap[m.curMonitorSpace] != nil { - m.wsLoopMap[m.curMonitorSpace].AddToShowed(file) - } - case TypeGreeterBackground: - err = m.doSetGreeterBackground(value) - case TypeStandardFont: - if m.StandardFont.Get() == value { - return nil - } - err = m.doSetStandardFont(value) - if err == nil { - m.StandardFont.Set(value) - } - case TypeMonospaceFont: - if m.MonospaceFont.Get() == value { - return nil - } - err = m.doSetMonospaceFont(value) - if err == nil { - m.MonospaceFont.Set(value) - } - case TypeDTKSizeMode: - enabled, err := strconv.ParseInt(value, 10, 30) - if err != nil { - return err - } - if m.isHasDTKSizeModeKey() { - if m.DTKSizeMode.Get() == int32(enabled) { - return nil - } - - err = m.doSetDTKSizeMode(int32(enabled)) - if err == nil { - m.DTKSizeMode.Set(int32(enabled)) - } - } - case TypeFontSize: - size, e := strconv.ParseFloat(value, 64) - if e != nil { - return e - } - - cur := m.FontSize.Get() - if cur > size-0.01 && cur < size+0.01 { - return nil - } - err = m.doSetFontSize(size) - if err == nil { - m.FontSize.Set(size) - } - default: - return fmt.Errorf("invalid type: %v", ty) - } - return err -} - -func (m *Manager) SetMonitorBackground(monitorName string, imageFile string) *dbus.Error { - logger.Debugf("Set Background '%s' for Monitor '%s'", imageFile, monitorName) - file, err := m.doSetMonitorBackground(monitorName, imageFile) - if err == nil { - idx, err := m.wm.GetCurrentWorkspace(0) - if err == nil { - wsLoop := m.wsLoopMap[genMonitorKeyString(monitorName, int(idx))] - if wsLoop != nil { - wsLoop.AddToShowed(file) - } - } - } - return dbusutil.ToError(err) -} - -func (m *Manager) SetWallpaperSlideShow(monitorName string, wallpaperSlideShow string) *dbus.Error { - logger.Debugf("Set Current Workspace Wallpaper SlideShow '%s' For Monitor '%s'", wallpaperSlideShow, monitorName) - err := m.doSetWallpaperSlideShow(monitorName, wallpaperSlideShow) - return dbusutil.ToError(err) -} - -func (m *Manager) GetWallpaperSlideShow(monitorName string) (slideShow string, busErr *dbus.Error) { - logger.Debugf("Get Current Workspace Wallpaper SlideShow For Monitor '%s'", monitorName) - slideShow, err := m.doGetWallpaperSlideShow(monitorName) - return slideShow, dbusutil.ToError(err) -} - -// Delete delete the special 'name' -func (m *Manager) Delete(ty, name string) *dbus.Error { - logger.Debugf("Delete '%s' type '%s'", name, ty) - err := m.delete(ty, name) - return dbusutil.ToError(err) -} - -func (m *Manager) delete(ty, name string) error { - switch strings.ToLower(ty) { - case TypeGtkTheme: - return subthemes.ListGtkTheme().Delete(name) - case TypeIconTheme: - return subthemes.ListIconTheme().Delete(name) - case TypeCursorTheme: - return subthemes.ListCursorTheme().Delete(name) - case TypeBackground: - return m.listBackground().Delete(name) - //case TypeStandardFont: - //case TypeMonospaceFont: - } - return fmt.Errorf("invalid type: %v", ty) -} - -// Thumbnail get thumbnail for the special 'name' -func (m *Manager) Thumbnail(ty, name string) (file string, busErr *dbus.Error) { - file, err := m.thumbnail(ty, name) - if err != nil { - return "", dbusutil.ToError(err) - } - return file, nil -} - -var gtkThumbnailMap = map[string]string{ - "deepin": "light", - "deepin-dark": "dark", - "deepin-auto": "auto", -} - -func (m *Manager) thumbnail(ty, name string) (string, error) { - logger.Debugf("Get thumbnail for '%s' type '%s'", name, ty) - switch strings.ToLower(ty) { - case TypeGtkTheme: - fName, ok := gtkThumbnailMap[name] - if ok { - return filepath.Join("/usr/share/dde-daemon/appearance", fName+".svg"), nil - } - return subthemes.GetGtkThumbnail(name) - case TypeIconTheme: - return subthemes.GetIconThumbnail(name) - case TypeCursorTheme: - return subthemes.GetCursorThumbnail(name) - } - return "", fmt.Errorf("invalid type: %v", ty) -} - -func (m *Manager) GetScaleFactor() (scaleFactor float64, busErr *dbus.Error) { - return m.getScaleFactor(), nil -} - -func (m *Manager) SetScaleFactor(scale float64) *dbus.Error { - err := m.setScaleFactor(scale) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - return nil -} - -func (m *Manager) SetScreenScaleFactors(v map[string]float64) *dbus.Error { - err := m.setScreenScaleFactors(v) - if err != nil { - logger.Warning(err) - } - return dbusutil.ToError(err) -} - -func (m *Manager) GetScreenScaleFactors() (scaleFactors map[string]float64, busErr *dbus.Error) { - v, err := m.getScreenScaleFactors() - return v, dbusutil.ToError(err) -} diff --git a/appearance/listener.go b/appearance/listener.go deleted file mode 100644 index ffc3b228f..000000000 --- a/appearance/listener.go +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package appearance - -// #cgo pkg-config: gtk+-3.0 -// #cgo CFLAGS: -W -Wall -fstack-protector-all -fPIC -// #include -// #include "cursor.h" -import "C" - -func (*Manager) listenCursorChanged() { - C.handle_gtk_cursor_changed() -} - -func (*Manager) endCursorChangedHandler() { - C.end_cursor_changed_handler() -} diff --git a/appearance/manager.go b/appearance/manager.go deleted file mode 100644 index fd248b555..000000000 --- a/appearance/manager.go +++ /dev/null @@ -1,1714 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package appearance - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "math" - "math/rand" - "os" - "os/user" - "path/filepath" - "regexp" - "strconv" - "strings" - "time" - - "github.com/fsnotify/fsnotify" - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-api/theme_thumb" - accounts "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.accounts" - display "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.display" - imageeffect "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.imageeffect" - sessiontimedate "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.timedate" - sessionmanager "github.com/linuxdeepin/go-dbus-factory/com.deepin.sessionmanager" - wm "github.com/linuxdeepin/go-dbus-factory/com.deepin.wm" - configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" - timedate "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.timedate1" - gio "github.com/linuxdeepin/go-gir/gio-2.0" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/dbusutil/gsprop" - "github.com/linuxdeepin/go-lib/dbusutil/proxy" - "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/go-lib/strv" - dutils "github.com/linuxdeepin/go-lib/utils" - "github.com/linuxdeepin/go-lib/xdg/basedir" - x "github.com/linuxdeepin/go-x11-client" - "github.com/linuxdeepin/go-x11-client/ext/randr" - - "github.com/linuxdeepin/dde-daemon/appearance/background" - "github.com/linuxdeepin/dde-daemon/appearance/fonts" - "github.com/linuxdeepin/dde-daemon/appearance/subthemes" - "github.com/linuxdeepin/dde-daemon/common/dsync" - ddbus "github.com/linuxdeepin/dde-daemon/dbus" - "github.com/linuxdeepin/dde-daemon/session/common" -) - -//go:generate dbusutil-gen em -type Manager - -// The supported types -const ( - TypeGtkTheme = "gtk" - TypeIconTheme = "icon" - TypeCursorTheme = "cursor" - TypeBackground = "background" - TypeGreeterBackground = "greeterbackground" - TypeStandardFont = "standardfont" - TypeMonospaceFont = "monospacefont" - TypeFontSize = "fontsize" - TypeCompactFontSize = "compactfontsize" - TypeDTKSizeMode = "dtksizemode" -) - -const ( - wrapBgSchema = "com.deepin.wrap.gnome.desktop.background" - gnomeBgSchema = "org.gnome.desktop.background" - gsKeyBackground = "picture-uri" - zonePath = "/usr/share/zoneinfo/zone1970.tab" - - appearanceSchema = "com.deepin.dde.appearance" - xSettingsSchema = "com.deepin.xsettings" - gsKeyGtkTheme = "gtk-theme" - gsKeyIconTheme = "icon-theme" - gsKeyCursorTheme = "cursor-theme" - gsKeyFontStandard = "font-standard" - gsKeyFontMonospace = "font-monospace" - gsKeyFontSize = "font-size" - gsKeyCompactFontSize = "compact-font-size" - gsKeyBackgroundURIs = "background-uris" - gsKeyOpacity = "opacity" - gsKeyWallpaperSlideshow = "wallpaper-slideshow" - gsKeyWallpaperURIs = "wallpaper-uris" - gsKeyQtActiveColor = "qt-active-color" - gsKeyDTKWindowRadius = "dtk-window-radius" - gsKeyQtScrollBarPolicy = "qt-scrollbar-policy" - gsKeyDTKSizeMode = "dtk-size-mode" - - propQtActiveColor = "QtActiveColor" - propFontSize = "FontSize" - propDTKSizeMode = "DTKSizeMode" - - wsPolicyLogin = "login" - wsPolicyWakeup = "wakeup" - - defaultIconTheme = "bloom" - defaultGtkTheme = "deepin" - autoGtkTheme = "deepin-auto" - defaultCursorTheme = "bloom" - defaultStandardFont = "Noto Sans" - defaultMonospaceFont = "Noto Mono" - - dbusServiceName = "com.deepin.daemon.Appearance" - dbusPath = "/com/deepin/daemon/Appearance" - dbusInterface = dbusServiceName -) - -// TODO 后续需要设计成用 subpath + 独立的 dconfig 配置来实现,增加可读性 -const ( - dsettingsAppID = "org.deepin.dde.daemon" - dsettingsAppearanceName = "org.deepin.dde.daemon.appearance" - dsettingsIrregularFontOverrideKey = "irregularFontOverride" -) - -var wsConfigFile = filepath.Join(basedir.GetUserConfigDir(), "deepin/dde-daemon/appearance/wallpaper-slideshow.json") - -// Manager shows current themes and fonts settings, emit 'Changed' signal if modified -// if themes list changed will emit 'Refreshed' signal -type Manager struct { - service *dbusutil.Service - sessionSigLoop *dbusutil.SignalLoop - sysSigLoop *dbusutil.SignalLoop - xConn *x.Conn - syncConfig *dsync.Config - bgSyncConfig *dsync.Config - - GtkTheme gsprop.String - IconTheme gsprop.String - CursorTheme gsprop.String - Background gsprop.String - StandardFont gsprop.String - MonospaceFont gsprop.String - Opacity gsprop.Double `prop:"access:rw"` - FontSize gsprop.Double `prop:"access:rw"` - WallpaperSlideShow gsprop.String `prop:"access:rw"` - WallpaperURIs gsprop.String - QtActiveColor string `prop:"access:rw"` - // 社区版定制需求,保存窗口圆角值,默认 18 - WindowRadius gsprop.Int `prop:"access:rw"` - QtScrollBarPolicy gsprop.Int `prop:"access:rw"` - DTKSizeMode gsprop.Int `prop:"access:rw"` - - wsLoopMap map[string]*WSLoop - wsSchedulerMap map[string]*WSScheduler - monitorMap map[string]string - coordinateMap map[string]*coordinate - - userObj accounts.User - imageBlur accounts.ImageBlur - timeDate timedate.Timedate - sessionTimeDate sessiontimedate.Timedate - imageEffect imageeffect.ImageEffect - xSettings sessionmanager.XSettings - login1Manager login1.Manager - themeAutoTimer *time.Timer - display display.Display - latitude float64 - longitude float64 - locationValid bool - detectSysClockTimer *time.Timer - ts int64 - loc *time.Location - - setting *gio.Settings - xSettingsGs *gio.Settings - wrapBgSetting *gio.Settings - gnomeBgSetting *gio.Settings - - watcher *fsnotify.Watcher - endWatcher chan struct{} - - desktopBgs []string - greeterBg string - curMonitorSpace string - wm wm.Wm - - //nolint - signals *struct { - // Theme setting changed - Changed struct { - type0 string - value string - } - - // Theme list refreshed - Refreshed struct { - type0 string - } - } -} - -type mapMonitorWorkspaceWSPolicy map[string]string -type mapMonitorWorkspaceWSConfig map[string]WSConfig -type mapMonitorWorkspaceWallpaperURIs map[string]string - -type coordinate struct { - latitude, longitude float64 -} - -// NewManager will create a 'Manager' object -func newManager(service *dbusutil.Service) *Manager { - var m = new(Manager) - m.service = service - m.setting = gio.NewSettings(appearanceSchema) - m.xSettingsGs = gio.NewSettings(xSettingsSchema) - m.wrapBgSetting = gio.NewSettings(wrapBgSchema) - - m.GtkTheme.Bind(m.setting, gsKeyGtkTheme) - m.IconTheme.Bind(m.setting, gsKeyIconTheme) - m.CursorTheme.Bind(m.setting, gsKeyCursorTheme) - m.StandardFont.Bind(m.setting, gsKeyFontStandard) - m.MonospaceFont.Bind(m.setting, gsKeyFontMonospace) - m.Background.Bind(m.wrapBgSetting, gsKeyBackground) - m.Opacity.Bind(m.setting, gsKeyOpacity) - m.WallpaperSlideShow.Bind(m.setting, gsKeyWallpaperSlideshow) - m.WallpaperURIs.Bind(m.setting, gsKeyWallpaperURIs) - // 社区版定制需求 保存窗口圆角值 - m.WindowRadius.Bind(m.xSettingsGs, gsKeyDTKWindowRadius) - m.QtScrollBarPolicy.Bind(m.xSettingsGs, gsKeyQtScrollBarPolicy) - m.DTKSizeMode.Bind(m.setting, gsKeyDTKSizeMode) - - var err error - m.QtActiveColor, err = m.getQtActiveColor() - if err != nil { - logger.Warning(err) - } - - if m.isHasDTKSizeModeKey() && (m.DTKSizeMode.Get() == 1) { - m.FontSize.Bind(m.setting, gsKeyCompactFontSize) - } else { - m.FontSize.Bind(m.setting, gsKeyFontSize) - } - - m.wsLoopMap = make(map[string]*WSLoop) - m.wsSchedulerMap = make(map[string]*WSScheduler) - m.coordinateMap = make(map[string]*coordinate) - - m.initCoordinate() - - m.gnomeBgSetting, _ = dutils.CheckAndNewGSettings(gnomeBgSchema) - - m.watcher, err = fsnotify.NewWatcher() - if err != nil { - logger.Warning("New file watcher failed:", err) - } else { - m.endWatcher = make(chan struct{}) - } - - return m -} - -func getLicenseAuthorizationProperty(conn *dbus.Conn) uint32 { - var variant dbus.Variant - err := conn.Object("com.deepin.license", "/com/deepin/license/Info").Call( - "org.freedesktop.DBus.Properties.Get", 0, "com.deepin.license.Info", "AuthorizationProperty").Store(&variant) - if err != nil { - logger.Warning(err) - return 0 - } - if variant.Signature().String() != "u" { - logger.Warning("not excepted value type") - return 0 - } - ret := variant.Value().(uint32) - logger.Debug(" [getLicenseAuthorizationProperty] com.deepin.license.Info.AuthorizationProperty : ", ret) - return ret -} - -func listenLicenseInfoDBusPropChanged(conn *dbus.Conn, sigLoop *dbusutil.SignalLoop) { - err := conn.Object("com.deepin.license.Info", - "/com/deepin/license/Info").AddMatchSignal("com.deepin.license.Info", "LicenseStateChange").Err - if err != nil { - logger.Warning(err) - return - } - - sigLoop.AddHandler(&dbusutil.SignalRule{ - Name: "com.deepin.license.Info.LicenseStateChange", - }, func(sig *dbus.Signal) { - if strings.Contains(string(sig.Name), "com.deepin.license.Info.LicenseStateChange") { - go func() { - licenseState := getLicenseAuthorizationProperty(conn) - background.SetLicenseAuthorizationProperty(licenseState) - background.UpdateLicenseAuthorizationProperty() - logger.Info("[listenLicenseInfoDBusPropChanged] com.deepin.license.Info.LicenseStateChange : ", licenseState) - }() - } - }) -} - -func (m *Manager) initCurrentBgs() { - m.desktopBgs = m.getBackgroundURIs() - - if m.userObj == nil { - return - } - greeterBg, err := m.userObj.GreeterBackground().Get(0) - if err == nil { - m.greeterBg = greeterBg - } else { - logger.Warning(err) - } -} - -func (m *Manager) getBackgroundURIs() []string { - return m.setting.GetStrv(gsKeyBackgroundURIs) -} - -func (m *Manager) isBgInUse(file string) bool { - if file == m.greeterBg { - return true - } - // 检查所有的工作区的屏幕壁纸是否占用 - mapWallpaperURIs, err := doUnmarshalMonitorWorkspaceWallpaperURIs(m.WallpaperURIs.Get()) - if err != nil { - logger.Error(err) - return false - } - for _, bg := range mapWallpaperURIs { - if file == bg { - return true - } - } - - return false -} - -func (m *Manager) listBackground() background.Backgrounds { - origin := background.ListBackground() - result := make(background.Backgrounds, len(origin)) - - for idx, bg := range origin { - var deletable bool - if bg.Deletable { - // custom - if !m.isBgInUse(bg.Id) { - deletable = true - } - } - result[idx] = &background.Background{ - Id: bg.Id, - Deletable: deletable, - } - } - return result -} - -func (m *Manager) destroy() { - m.sessionSigLoop.Stop() - m.xSettings.RemoveHandler(proxy.RemoveAllHandlers) - m.syncConfig.Destroy() - m.bgSyncConfig.Destroy() - - m.sysSigLoop.Stop() - m.login1Manager.RemoveHandler(proxy.RemoveAllHandlers) - for iSche := range m.wsSchedulerMap { - m.wsSchedulerMap[iSche].stop() - } - - if m.setting != nil { - m.setting.Unref() - m.setting = nil - } - - if m.wrapBgSetting != nil { - m.wrapBgSetting.Unref() - m.wrapBgSetting = nil - } - - if m.gnomeBgSetting != nil { - m.gnomeBgSetting.Unref() - m.gnomeBgSetting = nil - } - - if m.watcher != nil { - close(m.endWatcher) - err := m.watcher.Close() - if err != nil { - logger.Warning(err) - } - m.watcher = nil - } - - if m.xConn != nil { - m.xConn.Close() - m.xConn = nil - } - - m.endCursorChangedHandler() -} - -// resetFonts reset StandardFont and MonospaceFont -func (m *Manager) resetFonts() { - err := fonts.Reset() - if err != nil { - logger.Debug("ResetFonts failed", err) - return - } - m.checkFontConfVersion() -} - -func (m *Manager) initUserObj(systemConn *dbus.Conn) { - cur, err := user.Current() - if err != nil { - logger.Warning("failed to get current user:", err) - return - } - - err = common.ActivateSysDaemonService("com.deepin.daemon.Accounts") - if err != nil { - logger.Warning(err) - } - - m.userObj, err = ddbus.NewUserByUid(systemConn, cur.Uid) - if err != nil { - logger.Warning("failed to new user object:", err) - return - } - - // sync desktop backgrounds - userBackgrounds, err := m.userObj.DesktopBackgrounds().Get(0) - if err != nil { - logger.Warning(err) - return - } - - gsBackgrounds := m.setting.GetStrv(gsKeyBackgroundURIs) - if !strv.Strv(userBackgrounds).Equal(gsBackgrounds) { - m.setDesktopBackgrounds(gsBackgrounds) - } -} - -func (m *Manager) init() error { - background.SetCustomWallpaperDeleteCallback(func(file string) { - logger.Debug("imageBlur delete", file) - err := m.imageBlur.Delete(0, file) - if err != nil { - logger.Warning("imageBlur delete err:", err) - } - - logger.Debug("imageEffect delete", file) - err = m.imageEffect.Delete(0, "all", file) - if err != nil { - logger.Warning("imageEffect delete err:", err) - } - }) - - sessionBus := m.service.Conn() - systemBus, err := dbus.SystemBus() - if err != nil { - return err - } - go background.SetLicenseAuthorizationProperty(getLicenseAuthorizationProperty(systemBus)) - m.xConn, err = x.NewConn() - if err != nil { - return err - } - - _, err = randr.QueryVersion(m.xConn, randr.MajorVersion, - randr.MinorVersion).Reply(m.xConn) - if err != nil { - logger.Warning(err) - } - - m.sessionSigLoop = dbusutil.NewSignalLoop(sessionBus, 10) - m.sessionSigLoop.Start() - - m.wm = wm.NewWm(sessionBus) - m.wm.InitSignalExt(m.sessionSigLoop, true) - _, err = m.wm.ConnectWorkspaceCountChanged(m.handleWmWorkspaceCountChanged) - if err != nil { - logger.Warning(err) - } - _, err = m.wm.ConnectWorkspaceSwitched(m.handleWmWorkspaceSwithched) - if err != nil { - logger.Warning(err) - } - m.imageBlur = accounts.NewImageBlur(systemBus) - m.imageEffect = imageeffect.NewImageEffect(systemBus) - - m.xSettings = sessionmanager.NewXSettings(sessionBus) - theme_thumb.Init(m.getScaleFactor()) - - m.xSettings.InitSignalExt(m.sessionSigLoop, true) - _, err = m.xSettings.ConnectSetScaleFactorStarted(handleSetScaleFactorStarted) - if err != nil { - logger.Warning(err) - } - _, err = m.xSettings.ConnectSetScaleFactorDone(handleSetScaleFactorDone) - if err != nil { - logger.Warning(err) - } - - m.initUserObj(systemBus) - background.NotifyFunc = func(type0, value string) { - m.emitSignalChanged(type0, value) - } - m.initCurrentBgs() - m.display = display.NewDisplay(sessionBus) - m.display.InitSignalExt(m.sessionSigLoop, true) - err = m.display.Monitors().ConnectChanged(func(hasValue bool, value []dbus.ObjectPath) { - m.handleDisplayChanged(hasValue) - }) - if err != nil { - logger.Warning("failed to connect Monitors changed:", err) - } - err = m.display.Primary().ConnectChanged(func(hasValue bool, value string) { - m.handleDisplayChanged(hasValue) - }) - if err != nil { - logger.Warning("failed to connect Primary changed:", err) - } - m.updateMonitorMap() - m.syncConfig = dsync.NewConfig("appearance", &syncConfig{m: m}, m.sessionSigLoop, dbusPath, logger) - m.bgSyncConfig = dsync.NewConfig("background", &backgroundSyncConfig{m: m}, m.sessionSigLoop, - backgroundDBusPath, logger) - - m.sysSigLoop = dbusutil.NewSignalLoop(systemBus, 10) - m.sysSigLoop.Start() - m.login1Manager = login1.NewManager(systemBus) - m.login1Manager.InitSignalExt(m.sysSigLoop, true) - if m.WallpaperURIs.Get() == "" { // 壁纸设置更新为v2.0版本,但是数据依旧为v1.0的数据 - err := m.updateNewVersionData() - if err != nil { - logger.Warning(err) - } - } - m.initWallpaperSlideshow() - - m.timeDate = timedate.NewTimedate(systemBus) - m.timeDate.InitSignalExt(m.sysSigLoop, true) - - listenLicenseInfoDBusPropChanged(systemBus, m.sysSigLoop) - - m.sessionTimeDate = sessiontimedate.NewTimedate(sessionBus) - m.sessionTimeDate.InitSignalExt(m.sessionSigLoop, true) - - zone, err := m.timeDate.Timezone().Get(0) - if err != nil { - logger.Warning("Get Timezone Failed:", err) - } - l, err := time.LoadLocation(zone) - if err != nil { - logger.Warning("LoadLocation Failed :", err) - } - m.loc = l - err = m.timeDate.Timezone().ConnectChanged(func(hasValue bool, value string) { - if err != nil { - logger.Warning(err) - } - for ct, coordinate := range m.coordinateMap { - if value == ct { - m.longitude = coordinate.longitude - m.latitude = coordinate.latitude - } - } - l, err := time.LoadLocation(value) - if err != nil { - logger.Warning("LoadLocation Failed :", err) - } - m.loc = l - logger.Debug("value", value, m.longitude, m.latitude) - if m.GtkTheme.Get() == autoGtkTheme { - m.autoSetTheme(m.latitude, m.longitude) - m.resetThemeAutoTimer() - } - }) - - if err != nil { - logger.Warning(err) - } - - //修改时间后通过信号通知自动改变主题 - _, err = m.sessionTimeDate.ConnectTimeUpdate(func() { - time.AfterFunc(2*time.Second, m.handleSysClockChanged) - }) - if err != nil { - logger.Warning("connect signal TimeUpdate failed:", err) - } - err = m.timeDate.NTP().ConnectChanged(func(hasValue bool, value bool) { - time.AfterFunc(2*time.Second, m.handleSysClockChanged) - }) - if err != nil { - logger.Warning("connect NTP failed:", err) - } - - // set gtk theme - gtkThemes := subthemes.ListGtkTheme() - currentGtkTheme := m.GtkTheme.Get() - - if currentGtkTheme == autoGtkTheme { - m.updateThemeAuto(true) - } else { - gtkTheme := defaultGtkTheme - if gtkThemes.Get(currentGtkTheme) != nil { - gtkTheme = currentGtkTheme - } - m.GtkTheme.Set(gtkTheme) - err = m.doSetGtkTheme(gtkTheme) - if err != nil { - logger.Warning("failed to set gtk theme:", err) - } - } - - // set icon theme - iconThemes := subthemes.ListIconTheme() - currentIconTheme := m.IconTheme.Get() - if iconThemes.Get(currentIconTheme) == nil { - m.IconTheme.Set(defaultIconTheme) - currentIconTheme = defaultIconTheme - } - err = m.doSetIconTheme(currentIconTheme) - if err != nil { - logger.Warning("failed to set icon theme:", err) - } - - // set cursor theme - cursorThemes := subthemes.ListCursorTheme() - currentCursorTheme := m.CursorTheme.Get() - if cursorThemes.Get(currentCursorTheme) == nil { - m.CursorTheme.Set(defaultCursorTheme) - currentCursorTheme = defaultCursorTheme - } - err = m.doSetCursorTheme(currentCursorTheme) - if err != nil { - logger.Warning("failed to set cursor theme:", err) - } - - // Init IrregularFontWhiteList - m.initAppearanceDSettings() - return nil -} - -// initFont 初始化字体设置 -func (m *Manager) initFont() { - value := fonts.FcFont_Match("system-ui") - if m.StandardFont.Get() != value { - m.StandardFont.Set(value) - err := m.xSettings.SetString(0, "Qt/FontName", value) - if err != nil { - logger.Warning("failed to set xsetting Qt/FontName:", err) - } - } - value = fonts.FcFont_Match("monospace") - if m.MonospaceFont.Get() != value { - m.MonospaceFont.Set(value) - err := m.xSettings.SetString(0, "Qt/MonoFontName", value) - if err != nil { - logger.Warning("failed to set xsetting Qt/MonoFontName:", err) - } - } - - err := setDQtTheme(dQtFile, dQtSectionTheme, - []string{ - dQtKeyIcon, - dQtKeyFont, - dQtKeyMonoFont, - dQtKeyFontSize}, - []string{ - m.IconTheme.Get(), - m.StandardFont.Get(), - m.MonospaceFont.Get(), - strconv.FormatFloat(m.FontSize.Get(), 'f', 1, 64)}) - if err != nil { - logger.Warning("failed to set deepin qt theme:", err) - } - err = saveDQtTheme(dQtFile) - if err != nil { - logger.Warning("Failed to save deepin qt theme:", err) - } -} - -func (m *Manager) handleDisplayChanged(hasValue bool) { - if !hasValue { - return - } - m.updateMonitorMap() - err := m.doUpdateWallpaperURIs() - m.updateGreeterBackground() - if err != nil { - logger.Warning("failed to update WallpaperURIs:", err) - } -} - -func (m *Manager) handleWmWorkspaceCountChanged(count int32) { - logger.Debug("wm workspace count changed", count) - bgs := m.setting.GetStrv(gsKeyBackgroundURIs) - if len(bgs) < int(count) { - allBgs := background.ListBackground() - - numAdded := int(count) - len(bgs) - for i := 0; i < numAdded; i++ { - idx := rand.Intn(len(allBgs)) // #nosec G404 - // Id is file url - bgs = append(bgs, allBgs[idx].Id) - } - m.setting.SetStrv(gsKeyBackgroundURIs, bgs) - } else if len(bgs) > int(count) { - bgs = bgs[:int(count)] - m.setting.SetStrv(gsKeyBackgroundURIs, bgs) - } - err := m.doUpdateWallpaperURIs() - if err != nil { - logger.Warning("failed to update WallpaperURIs:", err) - } -} - -// 同步当前主屏的壁纸到greeter界面壁纸 -func (m *Manager) updateGreeterBackground() { - for item, _ := range m.monitorMap { - if m.monitorMap[item] == "Primary" { - bg, err := m.wm.GetCurrentWorkspaceBackgroundForMonitor(0, item) - if err != nil { - logger.Warning("get current background failed", err) - return - } - err = m.doSetGreeterBackground(bg) - if err != nil { - logger.Warning("set greeter background failed", err) - return - } - return - } - } -} - -// 切换工作区 -func (m *Manager) handleWmWorkspaceSwithched(from, to int32) { - logger.Debugf("wm workspace switched from %d to %d", from, to) - if m.userObj != nil { - err := m.userObj.SetCurrentWorkspace(0, to) - if err != nil { - logger.Warning("call userObj.SetCurrentWorkspace err:", err) - } - } - // 切换工作区,需要同步当前主屏的壁纸到greeter界面壁纸 - m.updateGreeterBackground() -} - -func (m *Manager) doSetGtkTheme(value string) error { - if value == autoGtkTheme { - return nil - } - if !subthemes.IsGtkTheme(value) { - return fmt.Errorf("invalid gtk theme '%v'", value) - } - - // set dde-kwin decoration theme - var ddeKWinTheme string - switch value { - case "deepin": - ddeKWinTheme = "light" - case "deepin-dark": - ddeKWinTheme = "dark" - } - if ddeKWinTheme != "" { - err := m.wm.SetDecorationDeepinTheme(0, ddeKWinTheme) - if err != nil { - logger.Warning(err) - } - } - - return subthemes.SetGtkTheme(value) -} - -func (m *Manager) doSetIconTheme(value string) error { - if !subthemes.IsIconTheme(value) { - return fmt.Errorf("invalid icon theme '%v'", value) - } - - err := subthemes.SetIconTheme(value) - if err != nil { - return err - } - - return m.writeDQtTheme(dQtKeyIcon, value) -} - -func (m *Manager) doSetCursorTheme(value string) error { - if !subthemes.IsCursorTheme(value) { - return fmt.Errorf("invalid cursor theme '%v'", value) - } - - return subthemes.SetCursorTheme(value) -} - -func (m *Manager) doSetMonitorBackground(monitorName string, imageFile string) (string, error) { - logger.Debugf("call doSetMonitorBackground monitor:%q file:%q", monitorName, imageFile) - file, t := background.GetWallpaperType(imageFile) - if t == background.Unknown { - return "", errors.New("invalid background") - } - // 如果设置的壁纸不是/usr/share/wallpapers/下的,则认为是用户自定义壁纸,需要发送add信号 - needNotify := false - if !strings.HasPrefix(file, "/usr/share/wallpapers/") { - needNotify = true - } - file, err := background.Prepare(file, t) - if err != nil { - logger.Warning("failed to prepare:", err) - return "", err - } - logger.Debug("prepare result:", file) - uri := dutils.EncodeURI(file, dutils.SCHEME_FILE) - err = m.wm.SetCurrentWorkspaceBackgroundForMonitor(0, uri, monitorName) - if err != nil { - return "", err - } - - // 如果文件发生增删,发送add/delete的信号 - if needNotify { - // 由于用户操作,统一将用户自定义设置的壁纸当做新的壁纸处理,发送新增信号,告知上层 - m.emitSignalChanged("background-add", file) - // 在此处理删除操作 - background.NotifyChanged() - } - err = m.doUpdateWallpaperURIs() - if err != nil { - logger.Warning("failed to update WallpaperURIs:", err) - } - _, err = m.imageBlur.Get(0, file) - if err != nil { - logger.Warning("call imageBlur.Get err:", err) - } - go func() { - outputFile, err := m.imageEffect.Get(0, "", file) - if err != nil { - logger.Warning("imageEffect Get err:", err) - } else { - logger.Warning("imageEffect Get outputFile:", outputFile) - } - }() - return file, nil -} - -func (m *Manager) updateMonitorMap() { - monitorList, _ := m.display.ListOutputNames(0) - primary, _ := m.display.Primary().Get(0) - index := 0 - m.monitorMap = make(map[string]string) - for _, item := range monitorList { - if item == primary { - m.monitorMap[item] = "Primary" - } else { - m.monitorMap[item] = "Subsidiary" + strconv.Itoa(index) - index++ - } - } -} - -func (m *Manager) reverseMonitorMap() map[string]string { - reverseMap := make(map[string]string) - for k, v := range m.monitorMap { - reverseMap[v] = k - } - return reverseMap -} - -func (m *Manager) doUpdateWallpaperURIs() error { - mapWallpaperURIs := make(mapMonitorWorkspaceWallpaperURIs) - workspaceCount, _ := m.wm.WorkspaceCount(0) - monitorList, _ := m.display.ListOutputNames(0) - for _, monitor := range monitorList { - for idx := int32(1); idx <= workspaceCount; idx++ { - wallpaperURI, err := m.wm.GetWorkspaceBackgroundForMonitor(0, idx, monitor) - if err != nil { - logger.Warning("get wallpaperURI failed:", err) - continue - } - key := genMonitorKeyString(m.monitorMap[monitor], int(idx)) - mapWallpaperURIs[key] = wallpaperURI - } - } - - err := m.setPropertyWallpaperURIs(mapWallpaperURIs) - if err != nil { - return err - } - return nil -} - -func doUnmarshalMonitorWorkspaceWallpaperURIs(jsonString string) (mapMonitorWorkspaceWallpaperURIs, error) { - var cfg mapMonitorWorkspaceWallpaperURIs - var byteMonitorWorkspaceWallpaperURIs = []byte(jsonString) - err := json.Unmarshal(byteMonitorWorkspaceWallpaperURIs, &cfg) - return cfg, err -} - -func doMarshalMonitorWorkspaceWallpaperURIs(cfg mapMonitorWorkspaceWallpaperURIs) (string, error) { - data, err := json.Marshal(cfg) - if err != nil { - return "", err - } - return string(data), err -} - -func (m *Manager) setPropertyWallpaperURIs(cfg mapMonitorWorkspaceWallpaperURIs) error { - uris, err := doMarshalMonitorWorkspaceWallpaperURIs(cfg) - if err != nil { - logger.Warning(err) - return err - } - m.WallpaperURIs.Set(uris) - return nil -} - -func doUnmarshalWallpaperSlideshow(jsonString string) (mapMonitorWorkspaceWSPolicy, error) { - var cfg mapMonitorWorkspaceWSPolicy - var byteWallpaperSlideShow []byte = []byte(jsonString) - err := json.Unmarshal(byteWallpaperSlideShow, &cfg) - return cfg, err -} - -func doMarshalWallpaperSlideshow(cfg mapMonitorWorkspaceWSPolicy) (string, error) { - data, err := json.Marshal(cfg) - if err != nil { - return "", err - } - return string(data), err -} - -func (m *Manager) setPropertyWallpaperSlideShow(cfg mapMonitorWorkspaceWSPolicy) error { - slideshow, err := doMarshalWallpaperSlideshow(cfg) - if err != nil { - logger.Warning(err) - return err - } - m.WallpaperSlideShow.Set(slideshow) - return nil -} - -func (m *Manager) doSetWallpaperSlideShow(monitorName string, wallpaperSlideShow string) error { - idx, err := m.wm.GetCurrentWorkspace(0) - if err != nil { - logger.Warning("Get Current Workspace failure:", err) - return err - } - cfg, err := doUnmarshalWallpaperSlideshow(m.WallpaperSlideShow.Get()) - if err != nil { - logger.Warning("doUnmarshalWallpaperSlideshow Failed:", err) - } - if cfg == nil { - cfg = make(mapMonitorWorkspaceWSPolicy) - } - - key := genMonitorKeyString(monitorName, int(idx)) - cfg[key] = wallpaperSlideShow - err = m.setPropertyWallpaperSlideShow(cfg) - if err != nil { - return err - } - m.curMonitorSpace = key - return nil -} - -func (m *Manager) doGetWallpaperSlideShow(monitorName string) (string, error) { - idx, err := m.wm.GetCurrentWorkspace(0) - if err != nil { - logger.Warning("Get Current Workspace failure:", err) - return "", err - } - cfg, err := doUnmarshalWallpaperSlideshow(m.WallpaperSlideShow.Get()) - if err != nil { - return "", nil - } - key := genMonitorKeyString(monitorName, int(idx)) - wallpaperSlideShow := cfg[key] - return wallpaperSlideShow, nil -} - -func (m *Manager) doSetBackground(value string) (string, error) { - logger.Debugf("call doSetBackground %q", value) - file, t := background.GetWallpaperType(value) - if t == background.Unknown { - return "", errors.New("invalid background") - } - - // 如果设置的壁纸不是/usr/share/wallpapers/下的,则认为是用户自定义壁纸,需要发送add信号 - needNotify := false - if !strings.HasPrefix(file, "/usr/share/wallpapers/") { - needNotify = true - } - file, err := background.Prepare(file, t) - if err != nil { - logger.Warning("failed to prepare:", err) - return "", err - } - logger.Debug("prepare result:", file) - uri := dutils.EncodeURI(file, dutils.SCHEME_FILE) - err = m.wm.ChangeCurrentWorkspaceBackground(0, uri) - if err != nil { - return "", err - } - // 如果文件发生增删,发送add/delete的信号 - if needNotify { - // 由于用户操作,统一将用户自定义设置的壁纸当做新的壁纸处理,发送新增信号,告知上层 - m.emitSignalChanged("background-add", file) - // 在此处理删除操作 - background.NotifyChanged() - } - _, err = m.imageBlur.Get(0, file) - if err != nil { - logger.Warning("call imageBlur.Get err:", err) - } - go func() { - outputFile, err := m.imageEffect.Get(0, "", file) - if err != nil { - logger.Warning("imageEffect Get err:", err) - } else { - logger.Warning("imageEffect Get outputFile:", outputFile) - } - }() - - return file, nil -} - -func (m *Manager) doSetGreeterBackground(value string) error { - logger.Debugf("call doSetGreeterBackground file:%q", value) - file, t := background.GetWallpaperType(value) - if t == background.Unknown { - return errors.New("invalid background") - } - - file, err := background.Prepare(file, t) - if err != nil { - logger.Warning("failed to prepare:", err) - return err - } - file = dutils.EncodeURI(file, dutils.SCHEME_FILE) - m.greeterBg = file - if m.userObj == nil { - return errors.New("user object is nil") - } - logger.Debug("set greeter background:", file) - return m.userObj.SetGreeterBackground(0, file) -} - -func (m *Manager) doSetStandardFont(value string) error { - if !fonts.IsFontFamily(value) { - return fmt.Errorf("invalid font family '%v'", value) - } - - monoFont := m.MonospaceFont.Get() - if !fonts.IsFontFamily(monoFont) { - monoList := fonts.GetFamilyTable().ListMonospace() - if len(monoList) == 0 { - return fmt.Errorf("no valid mono font") - } - monoFont = monoList[0] - } - - err := fonts.SetFamily(value, monoFont, m.FontSize.Get()) - if err != nil { - return err - } - - err = m.xSettings.SetString(0, "Qt/FontName", value) - if err != nil { - return err - } - - return m.writeDQtTheme(dQtKeyFont, value) -} - -func (m *Manager) doSetMonospaceFont(value string) error { - if !fonts.IsFontFamily(value) { - return fmt.Errorf("invalid font family '%v'", value) - } - - standardFont := m.StandardFont.Get() - if !fonts.IsFontFamily(standardFont) { - standardList := fonts.GetFamilyTable().ListStandard() - if len(standardList) == 0 { - return fmt.Errorf("no valid standard font") - } - standardFont = standardList[0] - } - - err := fonts.SetFamily(standardFont, value, m.FontSize.Get()) - if err != nil { - return err - } - - err = m.xSettings.SetString(0, "Qt/MonoFontName", value) - if err != nil { - return err - } - - return m.writeDQtTheme(dQtKeyMonoFont, value) -} - -func (m *Manager) doSetFontSize(size float64) error { - if !fonts.IsFontSizeValid(size) { - logger.Debug("[doSetFontSize] invalid size:", size) - return fmt.Errorf("invalid font size '%v'", size) - } - - err := fonts.SetFamily(m.StandardFont.Get(), m.MonospaceFont.Get(), size) - if err != nil { - return err - } - - err = m.xSettings.SetString(0, "Qt/FontPointSize", - strconv.FormatFloat(size, 'f', -1, 64)) - if err != nil { - return err - } - - return m.writeDQtTheme(dQtKeyFontSize, strconv.FormatFloat(size, 'f', 1, 64)) -} - -func (m *Manager) doSetDTKSizeMode(enabled int32) error { - err := m.xSettings.SetInteger(0, "DTK/SizeMode", enabled) - return err -} - -func (m *Manager) isHasDTKSizeModeKey() bool { - return m.setting.GetSchema().HasKey(gsKeyDTKSizeMode) -} - -func (*Manager) doShow(ifc interface{}) (string, error) { - if ifc == nil { - return "", fmt.Errorf("not found target") - } - content, err := json.Marshal(ifc) - return string(content), err -} - -func (m *Manager) writeDQtTheme(key, value string) error { - err := setDQtTheme(dQtFile, dQtSectionTheme, - []string{key}, []string{value}) - if err != nil { - logger.Warning("failed to set deepin qt theme:", err) - } - return saveDQtTheme(dQtFile) -} - -func (m *Manager) setDesktopBackgrounds(val []string) { - if m.userObj != nil { - err := m.userObj.SetDesktopBackgrounds(0, val) - if err != nil { - logger.Warning("call userObj.SetDesktopBackgrounds err:", err) - } - } -} - -func (*Manager) GetInterfaceName() string { - return dbusInterface -} - -func (m *Manager) saveWSConfig(monitorSpace string, t time.Time) error { - cfg, _ := loadWSConfig(wsConfigFile) - var tempCfg WSConfig - tempCfg.LastChange = t - if m.wsLoopMap[monitorSpace] != nil { - tempCfg.Showed = m.wsLoopMap[monitorSpace].GetShowed() - } - if cfg == nil { - cfg = make(mapMonitorWorkspaceWSConfig) - } - cfg[monitorSpace] = tempCfg - return cfg.save(wsConfigFile) -} - -func (m *Manager) autoChangeBg(monitorSpace string, t time.Time) { - logger.Debug("autoChangeBg", monitorSpace, t) - if m.wsLoopMap[monitorSpace] == nil { - return - } - idx, err := m.wm.GetCurrentWorkspace(0) - if err != nil { - logger.Warning(err) - } - strIdx := strconv.Itoa(int(idx)) - splitter := strings.Index(monitorSpace, "&&") - if splitter == -1 { - logger.Warning("monitorSpace format error") - return - } - if strIdx == monitorSpace[splitter+len("&&"):] { - monitorname := monitorSpace[:splitter] - // 获取当前monitor的wallpaper,check是否是纯色壁纸 - currentURI, err := m.wm.GetWorkspaceBackgroundForMonitor(0, idx, monitorname) - if err != nil { - logger.Warning("get wallpaperURI failed:", err) - return - } - _, t := background.GetWallpaperType(currentURI) - file := m.wsLoopMap[monitorSpace].GetNext(t) - if file == "" { - logger.Warning("file is empty") - return - } - _, err = m.doSetMonitorBackground(monitorname, file) - if m.monitorMap[monitorname] == "Primary" { - m.updateGreeterBackground() - } - if err != nil { - logger.Warning("failed to set background:", err) - } - } - err = m.saveWSConfig(monitorSpace, t) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) initWallpaperSlideshow() { - m.loadWSConfig() - cfg, err := doUnmarshalWallpaperSlideshow(m.WallpaperSlideShow.Get()) - if err == nil { - for monitorSpace, policy := range cfg { - _, ok := m.wsSchedulerMap[monitorSpace] - if !ok { - m.wsSchedulerMap[monitorSpace] = newWSScheduler(m.autoChangeBg) - } - _, ok = m.wsLoopMap[monitorSpace] - if !ok { - m.wsLoopMap[monitorSpace] = newWSLoop() - } - if isValidWSPolicy(policy) { - if policy == wsPolicyLogin { - err := m.changeBgAfterLogin(monitorSpace) - if err != nil { - logger.Warning("failed to change background after login:", err) - } - } else { - nSec, err := strconv.ParseUint(policy, 10, 32) - if err == nil && m.wsSchedulerMap[monitorSpace] != nil { - m.wsSchedulerMap[monitorSpace].updateInterval(monitorSpace, time.Duration(nSec)*time.Second) - } - } - } - } - } else { - logger.Debug("doUnmarshalWallpaperSlideshow err is ", err) - } -} - -func (m *Manager) changeBgAfterLogin(monitorSpace string) error { - runDir, err := basedir.GetUserRuntimeDir(true) - if err != nil { - return err - } - - currentSessionId, err := getSessionId("/proc/self/sessionid") - if err != nil { - return err - } - - var needChangeBg bool - markFile := filepath.Join(runDir, "dde-daemon-wallpaper-slideshow-login"+monitorSpace) - sessionId, err := getSessionId(markFile) - if err == nil { - if sessionId != currentSessionId { - needChangeBg = true - } - } else if os.IsNotExist(err) { - needChangeBg = true - } else if err != nil { - return err - } - - if needChangeBg { - m.autoChangeBg(monitorSpace, time.Now()) - err = ioutil.WriteFile(markFile, []byte(currentSessionId), 0644) - if err != nil { - return err - } - } - return nil -} - -func getSessionId(filename string) (string, error) { - content, err := ioutil.ReadFile(filename) - if err != nil { - return "", err - } - return string(bytes.TrimSpace(content)), nil -} - -func (m *Manager) loadWSConfig() { - cfg := loadWSConfigSafe(wsConfigFile) - for monitorSpace := range cfg { - _, ok := m.wsSchedulerMap[monitorSpace] - if !ok { - m.wsSchedulerMap[monitorSpace] = newWSScheduler(m.autoChangeBg) - } - m.wsSchedulerMap[monitorSpace].mu.Lock() - m.wsSchedulerMap[monitorSpace].lastSetBg = cfg[monitorSpace].LastChange - m.wsSchedulerMap[monitorSpace].mu.Unlock() - - _, ok = m.wsLoopMap[monitorSpace] - if !ok { - m.wsLoopMap[monitorSpace] = newWSLoop() - } - m.wsLoopMap[monitorSpace].mu.Lock() - for _, file := range cfg[monitorSpace].Showed { - m.wsLoopMap[monitorSpace].showed[file] = struct{}{} - } - m.wsLoopMap[monitorSpace].mu.Unlock() - } -} - -func (m *Manager) updateWSPolicy(policy string) { - cfg, err := doUnmarshalWallpaperSlideshow(policy) - m.loadWSConfig() - if err == nil { - for monitorSpace, policy := range cfg { - _, ok := m.wsSchedulerMap[monitorSpace] - if !ok { - m.wsSchedulerMap[monitorSpace] = newWSScheduler(m.autoChangeBg) - } - _, ok = m.wsLoopMap[monitorSpace] - if !ok { - m.wsLoopMap[monitorSpace] = newWSLoop() - } - if m.curMonitorSpace == monitorSpace && isValidWSPolicy(policy) { - nSec, err := strconv.ParseUint(policy, 10, 32) - if err == nil { - m.wsSchedulerMap[monitorSpace].lastSetBg = time.Now() - m.wsSchedulerMap[monitorSpace].updateInterval(monitorSpace, time.Duration(nSec)*time.Second) - err = m.saveWSConfig(monitorSpace, time.Now()) - if err != nil { - logger.Warning(err) - } - } else { - m.wsSchedulerMap[monitorSpace].stop() - } - } - } - } -} - -func (m *Manager) enableDetectSysClock(enabled bool) { - nSec := 60 // 1 min - if logger.GetLogLevel() == log.LevelDebug { - // debug mode: 10 s - nSec = 10 - } - interval := time.Duration(nSec) * time.Second - if enabled { - m.ts = time.Now().Unix() - if m.detectSysClockTimer == nil { - m.detectSysClockTimer = time.AfterFunc(interval, func() { - nowTs := time.Now().Unix() - d := nowTs - m.ts - int64(nSec) - if !(-2 < d && d < 2) { - m.handleSysClockChanged() - } - - m.ts = time.Now().Unix() - m.detectSysClockTimer.Reset(interval) - }) - } else { - m.detectSysClockTimer.Reset(interval) - } - } else { - // disable - if m.detectSysClockTimer != nil { - m.detectSysClockTimer.Stop() - } - } -} - -func (m *Manager) handleSysClockChanged() { - logger.Debug("system clock changed") - if m.locationValid { - m.autoSetTheme(m.latitude, m.longitude) - m.resetThemeAutoTimer() - } -} - -func (m *Manager) updateThemeAuto(enabled bool) { - m.enableDetectSysClock(enabled) - logger.Debug("updateThemeAuto:", enabled) - if enabled { - var err error - if m.themeAutoTimer == nil { - m.themeAutoTimer = time.AfterFunc(0, func() { - if m.locationValid { - m.autoSetTheme(m.latitude, m.longitude) - - time.AfterFunc(5*time.Second, func() { - m.resetThemeAutoTimer() - }) - } - }) - } else { - m.themeAutoTimer.Reset(0) - } - - city, err := m.timeDate.Timezone().Get(0) - if err != nil { - logger.Warning(err) - } - for ct, coordinate := range m.coordinateMap { - if city == ct { - m.longitude = coordinate.longitude - m.latitude = coordinate.latitude - } - } - - m.updateLocation(m.latitude, m.longitude) - logger.Debug("city", city, m.longitude, m.latitude) - - } else { - m.latitude = 0 - m.longitude = 0 - m.locationValid = false - if m.themeAutoTimer != nil { - m.themeAutoTimer.Stop() - } - } -} - -func (m *Manager) updateLocation(latitude, longitude float64) { - m.latitude = latitude - m.longitude = longitude - m.locationValid = true - logger.Debugf("update location, latitude: %v, longitude: %v", - latitude, longitude) - m.autoSetTheme(latitude, longitude) - m.resetThemeAutoTimer() -} - -func (m *Manager) resetThemeAutoTimer() { - if m.themeAutoTimer == nil { - logger.Debug("themeAutoTimer is nil") - return - } - if !m.locationValid { - logger.Debug("location is invalid") - return - } - - now := time.Now().In(m.loc) - changeTime, err := m.getThemeAutoChangeTime(now, m.latitude, m.longitude) - if err != nil { - logger.Warning("failed to get theme auto change time:", err) - return - } - - interval := changeTime.Sub(now) - logger.Debug("change theme after:", interval) - m.themeAutoTimer.Reset(interval) -} - -func (m *Manager) autoSetTheme(latitude, longitude float64) { - now := time.Now().In(m.loc) - if m.GtkTheme.Get() != autoGtkTheme { - return - } - - sunriseT, sunsetT, err := m.getSunriseSunset(now, latitude, longitude) - if err != nil { - logger.Warning(err) - return - } - logger.Debugf("now: %v, sunrise: %v, sunset: %v", - now, sunriseT, sunsetT) - themeName := getThemeAutoName(isDaytime(now, sunriseT, sunsetT)) - logger.Debug("auto theme name:", themeName) - - currentTheme := m.GtkTheme.Get() - if currentTheme != themeName { - err = m.doSetGtkTheme(themeName) - if err != nil { - logger.Warning(err) - } - } -} - -func (m *Manager) getQtActiveColor() (string, error) { - str := m.xSettingsGs.GetString(gsKeyQtActiveColor) - return xsColorToHexColor(str) -} - -func xsColorToHexColor(str string) (string, error) { - fields := strings.Split(str, ",") - if len(fields) != 4 { - return "", errors.New("length of fields is not 4") - } - - var array [4]uint16 - for idx, field := range fields { - v, err := strconv.ParseUint(field, 10, 16) - if err != nil { - return "", err - } - array[idx] = uint16(v) - } - - var byteArr [4]byte - for idx, value := range array { - byteArr[idx] = byte((float64(value) / float64(math.MaxUint16)) * float64(math.MaxUint8)) - } - return byteArrayToHexColor(byteArr), nil -} - -func byteArrayToHexColor(p [4]byte) string { - // p : [R G B A] - if p[3] == 255 { - return fmt.Sprintf("#%02X%02X%02X", p[0], p[1], p[2]) - } - return fmt.Sprintf("#%02X%02X%02X%02X", p[0], p[1], p[2], p[3]) -} - -var hexColorReg = regexp.MustCompile(`^#([0-9A-F]{6}|[0-9A-F]{8})$`) - -func parseHexColor(hexColor string) (array [4]byte, err error) { - hexColor = strings.ToUpper(hexColor) - match := hexColorReg.FindStringSubmatch(hexColor) - if match == nil { - err = errors.New("invalid hex color format") - return - } - hexNums := string(match[1]) - count := 4 - if len(hexNums) == 6 { - count = 3 - array[3] = 255 - } - - for i := 0; i < count; i++ { - array[i], err = parseHexNum(hexNums[i*2 : i*2+2]) - if err != nil { - return - } - } - return -} - -func parseHexNum(str string) (byte, error) { - v, err := strconv.ParseUint(str, 16, 8) - return byte(v), err -} - -func (m *Manager) setQtActiveColor(hexColor string) error { - xsColor, err := hexColorToXsColor(hexColor) - if err != nil { - return err - } - - ok := m.xSettingsGs.SetString(gsKeyQtActiveColor, xsColor) - if !ok { - return errors.New("failed to save") - } - return nil -} - -// 原有的壁纸数据保存在background-uris字段中,当壁纸模块升级后,将该数据迁移至wallpaper-uris中; -// wallpaper-slideshow前后版本的格式不同,根据旧数据重新生成新数据 -func (m *Manager) updateNewVersionData() error { - reverseMonitorMap := m.reverseMonitorMap() - primaryMonitor := reverseMonitorMap["Primary"] - slideshowConfig := make(mapMonitorWorkspaceWSPolicy) - slideShow := m.WallpaperSlideShow.Get() - workspaceCount, _ := m.wm.WorkspaceCount(0) - _, err := doUnmarshalWallpaperSlideshow(slideShow) - if err != nil { - // slideShow的内容无法解析为map[string]string数据表示低版本壁纸,进行数据格式转换 - for i := 1; i <= int(workspaceCount); i++ { - key := genMonitorKeyString(primaryMonitor, i) - slideshowConfig[key] = slideShow - } - err := m.setPropertyWallpaperSlideShow(slideshowConfig) - if err != nil { - return err - } - } - - monitorWorkspaceWallpaperURIs := make(mapMonitorWorkspaceWallpaperURIs) - backgroundURIs := m.getBackgroundURIs() - for i, uri := range backgroundURIs { - err := m.wm.SetWorkspaceBackgroundForMonitor(0, int32(i+1), primaryMonitor, uri) - if err != nil { - return fmt.Errorf("failed to set background:%v to workspace%v : %v", uri, i+1, err) - } - key := genMonitorKeyString("Primary", i+1) - monitorWorkspaceWallpaperURIs[key] = uri - } - err = m.setPropertyWallpaperURIs(monitorWorkspaceWallpaperURIs) - if err != nil { - return err - } - - go func() { - // V20对应SP3, SP2阶段gsettings background-uris中部分数据丢失,SP2升到SP3通过窗管接口获取壁纸 - // 目前第一次初始化,wm和appearance存在互相依赖,因此这里同步wm数据只能异步,这属于设计问题,后续可以优化交互逻辑 - monitorWorkspaceWallpaperURIs := make(mapMonitorWorkspaceWallpaperURIs) - for monitorName, convertMonitorName := range m.monitorMap { - for i := int32(0); i < workspaceCount; i++ { - uri, err := m.wm.GetWorkspaceBackgroundForMonitor(0, i+1, monitorName) - if err != nil { - logger.Warningf("failed to get monitor:%v workspace:%v background:%v", monitorName, i+1, err) - continue - } - - key := genMonitorKeyString(convertMonitorName, i+1) - monitorWorkspaceWallpaperURIs[key] = uri - } - } - err := m.setPropertyWallpaperURIs(monitorWorkspaceWallpaperURIs) - if err != nil { - logger.Warning("failed to set wallpaper:", err) - } - }() - return nil -} - -func genMonitorKeyString(monitor string, idx interface{}) string { - return fmt.Sprintf("%v&&%v", monitor, idx) -} - -func hexColorToXsColor(hexColor string) (string, error) { - byteArr, err := parseHexColor(hexColor) - if err != nil { - return "", err - } - var array [4]uint16 - for idx, value := range byteArr { - array[idx] = uint16((float64(value) / float64(math.MaxUint8)) * float64(math.MaxUint16)) - } - return fmt.Sprintf("%d,%d,%d,%d", array[0], array[1], - array[2], array[3]), nil -} - -func (m *Manager) initCoordinate() { - content, err := ioutil.ReadFile(zonePath) - if err != nil { - logger.Warning(err) - return - } - var ( - lines = strings.Split(string(content), "\n") - match = regexp.MustCompile(`^#`) - ) - for _, line := range lines { - if len(line) == 0 { - continue - } - - if match.MatchString(line) { - continue - } - strv := strings.Split(line, "\t") - m.iso6709Parsing(string(strv[2]), strv[1]) - } -} - -func (m *Manager) iso6709Parsing(city, coordinates string) { - var cdn coordinate - match := regexp.MustCompile(`(\+|-)\d+\.?\d*`) - - temp := match.FindAllString(coordinates, 2) - - temp[0] = temp[0][:3] + "." + temp[0][3:] - temp[1] = temp[1][:4] + "." + temp[1][4:] - lat, _ := strconv.ParseFloat(temp[0], 64) - lon, _ := strconv.ParseFloat(temp[1], 64) - cdn.longitude = lon - cdn.latitude = lat - m.coordinateMap[city] = &cdn -} - -func (m *Manager) initAppearanceDSettings() { - ds := configManager.NewConfigManager(m.sysSigLoop.Conn()) - - appearancePath, err := ds.AcquireManager(0, dsettingsAppID, dsettingsAppearanceName, "") - if err != nil { - logger.Warning(err) - return - } - - dsAppearance, err := configManager.NewManager(m.sysSigLoop.Conn(), appearancePath) - if err != nil { - logger.Warning(err) - return - } - - getIrregularFontWhiteListKey := func() { - v, err := dsAppearance.Value(0, dsettingsIrregularFontOverrideKey) - if err != nil { - logger.Warning(err) - return - } - var overrideMap fonts.IrregularFontOverrideMap - overrideMapString := v.Value().(string) - err = json.Unmarshal([]byte(overrideMapString), &overrideMap) - if err != nil { - logger.Warning(err) - return - } - fonts.SetIrregularFontWhiteList(overrideMap) - } - - getIrregularFontWhiteListKey() - - dsAppearance.InitSignalExt(m.sysSigLoop, true) - _, err = dsAppearance.ConnectValueChanged(func(key string) { - if key == dsettingsIrregularFontOverrideKey { - getIrregularFontWhiteListKey() - } - }) - if err != nil { - logger.Warning(err) - } -} diff --git a/appearance/manager_test.go b/appearance/manager_test.go deleted file mode 100644 index 8c98204e1..000000000 --- a/appearance/manager_test.go +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package appearance - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_genMonitorKeyString(t *testing.T) { - assert.Equal(t, genMonitorKeyString("abc", 123), "abc&&123") - assert.Equal(t, genMonitorKeyString("abc", "def"), "abc&&def") -} diff --git a/appearance/scale.go b/appearance/scale.go deleted file mode 100644 index 1e9cd33bb..000000000 --- a/appearance/scale.go +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package appearance - -import ( - "sync/atomic" - - "github.com/godbus/dbus" - notifications "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.notifications" - "github.com/linuxdeepin/go-lib/gettext" -) - -func (m *Manager) getScaleFactor() float64 { - scaleFactor, err := m.xSettings.GetScaleFactor(dbus.FlagNoAutoStart) - if err != nil { - logger.Warning("failed to get scale factor:", err) - scaleFactor = 1.0 - } - return scaleFactor -} - -func (m *Manager) setScaleFactor(scale float64) error { - err := m.xSettings.SetScaleFactor(dbus.FlagNoAutoStart, scale) - if err != nil { - logger.Warning("failed to set scale factor:", err) - } - return err -} - -var notifyId uint32 - -const icon = "dialog-window-scale" - -func handleSetScaleFactorDone() { - const ( - expireTimeout = 0 - requestLogout = "dbus-send,--type=method_call,--dest=com.deepin.SessionManager,/com/deepin/SessionManager,com.deepin.SessionManager.RequestLogout" - ) - body := gettext.Tr("Log out for display scaling settings to take effect") - summary := gettext.Tr("Set successfully") - sessionBus, err := dbus.SessionBus() - if err != nil { - logger.Warning(err) - return - } - nid := atomic.LoadUint32(¬ifyId) - notifier := notifications.NewNotifications(sessionBus) - nid, err = notifier.Notify(0, "dde-control-center", nid, - icon, summary, body, - []string{"_logout", gettext.Tr("Log Out Now"), "_later", gettext.Tr("Later")}, - map[string]dbus.Variant{ - "x-deepin-action-_logout": dbus.MakeVariant(requestLogout), - "x-deepin-action-_later": dbus.MakeVariant(""), - "x-deepin-ClickToDisappear": dbus.MakeVariant(false), - "x-deepin-DisappearAfterLock": dbus.MakeVariant(false), - }, expireTimeout) - if err != nil { - logger.Warning(err) - } else { - atomic.StoreUint32(¬ifyId, nid) - } - -} - -func handleSetScaleFactorStarted() { - body := gettext.Tr("Setting display scaling") - summary := gettext.Tr("Display scaling") - sessionBus, err := dbus.SessionBus() - if err != nil { - logger.Warning(err) - return - } - nid := atomic.LoadUint32(¬ifyId) - notifier := notifications.NewNotifications(sessionBus) - nid, err = notifier.Notify(0, "dde-control-center", nid, - icon, summary, body, - nil, nil, 0) - if err != nil { - logger.Warning(err) - } else { - atomic.StoreUint32(¬ifyId, nid) - } - -} - -func (m *Manager) setScreenScaleFactors(factors map[string]float64) error { - return m.xSettings.SetScreenScaleFactors(dbus.FlagNoAutoStart, factors) -} - -func (m *Manager) getScreenScaleFactors() (map[string]float64, error) { - return m.xSettings.GetScreenScaleFactors(dbus.FlagNoAutoStart) -} diff --git a/appearance/subthemes/themes.go b/appearance/subthemes/themes.go deleted file mode 100644 index 9bf96253c..000000000 --- a/appearance/subthemes/themes.go +++ /dev/null @@ -1,211 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package subthemes - -import ( - "fmt" - "os" - "path" - "strings" - - "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-api/theme_thumb" - "github.com/linuxdeepin/dde-api/themes" - cursorhelper "github.com/linuxdeepin/go-dbus-factory/com.deepin.api.cursorhelper" - "github.com/linuxdeepin/go-gir/gio-2.0" -) - -const ( - appearanceSchema = "com.deepin.dde.appearance" - gsKeyExcludedIcon = "excluded-icon-themes" -) - -type Theme struct { - Id string - Path string - - Deletable bool -} -type Themes []*Theme - -var ( - cacheGtkThemes Themes - cacheIconThemes Themes - cacheCursorThemes Themes - - home = os.Getenv("HOME") -) - -func RefreshGtkThemes() { - cacheGtkThemes = getThemes(themes.ListGtkTheme()) -} - -func RefreshIconThemes() { - infos := getThemes(themes.ListIconTheme()) - s := gio.NewSettings(appearanceSchema) - defer s.Unref() - blacklist := s.GetStrv(gsKeyExcludedIcon) - - var ret Themes - for _, info := range infos { - if isItemInList(info.Id, blacklist) { - continue - } - ret = append(ret, info) - } - cacheIconThemes = ret -} - -func RefreshCursorThemes() { - cacheCursorThemes = getThemes(themes.ListCursorTheme()) -} - -func ListGtkTheme() Themes { - if len(cacheGtkThemes) == 0 { - RefreshGtkThemes() - } - return cacheGtkThemes -} - -func ListIconTheme() Themes { - if len(cacheIconThemes) == 0 { - RefreshIconThemes() - } - return cacheIconThemes -} - -func ListCursorTheme() Themes { - if len(cacheCursorThemes) == 0 { - RefreshCursorThemes() - } - return cacheCursorThemes -} - -func IsGtkTheme(id string) bool { - return themes.IsThemeInList(id, themes.ListGtkTheme()) -} - -func IsIconTheme(id string) bool { - return themes.IsThemeInList(id, themes.ListIconTheme()) -} - -func IsCursorTheme(id string) bool { - return themes.IsThemeInList(id, themes.ListCursorTheme()) -} - -func SetGtkTheme(id string) error { - return themes.SetGtkTheme(id) -} - -func SetIconTheme(id string) error { - return themes.SetIconTheme(id) -} - -func SetCursorTheme(id string) error { - sessionBus, err := dbus.SessionBus() - if err != nil { - return err - } - helper := cursorhelper.NewCursorHelper(sessionBus) - return helper.Set(0, id) -} - -func GetGtkThumbnail(id string) (string, error) { - info := ListGtkTheme().Get(id) - if info == nil { - return "", fmt.Errorf("not found %q", id) - } - - descFile := path.Join(info.Path, "index.theme") - return theme_thumb.GetGtk(id, descFile) -} - -func GetIconThumbnail(id string) (string, error) { - info := ListIconTheme().Get(id) - if info == nil { - return "", fmt.Errorf("not found %q", id) - } - - descFile := path.Join(info.Path, "index.theme") - return theme_thumb.GetIcon(id, descFile) -} - -func GetCursorThumbnail(id string) (string, error) { - info := ListCursorTheme().Get(id) - if info == nil { - return "", fmt.Errorf("not found %q", id) - } - descFile := path.Join(info.Path, "cursor.theme") - return theme_thumb.GetCursor(id, descFile) -} - -func (infos Themes) GetIds() []string { - var ids []string - for _, info := range infos { - ids = append(ids, info.Id) - } - return ids -} - -func (infos Themes) Get(id string) *Theme { - for _, info := range infos { - if id == info.Id { - return info - } - } - return nil -} - -func (infos Themes) ListGet(ids []string) Themes { - var ret Themes - for _, id := range ids { - info := infos.Get(id) - if info == nil { - continue - } - ret = append(ret, info) - } - return ret -} - -func (infos Themes) Delete(id string) error { - info := infos.Get(id) - if info == nil { - return fmt.Errorf("not found %q", id) - } - return info.Delete() -} - -func (info *Theme) Delete() error { - if !info.Deletable { - return fmt.Errorf("permission denied") - } - return os.RemoveAll(info.Path) -} - -func getThemes(files []string) Themes { - var infos Themes - for _, v := range files { - infos = append(infos, &Theme{ - Id: path.Base(v), - Path: v, - Deletable: isDeletable(v), - }) - } - return infos -} - -func isDeletable(file string) bool { - return strings.Contains(file, home) -} - -func isItemInList(item string, list []string) bool { - for _, v := range list { - if item == v { - return true - } - } - return false -} diff --git a/appearance/sync_config.go b/appearance/sync_config.go deleted file mode 100644 index f183cfd81..000000000 --- a/appearance/sync_config.go +++ /dev/null @@ -1,309 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package appearance - -import ( - "encoding/json" - "errors" - "fmt" - "strconv" - "strings" -) - -const ( - backgroundDBusPath = dbusPath + "/Background" -) - -type syncConfig struct { - m *Manager -} - -func (sc *syncConfig) Get() (interface{}, error) { - var v syncData - v.Version = "1.0" - v.FontSize = sc.m.FontSize.Get() - v.GTK = sc.m.GtkTheme.Get() - v.Icon = sc.m.IconTheme.Get() - v.Cursor = sc.m.CursorTheme.Get() - v.FontStandard = sc.m.StandardFont.Get() - v.FontMonospace = sc.m.MonospaceFont.Get() - return &v, nil -} - -func (sc *syncConfig) Set(data []byte) error { - var v syncData - err := json.Unmarshal(data, &v) - if err != nil { - return err - } - - m := sc.m - if m.FontSize.Get() != v.FontSize { - err = m.doSetFontSize(v.FontSize) - if err != nil { - logger.Warning("failed to set font size:", err) - } else { - m.FontSize.Set(v.FontSize) - } - } - - if m.GtkTheme.Get() != v.GTK { - err = m.doSetGtkTheme(v.GTK) - if err != nil { - logger.Warning("failed to set gtk theme:", err) - } else { - m.GtkTheme.Set(v.GTK) - } - } - - if m.IconTheme.Get() != v.Icon { - err = m.doSetIconTheme(v.Icon) - if err != nil { - logger.Warning("failed to set icon theme:", err) - } else { - m.IconTheme.Set(v.Icon) - } - } - - if m.CursorTheme.Get() != v.Cursor { - err = m.doSetCursorTheme(v.Cursor) - if err != nil { - logger.Warning("failed to set cursor theme:", err) - } else { - m.CursorTheme.Set(v.Cursor) - } - } - - if m.StandardFont.Get() != v.FontStandard { - err = m.doSetStandardFont(v.FontStandard) - if err != nil { - logger.Warning("failed to set standard font:", err) - } else { - m.StandardFont.Set(v.FontStandard) - } - } - - if m.MonospaceFont.Get() != v.FontMonospace { - err = m.doSetMonospaceFont(v.FontMonospace) - if err != nil { - logger.Warning("failed to set monospace font:", err) - } else { - m.MonospaceFont.Set(v.FontMonospace) - } - } - - return nil -} - -// version: 1.0 -type syncData struct { - Version string `json:"version"` - FontSize float64 `json:"font_size"` - GTK string `json:"gtk"` - Icon string `json:"icon"` - Cursor string `json:"cursor"` - FontStandard string `json:"font_standard"` - FontMonospace string `json:"font_monospace"` -} - -type backgroundSyncConfig struct { - m *Manager -} - -func (sc *backgroundSyncConfig) Get() (interface{}, error) { - var v backgroundSyncData - v.Version = "2.0" - v.GreeterBackground = sc.m.greeterBg - slideShow := sc.m.WallpaperSlideShow.Get() - var cfgSlideshow mapMonitorWorkspaceWSPolicy - var err error - if slideShow != "" { //避免slideshow为空时,导致后续数据为空 - cfgSlideshow, err = doUnmarshalWallpaperSlideshow(slideShow) // slideShow是一个map 格式为: "HDMI-0&&1":"600" 分别是屏幕名称&&工作区编号和自动切换壁纸配置 - if err != nil { - logger.Warning(err) - return nil, err - } - } - - uploadSlideShow := make(mapMonitorWorkspaceWSPolicy) - for k, value := range cfgSlideshow { // 将具体的屏幕名称(例如"HDMI-0"或"VGA-0")转换为 主屏幕或副屏幕(Primary或Subsidiary0/Subsidiary1等) - keySlice := strings.Split(k, "&&") - if len(keySlice) < 2 { - continue - } - index, err := strconv.ParseInt(keySlice[1], 10, 32) - if err != nil { - logger.Warning(err) - return nil, err - } - if int32(index) < 1 { - return nil, errors.New("invalid workspace index") - } - monitorName := sc.m.monitorMap[keySlice[0]] - key := genMonitorKeyString(monitorName, keySlice[1]) - uploadSlideShow[key] = value - } - wallpaperURIsString := sc.m.WallpaperURIs.Get() - var cfgWallpaperURIs mapMonitorWorkspaceWallpaperURIs - if wallpaperURIsString != "" { - cfgWallpaperURIs, err = doUnmarshalMonitorWorkspaceWallpaperURIs(wallpaperURIsString) - if err != nil { - logger.Warning(err) - return nil, err - } - } - - uploadWallpaperURIs := make(mapMonitorWorkspaceWallpaperURIs) - for key, value := range cfgWallpaperURIs { // 对需要上传的壁纸信息进行过滤,只有当对应的自动切换的配置为空时(即:未配置自动切换相关内容),将该壁纸信息上传 - if uploadSlideShow[key] == "" { - uploadWallpaperURIs[key] = value - } - } - v.WallpaperURIs = uploadWallpaperURIs - v.SlideShowConfig = uploadSlideShow - - return &v, nil -} - -func (sc *backgroundSyncConfig) Set(data []byte) error { - var v backgroundSyncData - err := json.Unmarshal(data, &v) - if err != nil { - return err - } - m := sc.m - if m.greeterBg != v.GreeterBackground { - err = m.doSetGreeterBackground(v.GreeterBackground) - if err != nil { - logger.Warning(err) - } - } - - reverseMonitorMap := m.reverseMonitorMap() // 主副屏幕对应的具体屏幕名称的map 格式为{"Primary": "HDMI-0"} - if v.Version == "1.0" { // 兼容v1.0的数据内容 - primaryMonitor := reverseMonitorMap["Primary"] - // 处理自动切换的配置 - wallpaperSlideShow := m.WallpaperSlideShow.Get() - var slideshowConfig mapMonitorWorkspaceWSPolicy - if wallpaperSlideShow != "" { - slideshowConfig, err = doUnmarshalWallpaperSlideshow(wallpaperSlideShow) - if err != nil { - logger.Warning(err) - return err - } - } else { - slideshowConfig = make(mapMonitorWorkspaceWSPolicy) - } - - workspaceCount, _ := m.wm.WorkspaceCount(0) - for i := 1; i <= int(workspaceCount); i++ { - key := genMonitorKeyString(primaryMonitor, i) - slideshowConfig[key] = v.SlideShow - } - err := m.setPropertyWallpaperSlideShow(slideshowConfig) - if err != nil { - logger.Warning(err) - return err - } - if v.SlideShow != "" { - return nil - } - // 处理壁纸同步 - wallpaperURIs := m.WallpaperURIs.Get() - var monitorWorkspaceWallpaperURIs mapMonitorWorkspaceWallpaperURIs - if wallpaperURIs != "" { - monitorWorkspaceWallpaperURIs, err = doUnmarshalMonitorWorkspaceWallpaperURIs(wallpaperURIs) - if err != nil { - logger.Warning(err) - return err - } - } else { - monitorWorkspaceWallpaperURIs = make(mapMonitorWorkspaceWallpaperURIs) - } - - for i, uri := range v.BackgroundURIs { - err := m.wm.SetWorkspaceBackgroundForMonitor(0, int32(i+1), primaryMonitor, uri) - if err != nil { - err = fmt.Errorf("failed to set background:%v to workspace%v : %v", uri, i+1, err) - logger.Warning(err) - return err - } - key := genMonitorKeyString("Primary", i+1) - monitorWorkspaceWallpaperURIs[key] = uri - } - err = m.setPropertyWallpaperURIs(monitorWorkspaceWallpaperURIs) - if err != nil { - logger.Warning(err) - return err - } - return nil - } - - slideShow := make(mapMonitorWorkspaceWSPolicy) - for k, value := range v.SlideShowConfig { - keySlice := strings.Split(k, "&&") - if len(keySlice) < 2 { - continue - } - monitorName := reverseMonitorMap[keySlice[0]] //将主屏幕或副屏幕(Primary或Subsidiary0/Subsidiary1等)转换为具体的屏幕名称(例如"HDMI-0"或"VGA-0") - index, err := strconv.ParseInt(keySlice[1], 10, 32) - if err != nil { - logger.Warning(err) - return err - } - if int32(index) < 1 { - return errors.New("invalid workspace index") - } - key := genMonitorKeyString(monitorName, keySlice[1]) - slideShow[key] = value - } - - err = m.setPropertyWallpaperSlideShow(slideShow) - if err != nil { - return err - } - err = m.setPropertyWallpaperURIs(v.WallpaperURIs) - if err != nil { - return err - } - - workspaceCount, _ := m.wm.WorkspaceCount(0) // 当前工作区数量 - for key, value := range v.WallpaperURIs { - keySlice := strings.Split(key, "&&") - if len(keySlice) < 2 { - continue - } - monitorName := reverseMonitorMap[keySlice[0]] // 将主屏幕或副屏幕(Primary或Subsidiary0/Subsidiary1等)转换为具体的屏幕名称(例如"HDMI-0"或"VGA-0") - index, err := strconv.ParseInt(keySlice[1], 10, 32) - if err != nil { - logger.Warning(err) - return err - } - if monitorName == "" { - continue - } - if int32(index) < 1 { // index由1开始,代表工作区的编号,小于1代表编号错误 - return errors.New("invalid workspace index") - } - if int32(index) > workspaceCount { - continue - } - err = m.wm.SetWorkspaceBackgroundForMonitor(0, int32(index), monitorName, value) - if err != nil { - logger.Warning("failed to set WorkspaceBackgroundForMonitor:", err) - } - } - return nil -} - -// version: 2.0 -type backgroundSyncData struct { - Version string `json:"version"` - GreeterBackground string `json:"greeter_background"` - SlideShowConfig mapMonitorWorkspaceWSPolicy `json:"slide_show_config"` // v2.0配置 - WallpaperURIs mapMonitorWorkspaceWallpaperURIs `json:"wallpaper_uris"` // v2.0配置 - BackgroundURIs []string `json:"background_uris"` // 兼容v1.0的内容 - SlideShow string `json:"slide_show"` // 兼容v1.0的内容 -} diff --git a/appearance/testdata/fontVersionConf b/appearance/testdata/fontVersionConf deleted file mode 100644 index 840ca8cbf..000000000 --- a/appearance/testdata/fontVersionConf +++ /dev/null @@ -1 +0,0 @@ -1.4 \ No newline at end of file diff --git a/appearance/theme_auto.go b/appearance/theme_auto.go deleted file mode 100644 index 9f139e481..000000000 --- a/appearance/theme_auto.go +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package appearance - -import ( - "time" - - "github.com/kelvins/sunrisesunset" -) - -func (m *Manager) getSunriseSunset(t time.Time, latitude, longitude float64) (time.Time, time.Time, error) { - timeUtc := t.UTC() - _, offsetSec := t.Zone() - utcOffset := float64(offsetSec / 3600.0) - sunrise, sunset, err := sunrisesunset.GetSunriseSunset(latitude, longitude, utcOffset, timeUtc) - if err != nil { - return time.Time{}, time.Time{}, err - } - sunriseT := time.Date(t.Year(), t.Month(), t.Day(), - sunrise.Hour(), sunrise.Minute(), sunrise.Second(), - 0, m.loc) - sunsetT := time.Date(t.Year(), t.Month(), t.Day(), - sunset.Hour(), sunset.Minute(), sunset.Second(), - 0, m.loc) - return sunriseT, sunsetT, nil -} - -func isDaytime(t, sunriseT, sunsetT time.Time) bool { - return sunriseT.Before(t) && t.Before(sunsetT) -} - -func getThemeAutoName(isDaytime bool) string { - if isDaytime { - return "deepin" - } - return "deepin-dark" -} - -func (m *Manager) getThemeAutoChangeTime(t time.Time, latitude, longitude float64) (time.Time, error) { - sunrise, sunset, err := m.getSunriseSunset(t, latitude, longitude) - if err != nil { - return time.Time{}, err - } - logger.Debugf("t: %v, sunrise: %v, sunset: %v", t, sunrise, sunset) - if t.Before(sunrise) || t.Equal(sunrise) { - // t <= sunrise - return sunrise, nil - } - - if t.Before(sunset) || t.Equal(sunset) { - // t <= sunset - return sunset, nil - } - - nextDay := t.AddDate(0, 0, 1) - nextDaySunrise, _, err := m.getSunriseSunset(nextDay, latitude, longitude) - logger.Debug("next day sunrise:", nextDaySunrise) - if err != nil { - return time.Time{}, err - } - - return nextDaySunrise, nil -} diff --git a/appearance/theme_auto_test.go b/appearance/theme_auto_test.go deleted file mode 100644 index 7a6d94a48..000000000 --- a/appearance/theme_auto_test.go +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package appearance - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_getThemeAutoName(t *testing.T) { - assert.Equal(t, getThemeAutoName(true), "deepin") - assert.Equal(t, getThemeAutoName(false), "deepin-dark") -} diff --git a/appearance/wallpaper-slideshow.go b/appearance/wallpaper-slideshow.go deleted file mode 100644 index 5e80d8e0e..000000000 --- a/appearance/wallpaper-slideshow.go +++ /dev/null @@ -1,257 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package appearance - -import ( - "encoding/json" - "io/ioutil" - "math/rand" - "os" - "path/filepath" - "strconv" - "sync" - "time" - - "github.com/linuxdeepin/dde-daemon/appearance/background" - - "github.com/linuxdeepin/go-lib/utils" -) - -type changeBgFunc func(monitorSpace string, t time.Time) - -// wallpaper slideshow scheduler -type WSScheduler struct { - mu sync.Mutex - lastSetBg time.Time //last set wallpaper time - interval time.Duration - quit chan chan struct{} - intervalChanged chan struct{} - running bool - fn changeBgFunc -} - -func newWSScheduler(fun changeBgFunc) *WSScheduler { - s := &WSScheduler{ - quit: make(chan chan struct{}), - intervalChanged: make(chan struct{}), - fn: fun, - } - return s -} - -func (s *WSScheduler) remainDuration() time.Duration { - s.mu.Lock() - defer s.mu.Unlock() - - elapsed := time.Since(s.lastSetBg) - if elapsed < 0 { - elapsed = 0 - } - result := s.interval - elapsed - return result -} - -func (s *WSScheduler) loopCheck(mointorSpace string) { - s.running = true - for { - select { - case <-s.intervalChanged: - continue - case t := <-time.After(s.remainDuration()): - if s.fn != nil { - go s.fn(mointorSpace, t) - } - s.lastSetBg = t - case ch := <-s.quit: - s.running = false - close(ch) - return - } - } -} - -func (s *WSScheduler) updateInterval(monitorSpace string, v time.Duration) { - if v < time.Second { - v = time.Second - } - logger.Debug("update interval", v) - - s.mu.Lock() - s.interval = v - if s.running { - s.mu.Unlock() - s.intervalChanged <- struct{}{} - return - } - - s.mu.Unlock() - go s.loopCheck(monitorSpace) -} - -func (s *WSScheduler) stop() { - s.mu.Lock() - defer s.mu.Unlock() - - if !s.running { - return - } - - logger.Debug("stop") - ch := make(chan struct{}) - s.quit <- ch - // wait quit - <-ch -} - -// wallpaper slideshow config -type WSConfig struct { - LastChange time.Time - Showed []string -} - -func loadWSConfig(filename string) (mapMonitorWorkspaceWSConfig, error) { - var cfg mapMonitorWorkspaceWSConfig - data, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - err = json.Unmarshal(data, &cfg) - if err != nil { - return nil, err - } - return cfg, nil -} - -func loadWSConfigSafe(filename string) mapMonitorWorkspaceWSConfig { - cfg, _ := loadWSConfig(filename) - return cfg -} - -func (c mapMonitorWorkspaceWSConfig) save(filename string) error { - data, err := json.Marshal(c) - if err != nil { - return err - } - dir := filepath.Dir(filename) - err = os.MkdirAll(dir, 0755) - if err != nil { - return err - } - - err = ioutil.WriteFile(filename, data, 0644) - return err -} - -// wallpaper slideshow loop -type WSLoop struct { - mu sync.Mutex - rand *rand.Rand - showed map[string]struct{} - all []string - fsChanged bool -} - -func newWSLoop() *WSLoop { - // #nosec G404 - return &WSLoop{ - rand: rand.New(rand.NewSource(time.Now().UnixNano())), - showed: make(map[string]struct{}), - fsChanged: true, - } -} - -func (wrl *WSLoop) GetShowed() []string { - wrl.mu.Lock() - - result := make([]string, 0, len(wrl.showed)) - for file := range wrl.showed { - result = append(result, file) - } - - wrl.mu.Unlock() - return result -} - -func (wrl *WSLoop) getNotShowed(t uint32) []string { - if wrl.fsChanged { - bgs := background.ListBackground() - bgFiles := make([]string, 0, len(bgs)) - for _, bg := range bgs { - bgFiles = append(bgFiles, utils.DecodeURI(bg.Id)) - } - wrl.all = bgFiles - } - - var result []string - for _, file := range wrl.all { - _, ok := wrl.showed[file] - if !ok { - _, t1 := background.GetWallpaperType(file) - if t == t1 { - result = append(result, file) - } - } - } - return result -} - -func (wrl *WSLoop) getNext(t uint32) string { - notShowed := wrl.getNotShowed(t) - if len(notShowed) == 0 { - return "" - } - idx := wrl.rand.Intn(len(notShowed)) - next := notShowed[idx] - wrl.showed[next] = struct{}{} - return next -} - -func (wrl *WSLoop) reset() { - logger.Debug("WSLoop.reset") - wrl.rand = rand.New(rand.NewSource(time.Now().UnixNano())) // #nosec - // clear showed - for key := range wrl.showed { - delete(wrl.showed, key) - } -} - -func (wrl *WSLoop) AddToShowed(file string) { - file = utils.DecodeURI(file) - wrl.mu.Lock() - wrl.showed[file] = struct{}{} - wrl.mu.Unlock() -} - -func (wrl *WSLoop) GetNext(t uint32) string { - wrl.mu.Lock() - defer wrl.mu.Unlock() - - next := wrl.getNext(t) - if next != "" { - return next - } - - if len(wrl.all) > 0 { - wrl.reset() - next = wrl.getNext(t) - } - - return next -} - -func (wrl *WSLoop) NotifyFsChanged() { - wrl.mu.Lock() - wrl.fsChanged = true - wrl.mu.Unlock() -} - -func isValidWSPolicy(policy string) bool { - if policy == wsPolicyWakeup || policy == wsPolicyLogin || policy == "" { - return true - } - - _, err := strconv.ParseUint(policy, 10, 32) - return err == nil -} diff --git a/apps/exported_methods_auto.go b/apps/exported_methods_auto.go deleted file mode 100644 index 5c07adf46..000000000 --- a/apps/exported_methods_auto.go +++ /dev/null @@ -1,35 +0,0 @@ -// Code generated by "dbusutil-gen em -type ALRecorder,DFWatcher"; DO NOT EDIT. - -package apps - -import ( - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (v *ALRecorder) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "GetNew", - Fn: v.GetNew, - OutArgs: []string{"newApps"}, - }, - { - Name: "MarkLaunched", - Fn: v.MarkLaunched, - InArgs: []string{"file"}, - }, - { - Name: "UninstallHints", - Fn: v.UninstallHints, - InArgs: []string{"desktopFiles"}, - }, - { - Name: "WatchDirs", - Fn: v.WatchDirs, - InArgs: []string{"dataDirs"}, - }, - } -} -func (v *DFWatcher) GetExportedMethods() dbusutil.ExportedMethods { - return nil -} diff --git a/apps/main.go b/apps/main.go deleted file mode 100644 index e8986a275..000000000 --- a/apps/main.go +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package apps - -import ( - "github.com/linuxdeepin/dde-daemon/loader" - "github.com/linuxdeepin/go-lib/log" -) - -//go:generate dbusutil-gen em -type ALRecorder,DFWatcher - -var logger = log.NewLogger("daemon/apps") - -func init() { - loader.Register(NewDaemon(logger)) -} - -type Daemon struct { - *loader.ModuleBase - recorder *ALRecorder - watcher *DFWatcher -} - -func NewDaemon(logger *log.Logger) *Daemon { - daemon := new(Daemon) - daemon.ModuleBase = loader.NewModuleBase("apps", daemon, logger) - return daemon -} - -func (d *Daemon) Start() error { - service := loader.GetService() - - var err error - d.watcher, err = newDFWatcher(service) - if err != nil { - return err - } - - d.recorder, err = newALRecorder(d.watcher) - if err != nil { - return err - } - - // export recorder and watcher - err = service.Export(dbusPath, d.recorder, d.watcher) - if err != nil { - return err - } - - err = service.RequestName(dbusServiceName) - if err != nil { - return err - } - d.recorder.emitServiceRestarted() - - return nil -} - -func (d *Daemon) Stop() error { - // TODO - return nil -} - -func (d *Daemon) GetDependencies() []string { - return []string{} -} - -func (d *Daemon) Name() string { - return "apps" -} diff --git a/apps/utils.go b/apps/utils.go deleted file mode 100644 index 8863d6c27..000000000 --- a/apps/utils.go +++ /dev/null @@ -1,156 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package apps - -import ( - "os" - "os/user" - "path/filepath" - "strconv" - "strings" - "syscall" -) - -func intSliceContains(slice []int, a int) bool { - for _, elem := range slice { - if elem == a { - return true - } - } - return false -} - -func intSliceRemove(slice []int, a int) (ret []int) { - for _, elem := range slice { - if elem != a { - ret = append(ret, elem) - } - } - return -} - -func readDirNames(dirname string) ([]string, error) { - f, err := os.Open(dirname) - if err != nil { - return nil, err - } - defer f.Close() - names, err := f.Readdirnames(-1) - if err != nil { - return nil, err - } - return names, nil -} - -func Walk(root string, walkFn WalkFunc) { - info, err := os.Lstat(root) - if err != nil { - return - } - walk(root, ".", info, walkFn) -} - -func walk(root, name0 string, info os.FileInfo, walkFn WalkFunc) { - walkFn(name0, info) - if !info.IsDir() { - return - } - path := filepath.Join(root, name0) - names, err := readDirNames(path) - if err != nil { - return - } - for _, name := range names { - filename := filepath.Join(path, name) - fileInfo, err := os.Lstat(filename) - if err != nil { - continue - } - walk(root, filepath.Join(name0, name), fileInfo, walkFn) - } -} - -type WalkFunc func(name string, info os.FileInfo) - -func getDirsAndApps(root string) (dirs, apps []string) { - Walk(root, func(name string, info os.FileInfo) { - if info.IsDir() { - dirs = append(dirs, name) - } else if filepath.Ext(name) == desktopExt { - apps = append(apps, strings.TrimSuffix(name, desktopExt)) - } - }) - return -} - -const desktopExt = ".desktop" - -func isDesktopFile(path string) bool { - return filepath.Ext(path) == desktopExt -} - -func removeDesktopExt(name string) string { - return strings.TrimSuffix(name, desktopExt) -} - -func getSystemDataDirs() []string { - return []string{"/usr/share", "/usr/local/share"} -} - -// get user home -func getHomeByUid(uid int) (string, error) { - user, err := user.LookupId(strconv.Itoa(uid)) - if err != nil { - return "", err - } - return user.HomeDir, nil -} - -// copy from go source src/os/path.go -func MkdirAll(path string, uid int, perm os.FileMode) error { - logger.Debug("MkdirAll", path, uid, perm) - // Fast path: if we can tell whether path is a directory or file, stop with success or error. - dir, err := os.Stat(path) - if err == nil { - if dir.IsDir() { - return nil - } - return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR} - } - - // Slow path: make sure parent exists and then call Mkdir for path. - i := len(path) - for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator. - i-- - } - - j := i - for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element. - j-- - } - - if j > 1 { - // Create parent - err = MkdirAll(path[0:j-1], uid, perm) - if err != nil { - return err - } - } - - // Parent now exists; invoke Mkdir and use its result. - err = os.Mkdir(path, perm) - if err != nil { - // Handle arguments like "foo/." by - // double-checking that directory doesn't exist. - dir, err1 := os.Lstat(path) - if err1 == nil && dir.IsDir() { - return nil - } - return err - } - - err = os.Chown(path, uid, uid) - return err -} diff --git a/apps/utils_test.go b/apps/utils_test.go deleted file mode 100644 index 4cc1c32ae..000000000 --- a/apps/utils_test.go +++ /dev/null @@ -1,84 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package apps - -import ( - "os" - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_getHomeByUid(t *testing.T) { - uid := os.Getuid() - home, err := getHomeByUid(uid) - assert.NoError(t, err) - assert.Equal(t, home, os.Getenv("HOME")) -} - -func Test_isDesktopFile(t *testing.T) { - type args struct { - path string - } - tests := []struct { - name string - args args - want bool - }{ - { - name: "isDesktopFile", - args: args{ - path: "/usr/share/applications/firefox.desktop", - }, - want: true, - }, - { - name: "isDesktopFile not a desktop", - args: args{ - path: "/usr/share/applications/firefox.xxx", - }, - want: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := isDesktopFile(tt.args.path) - assert.Equal(t, tt.want, got) - }) - } -} - -func Test_removeDesktopExt(t *testing.T) { - type args struct { - name string - } - tests := []struct { - name string - args args - want string - }{ - - { - name: "removeDesktopFile", - args: args{ - name: "firefox.desktop", - }, - want: "firefox", - }, - { - name: "removeDesktopFile not a desktop", - args: args{ - name: "firefox.xxx", - }, - want: "firefox.xxx", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := removeDesktopExt(tt.args.name) - assert.Equal(t, tt.want, got) - }) - } -} diff --git a/apps/alrecorder.go b/apps1/alrecorder.go similarity index 96% rename from apps/alrecorder.go rename to apps1/alrecorder.go index 49f41261a..4b4327df4 100644 --- a/apps/alrecorder.go +++ b/apps1/alrecorder.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package apps +package apps1 import ( "errors" @@ -13,14 +13,14 @@ import ( "sync" "github.com/fsnotify/fsnotify" - dbus "github.com/godbus/dbus" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" + dbus "github.com/godbus/dbus/v5" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" "github.com/linuxdeepin/go-lib/dbusutil" ) const ( - dbusServiceName = "com.deepin.daemon.Apps" - dbusPath = "/com/deepin/daemon/Apps" + dbusServiceName = "org.deepin.dde.Apps1" + dbusPath = "/org/deepin/dde/Apps1" alRecorderDBusInterface = dbusServiceName + ".LaunchedRecorder" minUid = 1000 ) @@ -256,7 +256,7 @@ func (r *ALRecorder) watchAppsDir(uid int, home, appsDir string) { r.subRecorders[appsDir] = sr } -//判断filename是否是符号链接 +// 判断filename是否是符号链接 func isSymlink(filename string) bool { fileInfo, err := os.Lstat(filename) if err != nil { @@ -265,7 +265,7 @@ func isSymlink(filename string) bool { return fileInfo.Mode()&os.ModeSymlink != 0 } -//获取path所有子path +// 获取path所有子path func getPathDirs(filename string) (ret []string) { for { ret = append(ret, filename) diff --git a/apps/debug.go b/apps1/debug.go similarity index 92% rename from apps/debug.go rename to apps1/debug.go index 6b964c793..9ea9577f0 100644 --- a/apps/debug.go +++ b/apps1/debug.go @@ -1,10 +1,11 @@ +//go:build debug // +build debug // SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later -package apps +package apps1 //func (r *ALRecorder) DebugUserRemoved(sender dbus.Sender) *dbus.Error { // uid, err := r.Service().GetConnUID(string(sender)) diff --git a/apps/dfwatcher.go b/apps1/dfwatcher.go similarity index 99% rename from apps/dfwatcher.go rename to apps1/dfwatcher.go index dbc09c16c..0bcf20e2d 100644 --- a/apps/dfwatcher.go +++ b/apps1/dfwatcher.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package apps +package apps1 import ( "os" diff --git a/apps1/exported_methods_auto.go b/apps1/exported_methods_auto.go new file mode 100644 index 000000000..3af6e0f3f --- /dev/null +++ b/apps1/exported_methods_auto.go @@ -0,0 +1,35 @@ +// Code generated by "dbusutil-gen em -type ALRecorder,DFWatcher"; DO NOT EDIT. + +package apps1 + +import ( + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (v *ALRecorder) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "GetNew", + Fn: v.GetNew, + OutArgs: []string{"newApps"}, + }, + { + Name: "MarkLaunched", + Fn: v.MarkLaunched, + InArgs: []string{"file"}, + }, + { + Name: "UninstallHints", + Fn: v.UninstallHints, + InArgs: []string{"desktopFiles"}, + }, + { + Name: "WatchDirs", + Fn: v.WatchDirs, + InArgs: []string{"dataDirs"}, + }, + } +} +func (v *DFWatcher) GetExportedMethods() dbusutil.ExportedMethods { + return nil +} diff --git a/apps/file_event.go b/apps1/file_event.go similarity index 98% rename from apps/file_event.go rename to apps1/file_event.go index a2bb5f1f5..fc57c35ce 100644 --- a/apps/file_event.go +++ b/apps1/file_event.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package apps +package apps1 import ( "os" diff --git a/apps/fs_watcher.go b/apps1/fs_watcher.go similarity index 99% rename from apps/fs_watcher.go rename to apps1/fs_watcher.go index 6f9386838..6dd348c72 100644 --- a/apps/fs_watcher.go +++ b/apps1/fs_watcher.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package apps +package apps1 import ( "os" diff --git a/apps1/main.go b/apps1/main.go new file mode 100644 index 000000000..cf2fb1dce --- /dev/null +++ b/apps1/main.go @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package apps1 + +import ( + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" +) + +//go:generate dbusutil-gen em -type ALRecorder,DFWatcher + +var logger = log.NewLogger("daemon/apps") + +func init() { + loader.Register(NewDaemon(logger)) +} + +type Daemon struct { + *loader.ModuleBase + recorder *ALRecorder + watcher *DFWatcher +} + +func NewDaemon(logger *log.Logger) *Daemon { + daemon := new(Daemon) + daemon.ModuleBase = loader.NewModuleBase("apps", daemon, logger) + return daemon +} + +func (d *Daemon) Start() error { + service := loader.GetService() + + var err error + d.watcher, err = newDFWatcher(service) + if err != nil { + return err + } + + d.recorder, err = newALRecorder(d.watcher) + if err != nil { + return err + } + + // export recorder and watcher + err = service.Export(dbusPath, d.recorder, d.watcher) + if err != nil { + return err + } + + err = service.RequestName(dbusServiceName) + if err != nil { + return err + } + d.recorder.emitServiceRestarted() + + return nil +} + +func (d *Daemon) Stop() error { + // TODO + return nil +} + +func (d *Daemon) GetDependencies() []string { + return []string{} +} + +func (d *Daemon) Name() string { + return "apps" +} diff --git a/apps/subrecorder.go b/apps1/subrecorder.go similarity index 96% rename from apps/subrecorder.go rename to apps1/subrecorder.go index fef4812ed..680c599da 100644 --- a/apps/subrecorder.go +++ b/apps1/subrecorder.go @@ -2,13 +2,14 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package apps +package apps1 import ( "bufio" "crypto/md5" "encoding/csv" "fmt" + "github.com/linuxdeepin/go-lib/utils" "io" "io/ioutil" "os" @@ -250,7 +251,15 @@ func (sr *SubRecorder) save() error { } } else { if err := os.Rename(tmpFile, file); err != nil { - return err + if strings.Contains(err.Error(), "invalid cross-device link") { + logger.Debugf("invalid cross-device link, use move file, src is %v, dest is %v", tmpFile, file) + err = utils.MoveFile(tmpFile, file) + if err != nil { + return err + } + } else { + return err + } } } return nil diff --git a/apps1/utils.go b/apps1/utils.go new file mode 100644 index 000000000..527197f96 --- /dev/null +++ b/apps1/utils.go @@ -0,0 +1,156 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package apps1 + +import ( + "os" + "os/user" + "path/filepath" + "strconv" + "strings" + "syscall" +) + +func intSliceContains(slice []int, a int) bool { + for _, elem := range slice { + if elem == a { + return true + } + } + return false +} + +func intSliceRemove(slice []int, a int) (ret []int) { + for _, elem := range slice { + if elem != a { + ret = append(ret, elem) + } + } + return +} + +func readDirNames(dirname string) ([]string, error) { + f, err := os.Open(dirname) + if err != nil { + return nil, err + } + defer f.Close() + names, err := f.Readdirnames(-1) + if err != nil { + return nil, err + } + return names, nil +} + +func Walk(root string, walkFn WalkFunc) { + info, err := os.Lstat(root) + if err != nil { + return + } + walk(root, ".", info, walkFn) +} + +func walk(root, name0 string, info os.FileInfo, walkFn WalkFunc) { + walkFn(name0, info) + if !info.IsDir() { + return + } + path := filepath.Join(root, name0) + names, err := readDirNames(path) + if err != nil { + return + } + for _, name := range names { + filename := filepath.Join(path, name) + fileInfo, err := os.Lstat(filename) + if err != nil { + continue + } + walk(root, filepath.Join(name0, name), fileInfo, walkFn) + } +} + +type WalkFunc func(name string, info os.FileInfo) + +func getDirsAndApps(root string) (dirs, apps []string) { + Walk(root, func(name string, info os.FileInfo) { + if info.IsDir() { + dirs = append(dirs, name) + } else if filepath.Ext(name) == desktopExt { + apps = append(apps, strings.TrimSuffix(name, desktopExt)) + } + }) + return +} + +const desktopExt = ".desktop" + +func isDesktopFile(path string) bool { + return filepath.Ext(path) == desktopExt +} + +func removeDesktopExt(name string) string { + return strings.TrimSuffix(name, desktopExt) +} + +func getSystemDataDirs() []string { + return []string{"/usr/share", "/usr/local/share"} +} + +// get user home +func getHomeByUid(uid int) (string, error) { + user, err := user.LookupId(strconv.Itoa(uid)) + if err != nil { + return "", err + } + return user.HomeDir, nil +} + +// copy from go source src/os/path.go +func MkdirAll(path string, uid int, perm os.FileMode) error { + logger.Debug("MkdirAll", path, uid, perm) + // Fast path: if we can tell whether path is a directory or file, stop with success or error. + dir, err := os.Stat(path) + if err == nil { + if dir.IsDir() { + return nil + } + return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR} + } + + // Slow path: make sure parent exists and then call Mkdir for path. + i := len(path) + for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator. + i-- + } + + j := i + for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element. + j-- + } + + if j > 1 { + // Create parent + err = MkdirAll(path[0:j-1], uid, perm) + if err != nil { + return err + } + } + + // Parent now exists; invoke Mkdir and use its result. + err = os.Mkdir(path, perm) + if err != nil { + // Handle arguments like "foo/." by + // double-checking that directory doesn't exist. + dir, err1 := os.Lstat(path) + if err1 == nil && dir.IsDir() { + return nil + } + return err + } + + err = os.Chown(path, uid, uid) + return err +} diff --git a/apps1/utils_test.go b/apps1/utils_test.go new file mode 100644 index 000000000..2944b377c --- /dev/null +++ b/apps1/utils_test.go @@ -0,0 +1,84 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package apps1 + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_getHomeByUid(t *testing.T) { + uid := os.Getuid() + home, err := getHomeByUid(uid) + assert.NoError(t, err) + assert.Equal(t, home, os.Getenv("HOME")) +} + +func Test_isDesktopFile(t *testing.T) { + type args struct { + path string + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "isDesktopFile", + args: args{ + path: "/usr/share/applications/firefox.desktop", + }, + want: true, + }, + { + name: "isDesktopFile not a desktop", + args: args{ + path: "/usr/share/applications/firefox.xxx", + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := isDesktopFile(tt.args.path) + assert.Equal(t, tt.want, got) + }) + } +} + +func Test_removeDesktopExt(t *testing.T) { + type args struct { + name string + } + tests := []struct { + name string + args args + want string + }{ + + { + name: "removeDesktopFile", + args: args{ + name: "firefox.desktop", + }, + want: "firefox", + }, + { + name: "removeDesktopFile not a desktop", + args: args{ + name: "firefox.xxx", + }, + want: "firefox.xxx", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := removeDesktopExt(tt.args.name) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/audio/alsa.go b/audio/alsa.go deleted file mode 100644 index 439c7f0ae..000000000 --- a/audio/alsa.go +++ /dev/null @@ -1,127 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later -package audio - -/* -#cgo pkg-config: alsa -#cgo CFLAGS: -W -Wall -fstack-protector-all -fPIC -#include -#include -#include - -// if *control_id != NULL, need free *control_id -static int find_control(int card_num, char *name, char **control_id) { - snd_hctl_t *handle; - char card[8]; - snprintf(card, 8, "hw:%d", card_num); - int err; - err = snd_hctl_open(&handle, card, 0); - if (err < 0) { - fprintf(stderr, "Control %s open error: %s\n", card, snd_strerror(err)); - return err; - } - - err = snd_hctl_load(handle); - if (err < 0) { - fprintf(stderr, "Control %s load error: %s\n", card, snd_strerror(err)); - return err; - } - - snd_hctl_elem_t *elem; - snd_ctl_elem_id_t *id; - snd_ctl_elem_id_alloca(&id); - for (elem = snd_hctl_first_elem(handle); elem != NULL; elem = snd_hctl_elem_next(elem)) { - snd_hctl_elem_get_id(elem, id); - char *id_str = snd_ctl_ascii_elem_id_get(id); - if (id_str != NULL) { - if (strstr(id_str, name) != NULL) { - *control_id = id_str; - break; - } else { - free(id_str); - } - } - } - - snd_hctl_close(handle); - return 0; -} - -// if *control_id != NULL, need free *control_id -static int find_card_control(char *name, int *card_num, char **control_id) { - *card_num = -1; - int err; - while(1) { - err = snd_card_next(card_num); - if (err < 0) { - fprintf(stderr, "card next err: %s\n", snd_strerror(err)); - return err; - } - if (*card_num == -1) { - // no more cards are available. - break; - } - - err = find_control(*card_num, name, control_id); - if (err < 0) { - return err; - } - - if (*control_id != NULL) { - break; - } - } - return 0; -} -*/ -import "C" -import ( - "errors" - "fmt" - "os/exec" - "strconv" - "unsafe" -) - -var errNotFoundControl = errors.New("not found control") - -func findCardControl(name string) (card int, controlId string, err error) { - var cCard C.int - var cControlId *C.char - cName := C.CString(name) - - cErr := C.find_card_control(cName, &cCard, &cControlId) - C.free(unsafe.Pointer(cName)) - - if cErr < 0 { - err = fmt.Errorf("find_card_control err code: %d", err) - return - } - - if cControlId != nil { - card = int(cCard) - controlId = C.GoString(cControlId) - C.free(unsafe.Pointer(cControlId)) - return - } - - err = errNotFoundControl - return -} - -func disableAutoMuteMode() error { - cardNum, controlId, err := findCardControl("Auto-Mute Mode") - if err != nil { - if err == errNotFoundControl { - err = nil - } - return err - } - out, err := exec.Command("amixer", "-c", strconv.Itoa(cardNum), "cset", controlId, "Disabled").Output() - if err != nil { - return err - } - logger.Debugf("command amixer -c %d cset %s Disabled\n out: %s", cardNum, controlId, out) - return nil -} diff --git a/audio/sync_config.go b/audio/sync_config.go deleted file mode 100644 index 2e2da4307..000000000 --- a/audio/sync_config.go +++ /dev/null @@ -1,156 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package audio - -import ( - "encoding/json" - - dbus "github.com/godbus/dbus" - soundthemeplayer "github.com/linuxdeepin/go-dbus-factory/com.deepin.api.soundthemeplayer" - gio "github.com/linuxdeepin/go-gir/gio-2.0" -) - -const ( - gsKeyAudioVolumeChange = "audio-volume-change" - gsKeyCameraShutter = "camera-shutter" - gsKeyCompleteCopy = "complete-copy" - gsKeyCompletePrint = "complete-print" - gsKeyDesktopLogin = "desktop-login" - gsKeyDesktopLogout = "desktop-logout" - gsKeyDeviceAdded = "device-added" - gsKeyDeviceRemoved = "device-removed" - gsKeyDialogErrorCritical = "dialog-error-critical" - gsKeyDialogError = "dialog-error" - gsKeyDialogErrorSerious = "dialog-error-serious" - gsKeyMessage = "message" - gsKeyPowerPlug = "power-plug" - gsKeyPowerUnplug = "power-unplug" - gsKeyPowerUnplugBatteryLow = "power-unplug-battery-low" - gsKeyScreenCaptureComplete = "screen-capture-complete" - gsKeyScreenCapture = "screen-capture" - gsKeySuspendResume = "suspend-resume" - gsKeySystemShutdown = "system-shutdown" - gsKeyTrashEmpty = "trash-empty" - gsKeyXDeepinAppSentToDesktop = "x-deepin-app-sent-to-desktop" -) - -type syncSoundEffect struct { - Enabled bool `json:"enabled"` - AudioVolumeChange bool `json:"audio_volume_change"` - CameraShutter bool `json:"camera_shutter"` - CompleteCopy bool `json:"complete_copy"` - CompletePrint bool `json:"complete_print"` - DesktopLogin bool `json:"desktop_login"` - DesktopLogout bool `json:"desktop_logout"` - DeviceAdded bool `json:"device_added"` - DeviceRemoved bool `json:"device_removed"` - DialogErrorCritical bool `json:"dialog_error_critical"` - DialogError bool `json:"dialog_error"` - DialogErrorSerious bool `json:"dialog_error_serious"` - Message bool `json:"message"` - PowerPlug bool `json:"power_plug"` - PowerUnplug bool `json:"power_unplug"` - PowerUnplugBatteryLow bool `json:"power_unplug_battery_low"` - ScreenCaptureComplete bool `json:"screen_capture_complete"` - ScreenCapture bool `json:"screen_capture"` - SuspendResume bool `json:"suspend_resume"` - SystemShutdown bool `json:"system_shutdown"` - TrashEmpty bool `json:"trash_empty"` - XDeepinAppSentToDesktop bool `json:"x_deepin_app_sent_to_desktop"` -} - -type syncData struct { - Version string `json:"version"` - SoundEffect *syncSoundEffect `json:"soundeffect"` -} - -type syncConfig struct { - a *Audio -} - -const ( - syncVersion = "1.0" -) - -func (sc *syncConfig) Get() (interface{}, error) { - s := gio.NewSettings(gsSchemaSoundEffect) - defer s.Unref() - return &syncData{ - Version: syncVersion, - SoundEffect: &syncSoundEffect{ - Enabled: s.GetBoolean(gsKeyEnabled), - AudioVolumeChange: s.GetBoolean(gsKeyAudioVolumeChange), - CameraShutter: s.GetBoolean(gsKeyCameraShutter), - CompleteCopy: s.GetBoolean(gsKeyCompleteCopy), - CompletePrint: s.GetBoolean(gsKeyCompletePrint), - DesktopLogin: s.GetBoolean(gsKeyDesktopLogin), - DesktopLogout: s.GetBoolean(gsKeyDesktopLogout), - DeviceAdded: s.GetBoolean(gsKeyDeviceAdded), - DeviceRemoved: s.GetBoolean(gsKeyDeviceRemoved), - DialogErrorCritical: s.GetBoolean(gsKeyDialogErrorCritical), - DialogError: s.GetBoolean(gsKeyDialogError), - DialogErrorSerious: s.GetBoolean(gsKeyDialogErrorSerious), - Message: s.GetBoolean(gsKeyMessage), - PowerPlug: s.GetBoolean(gsKeyPowerPlug), - PowerUnplug: s.GetBoolean(gsKeyPowerUnplug), - PowerUnplugBatteryLow: s.GetBoolean(gsKeyPowerUnplugBatteryLow), - ScreenCaptureComplete: s.GetBoolean(gsKeyScreenCaptureComplete), - ScreenCapture: s.GetBoolean(gsKeyScreenCapture), - SuspendResume: s.GetBoolean(gsKeySuspendResume), - SystemShutdown: s.GetBoolean(gsKeySystemShutdown), - TrashEmpty: s.GetBoolean(gsKeyTrashEmpty), - XDeepinAppSentToDesktop: s.GetBoolean(gsKeyXDeepinAppSentToDesktop), - }, - }, nil -} - -func (sc *syncConfig) Set(data []byte) error { - var info syncData - err := json.Unmarshal(data, &info) - if err != nil { - return err - } - soundEffect := info.SoundEffect - if soundEffect != nil { - s := gio.NewSettings(gsSchemaSoundEffect) - s.SetBoolean(gsKeyEnabled, soundEffect.Enabled) - s.SetBoolean(gsKeyAudioVolumeChange, soundEffect.AudioVolumeChange) - s.SetBoolean(gsKeyCameraShutter, soundEffect.CameraShutter) - s.SetBoolean(gsKeyCompleteCopy, soundEffect.CompleteCopy) - s.SetBoolean(gsKeyCompletePrint, soundEffect.CompletePrint) - s.SetBoolean(gsKeyDesktopLogin, soundEffect.DesktopLogin) - err = sc.syncConfigToSoundThemePlayer(soundEffect.DesktopLogin) - if err != nil { - logger.Warning(err) - } - s.SetBoolean(gsKeyDesktopLogout, soundEffect.DesktopLogout) - s.SetBoolean(gsKeyDeviceAdded, soundEffect.DeviceAdded) - s.SetBoolean(gsKeyDeviceRemoved, soundEffect.DeviceRemoved) - s.SetBoolean(gsKeyDialogErrorCritical, soundEffect.DialogErrorCritical) - s.SetBoolean(gsKeyDialogError, soundEffect.DialogError) - s.SetBoolean(gsKeyDialogErrorSerious, soundEffect.DialogErrorSerious) - s.SetBoolean(gsKeyMessage, soundEffect.Message) - s.SetBoolean(gsKeyPowerPlug, soundEffect.PowerPlug) - s.SetBoolean(gsKeyPowerUnplug, soundEffect.PowerUnplug) - s.SetBoolean(gsKeyPowerUnplugBatteryLow, soundEffect.PowerUnplugBatteryLow) - s.SetBoolean(gsKeyScreenCaptureComplete, soundEffect.ScreenCaptureComplete) - s.SetBoolean(gsKeyScreenCapture, soundEffect.ScreenCapture) - s.SetBoolean(gsKeySuspendResume, soundEffect.SuspendResume) - s.SetBoolean(gsKeySystemShutdown, soundEffect.SystemShutdown) - s.SetBoolean(gsKeyTrashEmpty, soundEffect.TrashEmpty) - s.SetBoolean(gsKeyXDeepinAppSentToDesktop, soundEffect.XDeepinAppSentToDesktop) - s.Unref() - } - return nil -} - -func (sc *syncConfig) syncConfigToSoundThemePlayer(enabled bool) error { - sysBus, err := dbus.SystemBus() - if err != nil { - return err - } - player := soundthemeplayer.NewSoundThemePlayer(sysBus) - return player.EnableSoundDesktopLogin(0, enabled) -} diff --git a/audio/util.go b/audio/util.go deleted file mode 100644 index 48a073a04..000000000 --- a/audio/util.go +++ /dev/null @@ -1,134 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package audio - -import ( - "bufio" - "bytes" - "encoding/json" - "io/ioutil" - "math" - "strings" - "unicode" - - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-api/soundutils" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" - mpris2 "github.com/linuxdeepin/go-dbus-factory/org.mpris.mediaplayer2" - //"github.com/linuxdeepin/go-lib/pulse" -) - -func isVolumeValid(v float64) bool { - if v < 0 || v > gMaxUIVolume { - return false - } - return true -} - -func playFeedback() { - playFeedbackWithDevice("") -} - -func playFeedbackWithDevice(device string) { - go func() { - err := soundutils.PlaySystemSound(soundutils.EventAudioVolumeChanged, device) - if err != nil { - logger.Warning(err) - } - }() -} - -func toJSON(v interface{}) string { - data, err := json.Marshal(v) - if err != nil { - return "" - } - return string(data) -} - -const ( - mprisPlayerDestPrefix = "org.mpris.MediaPlayer2" -) - -func getMprisPlayers(sessionConn *dbus.Conn) ([]string, error) { - var playerNames []string - dbusDaemon := ofdbus.NewDBus(sessionConn) - names, err := dbusDaemon.ListNames(0) - if err != nil { - return nil, err - } - for _, name := range names { - if strings.HasPrefix(name, mprisPlayerDestPrefix) { - // is mpris player - playerNames = append(playerNames, name) - } - } - return playerNames, nil -} - -func pauseAllPlayers() { - sessionConn, err := dbus.SessionBus() - if err != nil { - return - } - playerNames, err := getMprisPlayers(sessionConn) - if err != nil { - logger.Warning("getMprisPlayers failed:", err) - return - } - - logger.Debug("pause all players") - for _, playerName := range playerNames { - player := mpris2.NewMediaPlayer(sessionConn, playerName) - err := player.Player().Pause(0) - if err != nil { - logger.Warningf("failed to pause player %s: %v", playerName, err) - } - } -} - -// 四舍五入 -func floatPrecision(f float64) float64 { - // 精确到小数点后2位 - pow10N := math.Pow10(2) - return math.Trunc((f+0.5/pow10N)*pow10N) / pow10N - // return math.Trunc((f)*pow10N) / pow10N -} - -const defaultPaFile = "/etc/pulse/default.pa" - -func loadDefaultPaConfig(filename string) (cfg defaultPaConfig) { - content, err := ioutil.ReadFile(filename) - if err != nil { - logger.Warning(err) - return - } - - scanner := bufio.NewScanner(bytes.NewReader(content)) - for scanner.Scan() { - line := scanner.Bytes() - line = bytes.TrimLeftFunc(line, unicode.IsSpace) - if bytes.HasPrefix(line, []byte{'#'}) { - continue - } - - if bytes.Contains(line, []byte("set-default-sink")) { - cfg.setDefaultSink = true - } - if bytes.Contains(line, []byte("set-default-source")) { - cfg.setDefaultSource = true - } - } - err = scanner.Err() - if err != nil { - logger.Warning(err) - } - return -} - -type defaultPaConfig struct { - setDefaultSource bool - setDefaultSink bool -} diff --git a/audio1/alsa.go b/audio1/alsa.go new file mode 100644 index 000000000..1cc0c27e6 --- /dev/null +++ b/audio1/alsa.go @@ -0,0 +1,127 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later +package audio + +/* +#cgo pkg-config: alsa +#cgo CFLAGS: -W -Wall -fstack-protector-all -fPIC +#include +#include +#include + +// if *control_id != NULL, need free *control_id +static int find_control(int card_num, char *name, char **control_id) { + snd_hctl_t *handle; + char card[8]; + snprintf(card, 8, "hw:%d", card_num); + int err; + err = snd_hctl_open(&handle, card, 0); + if (err < 0) { + fprintf(stderr, "Control %s open error: %s\n", card, snd_strerror(err)); + return err; + } + + err = snd_hctl_load(handle); + if (err < 0) { + fprintf(stderr, "Control %s load error: %s\n", card, snd_strerror(err)); + return err; + } + + snd_hctl_elem_t *elem; + snd_ctl_elem_id_t *id; + snd_ctl_elem_id_alloca(&id); + for (elem = snd_hctl_first_elem(handle); elem != NULL; elem = snd_hctl_elem_next(elem)) { + snd_hctl_elem_get_id(elem, id); + char *id_str = snd_ctl_ascii_elem_id_get(id); + if (id_str != NULL) { + if (strstr(id_str, name) != NULL) { + *control_id = id_str; + break; + } else { + free(id_str); + } + } + } + + snd_hctl_close(handle); + return 0; +} + +// if *control_id != NULL, need free *control_id +static int find_card_control(char *name, int *card_num, char **control_id) { + *card_num = -1; + int err; + while(1) { + err = snd_card_next(card_num); + if (err < 0) { + fprintf(stderr, "card next err: %s\n", snd_strerror(err)); + return err; + } + if (*card_num == -1) { + // no more cards are available. + break; + } + + err = find_control(*card_num, name, control_id); + if (err < 0) { + return err; + } + + if (*control_id != NULL) { + break; + } + } + return 0; +} +*/ +import "C" +import ( + "errors" + "fmt" + "os/exec" + "strconv" + "unsafe" +) + +var errNotFoundControl = errors.New("not found control") + +func findCardControl(name string) (card int, controlId string, err error) { + var cCard C.int + var cControlId *C.char + cName := C.CString(name) + + cErr := C.find_card_control(cName, &cCard, &cControlId) + C.free(unsafe.Pointer(cName)) + + if cErr < 0 { + err = fmt.Errorf("find_card_control err code: %d", err) + return + } + + if cControlId != nil { + card = int(cCard) + controlId = C.GoString(cControlId) + C.free(unsafe.Pointer(cControlId)) + return + } + + err = errNotFoundControl + return +} + +func disableAutoMuteMode() error { + cardNum, controlId, err := findCardControl("Auto-Mute Mode") + if err != nil { + if err == errNotFoundControl { + err = nil + } + return err + } + out, err := exec.Command("amixer", "-c", strconv.Itoa(cardNum), "cset", controlId, "Disabled").Output() + if err != nil { + return err + } + logger.Debugf("command amixer -c %d cset %s Disabled\n out: %s", cardNum, controlId, out) + return nil +} diff --git a/audio/audio.go b/audio1/audio.go similarity index 95% rename from audio/audio.go rename to audio1/audio.go index b572da78b..37d543d74 100644 --- a/audio/audio.go +++ b/audio1/audio.go @@ -15,7 +15,7 @@ import ( "sync" "time" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-daemon/common/dsync" gio "github.com/linuxdeepin/go-gir/gio-2.0" "github.com/linuxdeepin/go-lib/dbusutil" @@ -42,8 +42,8 @@ const ( gsKeyEnabled = "enabled" gsKeyDisableAutoMute = "disable-auto-mute" - dbusServiceName = "com.deepin.daemon.Audio" - dbusPath = "/com/deepin/daemon/Audio" + dbusServiceName = "org.deepin.dde.Audio1" + dbusPath = "/org/deepin/dde/Audio1" dbusInterface = dbusServiceName cmdSystemctl = "systemctl" @@ -58,6 +58,7 @@ const ( dsgKeyReduceNoise = "reduceNoise" dsgKeyInputDefaultPriorities = "inputDefaultPrioritiesByType" dsgKeyOutputDefaultPriorities = "outputDefaultPrioritiesByType" + dsgKeyBluezModeDefault = "bluezModeDefault" ) var ( @@ -672,11 +673,19 @@ func (a *Audio) init() error { } for _, source := range a.sources { - if source.Name == a.defaultSourceName { + if strings.Contains(a.defaultSourceName, "record_mono") && strings.Contains(source.Name, "alsa_input.platform-rk809-sound.analog-stereo") { a.defaultSource = source a.PropsMu.Lock() a.setPropDefaultSource(source.getPath()) a.PropsMu.Unlock() + logger.Debug("init setPropDefaultSource:", source.Name, source.getPath()) + } else { + if source.Name == a.defaultSourceName { + a.defaultSource = source + a.PropsMu.Lock() + a.setPropDefaultSource(source.getPath()) + a.PropsMu.Unlock() + } } } a.mu.Unlock() @@ -731,7 +740,7 @@ func (a *Audio) init() error { a.moveSinkInputsToDefaultSink() // 蓝牙支持的模式 - a.setPropBluetoothAudioModeOpts([]string{"a2dp", "headset"}) + a.setPropBluetoothAudioModeOpts([]string{"a2dp", "headset", "handsfree"}) return nil } @@ -879,10 +888,15 @@ func (a *Audio) setDefaultSourceWithPort(cardId uint32, portName string) error { logger.Debugf("set source #%d port %s", source.Index, portName) a.ctx.SetSourcePortByIndex(source.Index, portName) } - + logger.Debug("a.getDefaultSourceName() ", a.getDefaultSourceName()) if a.getDefaultSourceName() != source.Name { - logger.Debugf("set default source #%d %s", source.Index, source.Name) - a.ctx.SetDefaultSource(source.Name) + if strings.Contains(source.Name, "platform-rk809-sound.analog-stereo") { + a.ctx.SetDefaultSource("record_mono") + a.updateDefaultSource(source.Name) + logger.Debugf("set default source %s as record_mono", source.Name) + } else { + a.ctx.SetDefaultSource(source.Name) + } } return nil @@ -1373,6 +1387,14 @@ func (a *Audio) updateDefaultSource(sourceName string) { } logger.Debugf("updateDefaultSource #%d %s", sourceInfo.Index, sourceName) + if !isPhysicalDevice(sourceName) { + sourceInfo = a.getSourceInfoByName(sourceInfo.Proplist["device.master_device"]) + if sourceInfo == nil { + logger.Warning("failed to get virtual device sourceInfo for name:", sourceName) + return + } + } + logger.Debug("sourceInfo", sourceInfo) a.mu.Lock() source, ok := a.sources[sourceInfo.Index] a.mu.Unlock() @@ -1386,6 +1408,16 @@ func (a *Audio) updateDefaultSource(sourceName string) { } } + if strings.Contains(source.Name, "record_mono") { + sourceInfo := a.getSourceInfoByName("alsa_input.platform-rk809-sound.analog-stereo") + if sourceInfo != nil { + a.mu.Lock() + if v, ok := a.sources[sourceInfo.Index]; ok { + source = v + } + a.mu.Unlock() + } + } a.mu.Lock() a.defaultSource = source a.mu.Unlock() @@ -1584,7 +1616,7 @@ func (a *Audio) SetBluetoothAudioMode(mode string) *dbus.Error { card.core.SetProfile(profile.Name) // 手动切换蓝牙模式为headset, - if mode == bluezModeHeadset { + if mode == bluezModeHeadset || mode == bluezModeHandsfree { a.inputAutoSwitchCount = 0 GetPriorityManager().Input.SetTheFirstType(PortTypeBluetooth) } @@ -1707,6 +1739,21 @@ func (a *Audio) initDsgProp() error { } logger.Info("output default priority list", outputDefaultPriorities) } + + getBluezModeDefault := func() { + var val string + err = systemConnObj.Call("org.desktopspec.ConfigManager.Manager.value", 0, dsgKeyBluezModeDefault).Store(&val) + if err != nil { + logger.Warning(err) + } else { + if val == bluezModeA2dp || val == bluezModeHandsfree || val == bluezModeHeadset { + bluezModeDefault = val + logger.Info("bluez default mode:", bluezModeDefault) + } + } + } + getBluezModeDefault() + // 监听dsg配置变化 a.systemSigLoop.AddHandler(&dbusutil.SignalRule{ Name: "org.desktopspec.ConfigManager.Manager.valueChanged", @@ -1714,14 +1761,19 @@ func (a *Audio) initDsgProp() error { if strings.Contains(sig.Name, "org.desktopspec.ConfigManager.Manager.valueChanged") && strings.Contains(string(sig.Path), "org_deepin_dde_daemon_audio") && len(sig.Body) >= 1 { key, ok := sig.Body[0].(string) - if ok && key == dsgKeyAutoSwitchPort { - var val bool - err = systemConnObj.Call("org.desktopspec.ConfigManager.Manager.value", 0, key).Store(&val) - if err != nil { - logger.Warning(err) - } else { - logger.Info("auto switch port:", val) - a.setEnableAutoSwitchPort(val) + if ok { + switch key { + case dsgKeyAutoSwitchPort: + var val bool + err = systemConnObj.Call("org.desktopspec.ConfigManager.Manager.value", 0, key).Store(&val) + if err != nil { + logger.Warning(err) + } else { + logger.Info("auto switch port:", val) + a.setEnableAutoSwitchPort(val) + } + case dsgKeyBluezModeDefault: + getBluezModeDefault() } } diff --git a/audio/audio_config.go b/audio1/audio_config.go similarity index 97% rename from audio/audio_config.go rename to audio1/audio_config.go index 11d2cf97e..a452a177f 100644 --- a/audio/audio_config.go +++ b/audio1/audio_config.go @@ -9,8 +9,8 @@ import ( "os/exec" "time" - dbus "github.com/godbus/dbus" - soundthemeplayer "github.com/linuxdeepin/go-dbus-factory/com.deepin.api.soundthemeplayer" + dbus "github.com/godbus/dbus/v5" + soundthemeplayer "github.com/linuxdeepin/go-dbus-factory/system/com.deepin.api.soundthemeplayer" "github.com/linuxdeepin/go-lib/asound" "github.com/linuxdeepin/go-lib/pulse" ) diff --git a/audio/audio_dbusutil.go b/audio1/audio_dbusutil.go similarity index 99% rename from audio/audio_dbusutil.go rename to audio1/audio_dbusutil.go index 830ea95db..43a62d3f8 100644 --- a/audio/audio_dbusutil.go +++ b/audio1/audio_dbusutil.go @@ -3,7 +3,7 @@ package audio import ( - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" ) func (v *Audio) setPropSinkInputs(value []dbus.ObjectPath) (changed bool) { diff --git a/audio/audio_events.go b/audio1/audio_events.go similarity index 98% rename from audio/audio_events.go rename to audio1/audio_events.go index e09b7a91a..beaa1c0ff 100644 --- a/audio/audio_events.go +++ b/audio1/audio_events.go @@ -11,8 +11,8 @@ import ( "strconv" "strings" - dbus "github.com/godbus/dbus" - notifications "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.notifications" + dbus "github.com/godbus/dbus/v5" + notifications "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.notifications" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/gettext" "github.com/linuxdeepin/go-lib/gsettings" @@ -358,7 +358,7 @@ func (a *Audio) handleSinkChanged(idx uint32) { logger.Debugf("sink %d changed", idx) // 蓝牙模式切换、触发sink change - if a.defaultSink.index == idx && isBluezAudio(a.defaultSink.Name) { + if a.defaultSink != nil && a.defaultSink.index == idx && isBluezAudio(a.defaultSink.Name) { card, err := a.cards.get(a.defaultSink.Card) if err == nil { a.setPropBluetoothAudioMode(card.BluezMode()) @@ -435,9 +435,9 @@ func (a *Audio) handleSinkInputChanged(idx uint32) { /* 创建开启端口的命令,提供给notification调用 */ func makeNotifyCmdEnablePort(cardId uint32, portName string) string { - dest := "com.deepin.daemon.Audio" - path := "/com/deepin/daemon/Audio" - method := "com.deepin.daemon.Audio.SetPortEnabled" + dest := "org.deepin.dde.Audio1" + path := "/org/deepin/dde/Audio1" + method := "org.deepin.dde.Audio1.SetPortEnabled" return fmt.Sprintf("dbus-send,--type=method_call,--dest=%s,%s,%s,uint32:%d,string:%s,boolean:true", dest, path, method, cardId, portName) } diff --git a/audio/audio_test.go b/audio1/audio_test.go similarity index 87% rename from audio/audio_test.go rename to audio1/audio_test.go index 8da240235..c15b192dc 100644 --- a/audio/audio_test.go +++ b/audio1/audio_test.go @@ -9,15 +9,15 @@ import ( "github.com/stretchr/testify/assert" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/pulse" ) func Test_objectPathSliceEqual(t *testing.T) { - var str = []dbus.ObjectPath{"/com/deepin/daemon/Bluetooth", "/com/deepin/daemon/Audio"} - var str1 = []dbus.ObjectPath{"/com/deepin/daemon/Bluetooth", "/com/deepin/daemon/Audio"} - var str2 = []dbus.ObjectPath{"/com/deepin/daemon/Bluetooth", "/com/deepin/daemon/Audio", "/"} - var str3 = []dbus.ObjectPath{"/com/deepin/daemon/Bluetooth", "/com/deepin/daemon/Accounts"} + var str = []dbus.ObjectPath{"/org/deepin/dde/Bluetooth1", "/org/deepin/dde/Audio1"} + var str1 = []dbus.ObjectPath{"/org/deepin/dde/Bluetooth1", "/org/deepin/dde/Audio1"} + var str2 = []dbus.ObjectPath{"/org/deepin/dde/Bluetooth1", "/org/deepin/dde/Audio1", "/"} + var str3 = []dbus.ObjectPath{"/org/deepin/dde/Bluetooth1", "/org/deepin/dde/Accounts1"} assert.Equal(t, objectPathSliceEqual(str, str1), true) assert.Equal(t, objectPathSliceEqual(str, str2), false) diff --git a/audio/bluez_audio.go b/audio1/bluez_audio.go similarity index 91% rename from audio/bluez_audio.go rename to audio1/bluez_audio.go index e72361bc6..4e1e7fa76 100644 --- a/audio/bluez_audio.go +++ b/audio1/bluez_audio.go @@ -10,19 +10,20 @@ import ( "path/filepath" "strings" - dbus "github.com/godbus/dbus" - bluez "github.com/linuxdeepin/go-dbus-factory/org.bluez" + dbus "github.com/godbus/dbus/v5" + bluez "github.com/linuxdeepin/go-dbus-factory/system/org.bluez" "github.com/linuxdeepin/go-lib/strv" "github.com/linuxdeepin/go-lib/xdg/basedir" ) const ( - bluezModeA2dp = "a2dp" - bluezModeHeadset = "headset" - bluezModeDefault = bluezModeA2dp + bluezModeA2dp = "a2dp" + bluezModeHeadset = "headset" + bluezModeHandsfree = "handsfree" ) var ( + bluezModeDefault = bluezModeA2dp bluezModeFilterList = []string{"a2dp_source"} ) @@ -166,6 +167,8 @@ func (card *Card) BluezMode() string { return bluezModeA2dp } else if strings.Contains(strings.ToLower(profileName), bluezModeHeadset) { return bluezModeHeadset + } else if strings.Contains(strings.ToLower(profileName), bluezModeHandsfree) { + return bluezModeHandsfree } else { return "" } @@ -188,11 +191,6 @@ func (card *Card) BluezModeOpts() []string { continue } - if strings.Contains(profile.Description, "HFP") && !strings.Contains(profile.Description, "HSP") { - logger.Debugf("%s %s is a HFP profile", card.core.Name, profile.Name) - continue - } - if strings.Contains(strings.ToLower(profile.Name), "a2dp") { opts = append(opts, "a2dp") } @@ -200,6 +198,10 @@ func (card *Card) BluezModeOpts() []string { if strings.Contains(strings.ToLower(profile.Name), "headset") { opts = append(opts, "headset") } + + if strings.Contains(strings.ToLower(profile.Name), "handsfree") { + opts = append(opts, "handsfree") + } } return opts } diff --git a/audio/card.go b/audio1/card.go similarity index 98% rename from audio/card.go rename to audio1/card.go index 2fd23656a..641d18693 100644 --- a/audio/card.go +++ b/audio1/card.go @@ -171,7 +171,7 @@ func (cards CardList) string() string { Bluetooth: isBluetoothCard(cardInfo.core), Description: portInfo.Description, Direction: portInfo.Direction, - PortType: DetectPortType(cardInfo.core, &portInfo), + PortType: GetIconPortType(cardInfo.Name, portInfo.Name), }) } @@ -200,7 +200,7 @@ func (cards CardList) stringWithoutUnavailable() string { Bluetooth: isBluetoothCard(cardInfo.core), Description: portInfo.Description, Direction: portInfo.Direction, - PortType: DetectPortType(cardInfo.core, &portInfo), + PortType: GetIconPortType(cardInfo.Name, portInfo.Name), }) } diff --git a/audio/card_profile_workaround.go b/audio1/card_profile_workaround.go similarity index 94% rename from audio/card_profile_workaround.go rename to audio1/card_profile_workaround.go index 2058342fd..cca4fcb57 100644 --- a/audio/card_profile_workaround.go +++ b/audio1/card_profile_workaround.go @@ -8,8 +8,8 @@ import ( "fmt" "sort" - dbus "github.com/godbus/dbus" - bluez "github.com/linuxdeepin/go-dbus-factory/org.bluez" + dbus "github.com/godbus/dbus/v5" + bluez "github.com/linuxdeepin/go-dbus-factory/system/org.bluez" "github.com/linuxdeepin/go-lib/pulse" "github.com/linuxdeepin/go-lib/strv" ) @@ -46,7 +46,7 @@ func profileBlacklist(c *pulse.Card) strv.Strv { return strv.Strv(blacklist) } -//select New Card Profile By priority, protocl. +// select New Card Profile By priority, protocl. func selectNewCardProfile(c *pulse.Card) { blacklist := profileBlacklist(c) if !blacklist.Contains(c.ActiveProfile.Name) { diff --git a/audio/card_test.go b/audio1/card_test.go similarity index 100% rename from audio/card_test.go rename to audio1/card_test.go diff --git a/audio/config.go b/audio1/config.go similarity index 100% rename from audio/config.go rename to audio1/config.go diff --git a/audio/config_keeper.go b/audio1/config_keeper.go similarity index 100% rename from audio/config_keeper.go rename to audio1/config_keeper.go diff --git a/audio/config_keeper_test.go b/audio1/config_keeper_test.go similarity index 100% rename from audio/config_keeper_test.go rename to audio1/config_keeper_test.go diff --git a/audio/config_test.go b/audio1/config_test.go similarity index 100% rename from audio/config_test.go rename to audio1/config_test.go diff --git a/audio/exported_methods_auto.go b/audio1/exported_methods_auto.go similarity index 100% rename from audio/exported_methods_auto.go rename to audio1/exported_methods_auto.go diff --git a/audio/meter.go b/audio1/meter.go similarity index 93% rename from audio/meter.go rename to audio1/meter.go index a1a5b55ee..160cafb22 100644 --- a/audio/meter.go +++ b/audio1/meter.go @@ -8,7 +8,7 @@ import ( "sync" "time" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/pulse" ) @@ -23,7 +23,7 @@ type Meter struct { core *pulse.SourceMeter } -//TODO: use pulse.Meter instead of remove pulse.SourceMeter +// TODO: use pulse.Meter instead of remove pulse.SourceMeter func newMeter(id string, core *pulse.SourceMeter, audio *Audio) *Meter { m := &Meter{ id: id, diff --git a/audio/module.go b/audio1/module.go similarity index 100% rename from audio/module.go rename to audio1/module.go diff --git a/audio/port.go b/audio1/port.go similarity index 100% rename from audio/port.go rename to audio1/port.go diff --git a/audio/port_test.go b/audio1/port_test.go similarity index 100% rename from audio/port_test.go rename to audio1/port_test.go diff --git a/audio/priority_manager.go b/audio1/priority_manager.go similarity index 100% rename from audio/priority_manager.go rename to audio1/priority_manager.go diff --git a/audio/priority_old.go b/audio1/priority_old.go similarity index 94% rename from audio/priority_old.go rename to audio1/priority_old.go index e33d55ecc..3989ab8e8 100644 --- a/audio/priority_old.go +++ b/audio1/priority_old.go @@ -62,18 +62,50 @@ func GetPortType(cardName string, portName string) int { return PortTypeMultiChannel } + if contains(cardName, portName, "bluez") || + contains(cardName, portName, "bluetooth") { + return PortTypeBluetooth + } + + if contains(cardName, portName, "linein") || + contains(cardName, portName, "lineout") { + return PortTypeLineIO + } + + if contains(cardName, portName, "usb") || + contains(cardName, portName, "rear-mic") || + contains(cardName, portName, "front-mic") || + contains(cardName, portName, "headset") || + contains(cardName, portName, "headphone") { + return PortTypeHeadset + } + + if contains(cardName, portName, "hdmi") { + return PortTypeHdmi + } + if contains(cardName, portName, "speaker") || contains(cardName, portName, "input-mic") { return PortTypeBuiltin } + return PortTypeUnknown +} + +// 图标类型 扬声器 > 耳机 > HDMI > 蓝牙 +func GetIconPortType(cardName string, portName string) int { + if contains(cardName, portName, "linein") || contains(cardName, portName, "lineout") { return PortTypeLineIO } - if contains(cardName, portName, "usb") || - contains(cardName, portName, "rear-mic") || + if contains(cardName, portName, "speaker") || + contains(cardName, portName, "input-mic") { + return PortTypeBuiltin + } + + if contains(cardName, portName, "rear-mic") || contains(cardName, portName, "front-mic") || contains(cardName, portName, "headset") || contains(cardName, portName, "headphone") { @@ -89,6 +121,10 @@ func GetPortType(cardName string, portName string) int { return PortTypeBluetooth } + if contains(cardName, portName, "usb") { + return PortTypeUsb + } + return PortTypeUnknown } diff --git a/audio/priority_policy.go b/audio1/priority_policy.go similarity index 99% rename from audio/priority_policy.go rename to audio1/priority_policy.go index 8437dfad3..2200c6580 100644 --- a/audio/priority_policy.go +++ b/audio1/priority_policy.go @@ -49,12 +49,9 @@ func DetectPortType(card *pulse.Card, port *pulse.CardPortInfo) int { return PortTypeMultiChannel } - if hasKeyword(stringList, "speaker") || - hasKeyword(stringList, "input-mic") { - if hasKeyword(stringList, "usb") { - return PortTypeUsb - } - return PortTypeBuiltin + if hasKeyword(stringList, "bluez") || + hasKeyword(stringList, "bluetooth") { + return PortTypeBluetooth } if hasKeyword(stringList, "linein") || @@ -77,9 +74,9 @@ func DetectPortType(card *pulse.Card, port *pulse.CardPortInfo) int { return PortTypeHdmi } - if hasKeyword(stringList, "bluez") || - hasKeyword(stringList, "bluetooth") { - return PortTypeBluetooth + if hasKeyword(stringList, "speaker") || + hasKeyword(stringList, "input-mic") { + return PortTypeBuiltin } return PortTypeUnknown diff --git a/audio/priority_test.go b/audio1/priority_test.go similarity index 99% rename from audio/priority_test.go rename to audio1/priority_test.go index 5259b4c11..50163aa69 100644 --- a/audio/priority_test.go +++ b/audio1/priority_test.go @@ -25,7 +25,7 @@ func Test_GetPortType(t *testing.T) { assert.Equal(t, GetPortType("usb.abcd.1234", "world.abcd.1234"), PortTypeHeadset) assert.Equal(t, GetPortType("hbc.abcd.1234", "usb.abcd.1234"), PortTypeHeadset) assert.Equal(t, GetPortType("hello.abcd.speaker", "world.abcd.1234"), PortTypeBuiltin) - assert.Equal(t, GetPortType("hdmi.abcd.speaker", "world.abcd.1234"), PortTypeBuiltin) + assert.Equal(t, GetPortType("hdmi.abcd.speaker", "world.abcd.1234"), PortTypeHdmi) } func Test_IsInputTypeAfter(t *testing.T) { diff --git a/audio/profile.go b/audio1/profile.go similarity index 100% rename from audio/profile.go rename to audio1/profile.go diff --git a/audio/sink.go b/audio1/sink.go similarity index 99% rename from audio/sink.go rename to audio1/sink.go index 4e50eefb8..18e17025d 100644 --- a/audio/sink.go +++ b/audio1/sink.go @@ -9,7 +9,7 @@ import ( "strconv" "sync" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/pulse" ) @@ -184,7 +184,6 @@ func (s *Sink) SetFade(value float64) *dbus.Error { // v: volume音量值 // b: balance左右平衡值 // f: fade前后平衡值 -// func (s *Sink) setVBF(v, b, f float64) *dbus.Error { if !isVolumeValid(v) { return dbusutil.ToError(fmt.Errorf("invalid volume value: %v", v)) diff --git a/audio/sinkinput.go b/audio1/sinkinput.go similarity index 99% rename from audio/sinkinput.go rename to audio1/sinkinput.go index 17e6c9a88..3ef6fa226 100644 --- a/audio/sinkinput.go +++ b/audio1/sinkinput.go @@ -10,7 +10,7 @@ import ( "strings" "sync" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/procfs" "github.com/linuxdeepin/go-lib/pulse" diff --git a/audio/source.go b/audio1/source.go similarity index 99% rename from audio/source.go rename to audio1/source.go index ef0a533b6..0208caea3 100644 --- a/audio/source.go +++ b/audio1/source.go @@ -9,7 +9,7 @@ import ( "strconv" "sync" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/pulse" ) @@ -165,7 +165,6 @@ func (s *Source) SetFade(value float64) *dbus.Error { // v: volume音量值 // b: balance左右平衡值 // f: fade前后平衡值 -// func (s *Source) setVBF(v, b, f float64) *dbus.Error { if v < -1.00 || v > 1.00 { return dbusutil.ToError(fmt.Errorf("invalid volume value: %v", v)) diff --git a/audio1/sync_config.go b/audio1/sync_config.go new file mode 100644 index 000000000..79321e355 --- /dev/null +++ b/audio1/sync_config.go @@ -0,0 +1,156 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package audio + +import ( + "encoding/json" + + dbus "github.com/godbus/dbus/v5" + soundthemeplayer "github.com/linuxdeepin/go-dbus-factory/system/com.deepin.api.soundthemeplayer" + gio "github.com/linuxdeepin/go-gir/gio-2.0" +) + +const ( + gsKeyAudioVolumeChange = "audio-volume-change" + gsKeyCameraShutter = "camera-shutter" + gsKeyCompleteCopy = "complete-copy" + gsKeyCompletePrint = "complete-print" + gsKeyDesktopLogin = "desktop-login" + gsKeyDesktopLogout = "desktop-logout" + gsKeyDeviceAdded = "device-added" + gsKeyDeviceRemoved = "device-removed" + gsKeyDialogErrorCritical = "dialog-error-critical" + gsKeyDialogError = "dialog-error" + gsKeyDialogErrorSerious = "dialog-error-serious" + gsKeyMessage = "message" + gsKeyPowerPlug = "power-plug" + gsKeyPowerUnplug = "power-unplug" + gsKeyPowerUnplugBatteryLow = "power-unplug-battery-low" + gsKeyScreenCaptureComplete = "screen-capture-complete" + gsKeyScreenCapture = "screen-capture" + gsKeySuspendResume = "suspend-resume" + gsKeySystemShutdown = "system-shutdown" + gsKeyTrashEmpty = "trash-empty" + gsKeyXDeepinAppSentToDesktop = "x-deepin-app-sent-to-desktop" +) + +type syncSoundEffect struct { + Enabled bool `json:"enabled"` + AudioVolumeChange bool `json:"audio_volume_change"` + CameraShutter bool `json:"camera_shutter"` + CompleteCopy bool `json:"complete_copy"` + CompletePrint bool `json:"complete_print"` + DesktopLogin bool `json:"desktop_login"` + DesktopLogout bool `json:"desktop_logout"` + DeviceAdded bool `json:"device_added"` + DeviceRemoved bool `json:"device_removed"` + DialogErrorCritical bool `json:"dialog_error_critical"` + DialogError bool `json:"dialog_error"` + DialogErrorSerious bool `json:"dialog_error_serious"` + Message bool `json:"message"` + PowerPlug bool `json:"power_plug"` + PowerUnplug bool `json:"power_unplug"` + PowerUnplugBatteryLow bool `json:"power_unplug_battery_low"` + ScreenCaptureComplete bool `json:"screen_capture_complete"` + ScreenCapture bool `json:"screen_capture"` + SuspendResume bool `json:"suspend_resume"` + SystemShutdown bool `json:"system_shutdown"` + TrashEmpty bool `json:"trash_empty"` + XDeepinAppSentToDesktop bool `json:"x_deepin_app_sent_to_desktop"` +} + +type syncData struct { + Version string `json:"version"` + SoundEffect *syncSoundEffect `json:"soundeffect"` +} + +type syncConfig struct { + a *Audio +} + +const ( + syncVersion = "1.0" +) + +func (sc *syncConfig) Get() (interface{}, error) { + s := gio.NewSettings(gsSchemaSoundEffect) + defer s.Unref() + return &syncData{ + Version: syncVersion, + SoundEffect: &syncSoundEffect{ + Enabled: s.GetBoolean(gsKeyEnabled), + AudioVolumeChange: s.GetBoolean(gsKeyAudioVolumeChange), + CameraShutter: s.GetBoolean(gsKeyCameraShutter), + CompleteCopy: s.GetBoolean(gsKeyCompleteCopy), + CompletePrint: s.GetBoolean(gsKeyCompletePrint), + DesktopLogin: s.GetBoolean(gsKeyDesktopLogin), + DesktopLogout: s.GetBoolean(gsKeyDesktopLogout), + DeviceAdded: s.GetBoolean(gsKeyDeviceAdded), + DeviceRemoved: s.GetBoolean(gsKeyDeviceRemoved), + DialogErrorCritical: s.GetBoolean(gsKeyDialogErrorCritical), + DialogError: s.GetBoolean(gsKeyDialogError), + DialogErrorSerious: s.GetBoolean(gsKeyDialogErrorSerious), + Message: s.GetBoolean(gsKeyMessage), + PowerPlug: s.GetBoolean(gsKeyPowerPlug), + PowerUnplug: s.GetBoolean(gsKeyPowerUnplug), + PowerUnplugBatteryLow: s.GetBoolean(gsKeyPowerUnplugBatteryLow), + ScreenCaptureComplete: s.GetBoolean(gsKeyScreenCaptureComplete), + ScreenCapture: s.GetBoolean(gsKeyScreenCapture), + SuspendResume: s.GetBoolean(gsKeySuspendResume), + SystemShutdown: s.GetBoolean(gsKeySystemShutdown), + TrashEmpty: s.GetBoolean(gsKeyTrashEmpty), + XDeepinAppSentToDesktop: s.GetBoolean(gsKeyXDeepinAppSentToDesktop), + }, + }, nil +} + +func (sc *syncConfig) Set(data []byte) error { + var info syncData + err := json.Unmarshal(data, &info) + if err != nil { + return err + } + soundEffect := info.SoundEffect + if soundEffect != nil { + s := gio.NewSettings(gsSchemaSoundEffect) + s.SetBoolean(gsKeyEnabled, soundEffect.Enabled) + s.SetBoolean(gsKeyAudioVolumeChange, soundEffect.AudioVolumeChange) + s.SetBoolean(gsKeyCameraShutter, soundEffect.CameraShutter) + s.SetBoolean(gsKeyCompleteCopy, soundEffect.CompleteCopy) + s.SetBoolean(gsKeyCompletePrint, soundEffect.CompletePrint) + s.SetBoolean(gsKeyDesktopLogin, soundEffect.DesktopLogin) + err = sc.syncConfigToSoundThemePlayer(soundEffect.DesktopLogin) + if err != nil { + logger.Warning(err) + } + s.SetBoolean(gsKeyDesktopLogout, soundEffect.DesktopLogout) + s.SetBoolean(gsKeyDeviceAdded, soundEffect.DeviceAdded) + s.SetBoolean(gsKeyDeviceRemoved, soundEffect.DeviceRemoved) + s.SetBoolean(gsKeyDialogErrorCritical, soundEffect.DialogErrorCritical) + s.SetBoolean(gsKeyDialogError, soundEffect.DialogError) + s.SetBoolean(gsKeyDialogErrorSerious, soundEffect.DialogErrorSerious) + s.SetBoolean(gsKeyMessage, soundEffect.Message) + s.SetBoolean(gsKeyPowerPlug, soundEffect.PowerPlug) + s.SetBoolean(gsKeyPowerUnplug, soundEffect.PowerUnplug) + s.SetBoolean(gsKeyPowerUnplugBatteryLow, soundEffect.PowerUnplugBatteryLow) + s.SetBoolean(gsKeyScreenCaptureComplete, soundEffect.ScreenCaptureComplete) + s.SetBoolean(gsKeyScreenCapture, soundEffect.ScreenCapture) + s.SetBoolean(gsKeySuspendResume, soundEffect.SuspendResume) + s.SetBoolean(gsKeySystemShutdown, soundEffect.SystemShutdown) + s.SetBoolean(gsKeyTrashEmpty, soundEffect.TrashEmpty) + s.SetBoolean(gsKeyXDeepinAppSentToDesktop, soundEffect.XDeepinAppSentToDesktop) + s.Unref() + } + return nil +} + +func (sc *syncConfig) syncConfigToSoundThemePlayer(enabled bool) error { + sysBus, err := dbus.SystemBus() + if err != nil { + return err + } + player := soundthemeplayer.NewSoundThemePlayer(sysBus) + return player.EnableSoundDesktopLogin(0, enabled) +} diff --git a/audio/testdata/bluezAudio.json b/audio1/testdata/bluezAudio.json similarity index 100% rename from audio/testdata/bluezAudio.json rename to audio1/testdata/bluezAudio.json diff --git a/audio1/util.go b/audio1/util.go new file mode 100644 index 000000000..f128b8ae5 --- /dev/null +++ b/audio1/util.go @@ -0,0 +1,134 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package audio + +import ( + "bufio" + "bytes" + "encoding/json" + "io/ioutil" + "math" + "strings" + "unicode" + + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-api/soundutils" + ofdbus "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.dbus" + mpris2 "github.com/linuxdeepin/go-dbus-factory/session/org.mpris.mediaplayer2" + //"github.com/linuxdeepin/go-lib/pulse" +) + +func isVolumeValid(v float64) bool { + if v < 0 || v > gMaxUIVolume { + return false + } + return true +} + +func playFeedback() { + playFeedbackWithDevice("") +} + +func playFeedbackWithDevice(device string) { + go func() { + err := soundutils.PlaySystemSound(soundutils.EventAudioVolumeChanged, device) + if err != nil { + logger.Warning(err) + } + }() +} + +func toJSON(v interface{}) string { + data, err := json.Marshal(v) + if err != nil { + return "" + } + return string(data) +} + +const ( + mprisPlayerDestPrefix = "org.mpris.MediaPlayer2" +) + +func getMprisPlayers(sessionConn *dbus.Conn) ([]string, error) { + var playerNames []string + dbusDaemon := ofdbus.NewDBus(sessionConn) + names, err := dbusDaemon.ListNames(0) + if err != nil { + return nil, err + } + for _, name := range names { + if strings.HasPrefix(name, mprisPlayerDestPrefix) { + // is mpris player + playerNames = append(playerNames, name) + } + } + return playerNames, nil +} + +func pauseAllPlayers() { + sessionConn, err := dbus.SessionBus() + if err != nil { + return + } + playerNames, err := getMprisPlayers(sessionConn) + if err != nil { + logger.Warning("getMprisPlayers failed:", err) + return + } + + logger.Debug("pause all players") + for _, playerName := range playerNames { + player := mpris2.NewMediaPlayer(sessionConn, playerName) + err := player.Player().Pause(0) + if err != nil { + logger.Warningf("failed to pause player %s: %v", playerName, err) + } + } +} + +// 四舍五入 +func floatPrecision(f float64) float64 { + // 精确到小数点后2位 + pow10N := math.Pow10(2) + return math.Trunc((f+0.5/pow10N)*pow10N) / pow10N + // return math.Trunc((f)*pow10N) / pow10N +} + +const defaultPaFile = "/etc/pulse/default.pa" + +func loadDefaultPaConfig(filename string) (cfg defaultPaConfig) { + content, err := ioutil.ReadFile(filename) + if err != nil { + logger.Warning(err) + return + } + + scanner := bufio.NewScanner(bytes.NewReader(content)) + for scanner.Scan() { + line := scanner.Bytes() + line = bytes.TrimLeftFunc(line, unicode.IsSpace) + if bytes.HasPrefix(line, []byte{'#'}) { + continue + } + + if bytes.Contains(line, []byte("set-default-sink")) { + cfg.setDefaultSink = true + } + if bytes.Contains(line, []byte("set-default-source")) { + cfg.setDefaultSource = true + } + } + err = scanner.Err() + if err != nil { + logger.Warning(err) + } + return +} + +type defaultPaConfig struct { + setDefaultSource bool + setDefaultSink bool +} diff --git a/audio/util_test.go b/audio1/util_test.go similarity index 100% rename from audio/util_test.go rename to audio1/util_test.go diff --git a/bin/backlight_helper/ddcci/ddcci.go b/bin/backlight_helper/ddcci/ddcci.go index 1d10505cb..1277e47a2 100644 --- a/bin/backlight_helper/ddcci/ddcci.go +++ b/bin/backlight_helper/ddcci/ddcci.go @@ -112,10 +112,10 @@ func newDDCCI() (*ddcci, error) { displayHandleMap: make(map[string]*displayHandle), } - status := C.ddca_set_max_tries(C.DDCA_MULTI_PART_TRIES, 5) - if status < C.int(0) { - return nil, fmt.Errorf("brightness: Error setting retries: %d", status) - } + //status := C.ddca_set_max_tries(C.DDCA_MULTI_PART_TRIES, 5) + //if status < C.int(0) { + // return nil, fmt.Errorf("brightness: Error setting retries: %d", status) + //} err := ddc.RefreshDisplays() if err != nil { diff --git a/bin/backlight_helper/ddcci/manager.go b/bin/backlight_helper/ddcci/manager.go index 898153773..1200e5034 100644 --- a/bin/backlight_helper/ddcci/manager.go +++ b/bin/backlight_helper/ddcci/manager.go @@ -8,15 +8,15 @@ import ( "fmt" "sync" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/log" x "github.com/linuxdeepin/go-x11-client" ) const ( - DbusPath = "/com/deepin/daemon/helper/Backlight/DDCCI" - dbusInterface = "com.deepin.daemon.helper.Backlight.DDCCI" + DbusPath = "/org/deepin/dde/BacklightHelper1/DDCCI" + dbusInterface = "org.deepin.dde.BacklightHelper1.DDCCI" ) var logger = log.NewLogger("backlight_helper/ddcci") diff --git a/bin/backlight_helper/main.go b/bin/backlight_helper/main.go index b2b73e65a..783dc46d2 100644 --- a/bin/backlight_helper/main.go +++ b/bin/backlight_helper/main.go @@ -12,7 +12,7 @@ import ( "strings" "time" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-daemon/bin/backlight_helper/ddcci" ConfigManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" "github.com/linuxdeepin/go-lib/dbusutil" @@ -22,9 +22,9 @@ import ( //go:generate dbusutil-gen em -type Manager const ( - dbusServiceName = "com.deepin.daemon.helper.Backlight" - dbusPath = "/com/deepin/daemon/helper/Backlight" - dbusInterface = "com.deepin.daemon.helper.Backlight" + dbusServiceName = "org.deepin.dde.BacklightHelper1" + dbusPath = "/org/deepin/dde/BacklightHelper1" + dbusInterface = dbusServiceName configManagerId = "org.desktopspec.ConfigManager" ) diff --git a/bin/dde-authority/authority.go b/bin/dde-authority/authority.go index 219c6a692..176fe4157 100644 --- a/bin/dde-authority/authority.go +++ b/bin/dde-authority/authority.go @@ -5,6 +5,7 @@ package main import ( + "encoding/json" "errors" "fmt" "os" @@ -13,18 +14,21 @@ import ( "sync" "time" - "github.com/godbus/dbus" - accounts "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.accounts" - fprint "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.fprintd" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" + "github.com/godbus/dbus/v5" + accounts "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.accounts1" + fprint "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.fprintd1" + ofdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.dbus" + polkit "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.policykit1" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/pam" + "github.com/linuxdeepin/go-lib/utils" ) //go:generate dbusutil-gen em -type Authority,PAMTransaction,FPrintTransaction const ( - pamConfigDir = "/etc/pam.d" + pamConfigDir = "/etc/pam.d" + polkitActionDoAuthorized = "org.deepin.dde.Authority1.doAuthorized" ) func isPamServiceExist(name string) bool { @@ -43,6 +47,10 @@ type Authority struct { accounts accounts.Accounts } +type PolkitDetail struct { + Message string `json:"message"` +} + func newAuthority(service *dbusutil.Service) *Authority { sysBus := service.Conn() auth := &Authority{ @@ -229,6 +237,68 @@ func (a *Authority) CheckCookie(user, cookie string) (result bool, authToken str return false, "", nil } +func (a *Authority) CheckAuth(sender dbus.Sender, details string) *dbus.Error { + ret, err := checkAuthByPolkit(polkitActionDoAuthorized, details, string(sender)) + if err != nil { + return dbusutil.ToError(err) + } + if !ret.IsAuthorized { + inf, err := getDetailsKey(ret.Details, "polkit.dismissed") + if err == nil { + if dismiss, ok := inf.(string); ok { + if dismiss != "" { + return dbusutil.ToError(errors.New("")) + } + } + } + return dbusutil.ToError(errors.New("policykit authentication failed")) + } + return nil +} + +func checkAuthByPolkit(actionId string, details string, sysBusName string) (ret polkit.AuthorizationResult, err error) { + systemBus, err := dbus.SystemBus() + if err != nil { + return + } + authority := polkit.NewAuthority(systemBus) + subject := polkit.MakeSubject(polkit.SubjectKindSystemBusName) + subject.SetDetail("name", sysBusName) + + var polkitDetail PolkitDetail + err = json.Unmarshal([]byte(details), &polkitDetail) + if err != nil { + return + } + + detail := map[string]string{ + "polkit.message": polkitDetail.Message, + "exAuth": "true", + "exAuthFlags": "1", + } + + ret, err = authority.CheckAuthorization(0, subject, + actionId, detail, + polkit.CheckAuthorizationFlagsAllowUserInteraction, "") + if err != nil { + logger.Warningf("call check auth failed, err: %v", err) + return + } + logger.Debugf("call check auth success, ret: %v", ret) + return +} + +func getDetailsKey(details map[string]dbus.Variant, key string) (interface{}, error) { + result, ok := details[key] + if !ok { + return nil, errors.New("key dont exist in details") + } + if utils.IsInterfaceNil(result) { + return nil, errors.New("result is nil") + } + return result.Value(), nil +} + func (a *Authority) HasCookie(user string) (result bool, busErr *dbus.Error) { a.service.DelayAutoQuit() if user == "" { diff --git a/bin/dde-authority/exported_methods_auto.go b/bin/dde-authority/exported_methods_auto.go index ce057ff5e..5d0f8aa94 100644 --- a/bin/dde-authority/exported_methods_auto.go +++ b/bin/dde-authority/exported_methods_auto.go @@ -8,6 +8,11 @@ import ( func (v *Authority) GetExportedMethods() dbusutil.ExportedMethods { return dbusutil.ExportedMethods{ + { + Name: "CheckAuth", + Fn: v.CheckAuth, + InArgs: []string{"details"}, + }, { Name: "CheckCookie", Fn: v.CheckCookie, diff --git a/bin/dde-authority/fprint_transaction.go b/bin/dde-authority/fprint_transaction.go index 0e460ec34..ca2951a0f 100644 --- a/bin/dde-authority/fprint_transaction.go +++ b/bin/dde-authority/fprint_transaction.go @@ -13,9 +13,9 @@ import ( "time" "unicode/utf8" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/gosexy/gettext" - fprint "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.fprintd" + fprint "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.fprintd1" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/dbusutil/proxy" "github.com/linuxdeepin/go-lib/strv" diff --git a/bin/dde-authority/main.go b/bin/dde-authority/main.go index 1be27bb71..142b0234c 100644 --- a/bin/dde-authority/main.go +++ b/bin/dde-authority/main.go @@ -20,9 +20,9 @@ func init() { } const ( - dbusInterface = "com.deepin.daemon.Authority" + dbusInterface = "org.deepin.dde.Authority1" dbusServiceName = dbusInterface - dbusPath = "/com/deepin/daemon/Authority" + dbusPath = "/org/deepin/dde/Authority1" dbusAgentInterface = dbusInterface + ".Agent" ) diff --git a/bin/dde-authority/pam_transaction.go b/bin/dde-authority/pam_transaction.go index 23aaeada8..094c65568 100644 --- a/bin/dde-authority/pam_transaction.go +++ b/bin/dde-authority/pam_transaction.go @@ -11,7 +11,7 @@ import ( "errors" "sync" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/pam" ) diff --git a/bin/dde-authority/transaction.go b/bin/dde-authority/transaction.go index b35403ff0..3ef1f37fd 100644 --- a/bin/dde-authority/transaction.go +++ b/bin/dde-authority/transaction.go @@ -10,7 +10,7 @@ import ( "strconv" "sync" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" ) diff --git a/bin/dde-greeter-setter/manager.go b/bin/dde-greeter-setter/manager.go index 2eb33b71f..d8588ce04 100644 --- a/bin/dde-greeter-setter/manager.go +++ b/bin/dde-greeter-setter/manager.go @@ -11,7 +11,7 @@ import ( "regexp" "strconv" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/keyfile" "github.com/linuxdeepin/go-lib/procfs" @@ -20,8 +20,8 @@ import ( //go:generate dbusutil-gen em -type Manager const ( - dbusServiceName = "com.deepin.daemon.Greeter" - dbusPath = "/com/deepin/daemon/Greeter" + dbusServiceName = "org.deepin.dde.Greeter1" + dbusPath = "/org/deepin/dde/Greeter1" dbusInterface = dbusServiceName ) diff --git a/bin/dde-lockservice/livecd.go b/bin/dde-lockservice/livecd.go index 1ae11823d..cf0a44ab9 100644 --- a/bin/dde-lockservice/livecd.go +++ b/bin/dde-lockservice/livecd.go @@ -4,32 +4,17 @@ package main -//#include -//#include -//#include -//#include -//#cgo LDFLAGS: -lcrypt -//#cgo CFLAGS: -W -Wall -fstack-protector-all -fPIC -//int is_livecd(const char *username)\ -//{\ -// if (strcmp("deepin", username) != 0) {\ -// return 0;\ -// }\ -// struct spwd *data = getspnam(username);\ -// if (data == NULL || strlen(data->sp_pwdp) == 0) {\ -// return 0;\ -// }\ -// if (strcmp(crypt("", data->sp_pwdp), data->sp_pwdp) != 0) {\ -// return 0;\ -// }\ -// return 1;\ -//} -import "C" -import "unsafe" +import ( + "fmt" + "io/ioutil" + "strings" +) func isInLiveCD(username string) bool { - cName := C.CString(username) - ret := C.is_livecd(cName) - C.free(unsafe.Pointer(cName)) - return (int(ret) == 1) + cmdline, err := ioutil.ReadFile("/proc/cmdline") + if err != nil { + fmt.Println("failed to read /proc/cmdline") + return false + } + return strings.Contains(string(cmdline), "boot=live") } diff --git a/bin/dde-lockservice/manager.go b/bin/dde-lockservice/manager.go index 3d6e8c5e4..4ce9258fd 100644 --- a/bin/dde-lockservice/manager.go +++ b/bin/dde-lockservice/manager.go @@ -13,7 +13,7 @@ import ( "sync" "time" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/msteinert/pam" ) @@ -49,9 +49,9 @@ type Manager struct { } const ( - dbusServiceName = "com.deepin.dde.LockService" - dbusPath = "/com/deepin/dde/LockService" - dbusInterface = "com.deepin.dde.LockService" + dbusServiceName = "org.deepin.dde.LockService1" + dbusPath = "/org/deepin/dde/LockService1" + dbusInterface = dbusServiceName ) var _m *Manager diff --git a/bin/dde-session-daemon/daemon.go b/bin/dde-session-daemon/daemon.go index 99af7a612..bea9575b6 100644 --- a/bin/dde-session-daemon/daemon.go +++ b/bin/dde-session-daemon/daemon.go @@ -10,7 +10,7 @@ import ( "os" "strings" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-api/session" "github.com/linuxdeepin/dde-daemon/calltrace" "github.com/linuxdeepin/dde-daemon/loader" @@ -26,8 +26,8 @@ const ( ProfTypeCPU = "cpu" //nolint ProfTypeMem = "memory" //nolint - dbusPath = "/com/deepin/daemon/Daemon" - dbusServiceName = "com.deepin.daemon.Daemon" + dbusPath = "/org/deepin/dde/Daemon" + dbusServiceName = "org.deepin.dde.Daemon" dbusInterface = dbusServiceName configManagerId = "org.desktopspec.ConfigManager" ) @@ -177,16 +177,13 @@ func (s *SessionDaemon) register(service *dbusutil.Service) error { func (s *SessionDaemon) initModules() { part1ModuleNames := []string{ - "dock", "trayicon", "x-event-monitor", } part2ModuleNames := []string{ - "launcher", "network", "audio", - "appearance", "screensaver", "sessionwatcher", "power", // need screensaver and sessionwatcher @@ -200,12 +197,8 @@ func (s *SessionDaemon) initModules() { "timedate", "bluetooth", "screenedge", - "mime", - //"calendar", - //"miracast", // need network "systeminfo", "lastore", - "eventlog", "calltrace", "debug", } diff --git a/bin/dde-session-daemon/main.go b/bin/dde-session-daemon/main.go index 38d306dc7..b61bbfa3d 100644 --- a/bin/dde-session-daemon/main.go +++ b/bin/dde-session-daemon/main.go @@ -23,12 +23,12 @@ import ( "strings" "time" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-api/soundutils" "github.com/linuxdeepin/dde-api/userenv" "github.com/linuxdeepin/dde-daemon/loader" - soundthemeplayer "github.com/linuxdeepin/go-dbus-factory/com.deepin.api.soundthemeplayer" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" + soundthemeplayer "github.com/linuxdeepin/go-dbus-factory/system/com.deepin.api.soundthemeplayer" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" "github.com/linuxdeepin/go-gir/gio-2.0" "github.com/linuxdeepin/go-lib/dbusutil" . "github.com/linuxdeepin/go-lib/gettext" @@ -68,10 +68,10 @@ func allowRun() bool { logger.Warning(err) os.Exit(1) } - sessionManagerObj := systemBus.Object("com.deepin.SessionManager", - "/com/deepin/SessionManager") + sessionManagerObj := systemBus.Object("org.deepin.dde.SessionManager1", + "/org/deepin/dde/SessionManager1") var allowRun bool - err = sessionManagerObj.Call("com.deepin.SessionManager.AllowSessionDaemonRun", + err = sessionManagerObj.Call("org.deepin.dde.SessionManager1.AllowSessionDaemonRun", dbus.FlagNoAutoStart).Store(&allowRun) if err != nil { logger.Warning(err) diff --git a/bin/dde-session-daemon/module.go b/bin/dde-session-daemon/module.go index c49d1a59a..8219237fc 100644 --- a/bin/dde-session-daemon/module.go +++ b/bin/dde-session-daemon/module.go @@ -10,39 +10,31 @@ import ( "github.com/linuxdeepin/dde-daemon/loader" - _ "github.com/linuxdeepin/dde-daemon/appearance" - _ "github.com/linuxdeepin/dde-daemon/audio" - _ "github.com/linuxdeepin/dde-daemon/bluetooth" - _ "github.com/linuxdeepin/dde-daemon/screenedge" - - _ "github.com/linuxdeepin/dde-daemon/mime" + _ "github.com/linuxdeepin/dde-daemon/audio1" + _ "github.com/linuxdeepin/dde-daemon/bluetooth1" + _ "github.com/linuxdeepin/dde-daemon/screenedge1" // depends: network - _ "github.com/linuxdeepin/dde-daemon/systeminfo" - _ "github.com/linuxdeepin/dde-daemon/calltrace" - _ "github.com/linuxdeepin/dde-daemon/clipboard" + _ "github.com/linuxdeepin/dde-daemon/clipboard1" _ "github.com/linuxdeepin/dde-daemon/debug" - _ "github.com/linuxdeepin/dde-daemon/dock" - _ "github.com/linuxdeepin/dde-daemon/gesture" + + _ "github.com/linuxdeepin/dde-daemon/gesture1" _ "github.com/linuxdeepin/dde-daemon/housekeeping" - _ "github.com/linuxdeepin/dde-daemon/inputdevices" - _ "github.com/linuxdeepin/dde-daemon/keybinding" - _ "github.com/linuxdeepin/dde-daemon/lastore" - _ "github.com/linuxdeepin/dde-daemon/launcher" - _ "github.com/linuxdeepin/dde-daemon/mime" - _ "github.com/linuxdeepin/dde-daemon/network" - _ "github.com/linuxdeepin/dde-daemon/screenedge" - _ "github.com/linuxdeepin/dde-daemon/screensaver" + _ "github.com/linuxdeepin/dde-daemon/inputdevices1" + _ "github.com/linuxdeepin/dde-daemon/keybinding1" + _ "github.com/linuxdeepin/dde-daemon/lastore1" + + _ "github.com/linuxdeepin/dde-daemon/network1" + _ "github.com/linuxdeepin/dde-daemon/screensaver1" _ "github.com/linuxdeepin/dde-daemon/service_trigger" - _ "github.com/linuxdeepin/dde-daemon/session/eventlog" - _ "github.com/linuxdeepin/dde-daemon/session/power" - _ "github.com/linuxdeepin/dde-daemon/session/uadpagent" - _ "github.com/linuxdeepin/dde-daemon/sessionwatcher" - _ "github.com/linuxdeepin/dde-daemon/systeminfo" - _ "github.com/linuxdeepin/dde-daemon/timedate" - _ "github.com/linuxdeepin/dde-daemon/trayicon" - _ "github.com/linuxdeepin/dde-daemon/x_event_monitor" + _ "github.com/linuxdeepin/dde-daemon/session/power1" + _ "github.com/linuxdeepin/dde-daemon/session/uadpagent1" + _ "github.com/linuxdeepin/dde-daemon/sessionwatcher1" + _ "github.com/linuxdeepin/dde-daemon/systeminfo1" + _ "github.com/linuxdeepin/dde-daemon/timedate1" + _ "github.com/linuxdeepin/dde-daemon/trayicon1" + _ "github.com/linuxdeepin/dde-daemon/x_event_monitor1" ) var ( diff --git a/bin/dde-system-daemon/bluetooth.go b/bin/dde-system-daemon/bluetooth.go index ff8f1c447..1fa84f77b 100644 --- a/bin/dde-system-daemon/bluetooth.go +++ b/bin/dde-system-daemon/bluetooth.go @@ -8,7 +8,7 @@ import ( "fmt" "path/filepath" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/keyfile" ) diff --git a/bin/dde-system-daemon/gesture.go b/bin/dde-system-daemon/gesture.go index 5ed6a126b..04af07151 100644 --- a/bin/dde-system-daemon/gesture.go +++ b/bin/dde-system-daemon/gesture.go @@ -7,9 +7,9 @@ package main import ( "fmt" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-daemon/loader" - "github.com/linuxdeepin/dde-daemon/system/gesture" + "github.com/linuxdeepin/dde-daemon/system/gesture1" ) func (*Daemon) SetLongPressDuration(duration uint32) *dbus.Error { @@ -23,6 +23,6 @@ func (*Daemon) SetLongPressDuration(duration uint32) *dbus.Error { return dbus.NewError(epath, []interface{}{"Not found module 'gesture'"}) } - m.(*gesture.Daemon).SetLongPressDuration(int(duration)) + m.(*gesture1.Daemon).SetLongPressDuration(int(duration)) return nil } diff --git a/bin/dde-system-daemon/main.go b/bin/dde-system-daemon/main.go index 5e9aff3f8..8db3e3647 100644 --- a/bin/dde-system-daemon/main.go +++ b/bin/dde-system-daemon/main.go @@ -8,31 +8,31 @@ import ( "os" // modules: - _ "github.com/linuxdeepin/dde-daemon/accounts" - _ "github.com/linuxdeepin/dde-daemon/apps" - _ "github.com/linuxdeepin/dde-daemon/fprintd" - _ "github.com/linuxdeepin/dde-daemon/image_effect" - _ "github.com/linuxdeepin/dde-daemon/system/airplane_mode" - _ "github.com/linuxdeepin/dde-daemon/system/bluetooth" - _ "github.com/linuxdeepin/dde-daemon/system/display" - _ "github.com/linuxdeepin/dde-daemon/system/gesture" + _ "github.com/linuxdeepin/dde-daemon/accounts1" + _ "github.com/linuxdeepin/dde-daemon/apps1" + _ "github.com/linuxdeepin/dde-daemon/fprintd1" + _ "github.com/linuxdeepin/dde-daemon/image_effect1" + _ "github.com/linuxdeepin/dde-daemon/system/airplane_mode1" + _ "github.com/linuxdeepin/dde-daemon/system/bluetooth1" + _ "github.com/linuxdeepin/dde-daemon/system/display1" + _ "github.com/linuxdeepin/dde-daemon/system/gesture1" _ "github.com/linuxdeepin/dde-daemon/system/hostname" - _ "github.com/linuxdeepin/dde-daemon/system/inputdevices" - _ "github.com/linuxdeepin/dde-daemon/system/keyevent" + _ "github.com/linuxdeepin/dde-daemon/system/inputdevices1" + _ "github.com/linuxdeepin/dde-daemon/system/keyevent1" _ "github.com/linuxdeepin/dde-daemon/system/lang" - _ "github.com/linuxdeepin/dde-daemon/system/network" - _ "github.com/linuxdeepin/dde-daemon/system/power" - _ "github.com/linuxdeepin/dde-daemon/system/power_manager" + _ "github.com/linuxdeepin/dde-daemon/system/network1" + _ "github.com/linuxdeepin/dde-daemon/system/power1" + _ "github.com/linuxdeepin/dde-daemon/system/power_manager1" _ "github.com/linuxdeepin/dde-daemon/system/resource_ctl" _ "github.com/linuxdeepin/dde-daemon/system/scheduler" - _ "github.com/linuxdeepin/dde-daemon/system/swapsched" - _ "github.com/linuxdeepin/dde-daemon/system/systeminfo" - _ "github.com/linuxdeepin/dde-daemon/system/timedated" - _ "github.com/linuxdeepin/dde-daemon/system/uadp" - systemd1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.systemd1" + _ "github.com/linuxdeepin/dde-daemon/system/swapsched1" + _ "github.com/linuxdeepin/dde-daemon/system/systeminfo1" + _ "github.com/linuxdeepin/dde-daemon/system/timedate1" + _ "github.com/linuxdeepin/dde-daemon/system/uadp1" + systemd1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.systemd1" "github.com/linuxdeepin/dde-daemon/loader" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" glib "github.com/linuxdeepin/go-gir/glib-2.0" "github.com/linuxdeepin/go-lib/dbusutil" . "github.com/linuxdeepin/go-lib/gettext" @@ -54,8 +54,8 @@ type Daemon struct { } const ( - dbusServiceName = "com.deepin.daemon.Daemon" - dbusPath = "/com/deepin/daemon/Daemon" + dbusServiceName = "org.deepin.dde.Daemon1" + dbusPath = "/org/deepin/dde/Daemon1" dbusInterface = dbusServiceName ) diff --git a/bin/dde-system-daemon/network.go b/bin/dde-system-daemon/network.go index 9b3bd1912..9f8a56fe9 100644 --- a/bin/dde-system-daemon/network.go +++ b/bin/dde-system-daemon/network.go @@ -10,10 +10,10 @@ import ( "path/filepath" "sort" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" + . "github.com/linuxdeepin/dde-daemon/common/dsync" "github.com/linuxdeepin/go-gir/glib-2.0" "github.com/linuxdeepin/go-lib/dbusutil" - . "github.com/linuxdeepin/dde-daemon/common/dsync" ) const ( diff --git a/bin/dde-system-daemon/plymouth.go b/bin/dde-system-daemon/plymouth.go index 5f3638ea5..d26b10b45 100644 --- a/bin/dde-system-daemon/plymouth.go +++ b/bin/dde-system-daemon/plymouth.go @@ -10,7 +10,7 @@ import ( "os/exec" "sync" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" "github.com/linuxdeepin/go-lib/dbusutil" ) diff --git a/bin/dde-system-daemon/tty.go b/bin/dde-system-daemon/tty.go index c433c5b59..3322c2d04 100644 --- a/bin/dde-system-daemon/tty.go +++ b/bin/dde-system-daemon/tty.go @@ -12,7 +12,7 @@ import ( "path/filepath" "strings" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/keyfile" "github.com/linuxdeepin/go-lib/procfs" diff --git a/bin/dde-system-daemon/utils.go b/bin/dde-system-daemon/utils.go index 56b2902c1..a257aab2b 100644 --- a/bin/dde-system-daemon/utils.go +++ b/bin/dde-system-daemon/utils.go @@ -7,7 +7,7 @@ package main import ( "fmt" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" ) const ( @@ -52,7 +52,7 @@ func newSettingsBus() (dbus.BusObject, error) { func startBacklightHelperAsync(conn *dbus.Conn) { go func() { - obj := conn.Object("com.deepin.daemon.helper.Backlight", "/com/deepin/daemon/helper/Backlight") + obj := conn.Object("org.deepin.dde.BacklightHelper1", "/org/deepin/dde/BacklightHelper1") err := obj.Call("org.freedesktop.DBus.Peer.Ping", 0).Err if err != nil { diff --git a/bin/dde-system-daemon/virtual.go b/bin/dde-system-daemon/virtual.go index f3006d53a..1e4b1e37f 100644 --- a/bin/dde-system-daemon/virtual.go +++ b/bin/dde-system-daemon/virtual.go @@ -7,7 +7,7 @@ package main import ( "strings" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/keyfile" "github.com/linuxdeepin/go-lib/procfs" @@ -40,8 +40,8 @@ func init() { }() } -//从配置文件读取支持App的关键字段 -//当获取不到"/usr/share/dde-daemon/supportVirsConf.ini"数据的时候,使用默认值 +// 从配置文件读取支持App的关键字段 +// 当获取不到"/usr/share/dde-daemon/supportVirsConf.ini"数据的时候,使用默认值 func readSupConfigFile(key, value string) []string { kf := keyfile.NewKeyFile() err := kf.LoadFromFile(supportVirsConf) @@ -79,7 +79,7 @@ func getValidSupData(supApps []string) []string { return ret } -//获取App二进制名称,将exe和cmdline拼接成一个string +// 获取App二进制名称,将exe和cmdline拼接成一个string func getActivePidInfo(pid uint32) (execPath string, err error) { value := procfs.Process(pid) execPath, err = value.Exe() @@ -99,7 +99,7 @@ func getActivePidInfo(pid uint32) (execPath string, err error) { return strings.ToLower(execPath), err } -//判断是否是虚拟机 +// 判断是否是虚拟机 func isVirtual(exe string, supApps []string) bool { for _, vir := range supApps { //exe中是否包含,去掉空格的虚拟机相关字段 diff --git a/bin/dde-system-daemon/wallpaper.go b/bin/dde-system-daemon/wallpaper.go index 322ee360c..00057a3d9 100644 --- a/bin/dde-system-daemon/wallpaper.go +++ b/bin/dde-system-daemon/wallpaper.go @@ -17,7 +17,8 @@ import ( "strings" "sync" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" + polkit "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.policykit1" "github.com/linuxdeepin/go-lib/dbusutil" dutils "github.com/linuxdeepin/go-lib/utils" ) @@ -27,6 +28,7 @@ const maxSize = 32 * 1024 * 1024 const wallPaperDir = "/usr/share/wallpapers/custom-wallpapers/" const solidWallPaperPath = "/usr/share/wallpapers/custom-solidwallpapers/" const solidPrefix = "solid::" +const polkitActionUserAdministration = "org.deepin.dde.accounts1.user-administration" var wallPaperDirs = []string{ wallPaperDir, @@ -119,6 +121,76 @@ func DeleteWallPaper(username string, file string) error { var wallpaperMutex sync.Mutex +func checkAuth(actionId string, sysBusName string) error { + ret, err := checkAuthByPolkit(actionId, sysBusName) + if err != nil { + return err + } + if !ret.IsAuthorized { + inf, err := getDetailsKey(ret.Details, "polkit.dismissed") + if err == nil { + if dismiss, ok := inf.(string); ok { + if dismiss != "" { + return errors.New("") + } + } + } + return fmt.Errorf("Policykit authentication failed") + } + return nil +} + +func checkAuthByPolkit(actionId string, sysBusName string) (ret polkit.AuthorizationResult, err error) { + systemBus, err := dbus.SystemBus() + if err != nil { + return + } + authority := polkit.NewAuthority(systemBus) + subject := polkit.MakeSubject(polkit.SubjectKindSystemBusName) + subject.SetDetail("name", sysBusName) + + ret, err = authority.CheckAuthorization(0, subject, + actionId, nil, + polkit.CheckAuthorizationFlagsAllowUserInteraction, "") + if err != nil { + logger.Warningf("call check auth failed, err: %v", err) + return + } + logger.Debugf("call check auth success, ret: %v", ret) + return +} + +func getDetailsKey(details map[string]dbus.Variant, key string) (interface{}, error) { + result, ok := details[key] + if !ok { + return nil, errors.New("key dont exist in details") + } + if dutils.IsInterfaceNil(result) { + return nil, errors.New("result is nil") + } + return result.Value(), nil +} + +func (d *Daemon) isSelf(sender dbus.Sender, username string) error { + uid, err := d.service.GetConnUID(string(sender)) + if err != nil { + return dbusutil.ToError(err) + } + user, err := user.LookupId(strconv.Itoa(int(uid))) + if err != nil { + return dbusutil.ToError(err) + } + if user.Username != username { + err = fmt.Errorf("%s not allowed to delete %s custom wallpaper", user.Username, username) + return dbusutil.ToError(err) + } + return nil +} + +func (d *Daemon) checkAuth(sender dbus.Sender) error { + return checkAuth(polkitActionUserAdministration, string(sender)) +} + func (d *Daemon) SaveCustomWallPaper(sender dbus.Sender, username string, file string) (string, *dbus.Error) { var err error var isSolid bool = false @@ -214,7 +286,19 @@ func (d *Daemon) SaveCustomWallPaper(sender dbus.Sender, username string, file s return destFile, dbusutil.ToError(err) } -func (*Daemon) DeleteCustomWallPaper(username string, file string) *dbus.Error { +func (d *Daemon) DeleteCustomWallPaper(sender dbus.Sender, username string, file string) *dbus.Error { + err := d.isSelf(sender, username) + if err != nil { + logger.Warning(err) + + err = d.checkAuth(sender) + if err != nil { + return dbusutil.ToError(err) + } else { + return dbusutil.ToError(DeleteWallPaper(username, file)) + } + } + return dbusutil.ToError(DeleteWallPaper(username, file)) } diff --git a/bin/default-file-manager/main.c b/bin/default-file-manager/main.c deleted file mode 100644 index 61632c69a..000000000 --- a/bin/default-file-manager/main.c +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include - -#define FILE_MANAGER_MIME_TYPE "inode/directory" - -/** - * Open default file manager via mime type - * Some file managers custom the directory by user - **/ -int -main(int argc, char *argv[]) -{ - GAppInfo *app_info = g_app_info_get_default_for_type(FILE_MANAGER_MIME_TYPE, FALSE); - if (!app_info) { - g_error("Failed to get default app for %s", FILE_MANAGER_MIME_TYPE); - return -1; - } - g_debug("Executable: %s\n", g_app_info_get_executable(app_info)); - g_debug("Commandline: %s\n", g_app_info_get_commandline(app_info)); - - GError *error = NULL; - gboolean ret = g_app_info_launch(app_info, NULL, NULL, &error); - if (error) { - g_error("Failed to launch %s, error: %s", g_app_info_get_name(app_info), error->message); - g_error_free(error); - goto EXIT; - } - -EXIT: - g_object_unref(app_info); - return ret?0:-1; -} diff --git a/bin/default-file-manager/main.go b/bin/default-file-manager/main.go new file mode 100644 index 000000000..b2e4f8043 --- /dev/null +++ b/bin/default-file-manager/main.go @@ -0,0 +1,105 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package main + +import ( + "errors" + "log" + "os/user" + "path/filepath" + "strings" + + dbus "github.com/godbus/dbus/v5" + appmanager "github.com/linuxdeepin/go-dbus-factory/session/org.desktopspec.applicationmanager1" + "github.com/linuxdeepin/go-gir/gio-2.0" + "github.com/linuxdeepin/go-lib/appinfo/desktopappinfo" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +const ( + appManagerDBusServiceName = "org.desktopspec.ApplicationManager1" + appManagerDBusPath = "/org/desktopspec/ApplicationManager1" +) + +const ( + fileManagerMimeType = "inode/directory" +) + +func init() { + log.SetFlags(log.Lshortfile) +} + +func queryAppDesktopByMime() (string, error) { + appInfo := gio.AppInfoGetDefaultForType(fileManagerMimeType, false) + if appInfo == nil { + return "", errors.New("failed to get appInfo") + } + + defer appInfo.Unref() + + dAppInfo := gio.ToDesktopAppInfo(appInfo) + + return strings.TrimSpace(filepath.Base(dAppInfo.GetFilename())), nil +} + +func main() { + sessionBus, err := dbus.SessionBus() + if err != nil { + log.Fatal(err) + } + + session, err := dbusutil.NewSessionService() + if err != nil { + log.Fatal(err) + } + + has, err := session.NameHasOwner(appManagerDBusServiceName) + if err != nil { + log.Println("warning: call name has owner error:", err) + } + + if has { + var dBusObjPath dbus.ObjectPath + var mimeType string + + mimeManagerAppObj := appmanager.NewMimeManager(sessionBus) + + if mimeManagerAppObj != nil { + cur, err := user.Current() + if err != nil { + log.Fatal(err) + } + + mimeType, dBusObjPath, err = mimeManagerAppObj.QueryDefaultApplication(0, cur.HomeDir) + if err != nil { + log.Println("warning: query default application error:", err) + } + } + + if mimeType != fileManagerMimeType || dBusObjPath == "/" { + log.Println("warning: can not get default file manager from AM, query from xdg-mime:", err) + appDesktop, err := queryAppDesktopByMime() + if err != nil { + log.Fatal(err) + } + + dBusObjPath, err = desktopappinfo.GetDBusObjectFromAppDesktop(appDesktop, appManagerDBusServiceName, appManagerDBusPath) + if err != nil { + log.Println("warning: get dbus object path error:", err) + log.Fatal(err) + } + } + + appManagerAppObj, err := appmanager.NewApplication(sessionBus, dBusObjPath) + if err != nil { + log.Println("warning: new appManager error:", err) + } + + _, err = appManagerAppObj.Launch(0, "", []string{}, make(map[string]dbus.Variant)) + if err != nil { + log.Println("warning: launch app error:", err) + } + } +} diff --git a/bin/default-terminal/main.go b/bin/default-terminal/main.go index 5b21ed754..16418655f 100644 --- a/bin/default-terminal/main.go +++ b/bin/default-terminal/main.go @@ -9,11 +9,12 @@ import ( "os" "os/exec" - "github.com/godbus/dbus" - sessionmanager "github.com/linuxdeepin/go-dbus-factory/com.deepin.sessionmanager" - "github.com/linuxdeepin/dde-daemon/mime" - "github.com/linuxdeepin/go-gir/gio-2.0" + "github.com/godbus/dbus/v5" + appmanager "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.application1" + newAppmanager "github.com/linuxdeepin/go-dbus-factory/session/org.desktopspec.applicationmanager1" + gio "github.com/linuxdeepin/go-gir/gio-2.0" "github.com/linuxdeepin/go-lib/appinfo/desktopappinfo" + "github.com/linuxdeepin/go-lib/dbusutil" ) const ( @@ -22,6 +23,30 @@ const ( gsKeyExec = "exec" ) +const ( + appManagerDBusServiceName = "org.desktopspec.ApplicationManager1" + appManagerDBusPath = "/org/desktopspec/ApplicationManager1" +) + +var terms = []string{ + "deepin-terminal", + "gnome-terminal", + "terminator", + "xfce4-terminal", + "rxvt", + "xterm", +} + +func getPresetTerminalPath() string { + for _, exe := range terms { + file, _ := exec.LookPath(exe) + if file != "" { + return file + } + } + return "" +} + func init() { log.SetFlags(log.Lshortfile) } @@ -39,17 +64,47 @@ func main() { if err != nil { log.Fatal(err) } - startManager := sessionmanager.NewStartManager(sessionBus) - filename := appInfo.GetFileName() + workDir, err := os.Getwd() if err != nil { log.Println("warning: failed to get work dir:", err) } + options := map[string]dbus.Variant{ "path": dbus.MakeVariant(workDir), } - err = startManager.LaunchAppWithOptions(0, filename, 0, - nil, options) + + session, err := dbusutil.NewSessionService() + if err != nil { + log.Fatal(err) + } + + has, err := session.NameHasOwner(appManagerDBusServiceName) + if err != nil { + log.Println("warning: call name has owner error:", err) + + } + if has { + obj, err := desktopappinfo.GetDBusObjectFromAppDesktop(appId, appManagerDBusServiceName, appManagerDBusPath) + if err != nil { + log.Println("warning: get dbus object error:", err) + } + + appManagerAppObj, err := newAppmanager.NewApplication(sessionBus, obj) + if err != nil { + log.Println("warning: new appManager error:", err) + } + + _, err = appManagerAppObj.Launch(0, "", []string{}, options) + if err != nil { + log.Println("warning: launch app error:", err) + } + } else { + appManager := appmanager.NewManager(sessionBus) + err = appManager.LaunchAppWithOptions(0, appInfo.GetFileName(), 0, + nil, options) + } + if err != nil { log.Println(err) runFallbackTerm() @@ -63,7 +118,7 @@ func main() { termPath, _ := exec.LookPath(termExec) if termPath == "" { // try again - termPath = mime.GetPresetTerminalPath() + termPath = getPresetTerminalPath() if termPath == "" { log.Fatal("failed to get terminal path") } @@ -81,12 +136,12 @@ func main() { } func runFallbackTerm() { - termPath := mime.GetPresetTerminalPath() + termPath := getPresetTerminalPath() if termPath == "" { log.Println("failed to get terminal path") return } - cmd := exec.Command(termPath) // #nosec G204 + cmd := exec.Command(termPath) // #nosec G204 cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout err := cmd.Run() diff --git a/bin/langselector/main.go b/bin/langselector/main.go index f18a36461..459f36d23 100644 --- a/bin/langselector/main.go +++ b/bin/langselector/main.go @@ -5,8 +5,8 @@ package main import ( + "github.com/linuxdeepin/dde-daemon/langselector1" "github.com/linuxdeepin/go-lib/gettext" - "github.com/linuxdeepin/dde-daemon/langselector" ) func main() { diff --git a/bin/search/ifc.go b/bin/search/ifc.go index ecef3a03c..c0718faa3 100644 --- a/bin/search/ifc.go +++ b/bin/search/ifc.go @@ -7,7 +7,7 @@ package main import ( "path" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/pinyin" dutils "github.com/linuxdeepin/go-lib/utils" ) diff --git a/bin/search/main.go b/bin/search/main.go index cc08d2f7b..fdb623c20 100644 --- a/bin/search/main.go +++ b/bin/search/main.go @@ -20,9 +20,9 @@ type Manager struct { } const ( - dbusServiceName = "com.deepin.daemon.Search" - dbusPath = "/com/deepin/daemon/Search" - dbusInterface = "com.deepin.daemon.Search" + dbusServiceName = "org.deepin.dde.Search1" + dbusPath = "/org/deepin/dde/Search1" + dbusInterface = dbusServiceName ) var ( diff --git a/bin/soundeffect/main.go b/bin/soundeffect/main.go index bc7083bea..fa3670cdd 100644 --- a/bin/soundeffect/main.go +++ b/bin/soundeffect/main.go @@ -5,7 +5,7 @@ package main import ( - "github.com/linuxdeepin/dde-daemon/soundeffect" + "github.com/linuxdeepin/dde-daemon/soundeffect1" ) func main() { diff --git a/bin/theme-thumb-tool/main.go b/bin/theme-thumb-tool/main.go deleted file mode 100644 index 36e1b05f9..000000000 --- a/bin/theme-thumb-tool/main.go +++ /dev/null @@ -1,103 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package main - -import ( - "flag" - "fmt" - "os" - "path" - - dutils "github.com/linuxdeepin/go-lib/utils" -) - -const ( - TypeAll = "all" - TypeGtk = "gtk" - TypeIcon = "icon" - TypeCursor = "cursor" - TypeBackground = "background" - - forceFlagUsage = "Force generate thumbnails" - destDirUsage = "Thumbnails output directory" -) - -var _forceFlag bool -var _destDir string - -func init() { - flag.BoolVar(&_forceFlag, "force", false, forceFlagUsage) - flag.BoolVar(&_forceFlag, "f", false, forceFlagUsage) - flag.StringVar(&_destDir, "output", "", destDirUsage) - flag.StringVar(&_destDir, "o", "", destDirUsage) -} - -func main() { - flag.Usage = usage - flag.Parse() - - thumbType := flag.Arg(0) - var thumbFiles []string - switch thumbType { - case TypeAll: - thumbFiles = genAllThumbnails(_forceFlag) - case TypeGtk: - thumbFiles = genGtkThumbnails(_forceFlag) - case TypeIcon: - thumbFiles = genIconThumbnails(_forceFlag) - case TypeCursor: - thumbFiles = genCursorThumbnails(_forceFlag) - case TypeBackground: - thumbFiles = genBgThumbnails(_forceFlag) - default: - usage() - } - moveThumbFiles(thumbFiles) -} - -func usage() { - fmt.Println("Desc:") - fmt.Println("\ttheme-thumb-tool - gtk/icon/cursor/background thumbnail batch generator") - fmt.Println("Usage:") - fmt.Println("\ttheme-thumb-tool [Option] [Type]") - fmt.Println("Option:") - fmt.Println("\t-f --force: force to generate thumbnail regardless of file exist") - fmt.Println("\t-o --output: thumbnails output directory") - fmt.Println("Type:") - fmt.Println("\tall: generate all of the following types thumbnails") - fmt.Println("\tgtk: generate all gtk theme thumbnails") - fmt.Println("\ticon: generate all icon theme thumbnails") - fmt.Println("\tcursor: generate all cursor theme thumbnails") - fmt.Println("\tbackground: generate all background thumbnails") - - os.Exit(0) -} - -func moveThumbFiles(files []string) { - if len(_destDir) == 0 { - return - } - - err := os.MkdirAll(_destDir, 0755) - if err != nil { - _, _ = fmt.Fprintf(os.Stderr, "create %q failed: %v\n", _destDir, err) - return - } - for _, file := range files { - dest := path.Join(_destDir, path.Base(file)) - if !_forceFlag && dutils.IsFileExist(dest) { - continue - } - err = dutils.CopyFile(file, dest) - if err != nil { - _, _ = fmt.Fprintf(os.Stderr, "copy file %q to %q failed: %v\n", file, dest, err) - continue - } - err = os.Remove(file) - if err != nil { - _, _ = fmt.Fprintf(os.Stderr, "delete file %q failed: %v\n", file, err) - } - } -} diff --git a/bin/theme-thumb-tool/main_test.go b/bin/theme-thumb-tool/main_test.go deleted file mode 100644 index e88693269..000000000 --- a/bin/theme-thumb-tool/main_test.go +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package main - -import ( - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_moveThumbFiles(t *testing.T) { - type args struct { - files []string - } - tests := []struct { - name string - args args - dest string - }{ - { - name: "moveThumbFiles", - args: args{ - files: []string{ - "./testdata/moveThumbFiles/source1/f1", - }, - }, - dest: "./testdata/moveThumbFiles/dest1", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _destDir = tt.dest - moveThumbFiles(tt.args.files) - - for _, f := range tt.args.files { - assert.FileExists(t, filepath.Join(tt.dest, filepath.Base(f))) - } - }) - } -} diff --git a/bin/theme-thumb-tool/testdata/moveThumbFiles/source1/f1 b/bin/theme-thumb-tool/testdata/moveThumbFiles/source1/f1 deleted file mode 100644 index e69de29bb..000000000 diff --git a/bin/theme-thumb-tool/thumbnail.go b/bin/theme-thumb-tool/thumbnail.go deleted file mode 100644 index 32c8f0c6f..000000000 --- a/bin/theme-thumb-tool/thumbnail.go +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package main - -import ( - "fmt" - "io/ioutil" - "math/rand" - "path" - "time" - - "github.com/linuxdeepin/go-lib/graphic" - "github.com/linuxdeepin/dde-api/themes" - "github.com/linuxdeepin/dde-api/thumbnails/cursor" - "github.com/linuxdeepin/dde-api/thumbnails/gtk" - "github.com/linuxdeepin/dde-api/thumbnails/icon" - "github.com/linuxdeepin/dde-api/thumbnails/images" - "github.com/linuxdeepin/dde-daemon/appearance/background" -) - -const ( - thumbBgDir = "/var/cache/appearance/thumbnail/background" - - defaultWidth = 128 - defaultHeight = 72 -) - -func genAllThumbnails(force bool) []string { - var ret []string - ret = append(ret, genGtkThumbnails(force)...) - ret = append(ret, genIconThumbnails(force)...) - ret = append(ret, genCursorThumbnails(force)...) - ret = append(ret, genBgThumbnails(force)...) - return ret -} - -func genGtkThumbnails(force bool) []string { - var ret []string - list := themes.ListGtkTheme() - for _, v := range list { - thumb, err := gtk.ThumbnailForTheme(path.Join(v, "index.theme"), - getThumbBg(), defaultWidth, defaultHeight, force) - if err != nil { - fmt.Printf("Gen '%s' thumbnail failed: %v\n", v, err) - continue - } - ret = append(ret, thumb) - } - return ret -} - -func genIconThumbnails(force bool) []string { - var ret []string - list := themes.ListIconTheme() - for _, v := range list { - thumb, err := icon.ThumbnailForTheme(path.Join(v, "index.theme"), - getThumbBg(), defaultWidth, defaultHeight, force) - if err != nil { - fmt.Printf("Gen '%s' thumbnail failed: %v\n", v, err) - continue - } - ret = append(ret, thumb) - } - return ret -} - -func genCursorThumbnails(force bool) []string { - var ret []string - list := themes.ListCursorTheme() - for _, v := range list { - thumb, err := cursor.ThumbnailForTheme(path.Join(v, "cursor.theme"), - getThumbBg(), defaultWidth, defaultHeight, force) - if err != nil { - fmt.Printf("Gen '%s' thumbnail failed: %v\n", v, err) - continue - } - ret = append(ret, thumb) - } - return ret -} - -func genBgThumbnails(force bool) []string { - var ret []string - infos := background.ListBackground() - for _, info := range infos { - thumb, err := images.ThumbnailForTheme(info.Id, - defaultWidth, defaultHeight, force) - if err != nil { - fmt.Printf("Gen '%s' thumbnail failed: %v\n", info.Id, err) - continue - } - ret = append(ret, thumb) - } - return ret -} - -func getThumbBg() string { - var imgs = getImagesInDir() - if len(imgs) == 0 { - return "" - } - - rand.Seed(time.Now().UnixNano()) - // #nosec G404 - idx := rand.Intn(len(imgs)) - return imgs[idx] -} - -func getImagesInDir() []string { - finfos, err := ioutil.ReadDir(thumbBgDir) - if err != nil { - return nil - } - - var imgs []string - for _, finfo := range finfos { - tmp := path.Join(thumbBgDir, finfo.Name()) - if !graphic.IsSupportedImage(tmp) { - continue - } - imgs = append(imgs, tmp) - } - return imgs -} diff --git a/bin/user-config/config_datas.go b/bin/user-config/config_datas.go index e37a57707..4365c1c63 100644 --- a/bin/user-config/config_datas.go +++ b/bin/user-config/config_datas.go @@ -13,9 +13,9 @@ import ( "regexp" "strings" + "github.com/linuxdeepin/dde-daemon/accounts1/users" "github.com/linuxdeepin/go-lib/archive" dutils "github.com/linuxdeepin/go-lib/utils" - "github.com/linuxdeepin/dde-daemon/accounts/users" ) const ( diff --git a/bluetooth/adapter.go b/bluetooth/adapter.go deleted file mode 100644 index f748d800e..000000000 --- a/bluetooth/adapter.go +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package bluetooth - -import ( - "encoding/json" - "sync" - - "github.com/godbus/dbus" -) - -type AdapterInfo struct { - Address string - Path dbus.ObjectPath - Name string - Alias string - Powered bool - Discovering bool - Discoverable bool - DiscoverableTimeout uint32 -} - -func unmarshalAdapterInfo(data string) (*AdapterInfo, error) { - var adapter AdapterInfo - err := json.Unmarshal([]byte(data), &adapter) - if err != nil { - return nil, err - } - return &adapter, nil -} - -type AdapterInfos struct { - mu sync.Mutex - infos []AdapterInfo -} - -func (a *AdapterInfos) getAdapter(path dbus.ObjectPath) (int, *AdapterInfo) { - a.mu.Lock() - defer a.mu.Unlock() - return a.getAdapterNoLock(path) -} - -func (a *AdapterInfos) getAdapterNoLock(path dbus.ObjectPath) (int, *AdapterInfo) { - for idx, info := range a.infos { - if info.Path == path { - return idx, &info - } - } - return -1, nil -} - -func (a *AdapterInfos) addOrUpdateAdapter(adapterInfo *AdapterInfo) { - a.mu.Lock() - defer a.mu.Unlock() - - idx, _ := a.getAdapterNoLock(adapterInfo.Path) - if idx != -1 { - // 更新 - a.infos[idx] = *adapterInfo - return - } - a.infos = append(a.infos, *adapterInfo) -} - -func (a *AdapterInfos) removeAdapter(path dbus.ObjectPath) { - a.mu.Lock() - defer a.mu.Unlock() - - idx, _ := a.getAdapterNoLock(path) - if idx == -1 { - return - } - a.infos = append(a.infos[:idx], a.infos[idx+1:]...) -} - -func (a *AdapterInfos) toJSON() string { - a.mu.Lock() - defer a.mu.Unlock() - return marshalJSON(a.infos) -} - -func (a *AdapterInfos) clear() { - a.mu.Lock() - a.infos = nil - a.mu.Unlock() -} diff --git a/bluetooth/agent.go b/bluetooth/agent.go deleted file mode 100644 index c6d9ff781..000000000 --- a/bluetooth/agent.go +++ /dev/null @@ -1,377 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package bluetooth - -import ( - "encoding/json" - "fmt" - "strconv" - "strings" - "sync" - "time" - - "github.com/linuxdeepin/go-lib/strv" - - "github.com/godbus/dbus" - btcommon "github.com/linuxdeepin/dde-daemon/common/bluetooth" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/gettext" -) - -const ( - sessionAgentInterface = "com.deepin.system.Bluetooth.Agent" -) - -type authorize struct { - path dbus.ObjectPath - key string - accept bool -} - -type agent struct { - service *dbusutil.Service - - b *Bluetooth - rspChan chan authorize - - mu sync.Mutex - requestDevice dbus.ObjectPath -} - -func (*agent) GetInterfaceName() string { - return sessionAgentInterface -} - -/*****************************************************************************/ - -//Release method gets called when the service daemon unregisters the agent. -//An agent can use it to do cleanup tasks. There is no need to unregister the -//agent, because when this method gets called it has already been unregistered. -func (a *agent) Release() *dbus.Error { - logger.Info("dbus call agent Release") - - return nil -} - -//RequestPinCode method gets called when the service daemon needs to get the passkey for an authentication. -//The return value should be a string of 1-16 characters length. The string can be alphanumeric. -//Possible errors: org.bluez.Error.Rejected -// org.bluez.Error.Canceled -func (a *agent) RequestPinCode(device dbus.ObjectPath) (pinCode string, busErr *dbus.Error) { - logger.Infof("dbus call agent RequestPinCode with device %v", device) - - auth, err := a.emitRequest(device, "RequestPinCode") - if err != nil { - logger.Warning(err) - return "", toBusErrForAgent(err) - } - - return auth.key, nil -} - -//DisplayPinCode method gets called when the service daemon needs to display a pincode for an authentication. -//An empty reply should be returned. When the pincode needs no longer to be displayed, the Cancel method -//of the agent will be called. This is used during the pairing process of keyboards that don't support -//Bluetooth 2.1 Secure Simple Pairing, in contrast to DisplayPasskey which is used for those that do. -//This method will only ever be called once since older keyboards do not support typing notification. -//Note that the PIN will always be a 6-digit number, zero-padded to 6 digits. This is for harmony with -//the later specification. -//Possible errors: org.bluez.Error.Rejected -// org.bluez.Error.Canceled -func (a *agent) DisplayPinCode(device dbus.ObjectPath, pinCode string) *dbus.Error { - logger.Infof("dbus call agent DisplayPinCode with device %v and pinCode %s", - device, pinCode) - - _, err := a.emitRequest(device, "DisplayPinCode", pinCode) - if err != nil { - logger.Warning(err) - return toBusErrForAgent(err) - } - - return nil -} - -//RequestPasskey method gets called when the service daemon needs to get the passkey for an authentication. -//The return value should be a numeric value between 0-999999. -//Possible errors: org.bluez.Error.Rejected -// org.bluez.Error.Canceled -func (a *agent) RequestPasskey(device dbus.ObjectPath) (passkey uint32, busErr *dbus.Error) { - logger.Infof("dbus call agent RequestPasskey with device %v", device) - - auth, err := a.emitRequest(device, "RequestPasskey") - if err != nil { - logger.Warning(err) - return 0, toBusErrForAgent(err) - } - - key, err := strconv.ParseUint(auth.key, 10, 32) - if err != nil { - logger.Warning(err) - return 0, dbusutil.ToError(err) - } - passkey = uint32(key) - return passkey, nil -} - -//DisplayPasskey method gets called when the service daemon needs to display a passkey for an authentication. -//The entered parameter indicates the number of already typed keys on the remote side. -//An empty reply should be returned. When the passkey needs no longer to be displayed, the Cancel method -//of the agent will be called. -//During the pairing process this method might be called multiple times to update the entered value. -//Note that the passkey will always be a 6-digit number, so the display should be zero-padded at the start if -//the value contains less than 6 digits. -func (a *agent) DisplayPasskey(device dbus.ObjectPath, passkey uint32, entered uint16) *dbus.Error { - logger.Infof("dbus call agent DisplayPasskey with device %v,passkey %d and entered %d", - device, passkey, entered) - - key := fmt.Sprintf("%06d", passkey) - _, err := a.emitRequest(device, "DisplayPasskey", key) - if err != nil { - logger.Warning(err) - return toBusErrForAgent(err) - } - - return nil -} - -//RequestConfirmation This method gets called when the service daemon needs to confirm a passkey for an authentication. -//To confirm the value it should return an empty reply or an error in case the passkey is invalid. -//Note that the passkey will always be a 6-digit number, so the display should be zero-padded at the start if -//the value contains less than 6 digits. -//Possible errors: org.bluez.Error.Rejected -// org.bluez.Error.Canceled -func (a *agent) RequestConfirmation(device dbus.ObjectPath, passkey uint32) *dbus.Error { - logger.Infof("dbus call agent RequestConfirmation with device %v and passkey %d", - device, passkey) - - key := fmt.Sprintf("%06d", passkey) - _, err := a.emitRequest(device, "RequestConfirmation", key) - if err != nil { - logger.Warning(err) - return toBusErrForAgent(err) - } - - return nil -} - -//RequestAuthorization This method gets called to request the user to authorize an incoming pairing attempt -//which would in other circumstances trigger the just-works model, or when the user plugged in a device that -//implements cable pairing. In the latter case, the device would not be connected to the adapter via Bluetooth yet. -//Just-Works 配对适用于点击智能手机/计算机和蓝牙设备上的按钮以启动配对而无需输入密钥。 -//Possible errors: org.bluez.Error.Rejected -// org.bluez.Error.Canceled -func (a *agent) RequestAuthorization(device dbus.ObjectPath) *dbus.Error { - logger.Infof("dbus call agent RequestAuthorization with device %v", device) - - _, err := a.emitRequest(device, "RequestAuthorization") - if err != nil { - logger.Warning(err) - return toBusErrForAgent(err) - } - - return nil -} - -//AuthorizeService method gets called when the service daemon needs to authorize a connection/service request. -//Possible errors: org.bluez.Error.Rejected -// org.bluez.Error.Canceled -func (a *agent) AuthorizeService(device dbus.ObjectPath, uuid string) *dbus.Error { - logger.Infof("dbus call agent AuthorizeService with device %v and uuid %s", - device, uuid) - // TODO: DO NOT forbid device connect service - return nil -} - -//Cancel method gets called to indicate that the agent request failed before a reply was returned. -func (a *agent) Cancel() *dbus.Error { - logger.Info("dbus call agent Cancel") - - a.rspChan <- authorize{path: a.requestDevice, accept: false, key: ""} - a.emitCancelled() - return nil -} - -// toBusErrForAgent 把错误转换为 dbus 错误。 -// 对于已经是 dbus 错误的不经过转换。 -func toBusErrForAgent(err error) *dbus.Error { - v, ok := err.(*dbus.Error) - if ok { - return v - } - // NOTE: *dbus.Error 没有实现 dbusutil.DBusError 接口 - return dbusutil.ToError(err) -} - -func (a *agent) SendNotify(arg string) *dbus.Error { - logger.Infof("dbus call agent SendNotify with arg %v", arg) - - var msg btcommon.NotifyMsg - err := json.Unmarshal([]byte(arg), &msg) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - notify(msg.Icon, localizeStrToStr(msg.Summary), localizeStrToStr(msg.Body)) - return nil -} - -func localizeStrToStr(str *btcommon.LocalizeStr) string { - if str == nil { - return "" - } - - args := make([]interface{}, len(str.Args)) - for idx, arg := range str.Args { - args[idx] = arg - } - return fmt.Sprintf(gettext.Tr(str.Format), args...) -} - -/*****************************************************************************/ - -func newAgent(service *dbusutil.Service) (a *agent) { - a = &agent{ - service: service, - rspChan: make(chan authorize), - } - return -} - -func (a *agent) init() { - a.register() -} - -func (a *agent) register() { - err := a.b.sysBt.RegisterAgent(0, btcommon.SessionAgentPath) - if err != nil { - logger.Warning(err) - } else { - logger.Debug("register agent done") - } -} - -func (a *agent) destroy() { - err := a.b.sysBt.UnregisterAgent(0, btcommon.SessionAgentPath) - if err != nil { - logger.Warning(err) - } - - err = a.service.StopExport(a) - if err != nil { - logger.Warning(err) - } -} - -func (a *agent) waitResponse() (auth authorize, err error) { - logger.Info("waitResponse") - - defer func() { - a.mu.Lock() - a.requestDevice = "" - a.mu.Unlock() - }() - - t := time.NewTimer(60 * time.Second) - select { - case auth = <-a.rspChan: - logger.Info("receive", auth) - if !auth.accept { - err = btcommon.ErrRejected - logger.Warningf("emitRequest return with: %v", err) - return - } - logger.Infof("emitRequest accept %v with %v", a.requestDevice, auth.key) - return - case <-t.C: - logger.Info("timeout") - err = btcommon.ErrCanceled - logger.Warningf("emitRequest return with: %v", err) - a.emitCancelled() - return - } -} - -func (a *agent) emit(signal string, devPath dbus.ObjectPath, args ...interface{}) (err error) { - var args0 []interface{} - args0 = append(args0, devPath) - args0 = append(args0, args...) - return a.b.service.Emit(a.b, signal, args0...) -} - -func (a *agent) emitCancelled() { - a.mu.Lock() - devPath := a.requestDevice - a.mu.Unlock() - - if devPath == "" { - logger.Warning("failed to emitCancelled, devPath is empty") - return - } - err := a.b.service.Emit(a.b, "Cancelled", devPath) - if err != nil { - logger.Warning(err) - } -} - -func (b *Bluetooth) getInitiativeConnect(devPath dbus.ObjectPath) bool { - return b.initiativeConnectMap.get(devPath) -} - -func (b *Bluetooth) setInitiativeConnect(devPath dbus.ObjectPath, val bool) { - b.initiativeConnectMap.set(devPath, val) -} - -func (a *agent) emitRequest(devPath dbus.ObjectPath, signal string, args ...interface{}) (auth authorize, err error) { - logger.Info("emitRequest", devPath, signal, args) - - a.mu.Lock() - a.requestDevice = devPath - a.mu.Unlock() - - d, err := a.b.getDevice(devPath) - if nil != err { - logger.Warningf("emitRequest can not find device: %v, %v", devPath, err) - return auth, btcommon.ErrCanceled - } - needConfirmOrShowSignal := strv.Strv{ - "RequestConfirmation", - "DisplayPasskey", - "DisplayPinCode", - } - // if signal is request confirmation or request show, we deal signal self - if needConfirmOrShowSignal.Contains(signal) { - // judge ensure state, if is true, means pc request a connection - // dont need to show notification window - if a.b.getInitiativeConnect(d.Path) { - // reset state - a.b.setInitiativeConnect(d.Path, false) - //if true, means pc active invoke the connect request - needCancel := "true" - if strings.Contains(strings.ToLower(signal), "display") { - needCancel = "false" - } - err = notifyInitiativeConnect(d, args[0].(string), needCancel) - if err != nil { - logger.Warningf("notify initiative connect failed,err:%v", err) - } - } else { - // if not, means device invoke the connect request, - // need to show notification window - err = notifyPassiveConnect(d, args[0].(string)) - if err != nil { - logger.Warningf("notify passive connect failed,err:%v", err) - } - } - } else { - //if signal is not request confirmation, we emit it to dbus - logger.Debug("Send Signal for device: ", devPath, signal, args) - err = a.emit(signal, devPath, args...) - if err != nil { - logger.Warningf("emitRequest emit signal failed,err:%v", err) - } - } - return a.waitResponse() -} diff --git a/bluetooth/bluetooth.go b/bluetooth/bluetooth.go deleted file mode 100644 index 9054982fb..000000000 --- a/bluetooth/bluetooth.go +++ /dev/null @@ -1,851 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package bluetooth - -import ( - "encoding/json" - "errors" - "fmt" - "os" - "strings" - "sync" - "time" - - "github.com/godbus/dbus" - btcommon "github.com/linuxdeepin/dde-daemon/common/bluetooth" - airplanemode "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.airplanemode" - audio "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.audio" - sysbt "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.bluetooth" - obex "github.com/linuxdeepin/go-dbus-factory/org.bluez.obex" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" - mpris2 "github.com/linuxdeepin/go-dbus-factory/org.mpris.mediaplayer2" - gio "github.com/linuxdeepin/go-gir/gio-2.0" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/dbusutil/gsprop" - "github.com/linuxdeepin/go-lib/dbusutil/proxy" -) - -const ( - dbusServiceName = "com.deepin.daemon.Bluetooth" - dbusPath = "/com/deepin/daemon/Bluetooth" - dbusInterface = dbusServiceName - configManagerId = "org.desktopspec.ConfigManager" -) - -const ( - bluetoothSchema = "com.deepin.dde.bluetooth" - displaySwitch = "display-switch" -) - -// nolint -const ( - transferStatusQueued = "queued" - transferStatusActive = "active" - transferStatusSuspended = "suspended" - transferStatusComplete = "complete" - transferStatusError = "error" -) - -//go:generate dbusutil-gen -type Bluetooth bluetooth.go -//go:generate dbusutil-gen em -type Bluetooth,agent,obexAgent - -type Bluetooth struct { - service *dbusutil.Service - sysBt sysbt.Bluetooth - sigLoop *dbusutil.SignalLoop - systemSigLoop *dbusutil.SignalLoop - sysDBusDaemon ofdbus.DBus - agent *agent - obexAgent *obexAgent - obexManager obex.Manager - - // airplane - airplaneBltOriginState map[dbus.ObjectPath]bool - airplane airplanemode.AirplaneMode - - adapters AdapterInfos - devices DeviceInfoMap - - initiativeConnectMap *initiativeConnectMap - - PropsMu sync.RWMutex - State uint32 // StateUnavailable/StateAvailable/StateConnected - Transportable bool //能否传输 True可以传输 false不能传输 - CanSendFile bool - - sessionCancelChMap map[dbus.ObjectPath]chan struct{} - sessionCancelChMapMu sync.Mutex - - settings *gio.Settings - //dbusutil-gen: ignore - DisplaySwitch gsprop.Bool `prop:"access:rw"` - - sessionCon *dbus.Conn - sessionAudio audio.Audio - - configManagerPath dbus.ObjectPath - // nolint - signals *struct { - // adapter/device properties changed signals - AdapterAdded, AdapterRemoved, AdapterPropertiesChanged struct { - adapterJSON string - } - - DeviceAdded, DeviceRemoved, DevicePropertiesChanged struct { - devJSON string - } - - // pair request signals - DisplayPinCode struct { - device dbus.ObjectPath - pinCode string - } - DisplayPasskey struct { - device dbus.ObjectPath - passkey uint32 - entered uint32 - } - - // RequestConfirmation you should call Confirm with accept - RequestConfirmation struct { - device dbus.ObjectPath - passkey string - } - - // RequestAuthorization you should call Confirm with accept - RequestAuthorization struct { - device dbus.ObjectPath - } - - // RequestPinCode you should call FeedPinCode with accept and key - RequestPinCode struct { - device dbus.ObjectPath - } - - // RequestPasskey you should call FeedPasskey with accept and key - RequestPasskey struct { - device dbus.ObjectPath - } - - Cancelled struct { - device dbus.ObjectPath - } - - ObexSessionCreated struct { - sessionPath dbus.ObjectPath - } - - ObexSessionRemoved struct { - sessionPath dbus.ObjectPath - } - - ObexSessionProgress struct { - sessionPath dbus.ObjectPath - totalSize uint64 - transferred uint64 - currentIdx int - } - - TransferCreated struct { - file string - transferPath dbus.ObjectPath - sessionPath dbus.ObjectPath - } - - TransferRemoved struct { - file string - transferPath dbus.ObjectPath - sessionPath dbus.ObjectPath - done bool - } - TransferFailed struct { - file string - sessionPath dbus.ObjectPath - errInfo string - } - } -} - -func newBluetooth(service *dbusutil.Service) (b *Bluetooth) { - sysBus, err := dbus.SystemBus() - if err != nil { - logger.Warning(err) - return nil - } - - b = &Bluetooth{ - service: service, - sigLoop: dbusutil.NewSignalLoop(service.Conn(), 0), - systemSigLoop: dbusutil.NewSignalLoop(sysBus, 10), - obexManager: obex.NewManager(service.Conn()), - Transportable: true, - } - - b.sysBt = sysbt.NewBluetooth(sysBus) - b.devices.infos = make(map[dbus.ObjectPath]DeviceInfos) - b.initiativeConnectMap = newInitiativeConnectMap() - // create airplane mode - b.airplane = airplanemode.NewAirplaneMode(sysBus) - - b.sessionCon, err = dbus.SessionBus() - if err != nil { - logger.Warning(err) - return nil - } - b.sessionAudio = audio.NewAudio(b.sessionCon) - - // 加载dsg配置 - systemConnObj := sysBus.Object(configManagerId, "/") - err = systemConnObj.Call(configManagerId+".acquireManager", 0, "org.deepin.dde.daemon", "org.deepin.dde.daemon.bluetooth", "").Store(&b.configManagerPath) - if err != nil { - logger.Warning(err) - return nil - } - - err = dbusutil.NewMatchRuleBuilder().Type("signal"). - PathNamespace(string(b.configManagerPath)). - Interface("org.desktopspec.ConfigManager.Manager"). - Member("valueChanged").Build().AddTo(sysBus) - if err != nil { - logger.Warning(err) - return nil - } - - return -} - -func (b *Bluetooth) destroy() { - b.agent.destroy() - b.sysDBusDaemon.RemoveHandler(proxy.RemoveAllHandlers) - - err := b.service.StopExport(b) - if err != nil { - logger.Warning(err) - } - b.systemSigLoop.Stop() -} - -func (*Bluetooth) GetInterfaceName() string { - return dbusInterface -} - -func (b *Bluetooth) init() { - b.sigLoop.Start() - b.systemSigLoop.Start() - systemBus := b.systemSigLoop.Conn() - b.sessionCancelChMap = make(map[dbus.ObjectPath]chan struct{}) - - // start bluetooth goroutine - // monitor click signal or time out signal to close notification window - go beginTimerNotify(globalTimerNotifier) - - b.sysBt.InitSignalExt(b.systemSigLoop, true) - canSendFile, err := b.sysBt.CanSendFile().Get(0) - if err != nil { - logger.Warning(err) - } - - configCanSendFile := b.getSendFileEnable() - b.setPropCanSendFile(canSendFile && configCanSendFile) - - err = b.sysBt.State().ConnectChanged(func(hasValue bool, value uint32) { - if !hasValue { - return - } - b.setPropState(value) - }) - if err != nil { - logger.Warning(err) - } - state, err := b.sysBt.State().Get(0) - if err != nil { - logger.Warning(err) - } - b.setPropState(state) - - sysBus, err := dbus.SystemBus() - if err != nil { - logger.Warning(err) - return - } - - // 加载dsg配置 - systemConnObj := sysBus.Object(configManagerId, "/") - err = systemConnObj.Call(configManagerId+".acquireManager", 0, "org.deepin.dde.daemon", "org.deepin.dde.daemon.bluetooth", "").Store(&b.configManagerPath) - if err != nil { - logger.Warning(err) - } - - _, err = b.sysBt.ConnectAdapterAdded(func(adapterJSON string) { - adapterInfo, err := unmarshalAdapterInfo(adapterJSON) - if err != nil { - logger.Warning(err) - return - } - - b.adapters.addOrUpdateAdapter(adapterInfo) - err = b.service.Emit(b, "AdapterAdded", adapterJSON) - if err != nil { - logger.Warning(err) - } - }) - if err != nil { - logger.Warning(err) - } - - _, err = b.sysBt.ConnectAdapterRemoved(func(adapterJSON string) { - adapterInfo, err := unmarshalAdapterInfo(adapterJSON) - if err != nil { - logger.Warning(err) - return - } - - err = b.handleBluezPort(false) - if err != nil { - logger.Warning(err) - } - - b.adapters.removeAdapter(adapterInfo.Path) - err = b.service.Emit(b, "AdapterRemoved", adapterJSON) - if err != nil { - logger.Warning(err) - } - }) - if err != nil { - logger.Warning(err) - } - - _, err = b.sysBt.ConnectAdapterPropertiesChanged(func(adapterJSON string) { - adapterInfo, err := unmarshalAdapterInfo(adapterJSON) - if err != nil { - logger.Warning(err) - return - } - - b.adapters.addOrUpdateAdapter(adapterInfo) - err = b.service.Emit(b, "AdapterPropertiesChanged", adapterJSON) - if err != nil { - logger.Warning(err) - } - }) - if err != nil { - logger.Warning(err) - } - - // 初始化 b.adapters - adaptersJSON, err := b.sysBt.GetAdapters(0) - if err == nil { - var adapterInfos []AdapterInfo - err := json.Unmarshal([]byte(adaptersJSON), &adapterInfos) - if err == nil { - b.adapters.mu.Lock() - b.adapters.infos = adapterInfos - b.adapters.mu.Unlock() - } else { - logger.Warning(err) - } - } else { - logger.Warning(err) - } - - _, err = b.sysBt.ConnectDeviceAdded(func(deviceJSON string) { - devInfo, err := unmarshalDeviceInfo(deviceJSON) - if err != nil { - logger.Warning(err) - } - logger.Debug("DeviceAdded", devInfo.Alias, devInfo.Path) - b.devices.addOrUpdateDevice(devInfo) - err = b.service.Emit(b, "DeviceAdded", deviceJSON) - if err != nil { - logger.Warning(err) - } - }) - if err != nil { - logger.Warning(err) - } - - _, err = b.sysBt.ConnectDeviceRemoved(func(deviceJSON string) { - devInfo, err := unmarshalDeviceInfo(deviceJSON) - if err != nil { - logger.Warning(err) - } - logger.Debug("DeviceRemoved", devInfo.Alias, devInfo.Path) - b.initiativeConnectMap.del(devInfo.Path) - b.devices.removeDevice(devInfo.AdapterPath, devInfo.Path) - err = b.service.Emit(b, "DeviceRemoved", deviceJSON) - if err != nil { - logger.Warning(err) - } - }) - if err != nil { - logger.Warning(err) - } - - _, err = b.sysBt.ConnectDevicePropertiesChanged(func(deviceJSON string) { - devInfo, err := unmarshalDeviceInfo(deviceJSON) - if err != nil { - logger.Warning(err) - } - - b.devices.addOrUpdateDevice(devInfo) - err = b.service.Emit(b, "DevicePropertiesChanged", deviceJSON) - if err != nil { - logger.Warning(err) - } - }) - if err != nil { - logger.Warning(err) - } - - // 初始化 b.devices - var adapterPaths []dbus.ObjectPath - b.adapters.mu.Lock() - for _, info := range b.adapters.infos { - adapterPaths = append(adapterPaths, info.Path) - } - b.adapters.mu.Unlock() - - for _, adapterPath := range adapterPaths { - devicesJSON, err := b.sysBt.GetDevices(0, adapterPath) - if err == nil { - var devices DeviceInfos - err = json.Unmarshal([]byte(devicesJSON), &devices) - if err == nil { - b.devices.mu.Lock() - b.devices.infos[adapterPath] = devices - b.devices.mu.Unlock() - } else { - logger.Warning(err) - } - - } else { - logger.Warning(err) - } - - } - - b.sysDBusDaemon = ofdbus.NewDBus(systemBus) - b.sysDBusDaemon.InitSignalExt(b.systemSigLoop, true) - _, err = b.sysDBusDaemon.ConnectNameOwnerChanged(b.handleDBusNameOwnerChanged) - if err != nil { - logger.Warning(err) - } - b.settings = gio.NewSettings(bluetoothSchema) - b.DisplaySwitch.Bind(b.settings, displaySwitch) - - b.agent.init() - b.obexAgent.init() -} - -func getMprisPlayers(sessionConn *dbus.Conn) ([]string, error) { - var playerNames []string - dbusDaemon := ofdbus.NewDBus(sessionConn) - names, err := dbusDaemon.ListNames(0) - if err != nil { - return nil, err - } - for _, name := range names { - if strings.HasPrefix(name, "org.mpris.MediaPlayer2") { - // is mpris player - playerNames = append(playerNames, name) - } - } - return playerNames, nil -} - -// true : play; false : pause -func setAllPlayers(value bool) { - sessionConn, err := dbus.SessionBus() - if err != nil { - logger.Warning(err) - return - } - playerNames, err := getMprisPlayers(sessionConn) - if err != nil { - logger.Warning("getMprisPlayers failed:", err) - return - } - - logger.Debug("pause all players") - for _, playerName := range playerNames { - player := mpris2.NewMediaPlayer(sessionConn, playerName) - if value { - err := player.Player().Play(0) - if err != nil { - logger.Warningf("failed to pause player %s: %v", playerName, err) - } - } else { - err := player.Player().Pause(0) - if err != nil { - logger.Warningf("failed to pause player %s: %v", playerName, err) - } - } - - } -} - -// 获取当前是否为蓝牙端口音频,是:暂停音乐 -func (b *Bluetooth) handleBluezPort(value bool) error { - //get defaultSink Name - sinkPath, err := b.sessionAudio.DefaultSink().Get(0) - if err != nil { - return err - } - - sink, err := audio.NewSink(b.sessionCon, sinkPath) - if err != nil { - return err - } - sinkName, err := sink.Name().Get(0) - if err != nil { - return err - } - isBluePort := strings.Contains(strings.ToLower(sinkName), "blue") - logger.Info(" handleBluezPort sinkName : ", sinkName, isBluePort) - if isBluePort { - //stop music - go setAllPlayers(value) - } - return nil -} - -func (b *Bluetooth) handleDBusNameOwnerChanged(name, oldOwner, newOwner string) { - if name != b.sysBt.ServiceName_() { - return - } - if newOwner != "" { - logger.Info("sys bluetooth is starting") - time.AfterFunc(1*time.Second, func() { - b.agent.register() - }) - } else { - logger.Info("sys bluetooth stopped") - b.devices.clear() - b.adapters.clear() - } -} - -type initiativeConnectMap struct { - mu sync.Mutex - m map[dbus.ObjectPath]bool -} - -func newInitiativeConnectMap() *initiativeConnectMap { - return &initiativeConnectMap{ - m: make(map[dbus.ObjectPath]bool), - } -} - -func (icm *initiativeConnectMap) set(path dbus.ObjectPath, val bool) { - icm.mu.Lock() - defer icm.mu.Unlock() - icm.m[path] = val -} - -func (icm *initiativeConnectMap) get(path dbus.ObjectPath) bool { - icm.mu.Lock() - defer icm.mu.Unlock() - return icm.m[path] -} - -func (icm *initiativeConnectMap) del(path dbus.ObjectPath) { - icm.mu.Lock() - defer icm.mu.Unlock() - delete(icm.m, path) -} - -func (b *Bluetooth) getDevice(devPath dbus.ObjectPath) (*DeviceInfo, error) { - info := b.devices.getDeviceWithPath(devPath) - if info == nil { - return nil, errors.New("device not found") - } - return info, nil -} - -func (b *Bluetooth) feed(devPath dbus.ObjectPath, accept bool, key string) (err error) { - _, err = b.getDevice(devPath) - if nil != err { - logger.Warningf("FeedRequest can not find device: %v, %v", devPath, err) - return err - } - - b.agent.mu.Lock() - if b.agent.requestDevice != devPath { - b.agent.mu.Unlock() - logger.Warningf("FeedRequest can not find match device: %q, %q", b.agent.requestDevice, devPath) - return btcommon.ErrCanceled - } - b.agent.mu.Unlock() - - select { - case b.agent.rspChan <- authorize{path: devPath, accept: accept, key: key}: - return nil - default: - return errors.New("rspChan no reader") - } -} - -func (b *Bluetooth) getConnectedDeviceByAddress(address string) *DeviceInfo { - devInfo := b.devices.findFirst(func(devInfo *DeviceInfo) bool { - return devInfo.ConnectState && devInfo.Address == address - }) - return devInfo -} - -func (b *Bluetooth) getDeviceByAddress(address string) *DeviceInfo { - devInfo := b.devices.findFirst(func(devInfo *DeviceInfo) bool { - return devInfo.Address == address - }) - return devInfo -} - -func (b *Bluetooth) sendFiles(dev *DeviceInfo, files []string) (dbus.ObjectPath, error) { - var totalSize uint64 - - for _, f := range files { - info, err := os.Stat(f) - if err != nil { - return "/", err - } - - totalSize += uint64(info.Size()) - } - // 创建 OBEX session - args := make(map[string]dbus.Variant) - _, adapter := b.adapters.getAdapter(dev.AdapterPath) - if adapter == nil { - return "/", fmt.Errorf("not found adapter with path: %q", dev.AdapterPath) - } - args["Source"] = dbus.MakeVariant(adapter.Address) // 蓝牙适配器地址 - args["Target"] = dbus.MakeVariant("opp") // 连接方式「OPP」 - sessionPath, err := b.obexManager.Client().CreateSession(0, dev.Address, args) - if err != nil { - logger.Warning("failed to create obex session:", err) - return "", err - } - b.emitObexSessionCreated(sessionPath) - b.setPropTransportable(false) - logger.Debug("Transportable", b.Transportable) - - session, err := obex.NewSession(b.service.Conn(), sessionPath) - if err != nil { - logger.Warning("failed to get session bus:", err) - return "", err - } - - go b.doSendFiles(session, files, totalSize) - - return sessionPath, nil -} - -func (b *Bluetooth) doSendFiles(session obex.Session, files []string, totalSize uint64) { - sessionPath := session.Path_() - cancelCh := make(chan struct{}) - - b.sessionCancelChMapMu.Lock() - b.sessionCancelChMap[sessionPath] = cancelCh - b.sessionCancelChMapMu.Unlock() - - var transferredBase uint64 - - for i, f := range files { - _, err := os.Stat(f) - if err != nil { - b.emitTransferFailed(f, sessionPath, err.Error()) - break - } - transferPath, properties, err := session.ObjectPush().SendFile(0, f) - if err != nil { - logger.Warningf("failed to send file: %s: %s", f, err) - continue - } - logger.Infof("properties: %v", properties) - - transfer, err := obex.NewTransfer(b.service.Conn(), transferPath) - if err != nil { - logger.Warningf("failed to send file: %s: %s", f, err) - continue - } - - transfer.InitSignalExt(b.sigLoop, true) - - b.emitTransferCreated(f, transferPath, sessionPath) - - ch := make(chan bool) - err = transfer.Status().ConnectChanged(func(hasValue bool, value string) { - if !hasValue { - return - } - // 成功或者失败,说明这个传输结束 - if value == transferStatusComplete || value == transferStatusError { - ch <- value == transferStatusComplete - } - }) - if err != nil { - logger.Warning("connect to status changed failed:", err) - } - - err = transfer.Transferred().ConnectChanged(func(hasValue bool, value uint64) { - if !hasValue { - return - } - - transferred := transferredBase + value - b.emitObexSessionProgress(sessionPath, totalSize, transferred, i+1) - }) - if err != nil { - logger.Warning("connect to transferred changed failed:", err) - } - - var res bool - var cancel bool - select { - case res = <-ch: - case <-cancelCh: - b.sessionCancelChMapMu.Lock() - delete(b.sessionCancelChMap, sessionPath) - b.sessionCancelChMapMu.Unlock() - - cancel = true - err = transfer.Cancel(0) - if err != nil { - logger.Warning("failed to cancel transfer:", err) - } - } - transfer.RemoveAllHandlers() - b.emitTransferRemoved(f, transferPath, sessionPath, res) - - if !res { - break - } - - if cancel { - break - } - - info, err := os.Stat(f) - if err != nil { - logger.Warning("failed to stat file:", err) - break - } else { - transferredBase += uint64(info.Size()) - } - - b.emitObexSessionProgress(sessionPath, totalSize, transferredBase, i+1) - } - - b.sessionCancelChMapMu.Lock() - delete(b.sessionCancelChMap, sessionPath) - b.sessionCancelChMapMu.Unlock() - - b.emitObexSessionRemoved(sessionPath) - b.setPropTransportable(true) - - objs, err := obex.NewObjectManager(b.service.Conn()).GetManagedObjects(0) - if err != nil { - logger.Warning("failed to get managed objects:", err) - } else { - _, pathExists := objs[sessionPath] - if !pathExists { - logger.Debugf("session %s not exists", sessionPath) - return - } - } - - err = b.obexManager.Client().RemoveSession(0, sessionPath) - if err != nil { - logger.Warning("failed to remove session:", err) - } -} - -func (b *Bluetooth) emitObexSessionCreated(sessionPath dbus.ObjectPath) { - err := b.service.Emit(b, "ObexSessionCreated", sessionPath) - if err != nil { - logger.Warning("failed to emit ObexSessionCreated:", err) - } -} - -func (b *Bluetooth) emitObexSessionRemoved(sessionPath dbus.ObjectPath) { - err := b.service.Emit(b, "ObexSessionRemoved", sessionPath) - if err != nil { - logger.Warning("failed to emit ObexSessionRemoved:", err) - } -} - -func (b *Bluetooth) emitObexSessionProgress(sessionPath dbus.ObjectPath, totalSize uint64, transferred uint64, currentIdx int) { - err := b.service.Emit(b, "ObexSessionProgress", sessionPath, totalSize, transferred, currentIdx) - if err != nil { - logger.Warning("failed to emit ObexSessionProgress:", err) - } -} - -func (b *Bluetooth) emitTransferCreated(file string, transferPath dbus.ObjectPath, sessionPath dbus.ObjectPath) { - err := b.service.Emit(b, "TransferCreated", file, transferPath, sessionPath) - if err != nil { - logger.Warning("failed to emit TransferCreated:", err) - } -} - -func (b *Bluetooth) emitTransferRemoved(file string, transferPath dbus.ObjectPath, sessionPath dbus.ObjectPath, done bool) { - err := b.service.Emit(b, "TransferRemoved", file, transferPath, sessionPath, done) - if err != nil { - logger.Warning("failed to emit TransferRemoved:", err) - } -} - -func (b *Bluetooth) emitTransferFailed(file string, sessionPath dbus.ObjectPath, errInfo string) { - err := b.service.Emit(b, "TransferFailed", file, sessionPath, errInfo) - if err != nil { - logger.Warning("failed to emit TransferFailed:", err) - } -} - -func (b *Bluetooth) getAirplaneBltOriginStateConfig() string { - systemConn, err := dbus.SystemBus() - if err != nil { - return "" - } - systemConnObj := systemConn.Object("org.desktopspec.ConfigManager", b.configManagerPath) - var value string - err = systemConnObj.Call("org.desktopspec.ConfigManager.Manager.value", 0, "airplaneBltOriginState").Store(&value) - if err != nil { - logger.Warning(err) - return "" - } - return value -} - -func (b *Bluetooth) setAirplaneBltOriginStateConfig(value string) { - if value == "" { - return - } - systemConn, err := dbus.SystemBus() - if err != nil { - return - } - systemConnObj := systemConn.Object("org.desktopspec.ConfigManager", b.configManagerPath) - err = systemConnObj.Call("org.desktopspec.ConfigManager.Manager.setValue", 0, "airplaneBltOriginState", dbus.MakeVariant(value)).Err - if err != nil { - logger.Warning(err) - return - } - - return -} - -func (b *Bluetooth) getSendFileEnable() bool { - systemConn, err := dbus.SystemBus() - if err != nil { - return true - } - systemConnObj := systemConn.Object("org.desktopspec.ConfigManager", b.configManagerPath) - var value bool - err = systemConnObj.Call("org.desktopspec.ConfigManager.Manager.value", 0, "sendFileEnable").Store(&value) - if err != nil { - logger.Warning(err) - return true - } - return value -} diff --git a/bluetooth/bluetooth_ifc.go b/bluetooth/bluetooth_ifc.go deleted file mode 100644 index 0ee0772ff..000000000 --- a/bluetooth/bluetooth_ifc.go +++ /dev/null @@ -1,317 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package bluetooth - -import ( - "encoding/json" - "errors" - "fmt" - "time" - - "github.com/godbus/dbus" - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (b *Bluetooth) ConnectDevice(device dbus.ObjectPath, apath dbus.ObjectPath) *dbus.Error { - logger.Infof("dbus call ConnectDevice with device %v and apath %v", device, apath) - - b.setInitiativeConnect(device, true) - err := b.sysBt.ConnectDevice(0, device, apath) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - return nil -} - -func (b *Bluetooth) DisconnectDevice(device dbus.ObjectPath) *dbus.Error { - logger.Infof("dbus call DisconnectDevice with device %v", device) - - err := b.sysBt.DisconnectDevice(0, device) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - return nil -} - -func (b *Bluetooth) RemoveDevice(adapter, device dbus.ObjectPath) *dbus.Error { - logger.Infof("dbus call RemoveDevice with adapter %v and device %v", adapter, device) - - err := b.sysBt.RemoveDevice(0, adapter, device) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - return nil -} - -func (b *Bluetooth) SetDeviceAlias(device dbus.ObjectPath, alias string) *dbus.Error { - logger.Infof("dbus call SetDeviceAlias with device %v and alias %s", - device, alias) - - err := b.sysBt.SetDeviceAlias(0, device, alias) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - return nil -} - -func (b *Bluetooth) SetDeviceTrusted(device dbus.ObjectPath, trusted bool) *dbus.Error { - logger.Infof("dbus call SetDeviceTrusted with device %v and trusted %t", - device, trusted) - - err := b.sysBt.SetDeviceTrusted(0, device, trusted) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - return nil -} - -// GetDevices return all device objects that marshaled by json. -func (b *Bluetooth) GetDevices(adapter dbus.ObjectPath) (devicesJSON string, busErr *dbus.Error) { - logger.Infof("dbus call GetDevices with adapter %v", adapter) - - devices := b.devices.getDevices(adapter) - devicesJson := marshalJSON(devices) - return devicesJson, nil -} - -// GetAdapters return all adapter objects that marshaled by json. -func (b *Bluetooth) GetAdapters() (adaptersJSON string, busErr *dbus.Error) { - logger.Info("dbus call GetAdapters") - return b.adapters.toJSON(), nil -} - -func (b *Bluetooth) RequestDiscovery(adapter dbus.ObjectPath) *dbus.Error { - logger.Infof("dbus call RequestDiscovery with adapter %v ", adapter) - - err := b.sysBt.RequestDiscovery(0, adapter) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - return nil -} - -// SendFiles 用来发送文件给蓝牙设备,仅支持发送给已连接设备 -func (b *Bluetooth) SendFiles(devAddress string, files []string) (sessionPath dbus.ObjectPath, busErr *dbus.Error) { - logger.Infof("dbus call SendFiles with devAddress %s and files %v", devAddress, files) - - if len(files) == 0 { - err := errors.New("files is empty") - logger.Warning(err) - return "", dbusutil.ToError(err) - } - - if !b.CanSendFile { - err := errors.New("no permission") - logger.Warning(err) - return "", dbusutil.ToError(err) - } - - // 检查设备是否已经连接 - dev := b.getConnectedDeviceByAddress(devAddress) - if dev == nil { - err := errors.New("device not connected") - logger.Warning(err) - return "", dbusutil.ToError(err) - } - - sessionPath, err := b.sendFiles(dev, files) - if err != nil { - logger.Warning(err) - return "", dbusutil.ToError(err) - } - - return sessionPath, nil -} - -// CancelTransferSession 用来取消发送的会话,将会终止会话中所有的传送任务 -func (b *Bluetooth) CancelTransferSession(sessionPath dbus.ObjectPath) *dbus.Error { - logger.Infof("dbus call CancelTransferSession with sessionPath %v", sessionPath) - - //添加延时,确保sessionPath被remove,防止死锁 - time.Sleep(500 * time.Millisecond) - b.sessionCancelChMapMu.Lock() - defer b.sessionCancelChMapMu.Unlock() - - cancelCh, ok := b.sessionCancelChMap[sessionPath] - if !ok { - err := errors.New("session not exists") - logger.Warning(err) - return dbusutil.ToError(err) - } - - cancelCh <- struct{}{} - - return nil -} - -func (b *Bluetooth) SetAdapterPowered(adapter dbus.ObjectPath, - powered bool) *dbus.Error { - logger.Infof("dbus call SetAdapterPowered with adapter %v and powered %t", - adapter, powered) - // 当蓝牙开关打开时,需要同步session蓝牙中devices - if powered { - devicesJSON, err := b.sysBt.GetDevices(0, adapter) - if err == nil { - var devices DeviceInfos - err = json.Unmarshal([]byte(devicesJSON), &devices) - if err == nil { - b.devices.mu.Lock() - b.devices.infos[adapter] = devices - b.devices.mu.Unlock() - } else { - logger.Warning(err) - } - - } else { - logger.Warning(err) - } - } else { - err := b.handleBluezPort(powered) - if err != nil { - logger.Warning(err) - } - } - - err := b.sysBt.SetAdapterPowered(0, adapter, powered) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - return nil -} - -func (b *Bluetooth) SetAdapterAlias(adapter dbus.ObjectPath, alias string) *dbus.Error { - logger.Infof("dbus call SetAdapterAlias with adapter %v and alias %s", adapter, alias) - - err := b.sysBt.SetAdapterAlias(0, adapter, alias) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - return nil -} - -func (b *Bluetooth) SetAdapterDiscoverable(adapter dbus.ObjectPath, - discoverable bool) *dbus.Error { - logger.Infof("dbus call SetAdapterDiscoverable with adapter %v and discoverable %t", - adapter, discoverable) - - err := b.sysBt.SetAdapterDiscoverable(0, adapter, discoverable) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - return nil -} - -func (b *Bluetooth) SetAdapterDiscovering(adapter dbus.ObjectPath, - discovering bool) *dbus.Error { - logger.Infof("dbus call SetAdapterDiscovering with adapter %v and discovering %t", - adapter, discovering) - - err := b.sysBt.SetAdapterDiscovering(0, adapter, discovering) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - return nil -} - -func (b *Bluetooth) SetAdapterDiscoverableTimeout(adapter dbus.ObjectPath, - discoverableTimeout uint32) *dbus.Error { - logger.Infof("dbus call SetAdapterDiscoverableTimeout with adapter %v and discoverableTimeout %d", - adapter, discoverableTimeout) - - err := b.sysBt.SetAdapterDiscoverableTimeout(0, adapter, discoverableTimeout) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - return nil -} - -//Confirm should call when you receive RequestConfirmation signal -func (b *Bluetooth) Confirm(device dbus.ObjectPath, accept bool) *dbus.Error { - logger.Infof("dbus call Confirm with device %v and accept %t", device, accept) - - err := b.feed(device, accept, "") - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - return nil -} - -//FeedPinCode should call when you receive RequestPinCode signal, notice that accept must true -//if you accept connect request. If accept is false, pinCode will be ignored. -func (b *Bluetooth) FeedPinCode(device dbus.ObjectPath, accept bool, pinCode string) *dbus.Error { - logger.Infof("dbus call FeedPinCode with device %v, accept %t and pinCode %s", device, accept, pinCode) - - err := b.feed(device, accept, pinCode) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - return nil -} - -//FeedPasskey should call when you receive RequestPasskey signal, notice that accept must true -//if you accept connect request. If accept is false, passkey will be ignored. -//passkey must be range in 0~999999. -func (b *Bluetooth) FeedPasskey(device dbus.ObjectPath, accept bool, passkey uint32) *dbus.Error { - logger.Infof("dbus call FeedPasskey with device %v, accept %t and passkey %d", device, accept, passkey) - - err := b.feed(device, accept, fmt.Sprintf("%06d", passkey)) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - return nil -} - -func (b *Bluetooth) DebugInfo() (info string, busErr *dbus.Error) { - logger.Info("dbus call DebugInfo") - - info, err := b.sysBt.DebugInfo(0) - if err != nil { - logger.Warning(err) - return "", dbusutil.ToError(err) - } - - return info, nil -} - -//ClearUnpairedDevice will remove all device in unpaired list -func (b *Bluetooth) ClearUnpairedDevice() *dbus.Error { - logger.Infof("dbus call ClearUnpairedDevice") - - err := b.sysBt.ClearUnpairedDevice(0) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - return nil -} diff --git a/bluetooth/device.go b/bluetooth/device.go deleted file mode 100644 index 39476a1b8..000000000 --- a/bluetooth/device.go +++ /dev/null @@ -1,166 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package bluetooth - -import ( - "encoding/json" - "fmt" - "sync" - - "github.com/godbus/dbus" -) - -const ( - deviceStateDisconnected = 0 - // device state is connecting or disconnecting, mark them as device state doing - deviceStateConnecting = 1 - deviceStateConnected = 2 - deviceStateDisconnecting = 3 -) - -type deviceState uint32 - -func (s deviceState) String() string { - switch s { - case deviceStateDisconnected: - return "Disconnected" - case deviceStateConnecting: - return "Connecting" - case deviceStateConnected: - return "Connected" - case deviceStateDisconnecting: - return "Disconnecting" - default: - return fmt.Sprintf("Unknown(%d)", s) - } -} - -type DeviceInfo struct { - Path dbus.ObjectPath - AdapterPath dbus.ObjectPath - - Alias string - Trusted bool - Paired bool - State deviceState - ServicesResolved bool - ConnectState bool - - UUIDs []string - Name string - Icon string - RSSI int16 - Address string -} - -func unmarshalDeviceInfo(data string) (*DeviceInfo, error) { - var device DeviceInfo - err := json.Unmarshal([]byte(data), &device) - if err != nil { - return nil, err - } - return &device, nil -} - -type DeviceInfoMap struct { - mu sync.Mutex - infos map[dbus.ObjectPath]DeviceInfos -} - -type DeviceInfos []DeviceInfo - -func (infos DeviceInfos) getDevice(path dbus.ObjectPath) (int, *DeviceInfo) { - for idx, info := range infos { - if info.Path == path { - return idx, &info - } - } - return -1, nil -} - -func (infos DeviceInfos) removeDevice(path dbus.ObjectPath) (DeviceInfos, bool) { - idx, _ := infos.getDevice(path) - if idx == -1 { - return infos, false - } - return append(infos[:idx], infos[idx+1:]...), true -} - -func (m *DeviceInfoMap) getDeviceNoLock(adapterPath dbus.ObjectPath, - devPath dbus.ObjectPath) (int, *DeviceInfo) { - devices := m.infos[adapterPath] - return devices.getDevice(devPath) -} - -func (m *DeviceInfoMap) getDevice(adapterPath dbus.ObjectPath, devPath dbus.ObjectPath) (int, *DeviceInfo) { - m.mu.Lock() - defer m.mu.Unlock() - return m.getDeviceNoLock(adapterPath, devPath) -} - -func (m *DeviceInfoMap) getDevices(adapterPath dbus.ObjectPath) DeviceInfos { - m.mu.Lock() - defer m.mu.Unlock() - devices := m.infos[adapterPath] - devicesCopy := make(DeviceInfos, len(devices)) - copy(devicesCopy, devices) - return devicesCopy -} - -func (m *DeviceInfoMap) addOrUpdateDevice(devInfo *DeviceInfo) { - m.mu.Lock() - defer m.mu.Unlock() - - devices := m.infos[devInfo.AdapterPath] - idx, _ := devices.getDevice(devInfo.Path) - if idx != -1 { - // 更新 - devices[idx] = *devInfo - return - } - m.infos[devInfo.AdapterPath] = append(devices, *devInfo) -} - -func (m *DeviceInfoMap) removeDevice(adapterPath, devPath dbus.ObjectPath) bool { - m.mu.Lock() - defer m.mu.Unlock() - - devices := m.infos[adapterPath] - newDevices, ok := devices.removeDevice(devPath) - if ok { - m.infos[adapterPath] = newDevices - } - return ok -} - -func (m *DeviceInfoMap) clear() { - m.mu.Lock() - m.infos = make(map[dbus.ObjectPath]DeviceInfos) - m.mu.Unlock() -} - -func (m *DeviceInfoMap) findFirst(fn func(devInfo *DeviceInfo) bool) *DeviceInfo { - if fn == nil { - return nil - } - m.mu.Lock() - defer m.mu.Unlock() - - for _, infos := range m.infos { - for _, info := range infos { - // #nosec G601 - if fn(&info) { - return &info - } - } - } - return nil -} - -func (m *DeviceInfoMap) getDeviceWithPath(devPath dbus.ObjectPath) *DeviceInfo { - return m.findFirst(func(devInfo *DeviceInfo) bool { - return devInfo.Path == devPath - }) -} diff --git a/bluetooth/init.go b/bluetooth/init.go deleted file mode 100644 index fa451a025..000000000 --- a/bluetooth/init.go +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package bluetooth - -import ( - "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/dde-daemon/loader" -) - -var logger = log.NewLogger("daemon/bluetooth") - -func init() { - loader.Register(newBluetoothDaemon(logger)) -} diff --git a/bluetooth/utils_notify.go b/bluetooth/utils_notify.go deleted file mode 100644 index 9d05b9107..000000000 --- a/bluetooth/utils_notify.go +++ /dev/null @@ -1,188 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package bluetooth - -import ( - "fmt" - "os/exec" - "strconv" - "sync" - "time" - - "github.com/godbus/dbus" - notifications "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.notifications" - "github.com/linuxdeepin/go-lib/dbusutil" - . "github.com/linuxdeepin/go-lib/gettext" -) - -const ( - notifyIconBluetoothConnected = "notification-bluetooth-connected" - notifyIconBluetoothDisconnected = "notification-bluetooth-disconnected" - notifyIconBluetoothConnectFailed = "notification-bluetooth-error" - // dialog use for show pinCode - notifyDdeDialogPath = "/usr/lib/deepin-daemon/dde-bluetooth-dialog" - // notification window stay time - notifyTimerDuration = 30 * time.Second -) - -const bluetoothDialog string = "dde-bluetooth-dialog" - -var globalNotifications notifications.Notifications -var globalNotifyId uint32 -var globalNotifyMu sync.Mutex - -func initNotifications() error { - // init global notification timer instance - globalTimerNotifier = GetTimerNotifyInstance() - - sessionBus, err := dbus.SessionBus() - if err != nil { - return err - } - globalNotifications = notifications.NewNotifications(sessionBus) - - // monitor notification-close-signal - sessionLoop := dbusutil.NewSignalLoop(sessionBus, 10) - sessionLoop.Start() - globalNotifications.InitSignalExt(sessionLoop, true) - _, err = globalNotifications.ConnectActionInvoked(func(id uint32, actionKey string) { - // has received signal, use id to compare with last globalNotifyId - if id == globalNotifyId { - if actionKey == "cancel" { - err = globalBluetooth.agent.Cancel() - if err != nil { - logger.Warning("Cancel error:", err) - } - } - // if it is the same, then send chan to instance chan to close window - globalTimerNotifier.actionInvokedChan <- true - } - }) - if err != nil { - logger.Warningf("listen action invoked failed,err:%v", err) - } - - return nil -} - -func notify(icon, summary, body string) { - logger.Info("notify", icon, summary, body) - - globalNotifyMu.Lock() - nid := globalNotifyId - globalNotifyMu.Unlock() - - nid, err := globalNotifications.Notify(0, "dde-control-center", nid, icon, - summary, body, nil, nil, -1) - if err != nil { - logger.Warning(err) - return - } - globalNotifyMu.Lock() - globalNotifyId = nid - globalNotifyMu.Unlock() -} - -// notify pc initiative connect to device -// so do not need to show notification window -func notifyInitiativeConnect(dev *DeviceInfo, pinCode string, needCancel string) error { - if checkProcessExists(bluetoothDialog) { - logger.Info("initiative already exist") - return nil - } - - timestamp := strconv.FormatInt(time.Now().UnixNano(), 10) - //use command to open osd window to show pin code - // #nosec G204 - cmd := exec.Command(notifyDdeDialogPath, pinCode, string(dev.Path), timestamp, needCancel) - err := cmd.Start() - if err != nil { - logger.Infof("execute cmd command failed,err:%v", err) - return err - } - - go func() { - err := cmd.Wait() - if err != nil { - logger.Warning(err) - } - }() - - return nil -} - -// device passive connect to pc -// so need to show notification window -func notifyPassiveConnect(dev *DeviceInfo, pinCode string) error { - format := Tr("Click here to connect to %q") - summary := Tr("Add Bluetooth devices") - body := fmt.Sprintf(format, dev.Name) - globalNotifyMu.Lock() - nid := globalNotifyId - globalNotifyMu.Unlock() - // check if bluetooth dialog is exist - if checkProcessExists(bluetoothDialog) { - logger.Info("Passive is not exist") - return nil - } - var as = []string{"pair", Tr("Pair"), "cancel", Tr("Cancel")} - var timestamp = strconv.FormatInt(time.Now().UnixNano(), 10) - cmd := notifyDdeDialogPath + "," + pinCode + "," + string(dev.Path) + "," + timestamp - hints := map[string]dbus.Variant{"x-deepin-action-pair": dbus.MakeVariant(cmd)} - - // to make sure last notification has been closed - err := globalNotifications.CloseNotification(0, nid) - if err != nil { - logger.Warningf("close last notification failed,err:%v", err) - } - - // notify connect request to dde-control-center - // set notify time out as -1, default time out is 5 seconds - nid, err = globalNotifications.Notify(0, "dde-control-center", nid, notifyIconBluetoothConnected, - summary, body, as, hints, 30*1000) - if err != nil { - logger.Warningf("notify message failed,err:%v", err) - return err - } - - globalNotifyMu.Lock() - globalNotifyId = nid - globalNotifyMu.Unlock() - - return nil -} - -// global timer notifier -var globalTimerNotifier *timerNotify - -// notify timer instance -// use chan bool instead of timer, but in case to fit new requirements of future flexibly, we keep element timer -type timerNotify struct { - actionInvokedChan chan bool -} - -// GetTimerNotifyInstance get timer instance -func GetTimerNotifyInstance() *timerNotify { - // create a global timer notify object - timerNotifier := &timerNotify{ - actionInvokedChan: make(chan bool), - } - return timerNotifier -} - -// begin timer routine to monitor window click notification window -func beginTimerNotify(notifyTimer *timerNotify) { - for { - select { - case <-notifyTimer.actionInvokedChan: - // monitor click window signal - logger.Info("user click notify,close notify") - err := globalNotifications.CloseNotification(0, globalNotifyId) - if err != nil { - logger.Warningf("click event close notify icon failed,err:%v", err) - } - } - } -} diff --git a/bluetooth1/adapter.go b/bluetooth1/adapter.go new file mode 100644 index 000000000..dc64af93d --- /dev/null +++ b/bluetooth1/adapter.go @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package bluetooth + +import ( + "encoding/json" + "sync" + + "github.com/godbus/dbus/v5" +) + +type AdapterInfo struct { + Address string + Path dbus.ObjectPath + Name string + Alias string + Powered bool + Discovering bool + Discoverable bool + DiscoverableTimeout uint32 +} + +func unmarshalAdapterInfo(data string) (*AdapterInfo, error) { + var adapter AdapterInfo + err := json.Unmarshal([]byte(data), &adapter) + if err != nil { + return nil, err + } + return &adapter, nil +} + +type AdapterInfos struct { + mu sync.Mutex + infos []AdapterInfo +} + +func (a *AdapterInfos) getAdapter(path dbus.ObjectPath) (int, *AdapterInfo) { + a.mu.Lock() + defer a.mu.Unlock() + return a.getAdapterNoLock(path) +} + +func (a *AdapterInfos) getAdapterNoLock(path dbus.ObjectPath) (int, *AdapterInfo) { + for idx, info := range a.infos { + if info.Path == path { + return idx, &info + } + } + return -1, nil +} + +func (a *AdapterInfos) addOrUpdateAdapter(adapterInfo *AdapterInfo) { + a.mu.Lock() + defer a.mu.Unlock() + + idx, _ := a.getAdapterNoLock(adapterInfo.Path) + if idx != -1 { + // 更新 + a.infos[idx] = *adapterInfo + return + } + a.infos = append(a.infos, *adapterInfo) +} + +func (a *AdapterInfos) removeAdapter(path dbus.ObjectPath) { + a.mu.Lock() + defer a.mu.Unlock() + + idx, _ := a.getAdapterNoLock(path) + if idx == -1 { + return + } + a.infos = append(a.infos[:idx], a.infos[idx+1:]...) +} + +func (a *AdapterInfos) toJSON() string { + a.mu.Lock() + defer a.mu.Unlock() + return marshalJSON(a.infos) +} + +func (a *AdapterInfos) clear() { + a.mu.Lock() + a.infos = nil + a.mu.Unlock() +} diff --git a/bluetooth1/agent.go b/bluetooth1/agent.go new file mode 100644 index 000000000..cab5169c6 --- /dev/null +++ b/bluetooth1/agent.go @@ -0,0 +1,383 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package bluetooth + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" + "sync" + "time" + + "github.com/linuxdeepin/go-lib/strv" + + "github.com/godbus/dbus/v5" + btcommon "github.com/linuxdeepin/dde-daemon/common/bluetooth" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/gettext" +) + +const ( + sessionAgentInterface = "org.deepin.dde.Bluetooth1.Agent" +) + +type authorize struct { + path dbus.ObjectPath + key string + accept bool +} + +type agent struct { + service *dbusutil.Service + + b *Bluetooth + rspChan chan authorize + + mu sync.Mutex + requestDevice dbus.ObjectPath +} + +func (*agent) GetInterfaceName() string { + return sessionAgentInterface +} + +/*****************************************************************************/ + +// Release method gets called when the service daemon unregisters the agent. +// An agent can use it to do cleanup tasks. There is no need to unregister the +// agent, because when this method gets called it has already been unregistered. +func (a *agent) Release() *dbus.Error { + logger.Info("dbus call agent Release") + + return nil +} + +// RequestPinCode method gets called when the service daemon needs to get the passkey for an authentication. +// The return value should be a string of 1-16 characters length. The string can be alphanumeric. +// Possible errors: org.bluez.Error.Rejected +// +// org.bluez.Error.Canceled +func (a *agent) RequestPinCode(device dbus.ObjectPath) (pinCode string, busErr *dbus.Error) { + logger.Infof("dbus call agent RequestPinCode with device %v", device) + + auth, err := a.emitRequest(device, "RequestPinCode") + if err != nil { + logger.Warning(err) + return "", toBusErrForAgent(err) + } + + return auth.key, nil +} + +// DisplayPinCode method gets called when the service daemon needs to display a pincode for an authentication. +// An empty reply should be returned. When the pincode needs no longer to be displayed, the Cancel method +// of the agent will be called. This is used during the pairing process of keyboards that don't support +// Bluetooth 2.1 Secure Simple Pairing, in contrast to DisplayPasskey which is used for those that do. +// This method will only ever be called once since older keyboards do not support typing notification. +// Note that the PIN will always be a 6-digit number, zero-padded to 6 digits. This is for harmony with +// the later specification. +// Possible errors: org.bluez.Error.Rejected +// +// org.bluez.Error.Canceled +func (a *agent) DisplayPinCode(device dbus.ObjectPath, pinCode string) *dbus.Error { + logger.Infof("dbus call agent DisplayPinCode with device %v and pinCode %s", + device, pinCode) + + _, err := a.emitRequest(device, "DisplayPinCode", pinCode) + if err != nil { + logger.Warning(err) + return toBusErrForAgent(err) + } + + return nil +} + +// RequestPasskey method gets called when the service daemon needs to get the passkey for an authentication. +// The return value should be a numeric value between 0-999999. +// Possible errors: org.bluez.Error.Rejected +// +// org.bluez.Error.Canceled +func (a *agent) RequestPasskey(device dbus.ObjectPath) (passkey uint32, busErr *dbus.Error) { + logger.Infof("dbus call agent RequestPasskey with device %v", device) + + auth, err := a.emitRequest(device, "RequestPasskey") + if err != nil { + logger.Warning(err) + return 0, toBusErrForAgent(err) + } + + key, err := strconv.ParseUint(auth.key, 10, 32) + if err != nil { + logger.Warning(err) + return 0, dbusutil.ToError(err) + } + passkey = uint32(key) + return passkey, nil +} + +// DisplayPasskey method gets called when the service daemon needs to display a passkey for an authentication. +// The entered parameter indicates the number of already typed keys on the remote side. +// An empty reply should be returned. When the passkey needs no longer to be displayed, the Cancel method +// of the agent will be called. +// During the pairing process this method might be called multiple times to update the entered value. +// Note that the passkey will always be a 6-digit number, so the display should be zero-padded at the start if +// the value contains less than 6 digits. +func (a *agent) DisplayPasskey(device dbus.ObjectPath, passkey uint32, entered uint16) *dbus.Error { + logger.Infof("dbus call agent DisplayPasskey with device %v,passkey %d and entered %d", + device, passkey, entered) + + key := fmt.Sprintf("%06d", passkey) + _, err := a.emitRequest(device, "DisplayPasskey", key) + if err != nil { + logger.Warning(err) + return toBusErrForAgent(err) + } + + return nil +} + +// RequestConfirmation This method gets called when the service daemon needs to confirm a passkey for an authentication. +// To confirm the value it should return an empty reply or an error in case the passkey is invalid. +// Note that the passkey will always be a 6-digit number, so the display should be zero-padded at the start if +// the value contains less than 6 digits. +// Possible errors: org.bluez.Error.Rejected +// +// org.bluez.Error.Canceled +func (a *agent) RequestConfirmation(device dbus.ObjectPath, passkey uint32) *dbus.Error { + logger.Infof("dbus call agent RequestConfirmation with device %v and passkey %d", + device, passkey) + + key := fmt.Sprintf("%06d", passkey) + _, err := a.emitRequest(device, "RequestConfirmation", key) + if err != nil { + logger.Warning(err) + return toBusErrForAgent(err) + } + + return nil +} + +// RequestAuthorization This method gets called to request the user to authorize an incoming pairing attempt +// which would in other circumstances trigger the just-works model, or when the user plugged in a device that +// implements cable pairing. In the latter case, the device would not be connected to the adapter via Bluetooth yet. +// Just-Works 配对适用于点击智能手机/计算机和蓝牙设备上的按钮以启动配对而无需输入密钥。 +// Possible errors: org.bluez.Error.Rejected +// +// org.bluez.Error.Canceled +func (a *agent) RequestAuthorization(device dbus.ObjectPath) *dbus.Error { + logger.Infof("dbus call agent RequestAuthorization with device %v", device) + + _, err := a.emitRequest(device, "RequestAuthorization") + if err != nil { + logger.Warning(err) + return toBusErrForAgent(err) + } + + return nil +} + +// AuthorizeService method gets called when the service daemon needs to authorize a connection/service request. +// Possible errors: org.bluez.Error.Rejected +// +// org.bluez.Error.Canceled +func (a *agent) AuthorizeService(device dbus.ObjectPath, uuid string) *dbus.Error { + logger.Infof("dbus call agent AuthorizeService with device %v and uuid %s", + device, uuid) + // TODO: DO NOT forbid device connect service + return nil +} + +// Cancel method gets called to indicate that the agent request failed before a reply was returned. +func (a *agent) Cancel() *dbus.Error { + logger.Info("dbus call agent Cancel") + + a.rspChan <- authorize{path: a.requestDevice, accept: false, key: ""} + a.emitCancelled() + return nil +} + +// toBusErrForAgent 把错误转换为 dbus 错误。 +// 对于已经是 dbus 错误的不经过转换。 +func toBusErrForAgent(err error) *dbus.Error { + v, ok := err.(*dbus.Error) + if ok { + return v + } + // NOTE: *dbus.Error 没有实现 dbusutil.DBusError 接口 + return dbusutil.ToError(err) +} + +func (a *agent) SendNotify(arg string) *dbus.Error { + logger.Infof("dbus call agent SendNotify with arg %v", arg) + + var msg btcommon.NotifyMsg + err := json.Unmarshal([]byte(arg), &msg) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + notify(msg.Icon, localizeStrToStr(msg.Summary), localizeStrToStr(msg.Body)) + return nil +} + +func localizeStrToStr(str *btcommon.LocalizeStr) string { + if str == nil { + return "" + } + + args := make([]interface{}, len(str.Args)) + for idx, arg := range str.Args { + args[idx] = arg + } + return fmt.Sprintf(gettext.Tr(str.Format), args...) +} + +/*****************************************************************************/ + +func newAgent(service *dbusutil.Service) (a *agent) { + a = &agent{ + service: service, + rspChan: make(chan authorize), + } + return +} + +func (a *agent) init() { + a.register() +} + +func (a *agent) register() { + err := a.b.sysBt.RegisterAgent(0, btcommon.SessionAgentPath) + if err != nil { + logger.Warning(err) + } else { + logger.Debug("register agent done") + } +} + +func (a *agent) destroy() { + err := a.b.sysBt.UnregisterAgent(0, btcommon.SessionAgentPath) + if err != nil { + logger.Warning(err) + } + + err = a.service.StopExport(a) + if err != nil { + logger.Warning(err) + } +} + +func (a *agent) waitResponse() (auth authorize, err error) { + logger.Info("waitResponse") + + defer func() { + a.mu.Lock() + a.requestDevice = "" + a.mu.Unlock() + }() + + t := time.NewTimer(60 * time.Second) + select { + case auth = <-a.rspChan: + logger.Info("receive", auth) + if !auth.accept { + err = btcommon.ErrRejected + logger.Warningf("emitRequest return with: %v", err) + return + } + logger.Infof("emitRequest accept %v with %v", a.requestDevice, auth.key) + return + case <-t.C: + logger.Info("timeout") + err = btcommon.ErrCanceled + logger.Warningf("emitRequest return with: %v", err) + a.emitCancelled() + return + } +} + +func (a *agent) emit(signal string, devPath dbus.ObjectPath, args ...interface{}) (err error) { + var args0 []interface{} + args0 = append(args0, devPath) + args0 = append(args0, args...) + return a.b.service.Emit(a.b, signal, args0...) +} + +func (a *agent) emitCancelled() { + a.mu.Lock() + devPath := a.requestDevice + a.mu.Unlock() + + if devPath == "" { + logger.Warning("failed to emitCancelled, devPath is empty") + return + } + err := a.b.service.Emit(a.b, "Cancelled", devPath) + if err != nil { + logger.Warning(err) + } +} + +func (b *Bluetooth) getInitiativeConnect(devPath dbus.ObjectPath) bool { + return b.initiativeConnectMap.get(devPath) +} + +func (b *Bluetooth) setInitiativeConnect(devPath dbus.ObjectPath, val bool) { + b.initiativeConnectMap.set(devPath, val) +} + +func (a *agent) emitRequest(devPath dbus.ObjectPath, signal string, args ...interface{}) (auth authorize, err error) { + logger.Info("emitRequest", devPath, signal, args) + + a.mu.Lock() + a.requestDevice = devPath + a.mu.Unlock() + + d, err := a.b.getDevice(devPath) + if nil != err { + logger.Warningf("emitRequest can not find device: %v, %v", devPath, err) + return auth, btcommon.ErrCanceled + } + needConfirmOrShowSignal := strv.Strv{ + "RequestConfirmation", + "DisplayPasskey", + "DisplayPinCode", + } + // if signal is request confirmation or request show, we deal signal self + if needConfirmOrShowSignal.Contains(signal) { + // judge ensure state, if is true, means pc request a connection + // dont need to show notification window + if a.b.getInitiativeConnect(d.Path) { + // reset state + a.b.setInitiativeConnect(d.Path, false) + //if true, means pc active invoke the connect request + needCancel := "true" + if strings.Contains(strings.ToLower(signal), "display") { + needCancel = "false" + } + err = notifyInitiativeConnect(d, args[0].(string), needCancel) + if err != nil { + logger.Warningf("notify initiative connect failed,err:%v", err) + } + } else { + // if not, means device invoke the connect request, + // need to show notification window + err = notifyPassiveConnect(d, args[0].(string)) + if err != nil { + logger.Warningf("notify passive connect failed,err:%v", err) + } + } + } else { + //if signal is not request confirmation, we emit it to dbus + logger.Debug("Send Signal for device: ", devPath, signal, args) + err = a.emit(signal, devPath, args...) + if err != nil { + logger.Warningf("emitRequest emit signal failed,err:%v", err) + } + } + return a.waitResponse() +} diff --git a/bluetooth1/bluetooth.go b/bluetooth1/bluetooth.go new file mode 100644 index 000000000..f92ccbcf5 --- /dev/null +++ b/bluetooth1/bluetooth.go @@ -0,0 +1,852 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package bluetooth + +import ( + "encoding/json" + "errors" + "fmt" + + "os" + "strings" + "sync" + "time" + + "github.com/godbus/dbus/v5" + btcommon "github.com/linuxdeepin/dde-daemon/common/bluetooth" + audio "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.audio1" + mpris2 "github.com/linuxdeepin/go-dbus-factory/session/org.mpris.mediaplayer2" + obex "github.com/linuxdeepin/go-dbus-factory/system/org.bluez.obex" + airplanemode "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.airplanemode1" + sysbt "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.bluetooth1" + ofdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.dbus" + gio "github.com/linuxdeepin/go-gir/gio-2.0" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/dbusutil/gsprop" + "github.com/linuxdeepin/go-lib/dbusutil/proxy" +) + +const ( + dbusServiceName = "org.deepin.dde.Bluetooth1" + dbusPath = "/org/deepin/dde/Bluetooth1" + dbusInterface = dbusServiceName + configManagerId = "org.desktopspec.ConfigManager" +) + +const ( + bluetoothSchema = "com.deepin.dde.bluetooth" + displaySwitch = "display-switch" +) + +// nolint +const ( + transferStatusQueued = "queued" + transferStatusActive = "active" + transferStatusSuspended = "suspended" + transferStatusComplete = "complete" + transferStatusError = "error" +) + +//go:generate dbusutil-gen -type Bluetooth bluetooth.go +//go:generate dbusutil-gen em -type Bluetooth,agent,obexAgent + +type Bluetooth struct { + service *dbusutil.Service + sysBt sysbt.Bluetooth + sigLoop *dbusutil.SignalLoop + systemSigLoop *dbusutil.SignalLoop + sysDBusDaemon ofdbus.DBus + agent *agent + obexAgent *obexAgent + obexManager obex.Manager + + // airplane + airplaneBltOriginState map[dbus.ObjectPath]bool + airplane airplanemode.AirplaneMode + + adapters AdapterInfos + devices DeviceInfoMap + + initiativeConnectMap *initiativeConnectMap + + PropsMu sync.RWMutex + State uint32 // StateUnavailable/StateAvailable/StateConnected + Transportable bool //能否传输 True可以传输 false不能传输 + CanSendFile bool + + sessionCancelChMap map[dbus.ObjectPath]chan struct{} + sessionCancelChMapMu sync.Mutex + + settings *gio.Settings + //dbusutil-gen: ignore + DisplaySwitch gsprop.Bool `prop:"access:rw"` + + sessionCon *dbus.Conn + sessionAudio audio.Audio + + configManagerPath dbus.ObjectPath + // nolint + signals *struct { + // adapter/device properties changed signals + AdapterAdded, AdapterRemoved, AdapterPropertiesChanged struct { + adapterJSON string + } + + DeviceAdded, DeviceRemoved, DevicePropertiesChanged struct { + devJSON string + } + + // pair request signals + DisplayPinCode struct { + device dbus.ObjectPath + pinCode string + } + DisplayPasskey struct { + device dbus.ObjectPath + passkey uint32 + entered uint32 + } + + // RequestConfirmation you should call Confirm with accept + RequestConfirmation struct { + device dbus.ObjectPath + passkey string + } + + // RequestAuthorization you should call Confirm with accept + RequestAuthorization struct { + device dbus.ObjectPath + } + + // RequestPinCode you should call FeedPinCode with accept and key + RequestPinCode struct { + device dbus.ObjectPath + } + + // RequestPasskey you should call FeedPasskey with accept and key + RequestPasskey struct { + device dbus.ObjectPath + } + + Cancelled struct { + device dbus.ObjectPath + } + + ObexSessionCreated struct { + sessionPath dbus.ObjectPath + } + + ObexSessionRemoved struct { + sessionPath dbus.ObjectPath + } + + ObexSessionProgress struct { + sessionPath dbus.ObjectPath + totalSize uint64 + transferred uint64 + currentIdx int + } + + TransferCreated struct { + file string + transferPath dbus.ObjectPath + sessionPath dbus.ObjectPath + } + + TransferRemoved struct { + file string + transferPath dbus.ObjectPath + sessionPath dbus.ObjectPath + done bool + } + TransferFailed struct { + file string + sessionPath dbus.ObjectPath + errInfo string + } + } +} + +func newBluetooth(service *dbusutil.Service) (b *Bluetooth) { + sysBus, err := dbus.SystemBus() + if err != nil { + logger.Warning(err) + return nil + } + + b = &Bluetooth{ + service: service, + sigLoop: dbusutil.NewSignalLoop(service.Conn(), 0), + systemSigLoop: dbusutil.NewSignalLoop(sysBus, 10), + obexManager: obex.NewManager(service.Conn()), + Transportable: true, + } + + b.sysBt = sysbt.NewBluetooth(sysBus) + b.devices.infos = make(map[dbus.ObjectPath]DeviceInfos) + b.initiativeConnectMap = newInitiativeConnectMap() + // create airplane mode + b.airplane = airplanemode.NewAirplaneMode(sysBus) + + b.sessionCon, err = dbus.SessionBus() + if err != nil { + logger.Warning(err) + return nil + } + b.sessionAudio = audio.NewAudio(b.sessionCon) + + // 加载dsg配置 + systemConnObj := sysBus.Object(configManagerId, "/") + err = systemConnObj.Call(configManagerId+".acquireManager", 0, "org.deepin.dde.daemon", "org.deepin.dde.daemon.bluetooth", "").Store(&b.configManagerPath) + if err != nil { + logger.Warning(err) + return nil + } + + err = dbusutil.NewMatchRuleBuilder().Type("signal"). + PathNamespace(string(b.configManagerPath)). + Interface("org.desktopspec.ConfigManager.Manager"). + Member("valueChanged").Build().AddTo(sysBus) + if err != nil { + logger.Warning(err) + return nil + } + + return +} + +func (b *Bluetooth) destroy() { + b.agent.destroy() + b.sysDBusDaemon.RemoveHandler(proxy.RemoveAllHandlers) + + err := b.service.StopExport(b) + if err != nil { + logger.Warning(err) + } + b.systemSigLoop.Stop() +} + +func (*Bluetooth) GetInterfaceName() string { + return dbusInterface +} + +func (b *Bluetooth) init() { + b.sigLoop.Start() + b.systemSigLoop.Start() + systemBus := b.systemSigLoop.Conn() + b.sessionCancelChMap = make(map[dbus.ObjectPath]chan struct{}) + + // start bluetooth goroutine + // monitor click signal or time out signal to close notification window + go beginTimerNotify(globalTimerNotifier) + + b.sysBt.InitSignalExt(b.systemSigLoop, true) + canSendFile, err := b.sysBt.CanSendFile().Get(0) + if err != nil { + logger.Warning(err) + } + + configCanSendFile := b.getSendFileEnable() + b.setPropCanSendFile(canSendFile && configCanSendFile) + + err = b.sysBt.State().ConnectChanged(func(hasValue bool, value uint32) { + if !hasValue { + return + } + b.setPropState(value) + }) + if err != nil { + logger.Warning(err) + } + state, err := b.sysBt.State().Get(0) + if err != nil { + logger.Warning(err) + } + b.setPropState(state) + + sysBus, err := dbus.SystemBus() + if err != nil { + logger.Warning(err) + return + } + + // 加载dsg配置 + systemConnObj := sysBus.Object(configManagerId, "/") + err = systemConnObj.Call(configManagerId+".acquireManager", 0, "org.deepin.dde.daemon", "org.deepin.dde.daemon.bluetooth", "").Store(&b.configManagerPath) + if err != nil { + logger.Warning(err) + } + + _, err = b.sysBt.ConnectAdapterAdded(func(adapterJSON string) { + adapterInfo, err := unmarshalAdapterInfo(adapterJSON) + if err != nil { + logger.Warning(err) + return + } + + b.adapters.addOrUpdateAdapter(adapterInfo) + err = b.service.Emit(b, "AdapterAdded", adapterJSON) + if err != nil { + logger.Warning(err) + } + }) + if err != nil { + logger.Warning(err) + } + + _, err = b.sysBt.ConnectAdapterRemoved(func(adapterJSON string) { + adapterInfo, err := unmarshalAdapterInfo(adapterJSON) + if err != nil { + logger.Warning(err) + return + } + + err = b.handleBluezPort(false) + if err != nil { + logger.Warning(err) + } + + b.adapters.removeAdapter(adapterInfo.Path) + err = b.service.Emit(b, "AdapterRemoved", adapterJSON) + if err != nil { + logger.Warning(err) + } + }) + if err != nil { + logger.Warning(err) + } + + _, err = b.sysBt.ConnectAdapterPropertiesChanged(func(adapterJSON string) { + adapterInfo, err := unmarshalAdapterInfo(adapterJSON) + if err != nil { + logger.Warning(err) + return + } + + b.adapters.addOrUpdateAdapter(adapterInfo) + err = b.service.Emit(b, "AdapterPropertiesChanged", adapterJSON) + if err != nil { + logger.Warning(err) + } + }) + if err != nil { + logger.Warning(err) + } + + // 初始化 b.adapters + adaptersJSON, err := b.sysBt.GetAdapters(0) + if err == nil { + var adapterInfos []AdapterInfo + err := json.Unmarshal([]byte(adaptersJSON), &adapterInfos) + if err == nil { + b.adapters.mu.Lock() + b.adapters.infos = adapterInfos + b.adapters.mu.Unlock() + } else { + logger.Warning(err) + } + } else { + logger.Warning(err) + } + + _, err = b.sysBt.ConnectDeviceAdded(func(deviceJSON string) { + devInfo, err := unmarshalDeviceInfo(deviceJSON) + if err != nil { + logger.Warning(err) + } + logger.Debug("DeviceAdded", devInfo.Alias, devInfo.Path) + b.devices.addOrUpdateDevice(devInfo) + err = b.service.Emit(b, "DeviceAdded", deviceJSON) + if err != nil { + logger.Warning(err) + } + }) + if err != nil { + logger.Warning(err) + } + + _, err = b.sysBt.ConnectDeviceRemoved(func(deviceJSON string) { + devInfo, err := unmarshalDeviceInfo(deviceJSON) + if err != nil { + logger.Warning(err) + } + logger.Debug("DeviceRemoved", devInfo.Alias, devInfo.Path) + b.initiativeConnectMap.del(devInfo.Path) + b.devices.removeDevice(devInfo.AdapterPath, devInfo.Path) + err = b.service.Emit(b, "DeviceRemoved", deviceJSON) + if err != nil { + logger.Warning(err) + } + }) + if err != nil { + logger.Warning(err) + } + + _, err = b.sysBt.ConnectDevicePropertiesChanged(func(deviceJSON string) { + devInfo, err := unmarshalDeviceInfo(deviceJSON) + if err != nil { + logger.Warning(err) + } + + b.devices.addOrUpdateDevice(devInfo) + err = b.service.Emit(b, "DevicePropertiesChanged", deviceJSON) + if err != nil { + logger.Warning(err) + } + }) + if err != nil { + logger.Warning(err) + } + + // 初始化 b.devices + var adapterPaths []dbus.ObjectPath + b.adapters.mu.Lock() + for _, info := range b.adapters.infos { + adapterPaths = append(adapterPaths, info.Path) + } + b.adapters.mu.Unlock() + + for _, adapterPath := range adapterPaths { + devicesJSON, err := b.sysBt.GetDevices(0, adapterPath) + if err == nil { + var devices DeviceInfos + err = json.Unmarshal([]byte(devicesJSON), &devices) + if err == nil { + b.devices.mu.Lock() + b.devices.infos[adapterPath] = devices + b.devices.mu.Unlock() + } else { + logger.Warning(err) + } + + } else { + logger.Warning(err) + } + + } + + b.sysDBusDaemon = ofdbus.NewDBus(systemBus) + b.sysDBusDaemon.InitSignalExt(b.systemSigLoop, true) + _, err = b.sysDBusDaemon.ConnectNameOwnerChanged(b.handleDBusNameOwnerChanged) + if err != nil { + logger.Warning(err) + } + b.settings = gio.NewSettings(bluetoothSchema) + b.DisplaySwitch.Bind(b.settings, displaySwitch) + + b.agent.init() + b.obexAgent.init() +} + +func getMprisPlayers(sessionConn *dbus.Conn) ([]string, error) { + var playerNames []string + dbusDaemon := ofdbus.NewDBus(sessionConn) + names, err := dbusDaemon.ListNames(0) + if err != nil { + return nil, err + } + for _, name := range names { + if strings.HasPrefix(name, "org.mpris.MediaPlayer2") { + // is mpris player + playerNames = append(playerNames, name) + } + } + return playerNames, nil +} + +// true : play; false : pause +func setAllPlayers(value bool) { + sessionConn, err := dbus.SessionBus() + if err != nil { + logger.Warning(err) + return + } + playerNames, err := getMprisPlayers(sessionConn) + if err != nil { + logger.Warning("getMprisPlayers failed:", err) + return + } + + logger.Debug("pause all players") + for _, playerName := range playerNames { + player := mpris2.NewMediaPlayer(sessionConn, playerName) + if value { + err := player.Player().Play(0) + if err != nil { + logger.Warningf("failed to pause player %s: %v", playerName, err) + } + } else { + err := player.Player().Pause(0) + if err != nil { + logger.Warningf("failed to pause player %s: %v", playerName, err) + } + } + + } +} + +// 获取当前是否为蓝牙端口音频,是:暂停音乐 +func (b *Bluetooth) handleBluezPort(value bool) error { + //get defaultSink Name + sinkPath, err := b.sessionAudio.DefaultSink().Get(0) + if err != nil { + return err + } + + sink, err := audio.NewSink(b.sessionCon, sinkPath) + if err != nil { + return err + } + sinkName, err := sink.Name().Get(0) + if err != nil { + return err + } + isBluePort := strings.Contains(strings.ToLower(sinkName), "blue") + logger.Info(" handleBluezPort sinkName : ", sinkName, isBluePort) + if isBluePort { + //stop music + go setAllPlayers(value) + } + return nil +} + +func (b *Bluetooth) handleDBusNameOwnerChanged(name, oldOwner, newOwner string) { + if name != b.sysBt.ServiceName_() { + return + } + if newOwner != "" { + logger.Info("sys bluetooth is starting") + time.AfterFunc(1*time.Second, func() { + b.agent.register() + }) + } else { + logger.Info("sys bluetooth stopped") + b.devices.clear() + b.adapters.clear() + } +} + +type initiativeConnectMap struct { + mu sync.Mutex + m map[dbus.ObjectPath]bool +} + +func newInitiativeConnectMap() *initiativeConnectMap { + return &initiativeConnectMap{ + m: make(map[dbus.ObjectPath]bool), + } +} + +func (icm *initiativeConnectMap) set(path dbus.ObjectPath, val bool) { + icm.mu.Lock() + defer icm.mu.Unlock() + icm.m[path] = val +} + +func (icm *initiativeConnectMap) get(path dbus.ObjectPath) bool { + icm.mu.Lock() + defer icm.mu.Unlock() + return icm.m[path] +} + +func (icm *initiativeConnectMap) del(path dbus.ObjectPath) { + icm.mu.Lock() + defer icm.mu.Unlock() + delete(icm.m, path) +} + +func (b *Bluetooth) getDevice(devPath dbus.ObjectPath) (*DeviceInfo, error) { + info := b.devices.getDeviceWithPath(devPath) + if info == nil { + return nil, errors.New("device not found") + } + return info, nil +} + +func (b *Bluetooth) feed(devPath dbus.ObjectPath, accept bool, key string) (err error) { + _, err = b.getDevice(devPath) + if nil != err { + logger.Warningf("FeedRequest can not find device: %v, %v", devPath, err) + return err + } + + b.agent.mu.Lock() + if b.agent.requestDevice != devPath { + b.agent.mu.Unlock() + logger.Warningf("FeedRequest can not find match device: %q, %q", b.agent.requestDevice, devPath) + return btcommon.ErrCanceled + } + b.agent.mu.Unlock() + + select { + case b.agent.rspChan <- authorize{path: devPath, accept: accept, key: key}: + return nil + default: + return errors.New("rspChan no reader") + } +} + +func (b *Bluetooth) getConnectedDeviceByAddress(address string) *DeviceInfo { + devInfo := b.devices.findFirst(func(devInfo *DeviceInfo) bool { + return devInfo.ConnectState && devInfo.Address == address + }) + return devInfo +} + +func (b *Bluetooth) getDeviceByAddress(address string) *DeviceInfo { + devInfo := b.devices.findFirst(func(devInfo *DeviceInfo) bool { + return devInfo.Address == address + }) + return devInfo +} + +func (b *Bluetooth) sendFiles(dev *DeviceInfo, files []string) (dbus.ObjectPath, error) { + var totalSize uint64 + + for _, f := range files { + info, err := os.Stat(f) + if err != nil { + return "/", err + } + + totalSize += uint64(info.Size()) + } + // 创建 OBEX session + args := make(map[string]dbus.Variant) + _, adapter := b.adapters.getAdapter(dev.AdapterPath) + if adapter == nil { + return "/", fmt.Errorf("not found adapter with path: %q", dev.AdapterPath) + } + args["Source"] = dbus.MakeVariant(adapter.Address) // 蓝牙适配器地址 + args["Target"] = dbus.MakeVariant("opp") // 连接方式「OPP」 + sessionPath, err := b.obexManager.Client().CreateSession(0, dev.Address, args) + if err != nil { + logger.Warning("failed to create obex session:", err) + return "", err + } + b.emitObexSessionCreated(sessionPath) + b.setPropTransportable(false) + logger.Debug("Transportable", b.Transportable) + + session, err := obex.NewSession(b.service.Conn(), sessionPath) + if err != nil { + logger.Warning("failed to get session bus:", err) + return "", err + } + + go b.doSendFiles(session, files, totalSize) + + return sessionPath, nil +} + +func (b *Bluetooth) doSendFiles(session obex.Session, files []string, totalSize uint64) { + sessionPath := session.Path_() + cancelCh := make(chan struct{}) + + b.sessionCancelChMapMu.Lock() + b.sessionCancelChMap[sessionPath] = cancelCh + b.sessionCancelChMapMu.Unlock() + + var transferredBase uint64 + + for i, f := range files { + _, err := os.Stat(f) + if err != nil { + b.emitTransferFailed(f, sessionPath, err.Error()) + break + } + transferPath, properties, err := session.ObjectPush().SendFile(0, f) + if err != nil { + logger.Warningf("failed to send file: %s: %s", f, err) + continue + } + logger.Infof("properties: %v", properties) + + transfer, err := obex.NewTransfer(b.service.Conn(), transferPath) + if err != nil { + logger.Warningf("failed to send file: %s: %s", f, err) + continue + } + + transfer.InitSignalExt(b.sigLoop, true) + + b.emitTransferCreated(f, transferPath, sessionPath) + + ch := make(chan bool) + err = transfer.Status().ConnectChanged(func(hasValue bool, value string) { + if !hasValue { + return + } + // 成功或者失败,说明这个传输结束 + if value == transferStatusComplete || value == transferStatusError { + ch <- value == transferStatusComplete + } + }) + if err != nil { + logger.Warning("connect to status changed failed:", err) + } + + err = transfer.Transferred().ConnectChanged(func(hasValue bool, value uint64) { + if !hasValue { + return + } + + transferred := transferredBase + value + b.emitObexSessionProgress(sessionPath, totalSize, transferred, i+1) + }) + if err != nil { + logger.Warning("connect to transferred changed failed:", err) + } + + var res bool + var cancel bool + select { + case res = <-ch: + case <-cancelCh: + b.sessionCancelChMapMu.Lock() + delete(b.sessionCancelChMap, sessionPath) + b.sessionCancelChMapMu.Unlock() + + cancel = true + err = transfer.Cancel(0) + if err != nil { + logger.Warning("failed to cancel transfer:", err) + } + } + transfer.RemoveAllHandlers() + b.emitTransferRemoved(f, transferPath, sessionPath, res) + + if !res { + break + } + + if cancel { + break + } + + info, err := os.Stat(f) + if err != nil { + logger.Warning("failed to stat file:", err) + break + } else { + transferredBase += uint64(info.Size()) + } + + b.emitObexSessionProgress(sessionPath, totalSize, transferredBase, i+1) + } + + b.sessionCancelChMapMu.Lock() + delete(b.sessionCancelChMap, sessionPath) + b.sessionCancelChMapMu.Unlock() + + b.emitObexSessionRemoved(sessionPath) + b.setPropTransportable(true) + + objs, err := obex.NewObjectManager(b.service.Conn()).GetManagedObjects(0) + if err != nil { + logger.Warning("failed to get managed objects:", err) + } else { + _, pathExists := objs[sessionPath] + if !pathExists { + logger.Debugf("session %s not exists", sessionPath) + return + } + } + + err = b.obexManager.Client().RemoveSession(0, sessionPath) + if err != nil { + logger.Warning("failed to remove session:", err) + } +} + +func (b *Bluetooth) emitObexSessionCreated(sessionPath dbus.ObjectPath) { + err := b.service.Emit(b, "ObexSessionCreated", sessionPath) + if err != nil { + logger.Warning("failed to emit ObexSessionCreated:", err) + } +} + +func (b *Bluetooth) emitObexSessionRemoved(sessionPath dbus.ObjectPath) { + err := b.service.Emit(b, "ObexSessionRemoved", sessionPath) + if err != nil { + logger.Warning("failed to emit ObexSessionRemoved:", err) + } +} + +func (b *Bluetooth) emitObexSessionProgress(sessionPath dbus.ObjectPath, totalSize uint64, transferred uint64, currentIdx int) { + err := b.service.Emit(b, "ObexSessionProgress", sessionPath, totalSize, transferred, currentIdx) + if err != nil { + logger.Warning("failed to emit ObexSessionProgress:", err) + } +} + +func (b *Bluetooth) emitTransferCreated(file string, transferPath dbus.ObjectPath, sessionPath dbus.ObjectPath) { + err := b.service.Emit(b, "TransferCreated", file, transferPath, sessionPath) + if err != nil { + logger.Warning("failed to emit TransferCreated:", err) + } +} + +func (b *Bluetooth) emitTransferRemoved(file string, transferPath dbus.ObjectPath, sessionPath dbus.ObjectPath, done bool) { + err := b.service.Emit(b, "TransferRemoved", file, transferPath, sessionPath, done) + if err != nil { + logger.Warning("failed to emit TransferRemoved:", err) + } +} + +func (b *Bluetooth) emitTransferFailed(file string, sessionPath dbus.ObjectPath, errInfo string) { + err := b.service.Emit(b, "TransferFailed", file, sessionPath, errInfo) + if err != nil { + logger.Warning("failed to emit TransferFailed:", err) + } +} + +func (b *Bluetooth) getAirplaneBltOriginStateConfig() string { + systemConn, err := dbus.SystemBus() + if err != nil { + return "" + } + systemConnObj := systemConn.Object("org.desktopspec.ConfigManager", b.configManagerPath) + var value string + err = systemConnObj.Call("org.desktopspec.ConfigManager.Manager.value", 0, "airplaneBltOriginState").Store(&value) + if err != nil { + logger.Warning(err) + return "" + } + return value +} + +func (b *Bluetooth) setAirplaneBltOriginStateConfig(value string) { + if value == "" { + return + } + systemConn, err := dbus.SystemBus() + if err != nil { + return + } + systemConnObj := systemConn.Object("org.desktopspec.ConfigManager", b.configManagerPath) + err = systemConnObj.Call("org.desktopspec.ConfigManager.Manager.setValue", 0, "airplaneBltOriginState", dbus.MakeVariant(value)).Err + if err != nil { + logger.Warning(err) + return + } + + return +} + +func (b *Bluetooth) getSendFileEnable() bool { + systemConn, err := dbus.SystemBus() + if err != nil { + return true + } + systemConnObj := systemConn.Object("org.desktopspec.ConfigManager", b.configManagerPath) + var value bool + err = systemConnObj.Call("org.desktopspec.ConfigManager.Manager.value", 0, "sendFileEnable").Store(&value) + if err != nil { + logger.Warning(err) + return true + } + return value +} diff --git a/bluetooth/bluetooth_dbusutil.go b/bluetooth1/bluetooth_dbusutil.go similarity index 100% rename from bluetooth/bluetooth_dbusutil.go rename to bluetooth1/bluetooth_dbusutil.go diff --git a/bluetooth1/bluetooth_ifc.go b/bluetooth1/bluetooth_ifc.go new file mode 100644 index 000000000..b0c17cdb9 --- /dev/null +++ b/bluetooth1/bluetooth_ifc.go @@ -0,0 +1,317 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package bluetooth + +import ( + "encoding/json" + "errors" + "fmt" + "time" + + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (b *Bluetooth) ConnectDevice(device dbus.ObjectPath, apath dbus.ObjectPath) *dbus.Error { + logger.Infof("dbus call ConnectDevice with device %v and apath %v", device, apath) + + b.setInitiativeConnect(device, true) + err := b.sysBt.ConnectDevice(0, device, apath) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + return nil +} + +func (b *Bluetooth) DisconnectDevice(device dbus.ObjectPath) *dbus.Error { + logger.Infof("dbus call DisconnectDevice with device %v", device) + + err := b.sysBt.DisconnectDevice(0, device) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + return nil +} + +func (b *Bluetooth) RemoveDevice(adapter, device dbus.ObjectPath) *dbus.Error { + logger.Infof("dbus call RemoveDevice with adapter %v and device %v", adapter, device) + + err := b.sysBt.RemoveDevice(0, adapter, device) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + return nil +} + +func (b *Bluetooth) SetDeviceAlias(device dbus.ObjectPath, alias string) *dbus.Error { + logger.Infof("dbus call SetDeviceAlias with device %v and alias %s", + device, alias) + + err := b.sysBt.SetDeviceAlias(0, device, alias) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + return nil +} + +func (b *Bluetooth) SetDeviceTrusted(device dbus.ObjectPath, trusted bool) *dbus.Error { + logger.Infof("dbus call SetDeviceTrusted with device %v and trusted %t", + device, trusted) + + err := b.sysBt.SetDeviceTrusted(0, device, trusted) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + return nil +} + +// GetDevices return all device objects that marshaled by json. +func (b *Bluetooth) GetDevices(adapter dbus.ObjectPath) (devicesJSON string, busErr *dbus.Error) { + logger.Infof("dbus call GetDevices with adapter %v", adapter) + + devices := b.devices.getDevices(adapter) + devicesJson := marshalJSON(devices) + return devicesJson, nil +} + +// GetAdapters return all adapter objects that marshaled by json. +func (b *Bluetooth) GetAdapters() (adaptersJSON string, busErr *dbus.Error) { + logger.Info("dbus call GetAdapters") + return b.adapters.toJSON(), nil +} + +func (b *Bluetooth) RequestDiscovery(adapter dbus.ObjectPath) *dbus.Error { + logger.Infof("dbus call RequestDiscovery with adapter %v ", adapter) + + err := b.sysBt.RequestDiscovery(0, adapter) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + return nil +} + +// SendFiles 用来发送文件给蓝牙设备,仅支持发送给已连接设备 +func (b *Bluetooth) SendFiles(devAddress string, files []string) (sessionPath dbus.ObjectPath, busErr *dbus.Error) { + logger.Infof("dbus call SendFiles with devAddress %s and files %v", devAddress, files) + + if len(files) == 0 { + err := errors.New("files is empty") + logger.Warning(err) + return "", dbusutil.ToError(err) + } + + if !b.CanSendFile { + err := errors.New("no permission") + logger.Warning(err) + return "", dbusutil.ToError(err) + } + + // 检查设备是否已经连接 + dev := b.getConnectedDeviceByAddress(devAddress) + if dev == nil { + err := errors.New("device not connected") + logger.Warning(err) + return "", dbusutil.ToError(err) + } + + sessionPath, err := b.sendFiles(dev, files) + if err != nil { + logger.Warning(err) + return "", dbusutil.ToError(err) + } + + return sessionPath, nil +} + +// CancelTransferSession 用来取消发送的会话,将会终止会话中所有的传送任务 +func (b *Bluetooth) CancelTransferSession(sessionPath dbus.ObjectPath) *dbus.Error { + logger.Infof("dbus call CancelTransferSession with sessionPath %v", sessionPath) + + //添加延时,确保sessionPath被remove,防止死锁 + time.Sleep(500 * time.Millisecond) + b.sessionCancelChMapMu.Lock() + defer b.sessionCancelChMapMu.Unlock() + + cancelCh, ok := b.sessionCancelChMap[sessionPath] + if !ok { + err := errors.New("session not exists") + logger.Warning(err) + return dbusutil.ToError(err) + } + + cancelCh <- struct{}{} + + return nil +} + +func (b *Bluetooth) SetAdapterPowered(adapter dbus.ObjectPath, + powered bool) *dbus.Error { + logger.Infof("dbus call SetAdapterPowered with adapter %v and powered %t", + adapter, powered) + // 当蓝牙开关打开时,需要同步session蓝牙中devices + if powered { + devicesJSON, err := b.sysBt.GetDevices(0, adapter) + if err == nil { + var devices DeviceInfos + err = json.Unmarshal([]byte(devicesJSON), &devices) + if err == nil { + b.devices.mu.Lock() + b.devices.infos[adapter] = devices + b.devices.mu.Unlock() + } else { + logger.Warning(err) + } + + } else { + logger.Warning(err) + } + } else { + err := b.handleBluezPort(powered) + if err != nil { + logger.Warning(err) + } + } + + err := b.sysBt.SetAdapterPowered(0, adapter, powered) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + return nil +} + +func (b *Bluetooth) SetAdapterAlias(adapter dbus.ObjectPath, alias string) *dbus.Error { + logger.Infof("dbus call SetAdapterAlias with adapter %v and alias %s", adapter, alias) + + err := b.sysBt.SetAdapterAlias(0, adapter, alias) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + return nil +} + +func (b *Bluetooth) SetAdapterDiscoverable(adapter dbus.ObjectPath, + discoverable bool) *dbus.Error { + logger.Infof("dbus call SetAdapterDiscoverable with adapter %v and discoverable %t", + adapter, discoverable) + + err := b.sysBt.SetAdapterDiscoverable(0, adapter, discoverable) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + return nil +} + +func (b *Bluetooth) SetAdapterDiscovering(adapter dbus.ObjectPath, + discovering bool) *dbus.Error { + logger.Infof("dbus call SetAdapterDiscovering with adapter %v and discovering %t", + adapter, discovering) + + err := b.sysBt.SetAdapterDiscovering(0, adapter, discovering) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + return nil +} + +func (b *Bluetooth) SetAdapterDiscoverableTimeout(adapter dbus.ObjectPath, + discoverableTimeout uint32) *dbus.Error { + logger.Infof("dbus call SetAdapterDiscoverableTimeout with adapter %v and discoverableTimeout %d", + adapter, discoverableTimeout) + + err := b.sysBt.SetAdapterDiscoverableTimeout(0, adapter, discoverableTimeout) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + return nil +} + +// Confirm should call when you receive RequestConfirmation signal +func (b *Bluetooth) Confirm(device dbus.ObjectPath, accept bool) *dbus.Error { + logger.Infof("dbus call Confirm with device %v and accept %t", device, accept) + + err := b.feed(device, accept, "") + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + return nil +} + +// FeedPinCode should call when you receive RequestPinCode signal, notice that accept must true +// if you accept connect request. If accept is false, pinCode will be ignored. +func (b *Bluetooth) FeedPinCode(device dbus.ObjectPath, accept bool, pinCode string) *dbus.Error { + logger.Infof("dbus call FeedPinCode with device %v, accept %t and pinCode %s", device, accept, pinCode) + + err := b.feed(device, accept, pinCode) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + return nil +} + +// FeedPasskey should call when you receive RequestPasskey signal, notice that accept must true +// if you accept connect request. If accept is false, passkey will be ignored. +// passkey must be range in 0~999999. +func (b *Bluetooth) FeedPasskey(device dbus.ObjectPath, accept bool, passkey uint32) *dbus.Error { + logger.Infof("dbus call FeedPasskey with device %v, accept %t and passkey %d", device, accept, passkey) + + err := b.feed(device, accept, fmt.Sprintf("%06d", passkey)) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + return nil +} + +func (b *Bluetooth) DebugInfo() (info string, busErr *dbus.Error) { + logger.Info("dbus call DebugInfo") + + info, err := b.sysBt.DebugInfo(0) + if err != nil { + logger.Warning(err) + return "", dbusutil.ToError(err) + } + + return info, nil +} + +// ClearUnpairedDevice will remove all device in unpaired list +func (b *Bluetooth) ClearUnpairedDevice() *dbus.Error { + logger.Infof("dbus call ClearUnpairedDevice") + + err := b.sysBt.ClearUnpairedDevice(0) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + return nil +} diff --git a/bluetooth/bluez_profile.go b/bluetooth1/bluez_profile.go similarity index 98% rename from bluetooth/bluez_profile.go rename to bluetooth1/bluez_profile.go index 77ad69f49..733dde73c 100644 --- a/bluetooth/bluez_profile.go +++ b/bluetooth1/bluez_profile.go @@ -10,7 +10,7 @@ type profile struct { uuid, name string } -//nolint +// nolint var profiles = []profile{ profile{SPP_UUID, Tr("Serial port")}, profile{DUN_GW_UUID, Tr("Dial-Up networking")}, diff --git a/bluetooth/bluez_uuid.go b/bluetooth1/bluez_uuid.go similarity index 100% rename from bluetooth/bluez_uuid.go rename to bluetooth1/bluez_uuid.go diff --git a/bluetooth/develop.md b/bluetooth1/develop.md similarity index 100% rename from bluetooth/develop.md rename to bluetooth1/develop.md diff --git a/bluetooth1/device.go b/bluetooth1/device.go new file mode 100644 index 000000000..115eeb6b9 --- /dev/null +++ b/bluetooth1/device.go @@ -0,0 +1,166 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package bluetooth + +import ( + "encoding/json" + "fmt" + "sync" + + "github.com/godbus/dbus/v5" +) + +const ( + deviceStateDisconnected = 0 + // device state is connecting or disconnecting, mark them as device state doing + deviceStateConnecting = 1 + deviceStateConnected = 2 + deviceStateDisconnecting = 3 +) + +type deviceState uint32 + +func (s deviceState) String() string { + switch s { + case deviceStateDisconnected: + return "Disconnected" + case deviceStateConnecting: + return "Connecting" + case deviceStateConnected: + return "Connected" + case deviceStateDisconnecting: + return "Disconnecting" + default: + return fmt.Sprintf("Unknown(%d)", s) + } +} + +type DeviceInfo struct { + Path dbus.ObjectPath + AdapterPath dbus.ObjectPath + + Alias string + Trusted bool + Paired bool + State deviceState + ServicesResolved bool + ConnectState bool + + UUIDs []string + Name string + Icon string + RSSI int16 + Address string +} + +func unmarshalDeviceInfo(data string) (*DeviceInfo, error) { + var device DeviceInfo + err := json.Unmarshal([]byte(data), &device) + if err != nil { + return nil, err + } + return &device, nil +} + +type DeviceInfoMap struct { + mu sync.Mutex + infos map[dbus.ObjectPath]DeviceInfos +} + +type DeviceInfos []DeviceInfo + +func (infos DeviceInfos) getDevice(path dbus.ObjectPath) (int, *DeviceInfo) { + for idx, info := range infos { + if info.Path == path { + return idx, &info + } + } + return -1, nil +} + +func (infos DeviceInfos) removeDevice(path dbus.ObjectPath) (DeviceInfos, bool) { + idx, _ := infos.getDevice(path) + if idx == -1 { + return infos, false + } + return append(infos[:idx], infos[idx+1:]...), true +} + +func (m *DeviceInfoMap) getDeviceNoLock(adapterPath dbus.ObjectPath, + devPath dbus.ObjectPath) (int, *DeviceInfo) { + devices := m.infos[adapterPath] + return devices.getDevice(devPath) +} + +func (m *DeviceInfoMap) getDevice(adapterPath dbus.ObjectPath, devPath dbus.ObjectPath) (int, *DeviceInfo) { + m.mu.Lock() + defer m.mu.Unlock() + return m.getDeviceNoLock(adapterPath, devPath) +} + +func (m *DeviceInfoMap) getDevices(adapterPath dbus.ObjectPath) DeviceInfos { + m.mu.Lock() + defer m.mu.Unlock() + devices := m.infos[adapterPath] + devicesCopy := make(DeviceInfos, len(devices)) + copy(devicesCopy, devices) + return devicesCopy +} + +func (m *DeviceInfoMap) addOrUpdateDevice(devInfo *DeviceInfo) { + m.mu.Lock() + defer m.mu.Unlock() + + devices := m.infos[devInfo.AdapterPath] + idx, _ := devices.getDevice(devInfo.Path) + if idx != -1 { + // 更新 + devices[idx] = *devInfo + return + } + m.infos[devInfo.AdapterPath] = append(devices, *devInfo) +} + +func (m *DeviceInfoMap) removeDevice(adapterPath, devPath dbus.ObjectPath) bool { + m.mu.Lock() + defer m.mu.Unlock() + + devices := m.infos[adapterPath] + newDevices, ok := devices.removeDevice(devPath) + if ok { + m.infos[adapterPath] = newDevices + } + return ok +} + +func (m *DeviceInfoMap) clear() { + m.mu.Lock() + m.infos = make(map[dbus.ObjectPath]DeviceInfos) + m.mu.Unlock() +} + +func (m *DeviceInfoMap) findFirst(fn func(devInfo *DeviceInfo) bool) *DeviceInfo { + if fn == nil { + return nil + } + m.mu.Lock() + defer m.mu.Unlock() + + for _, infos := range m.infos { + for _, info := range infos { + // #nosec G601 + if fn(&info) { + return &info + } + } + } + return nil +} + +func (m *DeviceInfoMap) getDeviceWithPath(devPath dbus.ObjectPath) *DeviceInfo { + return m.findFirst(func(devInfo *DeviceInfo) bool { + return devInfo.Path == devPath + }) +} diff --git a/bluetooth/doc.go b/bluetooth1/doc.go similarity index 100% rename from bluetooth/doc.go rename to bluetooth1/doc.go diff --git a/bluetooth/exported_methods_auto.go b/bluetooth1/exported_methods_auto.go similarity index 100% rename from bluetooth/exported_methods_auto.go rename to bluetooth1/exported_methods_auto.go diff --git a/bluetooth1/init.go b/bluetooth1/init.go new file mode 100644 index 000000000..630d7e684 --- /dev/null +++ b/bluetooth1/init.go @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package bluetooth + +import ( + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" +) + +var logger = log.NewLogger("daemon/bluetooth") + +func init() { + loader.Register(newBluetoothDaemon(logger)) +} diff --git a/bluetooth/main.go b/bluetooth1/main.go similarity index 100% rename from bluetooth/main.go rename to bluetooth1/main.go diff --git a/bluetooth/obex_agent.go b/bluetooth1/obex_agent.go similarity index 98% rename from bluetooth/obex_agent.go rename to bluetooth1/obex_agent.go index 02bc22ea4..f7b8203fb 100644 --- a/bluetooth/obex_agent.go +++ b/bluetooth1/obex_agent.go @@ -7,6 +7,7 @@ package bluetooth import ( "errors" "fmt" + "math" "math/rand" "os" @@ -17,9 +18,9 @@ import ( dutils "github.com/linuxdeepin/go-lib/utils" - "github.com/godbus/dbus" - obex "github.com/linuxdeepin/go-dbus-factory/org.bluez.obex" - notifications "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.notifications" + "github.com/godbus/dbus/v5" + notifications "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.notifications" + obex "github.com/linuxdeepin/go-dbus-factory/system/org.bluez.obex" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/gettext" "github.com/linuxdeepin/go-lib/xdg/userdir" diff --git a/bluetooth/utils.go b/bluetooth1/utils.go similarity index 100% rename from bluetooth/utils.go rename to bluetooth1/utils.go diff --git a/bluetooth1/utils_notify.go b/bluetooth1/utils_notify.go new file mode 100644 index 000000000..a5528e7a7 --- /dev/null +++ b/bluetooth1/utils_notify.go @@ -0,0 +1,188 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package bluetooth + +import ( + "fmt" + "os/exec" + "strconv" + "sync" + "time" + + "github.com/godbus/dbus/v5" + notifications "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.notifications" + "github.com/linuxdeepin/go-lib/dbusutil" + . "github.com/linuxdeepin/go-lib/gettext" +) + +const ( + notifyIconBluetoothConnected = "notification-bluetooth-connected" + notifyIconBluetoothDisconnected = "notification-bluetooth-disconnected" + notifyIconBluetoothConnectFailed = "notification-bluetooth-error" + // dialog use for show pinCode + notifyDdeDialogPath = "/usr/lib/deepin-daemon/dde-bluetooth-dialog" + // notification window stay time + notifyTimerDuration = 30 * time.Second +) + +const bluetoothDialog string = "dde-bluetooth-dialog" + +var globalNotifications notifications.Notifications +var globalNotifyId uint32 +var globalNotifyMu sync.Mutex + +func initNotifications() error { + // init global notification timer instance + globalTimerNotifier = GetTimerNotifyInstance() + + sessionBus, err := dbus.SessionBus() + if err != nil { + return err + } + globalNotifications = notifications.NewNotifications(sessionBus) + + // monitor notification-close-signal + sessionLoop := dbusutil.NewSignalLoop(sessionBus, 10) + sessionLoop.Start() + globalNotifications.InitSignalExt(sessionLoop, true) + _, err = globalNotifications.ConnectActionInvoked(func(id uint32, actionKey string) { + // has received signal, use id to compare with last globalNotifyId + if id == globalNotifyId { + if actionKey == "cancel" { + err = globalBluetooth.agent.Cancel() + if err != nil { + logger.Warning("Cancel error:", err) + } + } + // if it is the same, then send chan to instance chan to close window + globalTimerNotifier.actionInvokedChan <- true + } + }) + if err != nil { + logger.Warningf("listen action invoked failed,err:%v", err) + } + + return nil +} + +func notify(icon, summary, body string) { + logger.Info("notify", icon, summary, body) + + globalNotifyMu.Lock() + nid := globalNotifyId + globalNotifyMu.Unlock() + + nid, err := globalNotifications.Notify(0, "dde-control-center", nid, icon, + summary, body, nil, nil, -1) + if err != nil { + logger.Warning(err) + return + } + globalNotifyMu.Lock() + globalNotifyId = nid + globalNotifyMu.Unlock() +} + +// notify pc initiative connect to device +// so do not need to show notification window +func notifyInitiativeConnect(dev *DeviceInfo, pinCode string, needCancel string) error { + if checkProcessExists(bluetoothDialog) { + logger.Info("initiative already exist") + return nil + } + + timestamp := strconv.FormatInt(time.Now().UnixNano(), 10) + //use command to open osd window to show pin code + // #nosec G204 + cmd := exec.Command(notifyDdeDialogPath, pinCode, string(dev.Path), timestamp, needCancel) + err := cmd.Start() + if err != nil { + logger.Infof("execute cmd command failed,err:%v", err) + return err + } + + go func() { + err := cmd.Wait() + if err != nil { + logger.Warning(err) + } + }() + + return nil +} + +// device passive connect to pc +// so need to show notification window +func notifyPassiveConnect(dev *DeviceInfo, pinCode string) error { + format := Tr("Click here to connect to %q") + summary := Tr("Add Bluetooth devices") + body := fmt.Sprintf(format, dev.Name) + globalNotifyMu.Lock() + nid := globalNotifyId + globalNotifyMu.Unlock() + // check if bluetooth dialog is exist + if checkProcessExists(bluetoothDialog) { + logger.Info("Passive is not exist") + return nil + } + var as = []string{"pair", Tr("Pair"), "cancel", Tr("Cancel")} + var timestamp = strconv.FormatInt(time.Now().UnixNano(), 10) + cmd := notifyDdeDialogPath + "," + pinCode + "," + string(dev.Path) + "," + timestamp + hints := map[string]dbus.Variant{"x-deepin-action-pair": dbus.MakeVariant(cmd)} + + // to make sure last notification has been closed + err := globalNotifications.CloseNotification(0, nid) + if err != nil { + logger.Warningf("close last notification failed,err:%v", err) + } + + // notify connect request to dde-control-center + // set notify time out as -1, default time out is 5 seconds + nid, err = globalNotifications.Notify(0, "dde-control-center", nid, notifyIconBluetoothConnected, + summary, body, as, hints, 30*1000) + if err != nil { + logger.Warningf("notify message failed,err:%v", err) + return err + } + + globalNotifyMu.Lock() + globalNotifyId = nid + globalNotifyMu.Unlock() + + return nil +} + +// global timer notifier +var globalTimerNotifier *timerNotify + +// notify timer instance +// use chan bool instead of timer, but in case to fit new requirements of future flexibly, we keep element timer +type timerNotify struct { + actionInvokedChan chan bool +} + +// GetTimerNotifyInstance get timer instance +func GetTimerNotifyInstance() *timerNotify { + // create a global timer notify object + timerNotifier := &timerNotify{ + actionInvokedChan: make(chan bool), + } + return timerNotifier +} + +// begin timer routine to monitor window click notification window +func beginTimerNotify(notifyTimer *timerNotify) { + for { + select { + case <-notifyTimer.actionInvokedChan: + // monitor click window signal + logger.Info("user click notify,close notify") + err := globalNotifications.CloseNotification(0, globalNotifyId) + if err != nil { + logger.Warningf("click event close notify icon failed,err:%v", err) + } + } + } +} diff --git a/bluetooth/utils_test.go b/bluetooth1/utils_test.go similarity index 100% rename from bluetooth/utils_test.go rename to bluetooth1/utils_test.go diff --git a/clipboard/manager.go b/clipboard/manager.go deleted file mode 100644 index a692bdbb1..000000000 --- a/clipboard/manager.go +++ /dev/null @@ -1,899 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package clipboard - -import ( - "bytes" - "errors" - "fmt" - "strings" - "sync" - "time" - - "github.com/godbus/dbus" - ConfigManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/log" - x "github.com/linuxdeepin/go-x11-client" - "github.com/linuxdeepin/go-x11-client/ext/xfixes" -) - -//go:generate dbusutil-gen em -type Manager - -var ( - atomClipboardManager x.Atom - atomClipboard x.Atom - atomSaveTargets x.Atom - atomTargets x.Atom - atomMultiple x.Atom - atomDelete x.Atom - atomInsertProperty x.Atom - atomInsertSelection x.Atom - atomAtomPair x.Atom //nolint - atomIncr x.Atom - atomTimestamp x.Atom - atomNull x.Atom //nolint - atomTimestampProp x.Atom - atomFromClipboardManager x.Atom - - selectionMaxSize int -) - -const ( - dSettingsAppID = "org.deepin.dde.daemon" - dSettingsClipboardName = "org.deepin.dde.daemon.clipboard" - dSettingsKeySaveAtomIncrDataEnabled = "saveAtomIncrDataEnabled" -) - -func initAtoms(xConn *x.Conn) { - atomClipboardManager, _ = xConn.GetAtom("CLIPBOARD_MANAGER") - atomClipboard, _ = xConn.GetAtom("CLIPBOARD") - atomSaveTargets, _ = xConn.GetAtom("SAVE_TARGETS") - atomTargets, _ = xConn.GetAtom("TARGETS") - atomMultiple, _ = xConn.GetAtom("MULTIPLE") - atomDelete, _ = xConn.GetAtom("DELETE") - atomInsertProperty, _ = xConn.GetAtom("INSERT_PROPERTY") - atomInsertSelection, _ = xConn.GetAtom("INSERT_SELECTION") - atomAtomPair, _ = xConn.GetAtom("ATOM_PAIR") - atomIncr, _ = xConn.GetAtom("INCR") - atomTimestamp, _ = xConn.GetAtom("TIMESTAMP") - atomTimestampProp, _ = xConn.GetAtom("_TIMESTAMP_PROP") - atomNull, _ = xConn.GetAtom("NULL") - atomFromClipboardManager, _ = xConn.GetAtom("FROM_DEEPIN_CLIPBOARD_MANAGER") - selectionMaxSize = 65432 - logger.Debug("selectionMaxSize:", selectionMaxSize) -} - -type TargetData struct { - Target x.Atom - Type x.Atom - Format uint8 - Data []byte -} - -func (td *TargetData) needINCR() bool { - return len(td.Data) > selectionMaxSize -} - -type Manager struct { - xc XClient - window x.Window - ec *eventCaptor - clipboardManagerAcquireTs x.Timestamp // 获取 CLIPBOARD_MANAGER selection 的时间戳 - clipboardManagerLostTs x.Timestamp // 丢失 CLIPBOARD_MANAGER selection 的时间戳 - clipboardAcquireTs x.Timestamp // 获取 CLIPBOARD selection 的时间戳 - clipboardLostTs x.Timestamp // 丢失 CLIPBOARD selection 的时间戳 - - contentMu sync.Mutex - content []*TargetData - - saveTargetsMu sync.Mutex - saveTargetsSuccessTime time.Time - saveTargetsRequestor x.Window - dsClipboardManager ConfigManager.Manager - saveAtomIncrDataEnabled bool -} - -func (m *Manager) getTargetData(target x.Atom) *TargetData { - m.contentMu.Lock() - defer m.contentMu.Unlock() - - for _, td := range m.content { - if td.Target == target { - return td - } - } - return nil -} - -func (m *Manager) setContent(targetDataMap map[x.Atom]*TargetData) { - // 给剪贴板数据带上特殊标记,为了让前端 dde-clipboard 知道是本程序给出的剪贴板数据 - targetDataMap[atomFromClipboardManager] = &TargetData{ - Target: atomFromClipboardManager, - Type: x.AtomString, - Format: 8, - Data: []byte("1"), - } - for _, data := range targetDataMap { - logger.Debugf("content target %s len: %v", - getAtomDesc(m.xc.Conn(), data.Target), len(data.Data)) - } - targetDataSlice := mapToSliceTargetData(targetDataMap) - m.contentMu.Lock() - m.content = targetDataSlice - m.contentMu.Unlock() -} - -func mapToSliceTargetData(dataMap map[x.Atom]*TargetData) []*TargetData { - result := make([]*TargetData, 0, len(dataMap)) - for _, data := range dataMap { - result = append(result, data) - } - return result -} - -func (m *Manager) getConfigFromDSettings() error { - sysBus, err := dbus.SystemBus() - if err != nil { - return err - } - - ds := ConfigManager.NewConfigManager(sysBus) - dsPath, err := ds.AcquireManager(0, dSettingsAppID, dSettingsClipboardName, "") - if err != nil { - return err - } - - m.dsClipboardManager, err = ConfigManager.NewManager(sysBus, dsPath) - if err != nil { - return err - } - - systemSigLoop := dbusutil.NewSignalLoop(sysBus, 10) - systemSigLoop.Start() - m.dsClipboardManager.InitSignalExt(systemSigLoop, true) - - m.saveAtomIncrDataEnabled = true - - getSaveAtomIncrDataEnabled := func() { - v, err := m.dsClipboardManager.Value(0, dSettingsKeySaveAtomIncrDataEnabled) - if err == nil { - logger.Infof("get saveAtomIncrDataEnabled %t", v.Value().(bool)) - m.saveAtomIncrDataEnabled = v.Value().(bool) - } - } - if err != nil { - logger.Warning(err) - } - - _, err = m.dsClipboardManager.ConnectValueChanged(func(key string) { - switch key { - case dSettingsKeySaveAtomIncrDataEnabled: - getSaveAtomIncrDataEnabled() - } - }) - - if err != nil { - logger.Warning(err) - } - - getSaveAtomIncrDataEnabled() - - return nil -} - -func (m *Manager) start() error { - // 初始化配置 - err := m.getConfigFromDSettings() - if err != nil { - logger.Warning(err) - } - - owner, err := m.xc.GetSelectionOwner(atomClipboardManager) - if err != nil { - return err - } - if owner != 0 { - return fmt.Errorf("another clipboard manager is already running, owner: %d", owner) - } - - m.window, err = m.xc.CreateWindow() - if err != nil { - return err - } - logger.Debug("m.window:", m.window) - - err = m.xc.SelectSelectionInputE(m.window, atomClipboard, - xfixes.SelectionEventMaskSetSelectionOwner| - xfixes.SelectionEventMaskSelectionClientClose| - xfixes.SelectionEventMaskSelectionWindowDestroy) - if err != nil { - logger.Warning(err) - } - - err = m.xc.SelectSelectionInputE(m.window, atomClipboardManager, - xfixes.SelectionEventMaskSetSelectionOwner) - if err != nil { - logger.Warning(err) - } - - m.ec = newEventCaptor() - eventChan := make(chan x.GenericEvent, 50) - m.xc.Conn().AddEventChan(eventChan) - go func() { - for ev := range eventChan { - m.handleEvent(ev) - } - }() - - ts, err := m.getTimestamp() - if err != nil { - return err - } - - logger.Debug("ts:", ts) - err = setSelectionOwner(m.xc, m.window, atomClipboardManager, ts) - if err != nil { - return err - } - - err = announceManageSelection(m.xc.Conn(), m.window, atomClipboardManager, ts) - if err != nil { - return err - } - - return nil -} - -func (m *Manager) handleEvent(ev x.GenericEvent) { - xConn := m.xc.Conn() - xfixesExtData := xConn.GetExtensionData(xfixes.Ext()) - code := ev.GetEventCode() - switch code { - case x.SelectionRequestEventCode: - event, _ := x.NewSelectionRequestEvent(ev) - logger.Debug(selReqEventToString(event, xConn)) - - if event.Selection == atomClipboardManager { - go m.convertClipboardManager(event) - } else if event.Selection == atomClipboard { - go m.convertClipboard(event) - } - - case x.PropertyNotifyEventCode: - event, _ := x.NewPropertyNotifyEvent(ev) - - if m.ec.handleEvent(event) { - logger.Debug("->", propNotifyEventToString(event, xConn)) - return - } - logger.Debug(">>", propNotifyEventToString(event, xConn)) - - case x.SelectionNotifyEventCode: - event, _ := x.NewSelectionNotifyEvent(ev) - - if m.ec.handleEvent(event) { - logger.Debug("->", selNotifyEventToString(event, xConn)) - return - } - logger.Debug(">>", selNotifyEventToString(event, xConn)) - - case x.DestroyNotifyEventCode: - event, _ := x.NewDestroyNotifyEvent(ev) - - logger.Debug(destroyNotifyEventToString(event)) - - case x.SelectionClearEventCode: - event, _ := x.NewSelectionClearEvent(ev) - logger.Debug(selClearEventToString(event)) - - case xfixes.SelectionNotifyEventCode + xfixesExtData.FirstEvent: - event, _ := xfixes.NewSelectionNotifyEvent(ev) - logger.Debug(xfixesSelNotifyEventToString(event)) - switch event.Subtype { - case xfixes.SelectionEventSetSelectionOwner: - if event.Selection == atomClipboard { - if event.Owner == m.window { - logger.Debug("i have become the owner of CLIPBOARD selection, ts:", event.SelectionTimestamp) - m.clipboardAcquireTs = event.SelectionTimestamp - m.clipboardLostTs = 0 - } else { - logger.Debug("other app have become the owner of CLIPBOARD selection, ts:", event.SelectionTimestamp) - if event.SelectionTimestamp >= m.clipboardAcquireTs { - m.clipboardLostTs = event.SelectionTimestamp - } - const delay = 300 * time.Millisecond - time.AfterFunc(delay, func() { - // 等300ms,等 clipboard manager 的 SAVE_TARGETS 转换开始, 如果已经开始了则不再进行主动的数据保存。 - m.saveTargetsMu.Lock() - defer func() { - m.saveTargetsRequestor = 0 - m.saveTargetsMu.Unlock() - }() - - shouldIgnore := m.saveTargetsRequestor == event.Owner && - time.Since(m.saveTargetsSuccessTime) < time.Second - - if shouldIgnore { - logger.Debug("do not call handleClipboardUpdated") - return - } - err := m.handleClipboardUpdated(event.SelectionTimestamp) - if err != nil { - logger.Warning("handle clipboard updated err:", err) - } - }) - } - } else if event.Selection == atomClipboardManager { - if event.Owner == m.window { - logger.Debug("i have become the owner of CLIPBOARD_MANAGER selection, ts:", event.SelectionTimestamp) - m.clipboardManagerAcquireTs = event.SelectionTimestamp - m.clipboardManagerLostTs = 0 - } else { - if event.SelectionTimestamp >= m.clipboardManagerAcquireTs { - m.clipboardManagerLostTs = event.SelectionTimestamp - } - } - } - - case xfixes.SelectionEventSelectionWindowDestroy, xfixes.SelectionEventSelectionClientClose: - if event.Selection == atomClipboard { - err := m.becomeClipboardOwner(event.Timestamp) - if err != nil { - logger.Warning(err) - } - } - } - } -} - -// 处理剪贴板数据更新 -func (m *Manager) handleClipboardUpdated(ts x.Timestamp) error { - logger.Debug("handleClipboardUpdated", ts) - - targets, err := m.getClipboardTargets(ts) - if err != nil { - return err - } - logger.Debug("targets:", targets) - targetDataMap := m.saveTargets(targets, ts) - m.setContent(targetDataMap) - - logger.Debug("handleClipboardUpdated finish", ts) - return nil -} - -func setSelectionOwner(xc XClient, win x.Window, selection x.Atom, ts x.Timestamp) error { - xc.SetSelectionOwner(win, selection, ts) - owner, err := xc.GetSelectionOwner(selection) - if err != nil { - return err - } - if owner != win { - return errors.New("failed to set selection owner") - } - return nil -} - -func (m *Manager) becomeClipboardOwner(ts x.Timestamp) error { - err := setSelectionOwner(m.xc, m.window, atomClipboard, ts) - if err != nil { - return err - } - logger.Debug("set clipboard selection owner to me") - return nil -} - -// 转换 CLIPBOARD selection 的 TARGETS target,剪贴板获取支持的所有 targets。 -func (m *Manager) getClipboardTargets(ts x.Timestamp) ([]x.Atom, error) { - selNotifyEvent, err := m.ec.captureSelectionNotifyEvent(func() error { - m.xc.ConvertSelection(m.window, atomClipboard, - atomTargets, atomTargets, ts) - return m.xc.Flush() - }, func(event *x.SelectionNotifyEvent) bool { - return event.Target == atomTargets && - event.Selection == atomClipboard && - event.Requestor == m.window - }) - if err != nil { - return nil, err - } - - if selNotifyEvent.Property == x.None { - return nil, errors.New("failed to convert clipboard targets") - } - - propReply, err := m.getProperty(m.window, selNotifyEvent.Property, true) - if err != nil { - return nil, err - } - - targets, err := getAtomListFormReply(propReply) - if err != nil { - return nil, err - } - - return targets, nil -} - -func canConvertSelection(acquireTs, lostTs, evTs x.Timestamp) bool { - logger.Debug("canConvertSelection", acquireTs, lostTs, evTs) - // evTs == 0 表示现在 - if acquireTs == 0 { - // 未获取 - return false - } - - if lostTs == 0 { - // 现在未失去 - if acquireTs <= evTs || evTs == 0 { - return true - } - - } else { - // 现在已经失去 - if evTs == 0 { - return false - } - - if acquireTs <= evTs && evTs < lostTs { - return true - } - } - return false -} - -// 处理 CLIPBOARD_MANAGER selection 的转换请求, -// target 支持:SAVE_TARGETS, TARGETS, TIMESTAMP -func (m *Manager) convertClipboardManager(ev *x.SelectionRequestEvent) { - logger.Debug("convert CLIPBOARD_MANAGER selection") - if !canConvertSelection(m.clipboardManagerAcquireTs, m.clipboardManagerLostTs, ev.Time) { - logger.Debug("can not covert selection, ts invalid") - m.finishSelectionRequest(ev, false) - return - } - - switch ev.Target { - case atomSaveTargets: - err := m.covertClipboardManagerSaveTargets(ev) - if err != nil { - logger.Warning("covert ClipboardManager saveTargets err:", err) - } - m.finishSelectionRequest(ev, err == nil) - - case atomTargets: - w := x.NewWriter() - w.Write4b(uint32(atomTargets)) - w.Write4b(uint32(atomSaveTargets)) - w.Write4b(uint32(atomTimestamp)) - err := m.xc.ChangePropertyE(x.PropModeReplace, ev.Requestor, - ev.Property, x.AtomAtom, 32, w.Bytes()) - if err != nil { - logger.Warning(err) - } - m.finishSelectionRequest(ev, err == nil) - - case atomTimestamp: - w := x.NewWriter() - w.Write4b(uint32(m.clipboardManagerAcquireTs)) - err := m.xc.ChangePropertyE(x.PropModeReplace, ev.Requestor, - ev.Property, x.AtomInteger, 32, w.Bytes()) - if err != nil { - logger.Warning(err) - } - m.finishSelectionRequest(ev, err == nil) - - default: - // 不支持的 target - m.finishSelectionRequest(ev, false) - } -} - -func (m *Manager) covertClipboardManagerSaveTargets(ev *x.SelectionRequestEvent) error { - m.saveTargetsMu.Lock() - defer m.saveTargetsMu.Unlock() - - err := m.xc.ChangeWindowEventMask(ev.Requestor, x.EventMaskStructureNotify) - if err != nil { - return err - } - - var targets []x.Atom - var replyType x.Atom - if ev.Property != x.None { - reply, err := m.xc.GetProperty(true, ev.Requestor, ev.Property, - x.AtomAtom, 0, 0x1FFFFFFF) - if err != nil { - return err - } - - replyType = reply.Type - if reply.Type != x.None { - targets, err = getAtomListFormReply(reply) - if err != nil { - return err - } - } - } - - if replyType == x.None { - logger.Debug("need convert clipboard targets") - targets, err = m.getClipboardTargets(ev.Time) - if err != nil { - return err - } - } - - targetDataMap := m.saveTargets(targets, ev.Time) - m.setContent(targetDataMap) - - m.saveTargetsRequestor = ev.Requestor - m.saveTargetsSuccessTime = time.Now() - return nil -} - -// 处理 CLIPBOARD selection 的转换请求 -func (m *Manager) convertClipboard(ev *x.SelectionRequestEvent) { - targetName, _ := m.xc.GetAtomName(ev.Target) - logger.Debugf("convert clipboard target %s|%d", targetName, ev.Target) - - if !canConvertSelection(m.clipboardAcquireTs, m.clipboardLostTs, ev.Time) { - logger.Debug("can not covert selection, ts invalid") - m.finishSelectionRequest(ev, false) - return - } - - switch ev.Target { - case atomTargets: - // TARGETS - w := x.NewWriter() - w.Write4b(uint32(atomTargets)) - w.Write4b(uint32(atomTimestamp)) - m.contentMu.Lock() - for _, targetData := range m.content { - w.Write4b(uint32(targetData.Target)) - } - m.contentMu.Unlock() - - err := m.xc.ChangePropertyE(x.PropModeReplace, ev.Requestor, - ev.Property, x.AtomAtom, 32, w.Bytes()) - if err != nil { - logger.Warning(err) - } - m.finishSelectionRequest(ev, err == nil) - case atomTimestamp: - // TIMESTAMP - w := x.NewWriter() - w.Write4b(uint32(m.clipboardAcquireTs)) - err := m.xc.ChangePropertyE(x.PropModeReplace, ev.Requestor, - ev.Property, x.AtomInteger, 32, w.Bytes()) - if err != nil { - logger.Warning(err) - } - m.finishSelectionRequest(ev, err == nil) - // TODO 支持 MULTIPLE target - default: - targetData := m.getTargetData(ev.Target) - if targetData == nil { - m.finishSelectionRequest(ev, false) - return - } - logger.Debugf("target %d len: %v, needINCR: %v", targetData.Target, len(targetData.Data), - targetData.needINCR()) - - if targetData.needINCR() { - err := m.sendTargetIncr(targetData, ev) - if err != nil { - logger.Warning(err) - } - } else { - err := m.xc.ChangePropertyE(x.PropModeReplace, ev.Requestor, - ev.Property, targetData.Type, targetData.Format, targetData.Data) - if err != nil { - logger.Warning(err) - } - m.finishSelectionRequest(ev, err == nil) - } - } -} - -// NOTE: 需要在这个函数调用 finishSelectionRequest -func (m *Manager) sendTargetIncr(targetData *TargetData, ev *x.SelectionRequestEvent) error { - err := m.xc.ChangeWindowEventMask(ev.Requestor, x.EventMaskPropertyChange) - if err != nil { - m.finishSelectionRequest(ev, false) - return err - } - - // 函数返回时还原请求窗口的 event mask - defer func() { - err := m.xc.ChangeWindowEventMask(ev.Requestor, 0) - if err != nil { - logger.Warning("reset requestor window event mask err:", err) - } - }() - - _, err = m.ec.capturePropertyNotifyEvent(func() error { - // 把 target 数据长度通过属性 ev.Property 告知请求者。 - w := x.NewWriter() - w.Write4b(uint32(len(targetData.Data))) - err = m.xc.ChangePropertyE(x.PropModeReplace, ev.Requestor, ev.Property, - atomIncr, 32, w.Bytes()) - if err != nil { - logger.Warning(err) - } - // NOTE: 一定要在开始传输具体数据之前 finish selection request - m.finishSelectionRequest(ev, err == nil) - return err - }, func(pev *x.PropertyNotifyEvent) bool { - return pev.Window == ev.Requestor && - pev.State == x.PropertyDelete && - pev.Atom == ev.Property - }) - - if err != nil { - return err - } - - var offset int - for { - data := targetData.Data[offset:] - length := len(data) - if length > selectionMaxSize { - length = selectionMaxSize - } - offset += length - - _, err = m.ec.capturePropertyNotifyEvent(func() error { - logger.Debug("send incr data", length) - err = m.xc.ChangePropertyE(x.PropModeReplace, ev.Requestor, ev.Property, - targetData.Type, targetData.Format, data[:length]) - if err != nil { - logger.Warning(err) - } - return err - }, func(pev *x.PropertyNotifyEvent) bool { - return pev.Window == ev.Requestor && - pev.State == x.PropertyDelete && - pev.Atom == ev.Property - }) - if err != nil { - return err - } - - if length == 0 { - break - } - } - - return nil -} - -func (m *Manager) finishSelectionRequest(ev *x.SelectionRequestEvent, success bool) { - var property x.Atom - if success { - property = ev.Property - } - - event := &x.SelectionNotifyEvent{ - Time: ev.Time, - Requestor: ev.Requestor, - Selection: ev.Selection, - Target: ev.Target, - Property: property, - } - - err := m.xc.SendEventE(false, ev.Requestor, x.EventMaskNoEvent, - event) - if err != nil { - logger.Warning(err) - } - - if logger.GetLogLevel() == log.LevelDebug { - successStr := "success" - if !success { - successStr = "fail" - } - xConn := m.xc.Conn() - logger.Debugf("finish selection request %s {Requestor: %d, Selection: %s,"+ - " Target: %s, Property: %s}", - successStr, ev.Requestor, - getAtomDesc(xConn, ev.Selection), - getAtomDesc(xConn, ev.Target), - getAtomDesc(xConn, ev.Property)) - } -} - -func (m *Manager) saveTargets(targets []x.Atom, ts x.Timestamp) map[x.Atom]*TargetData { - result := make(map[x.Atom]*TargetData, len(targets)) - - for _, target := range targets { - targetName, err := m.xc.GetAtomName(target) - if err != nil { - logger.Warning(err) - continue - } - if shouldIgnoreSaveTarget(target, targetName) { - logger.Debugf("ignore target %s|%d", targetName, target) - continue - } - - logger.Debugf("save target %s|%d", targetName, target) - td, err := m.saveTarget(target, ts) - if err != nil { - logger.Warningf("save target failed %s|%d, err: %v", targetName, target, err) - } else { - result[td.Target] = td - logger.Debugf("save target success %s|%d", targetName, target) - } - } - return result -} - -func shouldIgnoreSaveTarget(target x.Atom, targetName string) bool { - switch target { - case atomTargets, atomSaveTargets, - atomTimestamp, atomMultiple, atomDelete, - atomInsertProperty, atomInsertSelection, - x.AtomPixmap: - return true - } - if strings.HasPrefix(targetName, "image/") { - switch targetName { - case "image/jpeg", "image/png", "image/bmp": - return false - default: - return true - } - } - return false -} - -func (m *Manager) saveTarget(target x.Atom, ts x.Timestamp) (targetData *TargetData, err error) { - selNotifyEvent, err := m.ec.captureSelectionNotifyEvent(func() error { - m.xc.ConvertSelection(m.window, atomClipboard, target, target, ts) - return m.xc.Flush() - }, func(event *x.SelectionNotifyEvent) bool { - return event.Selection == atomClipboard && - event.Requestor == m.window && - event.Target == target - }) - if err != nil { - return - } - if selNotifyEvent.Property == x.None { - err = errors.New("failed to convert target") - return - } - - propReply, err := m.getProperty(m.window, selNotifyEvent.Property, false) - if err != nil { - return - } - - if propReply.Type == atomIncr { - if m.saveAtomIncrDataEnabled { - targetData, err = m.receiveTargetIncr(target, selNotifyEvent.Property) - } - } else { - err = m.xc.DeletePropertyE(m.window, selNotifyEvent.Property) - if err != nil { - return - } - logger.Debug("data len:", len(propReply.Value)) - targetData = &TargetData{ - Target: target, - Type: propReply.Type, - Format: propReply.Format, - Data: propReply.Value, - } - } - return -} - -func (m *Manager) getProperty(win x.Window, propertyAtom x.Atom, delete bool) (*x.GetPropertyReply, error) { - propReply, err := m.xc.GetProperty(false, win, propertyAtom, - x.GetPropertyTypeAny, 0, 0) - if err != nil { - return nil, err - } - - propReply, err = m.xc.GetProperty(delete, win, propertyAtom, - x.GetPropertyTypeAny, - 0, - (propReply.BytesAfter+uint32(x.Pad(int(propReply.BytesAfter))))/4, - ) - if err != nil { - return nil, err - } - return propReply, nil -} - -func (m *Manager) receiveTargetIncr(target, prop x.Atom) (targetData *TargetData, err error) { - logger.Debug("start receiveTargetIncr", target) - var data [][]byte - t0 := time.Now() - total := 0 - for { - var propNotifyEvent *x.PropertyNotifyEvent - propNotifyEvent, err = m.ec.capturePropertyNotifyEvent(func() error { - err := m.xc.DeletePropertyE(m.window, prop) - if err != nil { - logger.Warning(err) - } - return err - - }, func(event *x.PropertyNotifyEvent) bool { - return event.State == x.PropertyNewValue && event.Window == m.window && - event.Atom == prop - }) - if err != nil { - logger.Warning(err) - return - } - - var propReply *x.GetPropertyReply - propReply, err = m.xc.GetProperty(false, propNotifyEvent.Window, propNotifyEvent.Atom, - x.GetPropertyTypeAny, - 0, 0) - if err != nil { - logger.Warning(err) - return - } - propReply, err = m.xc.GetProperty(false, propNotifyEvent.Window, propNotifyEvent.Atom, - x.GetPropertyTypeAny, 0, - (propReply.BytesAfter+uint32(x.Pad(int(propReply.BytesAfter))))/4, - ) - if err != nil { - logger.Warning(err) - return - } - - if propReply.ValueLen == 0 { - logger.Debugf("end receiveTargetIncr %d, took %v, total size: %d", - target, time.Since(t0), total) - - err = m.xc.DeletePropertyE(propNotifyEvent.Window, propNotifyEvent.Atom) - if err != nil { - logger.Warning(err) - return - } - - targetData = &TargetData{ - Target: target, - Type: propReply.Type, - Format: propReply.Format, - Data: bytes.Join(data, nil), - } - return - } - if logger.GetLogLevel() == log.LevelDebug { - logger.Debugf("incr receive data size: %d", len(propReply.Value)) - } - total += len(propReply.Value) - data = append(data, propReply.Value) - } -} - -func (m *Manager) getTimestamp() (x.Timestamp, error) { - propNotifyEvent, err := m.ec.capturePropertyNotifyEvent(func() error { - return m.xc.ChangePropertyE(x.PropModeReplace, m.window, atomTimestampProp, - x.AtomInteger, 32, nil) - }, func(event *x.PropertyNotifyEvent) bool { - return event.Window == m.window && - event.Atom == atomTimestampProp && - event.State == x.PropertyNewValue - }) - - if err != nil { - return 0, err - } - - return propNotifyEvent.Time, nil -} - -func (m *Manager) GetInterfaceName() string { - return dbusServiceName -} diff --git a/clipboard/manager_test.go b/clipboard/manager_test.go deleted file mode 100644 index 0cced1516..000000000 --- a/clipboard/manager_test.go +++ /dev/null @@ -1,200 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package clipboard - -import ( - "errors" - "testing" - - "github.com/linuxdeepin/dde-daemon/clipboard/mocks" - x "github.com/linuxdeepin/go-x11-client" - "github.com/stretchr/testify/assert" -) - -func initAtomsForTest() { - const base = 100 - atomClipboardManager = base + 1 - atomClipboard = base + 2 - atomSaveTargets = base + 3 - atomTargets = base + 4 - atomMultiple = base + 5 - atomDelete = base + 6 - atomInsertProperty = base + 7 - atomInsertSelection = base + 8 - atomAtomPair = base + 9 - atomIncr = base + 10 - atomTimestamp = base + 11 - atomTimestampProp = base + 12 - atomNull = base + 13 -} - -func TestManager_finishSelectionRequest(t *testing.T) { - ts := x.Timestamp(11) - owner := x.Window(1) - reqWin := x.Window(2) - selection := x.Atom(3) - target := x.Atom(4) - prop := x.Atom(5) - - ev := &x.SelectionRequestEvent{ - Time: ts, - Owner: owner, - Requestor: reqWin, - Selection: selection, - Target: target, - Property: prop, - } - - m := &Manager{} - m.window = owner - xc := &mocks.XClient{} - m.xc = xc - xc.On("SendEventE", false, reqWin, uint32(x.EventMaskNoEvent), &x.SelectionNotifyEvent{ - Time: ts, - Requestor: reqWin, - Selection: selection, - Target: target, - Property: prop, - }).Return(nil).Once() - - m.finishSelectionRequest(ev, true) - - xc.On("SendEventE", false, reqWin, uint32(x.EventMaskNoEvent), &x.SelectionNotifyEvent{ - Time: ts, - Requestor: reqWin, - Selection: selection, - Target: target, - Property: x.AtomNone, - }).Return(nil).Once() - m.finishSelectionRequest(ev, false) - - xc.AssertExpectations(t) -} - -func TestManager_getProperty(t *testing.T) { - win := x.Window(1) - prop := x.Atom(2) - m := &Manager{} - xc := &mocks.XClient{} - m.xc = xc - - w := x.NewWriter() - w.Write4b(1) - w.Write4b(2) - w.Write4b(3) - w.Write4b(4) - - var err1 = errors.New("E1") - - tests := []struct { - desc string - propReply0 *x.GetPropertyReply - propReply1 *x.GetPropertyReply - err0 error - err1 error - resultPropReply *x.GetPropertyReply - resultErr error - longLength uint32 - }{ - { - desc: "normal: data type: []uint32, len: 4", - propReply0: &x.GetPropertyReply{ - Format: 32, - Type: x.AtomCardinal, - BytesAfter: 16, - }, - propReply1: &x.GetPropertyReply{ - Format: 32, - Type: x.AtomCardinal, - Value: w.Bytes(), - ValueLen: 4, - }, - resultPropReply: &x.GetPropertyReply{ - Format: 32, - Type: x.AtomCardinal, - Value: w.Bytes(), - ValueLen: 4, - }, - longLength: 4, - }, - { - desc: "normal: data type: string, len: 5", - propReply0: &x.GetPropertyReply{ - Format: 8, - Type: x.AtomString, - BytesAfter: 5, - }, - propReply1: &x.GetPropertyReply{ - Format: 8, - Type: x.AtomString, - Value: []byte("abcde"), - ValueLen: 5, - }, - resultPropReply: &x.GetPropertyReply{ - Format: 8, - Type: x.AtomString, - Value: []byte("abcde"), - ValueLen: 5, - }, - longLength: 2, - }, - { - desc: "the first call to get property failed", - err0: err1, - resultErr: err1, - }, - { - desc: "the second call to get property failed", - propReply0: &x.GetPropertyReply{ - Format: 8, - Type: x.AtomString, - BytesAfter: 5, - }, - propReply1: &x.GetPropertyReply{ - Format: 8, - Type: x.AtomString, - Value: []byte("hello"), - ValueLen: 5, - }, - longLength: 2, - err1: err1, - resultErr: err1, - }, - } - - for _, test := range tests { - xc.On("GetProperty", false, win, prop, x.Atom(x.GetPropertyTypeAny), - uint32(0), uint32(0)).Return(test.propReply0, test.err0).Once() - - if test.err0 == nil { - xc.On("GetProperty", false, win, prop, x.Atom(x.GetPropertyTypeAny), - uint32(0), test.longLength).Return(test.propReply1, test.err1).Once() - } - - propReply, err := m.getProperty(win, prop, false) - assert.Equal(t, test.resultPropReply, propReply, test.desc) - assert.Equal(t, test.resultErr, err, test.desc) - _ = err - } - - xc.AssertExpectations(t) -} - -func Test_shouldIgnoreSaveTarget(t *testing.T) { - initAtomsForTest() - fn := shouldIgnoreSaveTarget - assert.True(t, fn(atomTimestamp, "TIMESTAMP")) - assert.True(t, fn(atomTargets, "TARGETS")) - - assert.False(t, fn(200, "image/jpeg")) - assert.False(t, fn(200, "image/png")) - assert.False(t, fn(200, "image/bmp")) - - assert.True(t, fn(200, "image/xpm")) - assert.True(t, fn(200, "image/webp")) - - assert.False(t, fn(200, "text/plain")) - assert.False(t, fn(200, "application/x-qt-image")) -} diff --git a/clipboard/module.go b/clipboard/module.go deleted file mode 100644 index 0fb15127c..000000000 --- a/clipboard/module.go +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package clipboard - -import ( - "os" - - "github.com/linuxdeepin/dde-daemon/loader" - "github.com/linuxdeepin/go-lib/log" - x "github.com/linuxdeepin/go-x11-client" - "github.com/linuxdeepin/go-x11-client/ext/xfixes" -) - -const dbusServiceName = "com.deepin.daemon.ClipboardManager" - -var logger *log.Logger - -func init() { - logger = log.NewLogger("clipboard") - loader.Register(newModule()) -} - -func newModule() *Module { - m := new(Module) - m.ModuleBase = loader.NewModuleBase("clipboard", m, logger) - return m -} - -type Module struct { - *loader.ModuleBase -} - -func (*Module) GetDependencies() []string { - return nil -} - -func (mo *Module) Start() error { - if os.Getenv("WAYLAND_DISPLAY") != "" { - return nil - } - logger.Debug("clipboard module start") - - xConn, err := x.NewConn() - if err != nil { - return err - } - - initAtoms(xConn) - - _, err = xfixes.QueryVersion(xConn, xfixes.MajorVersion, xfixes.MinorVersion).Reply(xConn) - if err != nil { - logger.Warning(err) - } - - m := &Manager{} - m.xc = &xClient{ - conn: xConn, - } - - err = m.start() - if err != nil { - return err - } - - service := loader.GetService() - err = service.Export("/com/deepin/daemon/ClipboardManager", m) - if err != nil { - return err - } - - err = service.RequestName(dbusServiceName) - if err != nil { - return err - } - - return nil -} - -func (*Module) Stop() error { - return nil -} diff --git a/clipboard/clipboard_test.go b/clipboard1/clipboard_test.go similarity index 98% rename from clipboard/clipboard_test.go rename to clipboard1/clipboard_test.go index c1bd4e9e8..c06f288e2 100644 --- a/clipboard/clipboard_test.go +++ b/clipboard1/clipboard_test.go @@ -10,10 +10,10 @@ import ( "path/filepath" "testing" + "github.com/linuxdeepin/dde-daemon/clipboard1/mocks" x "github.com/linuxdeepin/go-x11-client" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/linuxdeepin/dde-daemon/clipboard/mocks" ) func TestEventCaptor(t *testing.T) { diff --git a/clipboard/event_captor.go b/clipboard1/event_captor.go similarity index 100% rename from clipboard/event_captor.go rename to clipboard1/event_captor.go diff --git a/clipboard/exported_methods_auto.go b/clipboard1/exported_methods_auto.go similarity index 100% rename from clipboard/exported_methods_auto.go rename to clipboard1/exported_methods_auto.go diff --git a/clipboard1/manager.go b/clipboard1/manager.go new file mode 100644 index 000000000..26b8c6d5a --- /dev/null +++ b/clipboard1/manager.go @@ -0,0 +1,978 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package clipboard + +import ( + "bytes" + "errors" + "fmt" + "strings" + "sync" + "time" + + "github.com/godbus/dbus/v5" + ConfigManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/log" + x "github.com/linuxdeepin/go-x11-client" + "github.com/linuxdeepin/go-x11-client/ext/xfixes" +) + +//go:generate dbusutil-gen em -type Manager + +var ( + atomClipboardManager x.Atom + atomClipboard x.Atom + atomSaveTargets x.Atom + atomTargets x.Atom + atomMultiple x.Atom + atomDelete x.Atom + atomInsertProperty x.Atom + atomInsertSelection x.Atom + atomAtomPair x.Atom //nolint + atomIncr x.Atom + atomTimestamp x.Atom + atomNull x.Atom //nolint + atomTimestampProp x.Atom + atomFromClipboardManager x.Atom + + selectionMaxSize int +) + +const ( + dSettingsAppID = "org.deepin.dde.daemon" + dSettingsClipboardName = "org.deepin.dde.daemon.clipboard" + dSettingsKeySaveAtomIncrDataEnabled = "saveAtomIncrDataEnabled" +) + +func initAtoms(xConn *x.Conn) { + atomClipboardManager, _ = xConn.GetAtom("CLIPBOARD_MANAGER") + atomClipboard, _ = xConn.GetAtom("CLIPBOARD") + atomSaveTargets, _ = xConn.GetAtom("SAVE_TARGETS") + atomTargets, _ = xConn.GetAtom("TARGETS") + atomMultiple, _ = xConn.GetAtom("MULTIPLE") + atomDelete, _ = xConn.GetAtom("DELETE") + atomInsertProperty, _ = xConn.GetAtom("INSERT_PROPERTY") + atomInsertSelection, _ = xConn.GetAtom("INSERT_SELECTION") + atomAtomPair, _ = xConn.GetAtom("ATOM_PAIR") + atomIncr, _ = xConn.GetAtom("INCR") + atomTimestamp, _ = xConn.GetAtom("TIMESTAMP") + atomTimestampProp, _ = xConn.GetAtom("_TIMESTAMP_PROP") + atomNull, _ = xConn.GetAtom("NULL") + atomFromClipboardManager, _ = xConn.GetAtom("FROM_DEEPIN_CLIPBOARD_MANAGER") + selectionMaxSize = 65432 + logger.Debug("selectionMaxSize:", selectionMaxSize) +} + +type TargetData struct { + Target x.Atom + Type x.Atom + Format uint8 + Data []byte +} + +func (td *TargetData) needINCR() bool { + return len(td.Data) > selectionMaxSize +} + +type Manager struct { + xc XClient + window x.Window + ec *eventCaptor + clipboardManagerAcquireTs x.Timestamp // 获取 CLIPBOARD_MANAGER selection 的时间戳 + clipboardManagerLostTs x.Timestamp // 丢失 CLIPBOARD_MANAGER selection 的时间戳 + clipboardAcquireTs x.Timestamp // 获取 CLIPBOARD selection 的时间戳 + clipboardLostTs x.Timestamp // 丢失 CLIPBOARD selection 的时间戳 + + contentMu sync.Mutex + content []*TargetData + + saveTargetsMu sync.Mutex + saveTargetsSuccessTime time.Time + saveTargetsRequestor x.Window + dsClipboardManager ConfigManager.Manager + saveAtomIncrDataEnabled bool +} + +func (m *Manager) getTargetData(target x.Atom) *TargetData { + m.contentMu.Lock() + defer m.contentMu.Unlock() + + for _, td := range m.content { + if td.Target == target { + return td + } + } + return nil +} + +func (m *Manager) setContent(targetDataMap map[x.Atom]*TargetData) { + // 给剪贴板数据带上特殊标记,为了让前端 dde-clipboard 知道是本程序给出的剪贴板数据 + targetDataMap[atomFromClipboardManager] = &TargetData{ + Target: atomFromClipboardManager, + Type: x.AtomString, + Format: 8, + Data: []byte("1"), + } + for _, data := range targetDataMap { + logger.Debugf("content target %s len: %v", + getAtomDesc(m.xc.Conn(), data.Target), len(data.Data)) + } + targetDataSlice := mapToSliceTargetData(targetDataMap) + m.contentMu.Lock() + m.content = targetDataSlice + m.contentMu.Unlock() +} + +func mapToSliceTargetData(dataMap map[x.Atom]*TargetData) []*TargetData { + result := make([]*TargetData, 0, len(dataMap)) + for _, data := range dataMap { + result = append(result, data) + } + return result +} + +func (m *Manager) getConfigFromDSettings() error { + sysBus, err := dbus.SystemBus() + if err != nil { + return err + } + + ds := ConfigManager.NewConfigManager(sysBus) + dsPath, err := ds.AcquireManager(0, dSettingsAppID, dSettingsClipboardName, "") + if err != nil { + return err + } + + m.dsClipboardManager, err = ConfigManager.NewManager(sysBus, dsPath) + if err != nil { + return err + } + + systemSigLoop := dbusutil.NewSignalLoop(sysBus, 10) + systemSigLoop.Start() + m.dsClipboardManager.InitSignalExt(systemSigLoop, true) + + m.saveAtomIncrDataEnabled = true + + getSaveAtomIncrDataEnabled := func() { + v, err := m.dsClipboardManager.Value(0, dSettingsKeySaveAtomIncrDataEnabled) + if err == nil { + logger.Infof("get saveAtomIncrDataEnabled %t", v.Value().(bool)) + m.saveAtomIncrDataEnabled = v.Value().(bool) + } + } + if err != nil { + logger.Warning(err) + } + + _, err = m.dsClipboardManager.ConnectValueChanged(func(key string) { + switch key { + case dSettingsKeySaveAtomIncrDataEnabled: + getSaveAtomIncrDataEnabled() + } + }) + + if err != nil { + logger.Warning(err) + } + + getSaveAtomIncrDataEnabled() + + return nil +} + +func (m *Manager) start() error { + // 初始化配置 + err := m.getConfigFromDSettings() + if err != nil { + logger.Warning(err) + } + + owner, err := m.xc.GetSelectionOwner(atomClipboardManager) + if err != nil { + return err + } + if owner != 0 { + return fmt.Errorf("another clipboard manager is already running, owner: %d", owner) + } + + m.window, err = m.xc.CreateWindow() + if err != nil { + return err + } + logger.Debug("m.window:", m.window) + + err = m.xc.SelectSelectionInputE(m.window, atomClipboard, + xfixes.SelectionEventMaskSetSelectionOwner| + xfixes.SelectionEventMaskSelectionClientClose| + xfixes.SelectionEventMaskSelectionWindowDestroy) + if err != nil { + logger.Warning(err) + } + + err = m.xc.SelectSelectionInputE(m.window, atomClipboardManager, + xfixes.SelectionEventMaskSetSelectionOwner) + if err != nil { + logger.Warning(err) + } + + m.ec = newEventCaptor() + eventChan := make(chan x.GenericEvent, 50) + m.xc.Conn().AddEventChan(eventChan) + go func() { + for ev := range eventChan { + m.handleEvent(ev) + } + }() + + ts, err := m.getTimestamp() + if err != nil { + return err + } + + logger.Debug("ts:", ts) + err = setSelectionOwner(m.xc, m.window, atomClipboardManager, ts) + if err != nil { + return err + } + + err = announceManageSelection(m.xc.Conn(), m.window, atomClipboardManager, ts) + if err != nil { + return err + } + + return nil +} + +func (m *Manager) handleEvent(ev x.GenericEvent) { + xConn := m.xc.Conn() + xfixesExtData := xConn.GetExtensionData(xfixes.Ext()) + code := ev.GetEventCode() + switch code { + case x.SelectionRequestEventCode: + event, _ := x.NewSelectionRequestEvent(ev) + logger.Debug(selReqEventToString(event, xConn)) + + if event.Selection == atomClipboardManager { + go m.convertClipboardManager(event) + } else if event.Selection == atomClipboard { + go m.convertClipboard(event) + } + + case x.PropertyNotifyEventCode: + event, _ := x.NewPropertyNotifyEvent(ev) + + if m.ec.handleEvent(event) { + logger.Debug("->", propNotifyEventToString(event, xConn)) + return + } + logger.Debug(">>", propNotifyEventToString(event, xConn)) + + case x.SelectionNotifyEventCode: + event, _ := x.NewSelectionNotifyEvent(ev) + + if m.ec.handleEvent(event) { + logger.Debug("->", selNotifyEventToString(event, xConn)) + return + } + logger.Debug(">>", selNotifyEventToString(event, xConn)) + + case x.DestroyNotifyEventCode: + event, _ := x.NewDestroyNotifyEvent(ev) + + logger.Debug(destroyNotifyEventToString(event)) + + case x.SelectionClearEventCode: + event, _ := x.NewSelectionClearEvent(ev) + logger.Debug(selClearEventToString(event)) + + case xfixes.SelectionNotifyEventCode + xfixesExtData.FirstEvent: + event, _ := xfixes.NewSelectionNotifyEvent(ev) + logger.Debug(xfixesSelNotifyEventToString(event)) + switch event.Subtype { + case xfixes.SelectionEventSetSelectionOwner: + if event.Selection == atomClipboard { + if event.Owner == m.window { + logger.Debug("i have become the owner of CLIPBOARD selection, ts:", event.SelectionTimestamp) + m.clipboardAcquireTs = event.SelectionTimestamp + m.clipboardLostTs = 0 + } else { + logger.Debug("other app have become the owner of CLIPBOARD selection, ts:", event.SelectionTimestamp) + if event.SelectionTimestamp >= m.clipboardAcquireTs { + m.clipboardLostTs = event.SelectionTimestamp + } + const delay = 300 * time.Millisecond + time.AfterFunc(delay, func() { + // 等300ms,等 clipboard manager 的 SAVE_TARGETS 转换开始, 如果已经开始了则不再进行主动的数据保存。 + m.saveTargetsMu.Lock() + defer func() { + m.saveTargetsRequestor = 0 + m.saveTargetsMu.Unlock() + }() + + shouldIgnore := m.saveTargetsRequestor == event.Owner && + time.Since(m.saveTargetsSuccessTime) < time.Second + + if shouldIgnore { + logger.Debug("do not call handleClipboardUpdated") + return + } + err := m.handleClipboardUpdated(event.SelectionTimestamp) + if err != nil { + logger.Warning("handle clipboard updated err:", err) + } + }) + } + } else if event.Selection == atomClipboardManager { + if event.Owner == m.window { + logger.Debug("i have become the owner of CLIPBOARD_MANAGER selection, ts:", event.SelectionTimestamp) + m.clipboardManagerAcquireTs = event.SelectionTimestamp + m.clipboardManagerLostTs = 0 + } else { + if event.SelectionTimestamp >= m.clipboardManagerAcquireTs { + m.clipboardManagerLostTs = event.SelectionTimestamp + } + } + } + + case xfixes.SelectionEventSelectionWindowDestroy, xfixes.SelectionEventSelectionClientClose: + if event.Selection == atomClipboard { + err := m.becomeClipboardOwner(event.Timestamp) + if err != nil { + logger.Warning(err) + } + } + } + } +} + +// 处理剪贴板数据更新 +func (m *Manager) handleClipboardUpdated(ts x.Timestamp) error { + logger.Debug("handleClipboardUpdated", ts) + + targets, err := m.getClipboardTargets(ts) + if err != nil { + return err + } + logger.Debug("targets:", targets) + + // 过滤云桌面复制的数据 + // 判断是否从wps复制的数据并且是否包含text格式 + var tmpTarget x.Atom + hasKingsoftData := false + hasTextData := false + + for _, target := range targets { + targetName, err := m.xc.GetAtomName(target) + targetName = strings.ToLower(targetName) + if err == nil { + if targetName == "uos/remote-copy" { + return nil + } else if targetName == "text/plain" { + hasTextData = true + tmpTarget = target + } else if strings.Contains(targetName, "kingsoft") { + hasKingsoftData = true + } + } + } + + logger.Debug("hasKingsoftData:", hasKingsoftData, ", hasTextData:", hasTextData) + + // 如果 是从wps复制的数据并且包含text格式数据,则先读取text数据大小 + // 如果text数据大小超过10M,则只缓存text数据,否则所有格式都缓存 + if hasKingsoftData && hasTextData { + td, err := m.saveTarget(tmpTarget, ts) + if err == nil && len(td.Data) > 10*1024*1024 { + m.setContent(map[x.Atom]*TargetData{ + td.Target: td, + }) + + logger.Debug("handleClipboardUpdated wps text format finish", ts) + return nil + } + } + + targetDataMap := m.saveTargets(targets, ts) + m.setContent(targetDataMap) + + logger.Debug("handleClipboardUpdated all format finish", ts) + return nil +} + +func setSelectionOwner(xc XClient, win x.Window, selection x.Atom, ts x.Timestamp) error { + xc.SetSelectionOwner(win, selection, ts) + owner, err := xc.GetSelectionOwner(selection) + if err != nil { + return err + } + if owner != win { + return errors.New("failed to set selection owner") + } + return nil +} + +func (m *Manager) becomeClipboardOwner(ts x.Timestamp) error { + err := setSelectionOwner(m.xc, m.window, atomClipboard, ts) + if err != nil { + return err + } + logger.Debug("set clipboard selection owner to me") + return nil +} + +// 转换 CLIPBOARD selection 的 TARGETS target,剪贴板获取支持的所有 targets。 +func (m *Manager) getClipboardTargets(ts x.Timestamp) ([]x.Atom, error) { + selNotifyEvent, err := m.ec.captureSelectionNotifyEvent(func() error { + m.xc.ConvertSelection(m.window, atomClipboard, + atomTargets, atomTargets, ts) + return m.xc.Flush() + }, func(event *x.SelectionNotifyEvent) bool { + return event.Target == atomTargets && + event.Selection == atomClipboard && + event.Requestor == m.window + }) + if err != nil { + return nil, err + } + + if selNotifyEvent.Property == x.None { + return nil, errors.New("failed to convert clipboard targets") + } + + propReply, err := m.getProperty(m.window, selNotifyEvent.Property, true) + if err != nil { + return nil, err + } + + targets, err := getAtomListFormReply(propReply) + if err != nil { + return nil, err + } + + return targets, nil +} + +func canConvertSelection(acquireTs, lostTs, evTs x.Timestamp) bool { + logger.Debug("canConvertSelection", acquireTs, lostTs, evTs) + // evTs == 0 表示现在 + if acquireTs == 0 { + // 未获取 + return false + } + + if lostTs == 0 { + // 现在未失去 + if acquireTs <= evTs || evTs == 0 { + return true + } + + } else { + // 现在已经失去 + if evTs == 0 { + return false + } + + if acquireTs <= evTs && evTs < lostTs { + return true + } + } + return false +} + +// 处理 CLIPBOARD_MANAGER selection 的转换请求, +// target 支持:SAVE_TARGETS, TARGETS, TIMESTAMP +func (m *Manager) convertClipboardManager(ev *x.SelectionRequestEvent) { + logger.Debug("convert CLIPBOARD_MANAGER selection") + if !canConvertSelection(m.clipboardManagerAcquireTs, m.clipboardManagerLostTs, ev.Time) { + logger.Debug("can not covert selection, ts invalid") + m.finishSelectionRequest(ev, false) + return + } + + switch ev.Target { + case atomSaveTargets: + err := m.covertClipboardManagerSaveTargets(ev) + if err != nil { + logger.Warning("covert ClipboardManager saveTargets err:", err) + } + m.finishSelectionRequest(ev, err == nil) + + case atomTargets: + w := x.NewWriter() + w.Write4b(uint32(atomTargets)) + w.Write4b(uint32(atomSaveTargets)) + w.Write4b(uint32(atomTimestamp)) + err := m.xc.ChangePropertyE(x.PropModeReplace, ev.Requestor, + ev.Property, x.AtomAtom, 32, w.Bytes()) + if err != nil { + logger.Warning(err) + } + m.finishSelectionRequest(ev, err == nil) + + case atomTimestamp: + w := x.NewWriter() + w.Write4b(uint32(m.clipboardManagerAcquireTs)) + err := m.xc.ChangePropertyE(x.PropModeReplace, ev.Requestor, + ev.Property, x.AtomInteger, 32, w.Bytes()) + if err != nil { + logger.Warning(err) + } + m.finishSelectionRequest(ev, err == nil) + + default: + // 不支持的 target + m.finishSelectionRequest(ev, false) + } +} + +func (m *Manager) covertClipboardManagerSaveTargets(ev *x.SelectionRequestEvent) error { + m.saveTargetsMu.Lock() + defer m.saveTargetsMu.Unlock() + + err := m.xc.ChangeWindowEventMask(ev.Requestor, x.EventMaskStructureNotify) + if err != nil { + return err + } + + var targets []x.Atom + var replyType x.Atom + if ev.Property != x.None { + reply, err := m.xc.GetProperty(true, ev.Requestor, ev.Property, + x.AtomAtom, 0, 0x1FFFFFFF) + if err != nil { + return err + } + + replyType = reply.Type + if reply.Type != x.None { + targets, err = getAtomListFormReply(reply) + if err != nil { + return err + } + } + } + + if replyType == x.None { + logger.Debug("need convert clipboard targets") + targets, err = m.getClipboardTargets(ev.Time) + if err != nil { + return err + } + } + + logger.Debug("targets:", targets) + + // 过滤云桌面复制的数据 + // 判断是否从wps复制的数据并且是否包含text格式 + var tmpTarget x.Atom + hasKingsoftData := false + hasTextData := false + + for _, target := range targets { + targetName, err := m.xc.GetAtomName(target) + targetName = strings.ToLower(targetName) + if err == nil { + if targetName == "uos/remote-copy" { + return nil + } else if targetName == "text/plain" { + hasTextData = true + tmpTarget = target + } else if strings.Contains(targetName, "kingsoft") { + hasKingsoftData = true + } + } + } + + logger.Debug("hasKingsoftData:", hasKingsoftData, ", hasTextData:", hasTextData) + + // 如果 是从wps复制的数据并且包含text格式数据,则先读取text数据大小 + // 如果text数据大小超过10M,则只缓存text数据,否则所有格式都缓存 + if hasKingsoftData && hasTextData { + td, err := m.saveTarget(tmpTarget, ev.Time) + if err == nil && len(td.Data) > 10*1024*1024 { + m.setContent(map[x.Atom]*TargetData{ + td.Target: td, + }) + + logger.Debug("covertClipboardManagerSaveTargets text format finish", ev.Time) + m.saveTargetsRequestor = ev.Requestor + m.saveTargetsSuccessTime = time.Now() + return nil + } + } + + targetDataMap := m.saveTargets(targets, ev.Time) + m.setContent(targetDataMap) + + m.saveTargetsRequestor = ev.Requestor + m.saveTargetsSuccessTime = time.Now() + return nil +} + +// 处理 CLIPBOARD selection 的转换请求 +func (m *Manager) convertClipboard(ev *x.SelectionRequestEvent) { + targetName, _ := m.xc.GetAtomName(ev.Target) + logger.Debugf("convert clipboard target %s|%d", targetName, ev.Target) + + if !canConvertSelection(m.clipboardAcquireTs, m.clipboardLostTs, ev.Time) { + logger.Debug("can not covert selection, ts invalid") + m.finishSelectionRequest(ev, false) + return + } + + switch ev.Target { + case atomTargets: + // TARGETS + w := x.NewWriter() + w.Write4b(uint32(atomTargets)) + w.Write4b(uint32(atomTimestamp)) + m.contentMu.Lock() + for _, targetData := range m.content { + w.Write4b(uint32(targetData.Target)) + } + m.contentMu.Unlock() + + err := m.xc.ChangePropertyE(x.PropModeReplace, ev.Requestor, + ev.Property, x.AtomAtom, 32, w.Bytes()) + if err != nil { + logger.Warning(err) + } + m.finishSelectionRequest(ev, err == nil) + case atomTimestamp: + // TIMESTAMP + w := x.NewWriter() + w.Write4b(uint32(m.clipboardAcquireTs)) + err := m.xc.ChangePropertyE(x.PropModeReplace, ev.Requestor, + ev.Property, x.AtomInteger, 32, w.Bytes()) + if err != nil { + logger.Warning(err) + } + m.finishSelectionRequest(ev, err == nil) + // TODO 支持 MULTIPLE target + default: + targetData := m.getTargetData(ev.Target) + if targetData == nil { + m.finishSelectionRequest(ev, false) + return + } + logger.Debugf("target %d len: %v, needINCR: %v", targetData.Target, len(targetData.Data), + targetData.needINCR()) + + if targetData.needINCR() { + err := m.sendTargetIncr(targetData, ev) + if err != nil { + logger.Warning(err) + } + } else { + err := m.xc.ChangePropertyE(x.PropModeReplace, ev.Requestor, + ev.Property, targetData.Type, targetData.Format, targetData.Data) + if err != nil { + logger.Warning(err) + } + m.finishSelectionRequest(ev, err == nil) + } + } +} + +// NOTE: 需要在这个函数调用 finishSelectionRequest +func (m *Manager) sendTargetIncr(targetData *TargetData, ev *x.SelectionRequestEvent) error { + err := m.xc.ChangeWindowEventMask(ev.Requestor, x.EventMaskPropertyChange) + if err != nil { + m.finishSelectionRequest(ev, false) + return err + } + + // 函数返回时还原请求窗口的 event mask + defer func() { + err := m.xc.ChangeWindowEventMask(ev.Requestor, 0) + if err != nil { + logger.Warning("reset requestor window event mask err:", err) + } + }() + + _, err = m.ec.capturePropertyNotifyEvent(func() error { + // 把 target 数据长度通过属性 ev.Property 告知请求者。 + w := x.NewWriter() + w.Write4b(uint32(len(targetData.Data))) + err = m.xc.ChangePropertyE(x.PropModeReplace, ev.Requestor, ev.Property, + atomIncr, 32, w.Bytes()) + if err != nil { + logger.Warning(err) + } + // NOTE: 一定要在开始传输具体数据之前 finish selection request + m.finishSelectionRequest(ev, err == nil) + return err + }, func(pev *x.PropertyNotifyEvent) bool { + return pev.Window == ev.Requestor && + pev.State == x.PropertyDelete && + pev.Atom == ev.Property + }) + + if err != nil { + return err + } + + var offset int + for { + data := targetData.Data[offset:] + length := len(data) + if length > selectionMaxSize { + length = selectionMaxSize + } + offset += length + + _, err = m.ec.capturePropertyNotifyEvent(func() error { + logger.Debug("send incr data", length) + err = m.xc.ChangePropertyE(x.PropModeReplace, ev.Requestor, ev.Property, + targetData.Type, targetData.Format, data[:length]) + if err != nil { + logger.Warning(err) + } + return err + }, func(pev *x.PropertyNotifyEvent) bool { + return pev.Window == ev.Requestor && + pev.State == x.PropertyDelete && + pev.Atom == ev.Property + }) + if err != nil { + return err + } + + if length == 0 { + break + } + } + + return nil +} + +func (m *Manager) finishSelectionRequest(ev *x.SelectionRequestEvent, success bool) { + var property x.Atom + if success { + property = ev.Property + } + + event := &x.SelectionNotifyEvent{ + Time: ev.Time, + Requestor: ev.Requestor, + Selection: ev.Selection, + Target: ev.Target, + Property: property, + } + + err := m.xc.SendEventE(false, ev.Requestor, x.EventMaskNoEvent, + event) + if err != nil { + logger.Warning(err) + } + + if logger.GetLogLevel() == log.LevelDebug { + successStr := "success" + if !success { + successStr = "fail" + } + xConn := m.xc.Conn() + logger.Debugf("finish selection request %s {Requestor: %d, Selection: %s,"+ + " Target: %s, Property: %s}", + successStr, ev.Requestor, + getAtomDesc(xConn, ev.Selection), + getAtomDesc(xConn, ev.Target), + getAtomDesc(xConn, ev.Property)) + } +} + +func (m *Manager) saveTargets(targets []x.Atom, ts x.Timestamp) map[x.Atom]*TargetData { + result := make(map[x.Atom]*TargetData, len(targets)) + + for _, target := range targets { + targetName, err := m.xc.GetAtomName(target) + if err != nil { + logger.Warning(err) + continue + } + if shouldIgnoreSaveTarget(target, targetName) { + logger.Debugf("ignore target %s|%d", targetName, target) + continue + } + + logger.Debugf("save target %s|%d", targetName, target) + td, err := m.saveTarget(target, ts) + if err != nil { + logger.Warningf("save target failed %s|%d, err: %v", targetName, target, err) + } else { + result[td.Target] = td + logger.Debugf("save target success %s|%d", targetName, target) + } + } + return result +} + +func shouldIgnoreSaveTarget(target x.Atom, targetName string) bool { + switch target { + case atomTargets, atomSaveTargets, + atomTimestamp, atomMultiple, atomDelete, + atomInsertProperty, atomInsertSelection, + x.AtomPixmap: + return true + } + if strings.HasPrefix(targetName, "image/") { + switch targetName { + case "image/jpeg", "image/png", "image/bmp": + return false + default: + return true + } + } + return false +} + +func (m *Manager) saveTarget(target x.Atom, ts x.Timestamp) (targetData *TargetData, err error) { + selNotifyEvent, err := m.ec.captureSelectionNotifyEvent(func() error { + m.xc.ConvertSelection(m.window, atomClipboard, target, target, ts) + return m.xc.Flush() + }, func(event *x.SelectionNotifyEvent) bool { + return event.Selection == atomClipboard && + event.Requestor == m.window && + event.Target == target + }) + if err != nil { + return + } + if selNotifyEvent.Property == x.None { + err = errors.New("failed to convert target") + return + } + + propReply, err := m.getProperty(m.window, selNotifyEvent.Property, false) + if err != nil { + return + } + + if propReply.Type == atomIncr { + if m.saveAtomIncrDataEnabled { + targetData, err = m.receiveTargetIncr(target, selNotifyEvent.Property) + } + } else { + err = m.xc.DeletePropertyE(m.window, selNotifyEvent.Property) + if err != nil { + return + } + logger.Debug("data len:", len(propReply.Value)) + targetData = &TargetData{ + Target: target, + Type: propReply.Type, + Format: propReply.Format, + Data: propReply.Value, + } + } + return +} + +func (m *Manager) getProperty(win x.Window, propertyAtom x.Atom, delete bool) (*x.GetPropertyReply, error) { + propReply, err := m.xc.GetProperty(false, win, propertyAtom, + x.GetPropertyTypeAny, 0, 0) + if err != nil { + return nil, err + } + + propReply, err = m.xc.GetProperty(delete, win, propertyAtom, + x.GetPropertyTypeAny, + 0, + (propReply.BytesAfter+uint32(x.Pad(int(propReply.BytesAfter))))/4, + ) + if err != nil { + return nil, err + } + return propReply, nil +} + +func (m *Manager) receiveTargetIncr(target, prop x.Atom) (targetData *TargetData, err error) { + logger.Debug("start receiveTargetIncr", target) + var data [][]byte + t0 := time.Now() + total := 0 + for { + var propNotifyEvent *x.PropertyNotifyEvent + propNotifyEvent, err = m.ec.capturePropertyNotifyEvent(func() error { + err := m.xc.DeletePropertyE(m.window, prop) + if err != nil { + logger.Warning(err) + } + return err + + }, func(event *x.PropertyNotifyEvent) bool { + return event.State == x.PropertyNewValue && event.Window == m.window && + event.Atom == prop + }) + if err != nil { + logger.Warning(err) + return + } + + var propReply *x.GetPropertyReply + propReply, err = m.xc.GetProperty(false, propNotifyEvent.Window, propNotifyEvent.Atom, + x.GetPropertyTypeAny, + 0, 0) + if err != nil { + logger.Warning(err) + return + } + propReply, err = m.xc.GetProperty(false, propNotifyEvent.Window, propNotifyEvent.Atom, + x.GetPropertyTypeAny, 0, + (propReply.BytesAfter+uint32(x.Pad(int(propReply.BytesAfter))))/4, + ) + if err != nil { + logger.Warning(err) + return + } + + if propReply.ValueLen == 0 { + logger.Debugf("end receiveTargetIncr %d, took %v, total size: %d", + target, time.Since(t0), total) + + err = m.xc.DeletePropertyE(propNotifyEvent.Window, propNotifyEvent.Atom) + if err != nil { + logger.Warning(err) + return + } + + targetData = &TargetData{ + Target: target, + Type: propReply.Type, + Format: propReply.Format, + Data: bytes.Join(data, nil), + } + return + } + if logger.GetLogLevel() == log.LevelDebug { + logger.Debugf("incr receive data size: %d", len(propReply.Value)) + } + total += len(propReply.Value) + data = append(data, propReply.Value) + } +} + +func (m *Manager) getTimestamp() (x.Timestamp, error) { + propNotifyEvent, err := m.ec.capturePropertyNotifyEvent(func() error { + return m.xc.ChangePropertyE(x.PropModeReplace, m.window, atomTimestampProp, + x.AtomInteger, 32, nil) + }, func(event *x.PropertyNotifyEvent) bool { + return event.Window == m.window && + event.Atom == atomTimestampProp && + event.State == x.PropertyNewValue + }) + + if err != nil { + return 0, err + } + + return propNotifyEvent.Time, nil +} + +func (m *Manager) GetInterfaceName() string { + return dbusServiceName +} diff --git a/clipboard/manager_debug.go b/clipboard1/manager_debug.go similarity index 99% rename from clipboard/manager_debug.go rename to clipboard1/manager_debug.go index c68e3c72b..78ea4b176 100644 --- a/clipboard/manager_debug.go +++ b/clipboard1/manager_debug.go @@ -12,7 +12,7 @@ import ( "path/filepath" "strconv" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" x "github.com/linuxdeepin/go-x11-client" ) diff --git a/clipboard1/manager_test.go b/clipboard1/manager_test.go new file mode 100644 index 000000000..676b9a0bf --- /dev/null +++ b/clipboard1/manager_test.go @@ -0,0 +1,200 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package clipboard + +import ( + "errors" + "testing" + + "github.com/linuxdeepin/dde-daemon/clipboard1/mocks" + x "github.com/linuxdeepin/go-x11-client" + "github.com/stretchr/testify/assert" +) + +func initAtomsForTest() { + const base = 100 + atomClipboardManager = base + 1 + atomClipboard = base + 2 + atomSaveTargets = base + 3 + atomTargets = base + 4 + atomMultiple = base + 5 + atomDelete = base + 6 + atomInsertProperty = base + 7 + atomInsertSelection = base + 8 + atomAtomPair = base + 9 + atomIncr = base + 10 + atomTimestamp = base + 11 + atomTimestampProp = base + 12 + atomNull = base + 13 +} + +func TestManager_finishSelectionRequest(t *testing.T) { + ts := x.Timestamp(11) + owner := x.Window(1) + reqWin := x.Window(2) + selection := x.Atom(3) + target := x.Atom(4) + prop := x.Atom(5) + + ev := &x.SelectionRequestEvent{ + Time: ts, + Owner: owner, + Requestor: reqWin, + Selection: selection, + Target: target, + Property: prop, + } + + m := &Manager{} + m.window = owner + xc := &mocks.XClient{} + m.xc = xc + xc.On("SendEventE", false, reqWin, uint32(x.EventMaskNoEvent), &x.SelectionNotifyEvent{ + Time: ts, + Requestor: reqWin, + Selection: selection, + Target: target, + Property: prop, + }).Return(nil).Once() + + m.finishSelectionRequest(ev, true) + + xc.On("SendEventE", false, reqWin, uint32(x.EventMaskNoEvent), &x.SelectionNotifyEvent{ + Time: ts, + Requestor: reqWin, + Selection: selection, + Target: target, + Property: x.AtomNone, + }).Return(nil).Once() + m.finishSelectionRequest(ev, false) + + xc.AssertExpectations(t) +} + +func TestManager_getProperty(t *testing.T) { + win := x.Window(1) + prop := x.Atom(2) + m := &Manager{} + xc := &mocks.XClient{} + m.xc = xc + + w := x.NewWriter() + w.Write4b(1) + w.Write4b(2) + w.Write4b(3) + w.Write4b(4) + + var err1 = errors.New("E1") + + tests := []struct { + desc string + propReply0 *x.GetPropertyReply + propReply1 *x.GetPropertyReply + err0 error + err1 error + resultPropReply *x.GetPropertyReply + resultErr error + longLength uint32 + }{ + { + desc: "normal: data type: []uint32, len: 4", + propReply0: &x.GetPropertyReply{ + Format: 32, + Type: x.AtomCardinal, + BytesAfter: 16, + }, + propReply1: &x.GetPropertyReply{ + Format: 32, + Type: x.AtomCardinal, + Value: w.Bytes(), + ValueLen: 4, + }, + resultPropReply: &x.GetPropertyReply{ + Format: 32, + Type: x.AtomCardinal, + Value: w.Bytes(), + ValueLen: 4, + }, + longLength: 4, + }, + { + desc: "normal: data type: string, len: 5", + propReply0: &x.GetPropertyReply{ + Format: 8, + Type: x.AtomString, + BytesAfter: 5, + }, + propReply1: &x.GetPropertyReply{ + Format: 8, + Type: x.AtomString, + Value: []byte("abcde"), + ValueLen: 5, + }, + resultPropReply: &x.GetPropertyReply{ + Format: 8, + Type: x.AtomString, + Value: []byte("abcde"), + ValueLen: 5, + }, + longLength: 2, + }, + { + desc: "the first call to get property failed", + err0: err1, + resultErr: err1, + }, + { + desc: "the second call to get property failed", + propReply0: &x.GetPropertyReply{ + Format: 8, + Type: x.AtomString, + BytesAfter: 5, + }, + propReply1: &x.GetPropertyReply{ + Format: 8, + Type: x.AtomString, + Value: []byte("hello"), + ValueLen: 5, + }, + longLength: 2, + err1: err1, + resultErr: err1, + }, + } + + for _, test := range tests { + xc.On("GetProperty", false, win, prop, x.Atom(x.GetPropertyTypeAny), + uint32(0), uint32(0)).Return(test.propReply0, test.err0).Once() + + if test.err0 == nil { + xc.On("GetProperty", false, win, prop, x.Atom(x.GetPropertyTypeAny), + uint32(0), test.longLength).Return(test.propReply1, test.err1).Once() + } + + propReply, err := m.getProperty(win, prop, false) + assert.Equal(t, test.resultPropReply, propReply, test.desc) + assert.Equal(t, test.resultErr, err, test.desc) + _ = err + } + + xc.AssertExpectations(t) +} + +func Test_shouldIgnoreSaveTarget(t *testing.T) { + initAtomsForTest() + fn := shouldIgnoreSaveTarget + assert.True(t, fn(atomTimestamp, "TIMESTAMP")) + assert.True(t, fn(atomTargets, "TARGETS")) + + assert.False(t, fn(200, "image/jpeg")) + assert.False(t, fn(200, "image/png")) + assert.False(t, fn(200, "image/bmp")) + + assert.True(t, fn(200, "image/xpm")) + assert.True(t, fn(200, "image/webp")) + + assert.False(t, fn(200, "text/plain")) + assert.False(t, fn(200, "application/x-qt-image")) +} diff --git a/clipboard/mocks/XClient.go b/clipboard1/mocks/XClient.go similarity index 100% rename from clipboard/mocks/XClient.go rename to clipboard1/mocks/XClient.go diff --git a/clipboard1/module.go b/clipboard1/module.go new file mode 100644 index 000000000..3f8adf9d2 --- /dev/null +++ b/clipboard1/module.go @@ -0,0 +1,86 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package clipboard + +import ( + "os" + + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" + x "github.com/linuxdeepin/go-x11-client" + "github.com/linuxdeepin/go-x11-client/ext/xfixes" +) + +const ( + dbusServiceName = "org.deepin.dde.ClipboardManager1" + dbusPath = "/org/deepin/dde/ClipboardManager1" +) + +var logger *log.Logger + +func init() { + logger = log.NewLogger("clipboard") + loader.Register(newModule()) +} + +func newModule() *Module { + m := new(Module) + m.ModuleBase = loader.NewModuleBase("clipboard", m, logger) + return m +} + +type Module struct { + *loader.ModuleBase +} + +func (*Module) GetDependencies() []string { + return nil +} + +func (mo *Module) Start() error { + if os.Getenv("WAYLAND_DISPLAY") != "" { + return nil + } + logger.Debug("clipboard module start") + + xConn, err := x.NewConn() + if err != nil { + return err + } + + initAtoms(xConn) + + _, err = xfixes.QueryVersion(xConn, xfixes.MajorVersion, xfixes.MinorVersion).Reply(xConn) + if err != nil { + logger.Warning(err) + } + + m := &Manager{} + m.xc = &xClient{ + conn: xConn, + } + + err = m.start() + if err != nil { + return err + } + + service := loader.GetService() + err = service.Export(dbusPath, m) + if err != nil { + return err + } + + err = service.RequestName(dbusServiceName) + if err != nil { + return err + } + + return nil +} + +func (*Module) Stop() error { + return nil +} diff --git a/clipboard/util.go b/clipboard1/util.go similarity index 100% rename from clipboard/util.go rename to clipboard1/util.go diff --git a/clipboard/x_client.go b/clipboard1/x_client.go similarity index 100% rename from clipboard/x_client.go rename to clipboard1/x_client.go diff --git a/common/bluetooth/bluetooth.go b/common/bluetooth/bluetooth.go index 24d024910..565b30840 100644 --- a/common/bluetooth/bluetooth.go +++ b/common/bluetooth/bluetooth.go @@ -4,7 +4,7 @@ package bluetooth -import "github.com/godbus/dbus" +import "github.com/godbus/dbus/v5" type NotifyMsg struct { Icon string @@ -33,4 +33,4 @@ var ErrCanceled = &dbus.Error{ } // SessionAgentPath 目前唯一支持的标准的 session agent 对象路径 -const SessionAgentPath = "/com/deepin/system/Bluetooth/Agent" +const SessionAgentPath = "/org/deepin/dde/Bluetooth1/Agent" diff --git a/common/dconfig/dconfig.go b/common/dconfig/dconfig.go index d00766513..d27b2dc2c 100644 --- a/common/dconfig/dconfig.go +++ b/common/dconfig/dconfig.go @@ -4,7 +4,7 @@ import ( "fmt" "sync" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" DConfigManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" "github.com/linuxdeepin/go-lib/dbusutil" ) diff --git a/common/dsync/dsync.go b/common/dsync/dsync.go index 68eb82f8f..bdccbc09e 100644 --- a/common/dsync/dsync.go +++ b/common/dsync/dsync.go @@ -7,8 +7,8 @@ package dsync import ( "encoding/json" - dbus "github.com/godbus/dbus" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" + dbus "github.com/godbus/dbus/v5" + ofdbus "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.dbus" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/dbusutil/proxy" "github.com/linuxdeepin/go-lib/log" diff --git a/common/sessionmsg/sessionmsg.go b/common/sessionmsg/sessionmsg.go index ca5e92671..0df6b1ea8 100644 --- a/common/sessionmsg/sessionmsg.go +++ b/common/sessionmsg/sessionmsg.go @@ -13,7 +13,7 @@ import ( "errors" "fmt" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/gettext" "github.com/linuxdeepin/go-lib/multierr" ) @@ -151,8 +151,8 @@ func (a *agent) sendMessage(msg *Message) error { // 这个 agent 实际在 dde-session-daemon 中的 service_trigger 模块中实现的 const ( - AgentPath = "/com/deepin/daemon/ServiceTrigger/Agent" - AgentIfc = "com.deepin.daemon.ServiceTrigger.Agent" + AgentPath = "/org/deepin/dde/ServiceTrigger1/Agent" + AgentIfc = "org.deepin.dde.ServiceTrigger1.Agent" MethodSendMessage = "SendMessage" ) diff --git a/dbus/accounts.go b/dbus/accounts.go index a72548135..22e1eb9a0 100644 --- a/dbus/accounts.go +++ b/dbus/accounts.go @@ -5,8 +5,8 @@ package dbus import ( - "github.com/godbus/dbus" - accounts "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.accounts" + "github.com/godbus/dbus/v5" + accounts "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.accounts1" ) func NewAccounts(systemConn *dbus.Conn) accounts.Accounts { diff --git a/dbus/dbus.go b/dbus/dbus.go index cf770777a..52c2b2931 100644 --- a/dbus/dbus.go +++ b/dbus/dbus.go @@ -5,7 +5,7 @@ package dbus import ( - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib" ) diff --git a/debian/changelog b/debian/changelog index 54a80902e..228514156 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,15 @@ +dde-daemon (6.1.1) unstable; urgency=medium + + * chore: cherry-pick paths from professional + + -- fuleyi Mon, 02 Sep 2024 15:18:43 +0800 + +dde-daemon (6.1.0) unstable; urgency=medium + + * 1070代码迁移,接口调整为v23风格 + + -- fuleyi Tue, 16 Jul 2024 09:47:14 +0800 + dde-daemon (5.15.13.1) unstable; urgency=medium [ Deepin Packages Builder ] diff --git a/debian/control b/debian/control index c25933e85..3b5fb2aac 100644 --- a/debian/control +++ b/debian/control @@ -70,7 +70,6 @@ Depends: deepin-installer-timezones, deepin-proxy, deepin-sound-theme, - deepin-wm | deepin-metacity | dde-kwin, dmidecode, dnsmasq-base, gnome-keyring, diff --git a/debian/rules b/debian/rules index a2745f5b5..b4f9bb9c3 100755 --- a/debian/rules +++ b/debian/rules @@ -4,6 +4,7 @@ include /usr/share/dpkg/architecture.mk export GOCACHE = /tmp/gocache export GOPATH = /usr/share/gocode +export GO111MODULE=off SYSTYPE=Desktop SYSTYPE=$(shell cat /etc/deepin-version | grep Type= | awk -F'=' '{print $$2}') @@ -13,10 +14,6 @@ override_dh_gencontrol: dh_gencontrol -- -Vdist:Depends="fprintd, libpam-fprintd" endif -ifneq ($(DEB_BUILD_ARCH), mips64el) - export GOBUILD_OPTIONS=-ldflags '-linkmode=external -extldflags "-pie"' -endif - %: dh $@ @@ -53,3 +50,7 @@ endif override_dh_installsystemd: dh_installsystemd --no-start + +override_dh_auto_clean: + dh_auto_clean -- + rm -fr obj-x86_64-linux-gnu diff --git a/debug/debug.go b/debug/debug.go index bc3cf1858..71df9ce9a 100644 --- a/debug/debug.go +++ b/debug/debug.go @@ -5,8 +5,8 @@ package debug import ( - "github.com/linuxdeepin/go-lib/log" "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" ) var ( diff --git a/dock/app_entries.go b/dock/app_entries.go deleted file mode 100644 index 80b6717e4..000000000 --- a/dock/app_entries.go +++ /dev/null @@ -1,219 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "errors" - "fmt" - "reflect" - "sync" - - "github.com/godbus/dbus" - x "github.com/linuxdeepin/go-x11-client" -) - -type AppEntries struct { - items []*AppEntry - mu sync.RWMutex - - insertCb func(entry *AppEntry, index int) - removeCb func(entry *AppEntry) -} - -func (entries *AppEntries) GetValue() (val interface{}, err *dbus.Error) { - entries.mu.RLock() - result := make([]dbus.ObjectPath, len(entries.items)) - for idx, entry := range entries.items { - result[idx] = dbus.ObjectPath(entryDBusObjPathPrefix + entry.Id) - } - entries.mu.RUnlock() - return result, nil -} - -func (entries *AppEntries) SetNotifyChangedFunc(func(val interface{})) { -} - -func (entries *AppEntries) SetValue(val interface{}) (changed bool, err *dbus.Error) { - // readonly - return -} - -func (entries *AppEntries) GetType() reflect.Type { - return reflect.TypeOf([]dbus.ObjectPath{}) -} - -func (entries *AppEntries) GetByInnerId(id string) *AppEntry { - entries.mu.RLock() - for _, entry := range entries.items { - if entry.innerId == id { - entries.mu.RUnlock() - return entry - } - } - entries.mu.RUnlock() - return nil -} - -func (entries *AppEntries) Append(entry *AppEntry) { - entries.Insert(entry, -1) -} - -func (entries *AppEntries) Insert(entry *AppEntry, index int) { - entries.mu.Lock() - if index < 0 || index >= len(entries.items) { - // append - index = len(entries.items) - entries.items = append(entries.items, entry) - } else { - // insert - entries.items = append(entries.items[:index], - append([]*AppEntry{entry}, entries.items[index:]...)...) - } - - if entries.insertCb != nil { - entries.insertCb(entry, index) - } - entries.mu.Unlock() -} - -func (entries *AppEntries) Remove(entry *AppEntry) { - entries.mu.Lock() - index := entries.indexOf(entry) - if index != -1 { - entries.items = append(entries.items[:index], entries.items[index+1:]...) - entries.removeCb(entry) - } - entries.mu.Unlock() -} - -func (entries *AppEntries) indexOf(entry *AppEntry) int { - index := -1 - for i, v := range entries.items { - if v.Id == entry.Id { - index = i - } - } - return index -} - -func (entries *AppEntries) IndexOf(entry *AppEntry) int { - entries.mu.RLock() - idx := entries.indexOf(entry) - entries.mu.RUnlock() - return idx -} - -func (entries *AppEntries) Move(index, newIndex int) error { - if index == newIndex { - return errors.New("index == newIndex") - } - - entries.mu.Lock() - - entriesLength := len(entries.items) - if 0 <= index && index < entriesLength && - 0 <= newIndex && newIndex < entriesLength { - - entry := entries.items[index] - // remove entry at index - removed := append(entries.items[:index], entries.items[index+1:]...) - // insert entry at newIndex - entries.items = append(removed[:newIndex], - append([]*AppEntry{entry}, removed[newIndex:]...)...) - - entries.mu.Unlock() - return nil - } - entries.mu.Unlock() - return fmt.Errorf("index out of bounds, index: %v, newIndex: %v, len: %v", index, newIndex, entriesLength) -} - -func (entries *AppEntries) FilterDocked() (dockedEntries []*AppEntry) { - entries.mu.RLock() - - for _, entry := range entries.items { - entry.PropsMu.RLock() - if entry.appInfo != nil && entry.IsDocked { - dockedEntries = append(dockedEntries, entry) - } - entry.PropsMu.RUnlock() - } - - entries.mu.RUnlock() - return dockedEntries -} - -func (entries *AppEntries) GetByWindowPid(pid uint) *AppEntry { - entries.mu.RLock() - defer entries.mu.RUnlock() - - var foundPid bool - for _, entry := range entries.items { - entry.PropsMu.RLock() - for _, winInfo := range entry.windows { - if winInfo.getPid() == pid { - foundPid = true - break - } - } - entry.PropsMu.RUnlock() - if foundPid { - return entry - } - } - return nil -} - -func (entries *AppEntries) getByWindowId(winId x.Window) *AppEntry { - entries.mu.RLock() - defer entries.mu.RUnlock() - - for _, entry := range entries.items { - entry.PropsMu.RLock() - _, ok := entry.windows[winId] - entry.PropsMu.RUnlock() - if ok { - return entry - } - } - // not found - return nil -} - -func getByDesktopFilePath(entriesItems []*AppEntry, desktopFilePath string) (*AppEntry, error) { - // same file - for _, entry := range entriesItems { - if entry.appInfo == nil { - continue - } - file := entry.appInfo.GetFileName() - if file == desktopFilePath { - return entry, nil - } - } - - // hash equal - appInfo := NewAppInfoFromFile(desktopFilePath) - if appInfo == nil { - return nil, errors.New("invalid desktopFilePath") - } - hash := appInfo.innerId - for _, entry := range entriesItems { - if entry.appInfo == nil { - continue - } - if entry.appInfo.innerId == hash { - return entry, nil - } - } - return nil, nil -} - -func (entries *AppEntries) GetByDesktopFilePath(desktopFilePath string) (*AppEntry, error) { - entries.mu.RLock() - e, err := getByDesktopFilePath(entries.items, desktopFilePath) - entries.mu.RUnlock() - return e, err -} diff --git a/dock/app_entry.go b/dock/app_entry.go deleted file mode 100644 index 14aeb23b8..000000000 --- a/dock/app_entry.go +++ /dev/null @@ -1,330 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "sort" - "sync" - "unicode/utf8" - - "github.com/linuxdeepin/go-lib/dbusutil" - x "github.com/linuxdeepin/go-x11-client" -) - -const ( - entryDBusObjPathPrefix = dbusPath + "/entries/" - entryDBusInterface = dbusInterface + ".Entry" -) - -//go:generate dbusutil-gen -type AppEntry -import=github.com/linuxdeepin/go-x11-client=x app_entry.go -//go:generate dbusutil-gen em -type AppEntry,Manager - -type AppEntry struct { - PropsMu sync.RWMutex - Id string - IsActive bool - Name string - Icon string - // dbusutil-gen: ignore - Menu AppEntryMenu - DesktopFile string - CurrentWindow x.Window - IsDocked bool - // dbusutil-gen: equal=method:Equal - WindowInfos windowInfosType - - service *dbusutil.Service - manager *Manager - innerId string - windows map[x.Window]WindowInfoImp - current WindowInfoImp - appInfo *AppInfo - winIconPreferred bool -} - -func newAppEntry(dockManager *Manager, innerId string, appInfo *AppInfo) *AppEntry { - entry := &AppEntry{ - manager: dockManager, - service: dockManager.service, - Id: dockManager.allocEntryId(), - innerId: innerId, - windows: make(map[x.Window]WindowInfoImp), - } - entry.Menu.manager = dockManager - entry.setAppInfo(appInfo) - entry.Name = entry.getName() - entry.Icon = entry.getIcon() - return entry -} - -func (entry *AppEntry) setAppInfo(newAppInfo *AppInfo) { - if entry.appInfo == newAppInfo { - logger.Debug("setAppInfo failed: old == new") - return - } - entry.appInfo = newAppInfo - - if newAppInfo == nil { - entry.winIconPreferred = true - entry.setPropDesktopFile("") - } else { - entry.winIconPreferred = false - entry.setPropDesktopFile(newAppInfo.GetFileName()) - id := newAppInfo.GetId() - if strSliceContains(entry.manager.getWinIconPreferredApps(), id) { - entry.winIconPreferred = true - return - } - - icon := newAppInfo.GetIcon() - if icon == "" { - entry.winIconPreferred = true - } - } -} - -func (entry *AppEntry) hasWindow() bool { - return len(entry.windows) != 0 -} - -func (entry *AppEntry) hasAllowedCloseWindow() bool { - winInfos := entry.getAllowedCloseWindows() - return len(winInfos) > 0 -} - -func (entry *AppEntry) getAllowedCloseWindows() []WindowInfoImp { - ret := make([]WindowInfoImp, 0, len(entry.windows)) - for _, winInfo := range entry.windows { - if winInfo.allowClose() { - ret = append(ret, winInfo) - } - } - return ret -} - -func (entry *AppEntry) getWindowIds() []uint32 { - list := make([]uint32, 0, len(entry.windows)) - for _, winInfo := range entry.windows { - list = append(list, uint32(winInfo.getXid())) - } - return list -} - -func (entry *AppEntry) getWindowInfoSlice() []WindowInfoImp { - winInfoSlice := make([]WindowInfoImp, 0, len(entry.windows)) - for _, winInfo := range entry.windows { - winInfoSlice = append(winInfoSlice, winInfo) - } - return winInfoSlice -} - -func (entry *AppEntry) getExec(oneLine bool) string { - if entry.current == nil { - return "" - } - winProcess := entry.current.getProcess() - if winProcess != nil { - if oneLine { - return winProcess.GetOneCommandLine() - } else { - return winProcess.GetShellScriptLines() - } - } - return "" -} - -func (entry *AppEntry) setCurrentWindowInfo(winInfo WindowInfoImp) { - entry.current = winInfo - if winInfo == nil { - entry.setPropCurrentWindow(0) - } else { - entry.setPropCurrentWindow(winInfo.getXid()) - } -} - -func (entry *AppEntry) findNextLeader() WindowInfoImp { - winSlice := make(windowSlice, 0, len(entry.windows)) - for win := range entry.windows { - winSlice = append(winSlice, win) - } - sort.Sort(winSlice) - currentWin := entry.current.getXid() - logger.Debug("sorted window slice:", winSlice) - logger.Debug("current window:", currentWin) - currentIndex := -1 - for i, win := range winSlice { - if win == currentWin { - currentIndex = i - } - } - if currentIndex == -1 { - logger.Warning("findNextLeader unexpect, return 0") - return nil - } - // if current window is max, return min: winSlice[0] - // else return winSlice[currentIndex+1] - nextIndex := 0 - if currentIndex < len(winSlice)-1 { - nextIndex = currentIndex + 1 - } - logger.Debug("next window:", winSlice[nextIndex]) - for _, winInfo := range entry.windows { - if winInfo.getXid() == winSlice[nextIndex] { - return winInfo - } - } - return nil -} - -func (entry *AppEntry) attachWindow(winInfo WindowInfoImp) bool { - win := winInfo.getXid() - logger.Debugf("attach win %v to entry", win) - - winInfo.setEntry(entry) - - entry.PropsMu.Lock() - defer entry.PropsMu.Unlock() - - if _, ok := entry.windows[win]; ok { - logger.Infof("win %v is already attach to entry", win) - return false - } - - entry.windows[win] = winInfo - entry.updateWindowInfos() - entry.updateIsActive() - - if entry.current == nil { - // from no window to has window - entry.setCurrentWindowInfo(winInfo) - } - entry.updateIcon() - entry.updateMenu() - - // print window info - winInfo.print() - - return true -} - -// return need remove? -func (entry *AppEntry) detachWindow(winInfo WindowInfoImp) bool { - winInfo.setEntry(nil) - win := winInfo.getXid() - logger.Debug("detach window ", win) - - entry.PropsMu.Lock() - defer entry.PropsMu.Unlock() - - delete(entry.windows, win) - - if len(entry.windows) == 0 { - if !entry.IsDocked { - // no window and not docked - return true - } - entry.setCurrentWindowInfo(nil) - } else { - for _, winInfo := range entry.windows { - // select first - entry.setCurrentWindowInfo(winInfo) - break - } - } - - entry.updateWindowInfos() - entry.updateIcon() - entry.updateIsActive() - entry.updateMenu() - return false -} - -func (entry *AppEntry) getName() (name string) { - if entry.appInfo != nil { - name = entry.appInfo.name - if !utf8.ValidString(name) { - name = "" - } - } - - if name == "" && entry.current != nil { - name = entry.current.getDisplayName() - } - - return -} - -func (entry *AppEntry) updateName() { - name := entry.getName() - entry.setPropName(name) -} - -func (entry *AppEntry) updateIcon() { - icon := entry.getIcon() - entry.setPropIcon(icon) -} - -func (entry *AppEntry) forceUpdateIcon() { - icon := entry.getIcon() - entry.Icon = icon - err := entry.emitPropChangedIcon(icon) - if err != nil { - logger.Warning(err) - } -} - -func (entry *AppEntry) getIcon() string { - var icon string - appInfo := entry.appInfo - current := entry.current - - if entry.hasWindow() { - if current == nil { - logger.Warning("AppEntry.getIcon entry.hasWindow but entry.current is nil") - return "" - } - - // has window && current not nil - if entry.winIconPreferred { - // try current window icon first - icon = current.getIcon() - if icon != "" { - return icon - } - } - if appInfo != nil { - icon = appInfo.GetIcon() - if icon != "" { - return icon - } - } - return current.getIcon() - - } else if appInfo != nil { - // no window - return appInfo.GetIcon() - } - return "" -} - -func (e *AppEntry) updateWindowInfos() { - windowInfos := newWindowInfos() - for _, winInfo := range e.windows { - windowInfos[winInfo.getXid()] = ExportWindowInfo{ - Title: winInfo.getTitle(), - Flash: winInfo.isDemandingAttention(), - } - } - e.setPropWindowInfos(windowInfos) -} - -func (e *AppEntry) updateIsActive() { - isActive := false - activeWin := e.manager.getActiveWindow() - if activeWin != nil { - _, isActive = e.windows[activeWin.getXid()] - } - e.setPropIsActive(isActive) -} diff --git a/dock/app_entry_ifc.go b/dock/app_entry_ifc.go deleted file mode 100644 index 2bd3f623f..000000000 --- a/dock/app_entry_ifc.go +++ /dev/null @@ -1,276 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "errors" - "os" - "syscall" - "time" - - "github.com/godbus/dbus" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/procfs" - "github.com/linuxdeepin/go-x11-client/util/wm/ewmh" -) - -func (e *AppEntry) GetInterfaceName() string { - return entryDBusInterface -} - -func (entry *AppEntry) Activate(timestamp uint32) *dbus.Error { - logger.Debug("Activate timestamp:", timestamp) - var err error - - m := entry.manager - if HideModeType(m.HideMode.Get()) == HideModeSmartHide { - m.setPropHideState(HideStateShow) - m.updateHideState(true) - } - - entry.PropsMu.RLock() - hasWindow := entry.hasWindow() - entry.PropsMu.RUnlock() - - if !hasWindow { - entry.launchApp(timestamp) - return nil - } - - if entry.current == nil { - err = errors.New("entry.current is nil") - logger.Warning(err) - return dbusutil.ToError(err) - } - - winInfo := entry.current - if winInfo == nil { - err = errors.New("winInfo is nil") - logger.Warning(err) - return dbusutil.ToError(err) - } - if m.isWaylandSession { - if m.isActiveWindow(winInfo) { - showing, _ := m.waylandWM.IsShowingDesktop(0) - if winInfo.isMinimized() || showing { - err = winInfo.activate() - } else { - if len(entry.windows) == 1 { - err = winInfo.minimize() - } else { - nextWinInfo := entry.findNextLeader() - if nextWinInfo != nil { - err = nextWinInfo.activate() - } else { - err = errors.New("nextWinInfo is nil") - } - } - } - } else { - err = winInfo.activate() - } - } else { - win := winInfo.getXid() - state, err0 := ewmh.GetWMState(globalXConn, win).Reply(globalXConn) - if err0 != nil { - logger.Warningf("failed to get ewmh WMState for win %d: %v", win, err0) - return dbusutil.ToError(err0) - } - - activeWin := entry.manager.getActiveWindow() - if activeWin == nil { - err = errors.New("activeWin is nil") - logger.Warning(err) - return dbusutil.ToError(err) - } - if win == activeWin.getXid() { - if atomsContains(state, atomNetWmStateHidden) { - err = activateWindow(win) - } else { - if len(entry.windows) == 1 { - err = minimizeWindow(win) - } else if entry.manager.getActiveWindow().getXid() == win { - nextWin := entry.findNextLeader() - if nextWin == nil { - err = errors.New("nextWin is nil") - logger.Warning(err) - return dbusutil.ToError(err) - } - err = nextWin.activate() - } - } - } else { - err = activateWindow(win) - } - } - - if err != nil { - logger.Warning(err) - } - return dbusutil.ToError(err) -} - -func (e *AppEntry) HandleMenuItem(timestamp uint32, id string) *dbus.Error { - logger.Debugf("HandleMenuItem id: %q timestamp: %v", id, timestamp) - menu := e.Menu.getMenu() - if menu != nil { - err := menu.HandleAction(id, timestamp) - return dbusutil.ToError(err) - } - logger.Warning("HandleMenuItem failed: entry.coreMenu is nil") - return nil -} - -func (e *AppEntry) HandleDragDrop(timestamp uint32, files []string) *dbus.Error { - logger.Debugf("handle drag drop files: %v, timestamp: %v", files, timestamp) - - ai := e.appInfo - if ai != nil { - e.manager.launch(ai.GetFileName(), timestamp, files) - } else { - logger.Warning("not supported") - } - return nil -} - -// RequestDock 驻留 -func (entry *AppEntry) RequestDock() *dbus.Error { - docked, err := entry.manager.dockEntry(entry) - if err != nil { - return dbusutil.ToError(err) - } - if docked { - entry.manager.saveDockedApps() - } - return nil -} - -// RequestUndock 取消驻留 -func (entry *AppEntry) RequestUndock() *dbus.Error { - entry.manager.undockEntry(entry) - return nil -} - -func (entry *AppEntry) PresentWindows() *dbus.Error { - entry.PropsMu.RLock() - windowIds := entry.getWindowIds() - entry.PropsMu.RUnlock() - if len(windowIds) > 0 { - err := entry.manager.wm.PresentWindows(dbus.FlagNoAutoStart, windowIds) - if err != nil { - logger.Warning("PresentWindows error:", err) - } - } - return nil -} - -func (entry *AppEntry) showWorkspace() error { - err := entry.manager.wm.ShowWorkspace(0) - if err != nil { - return dbusutil.ToError(err) - } - return nil -} - -func (entry *AppEntry) NewInstance(timestamp uint32) *dbus.Error { - entry.launchApp(timestamp) - return nil -} - -func (entry *AppEntry) Check() *dbus.Error { - entry.PropsMu.RLock() - winInfoSlice := entry.getWindowInfoSlice() - entry.PropsMu.RUnlock() - - for _, winInfo := range winInfoSlice { - entry.manager.attachOrDetachWindow(winInfo) - } - return nil -} - -func (entry *AppEntry) ForceQuit() *dbus.Error { - entry.PropsMu.RLock() - winInfoSlice := entry.getWindowInfoSlice() - entry.PropsMu.RUnlock() - - pidWinInfosMap := make(map[uint][]WindowInfoImp) - for _, winInfo := range winInfoSlice { - pid := winInfo.getPid() - if pid != 0 && isProcessAlive(pid) { - pidWinInfosMap[pid] = append(pidWinInfosMap[pid], winInfo) - } else { - err := winInfo.killClient() - if err != nil { - logger.Warning(err) - } - } - } - - for pid, winInfoSlice := range pidWinInfosMap { - err := killProcess(pid) - if err != nil { - logger.Warning(err) - if os.IsPermission(err) { - for _, winInfo := range winInfoSlice { - err = winInfo.killClient() - if err != nil { - logger.Warning(err) - } - } - } - } - } - return nil -} - -func killProcess(pid uint) error { - p := procfs.Process(pid) - if p.Exist() { - logger.Debug("kill process", pid) - osP, err := os.FindProcess(int(pid)) - if err != nil { - return err - } - err = osP.Signal(syscall.SIGTERM) - if err != nil { - logger.Warningf("failed to send signal TERM to process %d: %v", - osP.Pid, err) - return err - } - time.AfterFunc(5*time.Second, func() { - if p.Exist() { - err := osP.Kill() - if err != nil { - logger.Warningf("failed to send signal KILL to process %d: %v", - osP.Pid, err) - } - } - }) - } - return nil -} - -func (entry *AppEntry) GetAllowedCloseWindows() (windows []uint32, busErr *dbus.Error) { - entry.PropsMu.RLock() - ret := make([]uint32, len(entry.windows)) - winInfos := entry.getAllowedCloseWindows() - for idx, winInfo := range winInfos { - ret[idx] = uint32(winInfo.getXid()) - } - entry.PropsMu.RUnlock() - return ret, nil -} - -func isProcessAlive(pid uint) bool { - p, err := os.FindProcess(int(pid)) - if err != nil { - return false - } - err = p.Signal(syscall.Signal(0)) - if err != nil { - return false - } - return true -} diff --git a/dock/app_entry_menu.go b/dock/app_entry_menu.go deleted file mode 100644 index e77781c60..000000000 --- a/dock/app_entry_menu.go +++ /dev/null @@ -1,247 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "reflect" - "sync" - - "github.com/godbus/dbus" - . "github.com/linuxdeepin/go-lib/gettext" - "github.com/linuxdeepin/go-lib/strv" - _ "github.com/linuxdeepin/go-x11-client" -) - -func (entry *AppEntry) updateMenu() { - logger.Debug("Update menu") - menu := NewMenu() - menu.AppendItem(entry.getMenuItemLaunch()) - - desktopActionMenuItems := entry.getMenuItemDesktopActions() - menu.AppendItem(desktopActionMenuItems...) - hasWin := entry.hasWindow() - if hasWin { - menu.AppendItem(entry.getMenuItemAllWindows()) - } - if !strv.Strv(entry.manager.hideRequestDockAndUndockByNameList).Contains(entry.getName()) { - // menu item dock or undock - logger.Debug(entry.Id, "Item docked?", entry.IsDocked) - if entry.IsDocked { - menu.AppendItem(entry.getMenuItemUndock()) - } else { - menu.AppendItem(entry.getMenuItemDock()) - } - } - - if hasWin { - if entry.manager.forceQuitAppStatus != forceQuitAppDisabled { - if entry.appInfo != nil && (entry.appInfo.identifyMethod == "Android" || entry.appInfo.identifyMethod == "DSGVirtualApp") { - menu.AppendItem(entry.getMenuItemForceQuitAndroid()) - } else { - menu.AppendItem(entry.getMenuItemForceQuit()) - } - } - - if entry.hasAllowedCloseWindow() { - menu.AppendItem(entry.getMenuItemCloseAll()) - } - } - entry.Menu.setMenu(menu) -} - -func (entry *AppEntry) getMenuItemDesktopActions() []*MenuItem { - ai := entry.appInfo - if ai == nil { - return nil - } - - var items []*MenuItem - launchAction := func(action desktopAction) func(timestamp uint32) { - return func(timestamp uint32) { - logger.Debugf("launch action %+v", action) - err := entry.manager.startManager.LaunchAppAction(dbus.FlagNoAutoStart, - ai.GetFileName(), action.Section, timestamp) - if err != nil { - logger.Warning("launchAppAction failed:", err) - } - } - } - - for _, action := range ai.GetActions() { - item := NewMenuItem(action.Name, launchAction(action), true) - items = append(items, item) - } - return items -} - -func (entry *AppEntry) launchApp(timestamp uint32) { - logger.Debug("launchApp timestamp:", timestamp) - if entry.appInfo != nil { - logger.Debug("Has AppInfo") - entry.manager.launch(entry.appInfo.GetFileName(), timestamp, nil) - } else { - // TODO - logger.Debug("not supported") - } -} - -func (entry *AppEntry) getMenuItemLaunch() *MenuItem { - var itemName string - if entry.hasWindow() { - itemName = entry.getName() - } else { - itemName = Tr("Open") - } - logger.Debugf("getMenuItemLaunch, itemName: %q", itemName) - return NewMenuItem(itemName, entry.launchApp, true) -} - -func (entry *AppEntry) getMenuItemCloseAll() *MenuItem { - return NewMenuItem(Tr("Close All"), func(timestamp uint32) { - logger.Debug("Close All") - entry.PropsMu.RLock() - winInfos := entry.getAllowedCloseWindows() - entry.PropsMu.RUnlock() - - for i := 0; i < len(winInfos)-1; i++ { - for j := i + 1; j < len(winInfos); j++ { - if winInfos[i].getCreatedTime() < winInfos[j].getCreatedTime() { - winInfos[i], winInfos[j] = winInfos[j], winInfos[i] - } - } - } - - for _, winInfo := range winInfos { - logger.Debug("to close win, xid:", winInfo.getXid(), ", created time:", winInfo.getCreatedTime()) - err := winInfo.close(timestamp) - if err != nil { - logger.Warningf("failed to close window %d: %v", winInfo.getXid(), err) - } - } - }, true) -} - -func (entry *AppEntry) getMenuItemForceQuit() *MenuItem { - active := entry.manager.forceQuitAppStatus != forceQuitAppDeactivated - - return NewMenuItem(Tr("Force Quit"), func(timestamp uint32) { - logger.Debug("Force Quit") - err := entry.ForceQuit() - if err != nil { - logger.Warning("ForceQuit error:", err) - } - }, active) -} - -//dock栏上Android程序的Force Quit功能 -func (entry *AppEntry) getMenuItemForceQuitAndroid() *MenuItem { - active := entry.manager.forceQuitAppStatus != forceQuitAppDeactivated - - if entry.hasAllowedCloseWindow() { - return NewMenuItem(Tr("Force Quit"), func(timestamp uint32) { - logger.Debug("Force Quit") - entry.PropsMu.RLock() - winInfos := entry.getAllowedCloseWindows() - entry.PropsMu.RUnlock() - - for _, winInfo := range winInfos { - err := winInfo.close(timestamp) - if err != nil { - logger.Warningf("failed to close window %d: %v", winInfo.getXid(), err) - } - } - }, active) - } - - return NewMenuItem(Tr("Force Quit"), func(timestamp uint32) {}, true) -} - -func (entry *AppEntry) getMenuItemDock() *MenuItem { - return NewMenuItem(Tr("Dock"), func(uint32) { - logger.Debug("menu action dock entry") - err := entry.RequestDock() - if err != nil { - logger.Warning("RequestDock error:", err) - } - }, true) -} - -func (entry *AppEntry) getMenuItemUndock() *MenuItem { - return NewMenuItem(Tr("Undock"), func(uint32) { - logger.Debug("menu action undock entry") - err := entry.RequestUndock() - if err != nil { - logger.Warning("RequestUndock error:", err) - } - }, true) -} - -func (entry *AppEntry) getMenuItemAllWindows() *MenuItem { - menuItem := NewMenuItem(Tr("All Windows"), func(uint32) { - logger.Debug("menu action all windows") - err := entry.showWorkspace() - if err != nil { - logger.Warning("ShowWorkspace error:", err) - } - }, true) - menuItem.hint = menuItemHintShowAllWindows - return menuItem -} - -type AppEntryMenu struct { - manager *Manager - cache string - is3DWM bool - dirty bool - menu *Menu - mu sync.Mutex -} - -func (m *AppEntryMenu) setMenu(menu *Menu) { - m.mu.Lock() - m.menu = menu - m.dirty = true - m.mu.Unlock() -} - -func (m *AppEntryMenu) getMenu() *Menu { - m.mu.Lock() - ret := m.menu - m.mu.Unlock() - return ret -} - -func (*AppEntryMenu) SetValue(val interface{}) (changed bool, err *dbus.Error) { - // read only - return -} - -func (m *AppEntryMenu) GetValue() (val interface{}, err *dbus.Error) { - is3DWM := m.manager.is3DWM() - m.mu.Lock() - if m.dirty || m.cache == "" || m.is3DWM != is3DWM { - items := make([]*MenuItem, 0, len(m.menu.Items)) - for _, item := range m.menu.Items { - if is3DWM || item.hint != menuItemHintShowAllWindows { - items = append(items, item) - } - } - menu := NewMenu() - menu.Items = items - m.cache = menu.GenerateJSON() - m.dirty = false - m.is3DWM = is3DWM - } - val = m.cache - m.mu.Unlock() - return -} - -func (*AppEntryMenu) SetNotifyChangedFunc(func(val interface{})) { -} - -func (*AppEntryMenu) GetType() reflect.Type { - return reflect.TypeOf("") -} diff --git a/dock/app_info.go b/dock/app_info.go deleted file mode 100644 index e3691d483..000000000 --- a/dock/app_info.go +++ /dev/null @@ -1,176 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "crypto/md5" - "encoding/hex" - "fmt" - "strings" - - "github.com/linuxdeepin/dde-daemon/common/dconfig" - "github.com/linuxdeepin/go-lib/appinfo/desktopappinfo" - "github.com/linuxdeepin/go-lib/gettext" -) - -const desktopHashPrefix = "d:" - -type AppInfo struct { - filename string - id string - icon string - identifyMethod string - innerId string - name string - actions []desktopAction - isInstalled bool -} - -type desktopAction struct { - Section string - Name string -} - -func newAppInfo(dai *desktopappinfo.DesktopAppInfo) *AppInfo { - if dai == nil { - return nil - } - ai := &AppInfo{} - xDeepinVendor, _ := dai.GetString(desktopappinfo.MainSection, "X-Deepin-Vendor") - if xDeepinVendor == "deepin" { - ai.name = dai.GetGenericName() - if ai.name == "" { - ai.name = dai.GetName() - } - } else { - ai.name = dai.GetName() - } - - enableLinglongSuffix := false - getEnableLinglongSuffix := func() { - dc, err := dconfig.NewDConfig("org.deepin.dde.daemon", "org.deepin.dde.daemon.application", "") - if err != nil { - logger.Warning("new dconfig error:", err) - return - } - if dc == nil { - logger.Warning("new dconfig error: dconfig is nil.") - return - } - result, err := dc.GetValueBool("LinglongAppNameSuffixEnable") - if err != nil { - logger.Warning("failed to get dconfig LinglongAppNameSuffixEnable:", err) - return - } - enableLinglongSuffix = result - } - getEnableLinglongSuffix() - - if strings.Contains(dai.GetId(), "Linglong") && enableLinglongSuffix { - ai.name = ai.name + gettext.Tr("(Linglong)") - } - ai.innerId = genInnerIdWithDesktopAppInfo(dai) - ai.filename = dai.GetFileName() - ai.id = dai.GetId() - ai.icon = dai.GetIcon() - ai.isInstalled = dai.IsInstalled() - actions := dai.GetActions() - for _, act := range actions { - ai.actions = append(ai.actions, desktopAction{ - Section: act.Section, - Name: act.Name, - }) - } - return ai -} - -func getDockedDesktopAppInfo(app string) *desktopappinfo.DesktopAppInfo { - if app[0] != '/' || len(app) <= 3 { - return desktopappinfo.NewDesktopAppInfo(app) - } - - absPath := unzipDesktopPath(app) - ai, err := desktopappinfo.NewDesktopAppInfoFromFile(absPath) - if err != nil { - logger.Warning(err) - return nil - } - return ai -} - -func NewDockedAppInfo(app string) *AppInfo { - if app == "" { - return nil - } - return newAppInfo(getDockedDesktopAppInfo(app)) -} - -func NewAppInfo(id string) *AppInfo { - if id == "" { - return nil - } - return newAppInfo(desktopappinfo.NewDesktopAppInfo(id)) -} - -func NewAppInfoFromFile(file string) *AppInfo { - if file == "" { - return nil - } - dai, _ := desktopappinfo.NewDesktopAppInfoFromFile(file) - if dai == nil { - return nil - } - - if !dai.IsInstalled() { - appId, _ := dai.GetString(desktopappinfo.MainSection, "X-Deepin-AppID") - if appId != "" { - dai1 := desktopappinfo.NewDesktopAppInfo(appId) - if dai1 != nil { - dai = dai1 - } - } - } - return newAppInfo(dai) -} - -func (ai *AppInfo) GetFileName() string { - return ai.filename -} - -func (ai *AppInfo) GetIcon() string { - return ai.icon -} - -func (ai *AppInfo) GetId() string { - return ai.id -} - -func (ai *AppInfo) GetActions() []desktopAction { - return ai.actions -} - -func (ai *AppInfo) IsInstalled() bool { - return ai.isInstalled -} - -func genInnerIdWithDesktopAppInfo(dai *desktopappinfo.DesktopAppInfo) string { - cmdline := dai.GetCommandline() - hasher := md5.New() - _, err := hasher.Write([]byte(cmdline)) - if err != nil { - logger.Warning("Write error:", err) - } - return desktopHashPrefix + hex.EncodeToString(hasher.Sum(nil)) -} - -func (ai *AppInfo) String() string { - if ai == nil { - return "" - } - desktopFile := ai.GetFileName() - icon := ai.GetIcon() - id := ai.GetId() - return fmt.Sprintf("", id, ai.innerId, icon, desktopFile) -} diff --git a/dock/bamf.go b/dock/bamf.go deleted file mode 100644 index 6dee15f7d..000000000 --- a/dock/bamf.go +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "github.com/godbus/dbus" - bamf "github.com/linuxdeepin/go-dbus-factory/org.ayatana.bamf" - x "github.com/linuxdeepin/go-x11-client" -) - -func getDesktopFromWindowByBamf(win x.Window) (string, error) { - bus, err := dbus.SessionBus() - if err != nil { - return "", err - } - matcher := bamf.NewMatcher(bus) - applicationObjPathStr, err := matcher.ApplicationForXid(0, uint32(win)) - if err != nil { - return "", err - } - applicationObjPath := dbus.ObjectPath(applicationObjPathStr) - if !applicationObjPath.IsValid() { - return "", nil - } - application, err := bamf.NewApplication(bus, applicationObjPath) - if err != nil { - return "", err - } - desktopFile, err := application.Application().DesktopFile(0) - if err != nil { - return "", err - } - return desktopFile, nil -} diff --git a/dock/daemon.go b/dock/daemon.go deleted file mode 100644 index ced8df175..000000000 --- a/dock/daemon.go +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/dde-daemon/loader" - - x "github.com/linuxdeepin/go-x11-client" -) - -type Daemon struct { - *loader.ModuleBase -} - -const moduleName = "dock" - -func NewDaemon(logger *log.Logger) *Daemon { - daemon := new(Daemon) - daemon.ModuleBase = loader.NewModuleBase(moduleName, daemon, logger) - return daemon -} - -func (d *Daemon) Stop() error { - if dockManager != nil { - dockManager.destroy() - dockManager = nil - } - - if globalXConn != nil { - globalXConn.Close() - globalXConn = nil - } - - return nil -} - -func (d *Daemon) startFailed() { - err := d.Stop() - if err != nil { - logger.Warning("Stop error:", err) - } -} - -func (d *Daemon) Start() error { - if dockManager != nil { - return nil - } - - var err error - - globalXConn, err = x.NewConn() - if err != nil { - d.startFailed() - return err - } - - initAtom() - initDir() - initPathDirCodeMap() - - service := loader.GetService() - - dockManager, err = newManager(service) - if err != nil { - d.startFailed() - return err - } - - err = dockManager.service.Export(dbusPath, dockManager, dockManager.syncConfig) - if err != nil { - d.startFailed() - return err - } - - err = service.RequestName(dbusServiceName) - if err != nil { - d.startFailed() - return err - } - - err = dockManager.syncConfig.Register() - if err != nil { - logger.Warning(err) - } - - err = service.Emit(dockManager, "ServiceRestarted") - if err != nil { - logger.Warning(err) - } - return nil -} - -func (d *Daemon) GetDependencies() []string { - return []string{} -} - -func (d *Daemon) Name() string { - return moduleName -} diff --git a/dock/desktop_file_path.go b/dock/desktop_file_path.go deleted file mode 100644 index 7adc9f55b..000000000 --- a/dock/desktop_file_path.go +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "path/filepath" - "strings" -) - -var pathDirCodeMap map[string]string -var pathCodeDirMap map[string]string - -const desktopExt = ".desktop" - -func initPathDirCodeMap() { - pathDirCodeMap = map[string]string{ - "/usr/share/applications/": "/S@", - "/usr/local/share/applications/": "/L@", - } - - dir := filepath.Join(homeDir, ".local/share/applications") - dir = addDirTrailingSlash(dir) - pathDirCodeMap[dir] = "/H@" - - dir = addDirTrailingSlash(scratchDir) - pathDirCodeMap[dir] = "/D@" - - logger.Debugf("pathDirCodeMap: %#v", pathDirCodeMap) - - pathCodeDirMap = make(map[string]string, len(pathDirCodeMap)) - for dir, code := range pathDirCodeMap { - pathCodeDirMap[code] = dir - } -} - -func getDesktopIdByFilePath(path string) string { - var desktopId string - for dir := range pathDirCodeMap { - if strings.HasPrefix(path, dir) { - desktopId = path[len(dir):] - desktopId = strings.Replace(desktopId, "/", "-", -1) - } - } - return desktopId -} - -func addDirTrailingSlash(dir string) string { - if len(dir) == 0 { - panic("length of dir is 0") - } - if dir[len(dir)-1] != '/' { - dir += "/" - } - return dir -} - -func addDesktopExt(str string) string { - if strings.HasSuffix(str, desktopExt) { - return str - } - return str + desktopExt -} - -func trimDesktopExt(str string) string { - if strings.HasSuffix(str, desktopExt) { - return str[:len(str)-len(desktopExt)] - } - return str -} - -func zipDesktopPath(path string) string { - for dir, code := range pathDirCodeMap { - if strings.HasPrefix(path, dir) { - path = code + path[len(dir):] - } - } - return trimDesktopExt(path) -} - -func unzipDesktopPath(path string) string { - head := path[:3] - for code, dir := range pathCodeDirMap { - if code == head { - path = dir + path[3:] - break - } - } - return addDesktopExt(path) -} diff --git a/dock/desktop_file_path_test.go b/dock/desktop_file_path_test.go deleted file mode 100644 index 147535745..000000000 --- a/dock/desktop_file_path_test.go +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -var deskotpFilePathTestMap = map[string]string{ - "/usr/share/applications/deepin-screenshot.desktop": "/S@deepin-screenshot", - "/usr/local/share/applications/wps-office-et.desktop": "/L@wps-office-et", - "/home/tp/.config/dock/scratch/docked:w:42f9e4a33162e38b2febbad0d9e39a3f.desktop": "/D@docked:w:42f9e4a33162e38b2febbad0d9e39a3f", - "/home/tp/.local/share/applications/webtorrent-desktop.desktop": "/H@webtorrent-desktop", -} - -func init() { - homeDir = "/home/tp/" - scratchDir = homeDir + ".config/dock/scratch/" - initPathDirCodeMap() -} - -func Test_addDesktopExt(t *testing.T) { - assert.Equal(t, addDesktopExt("0ad"), "0ad.desktop") - assert.Equal(t, addDesktopExt("0ad.desktop"), "0ad.desktop") - assert.Equal(t, addDesktopExt("0ad.desktop-x"), "0ad.desktop-x.desktop") -} - -func Test_trimDesktopExt(t *testing.T) { - assert.Equal(t, trimDesktopExt("deepin-movie"), "deepin-movie") - assert.Equal(t, trimDesktopExt("deepin-movie.desktop"), "deepin-movie") - assert.Equal(t, trimDesktopExt("deepin-movie.desktop-x"), "deepin-movie.desktop-x") -} - -func Test_zipDesktopPath(t *testing.T) { - for path, zipped := range deskotpFilePathTestMap { - assert.Equal(t, zipped, zipDesktopPath(path)) - } -} - -func Test_unzipDesktopPath(t *testing.T) { - for path, zipped := range deskotpFilePathTestMap { - assert.Equal(t, path, unzipDesktopPath(zipped)) - } -} - -func Test_getDesktopIdByFilePath(t *testing.T) { - path := "/usr/share/applications/deepin-screenshot.desktop" - desktopId := getDesktopIdByFilePath(path) - assert.Equal(t, desktopId, "deepin-screenshot.desktop") - - path = "/usr/share/applications/kde4/krita.desktop" - desktopId = getDesktopIdByFilePath(path) - assert.Equal(t, desktopId, "kde4-krita.desktop") - - path = "/home/tp/.local/share/applications/telegramdesktop.desktop" - desktopId = getDesktopIdByFilePath(path) - assert.Equal(t, desktopId, "telegramdesktop.desktop") - - path = "/home/tp/.local/share/applications/dirfortest/dir2/space test.desktop" - desktopId = getDesktopIdByFilePath(path) - assert.Equal(t, desktopId, "dirfortest-dir2-space test.desktop") -} - -func Test_addDirTrailingSlash(t *testing.T) { - dir := "/usr/shareapplication" - dir2 := addDirTrailingSlash(dir) - assert.Equal(t, dir2, dir+"/") - - dir3 := addDirTrailingSlash(dir2) - assert.Equal(t, dir3, dir2) -} diff --git a/dock/dock_dbusutil.go b/dock/dock_dbusutil.go deleted file mode 100644 index 6ac67bbe3..000000000 --- a/dock/dock_dbusutil.go +++ /dev/null @@ -1,111 +0,0 @@ -// Code generated by "dbusutil-gen -type AppEntry -import=github.com/linuxdeepin/go-x11-client=x app_entry.go"; DO NOT EDIT. - -package dock - -import ( - x "github.com/linuxdeepin/go-x11-client" -) - -func (v *AppEntry) setPropId(value string) (changed bool) { - if v.Id != value { - v.Id = value - v.emitPropChangedId(value) - return true - } - return false -} - -func (v *AppEntry) emitPropChangedId(value string) error { - return v.service.EmitPropertyChanged(v, "Id", value) -} - -func (v *AppEntry) setPropIsActive(value bool) (changed bool) { - if v.IsActive != value { - v.IsActive = value - v.emitPropChangedIsActive(value) - return true - } - return false -} - -func (v *AppEntry) emitPropChangedIsActive(value bool) error { - return v.service.EmitPropertyChanged(v, "IsActive", value) -} - -func (v *AppEntry) setPropName(value string) (changed bool) { - if v.Name != value { - v.Name = value - v.emitPropChangedName(value) - return true - } - return false -} - -func (v *AppEntry) emitPropChangedName(value string) error { - return v.service.EmitPropertyChanged(v, "Name", value) -} - -func (v *AppEntry) setPropIcon(value string) (changed bool) { - if v.Icon != value { - v.Icon = value - v.emitPropChangedIcon(value) - return true - } - return false -} - -func (v *AppEntry) emitPropChangedIcon(value string) error { - return v.service.EmitPropertyChanged(v, "Icon", value) -} - -func (v *AppEntry) setPropDesktopFile(value string) (changed bool) { - if v.DesktopFile != value { - v.DesktopFile = value - v.emitPropChangedDesktopFile(value) - return true - } - return false -} - -func (v *AppEntry) emitPropChangedDesktopFile(value string) error { - return v.service.EmitPropertyChanged(v, "DesktopFile", value) -} - -func (v *AppEntry) setPropCurrentWindow(value x.Window) (changed bool) { - if v.CurrentWindow != value { - v.CurrentWindow = value - v.emitPropChangedCurrentWindow(value) - return true - } - return false -} - -func (v *AppEntry) emitPropChangedCurrentWindow(value x.Window) error { - return v.service.EmitPropertyChanged(v, "CurrentWindow", value) -} - -func (v *AppEntry) setPropIsDocked(value bool) (changed bool) { - if v.IsDocked != value { - v.IsDocked = value - v.emitPropChangedIsDocked(value) - return true - } - return false -} - -func (v *AppEntry) emitPropChangedIsDocked(value bool) error { - return v.service.EmitPropertyChanged(v, "IsDocked", value) -} - -func (v *AppEntry) setPropWindowInfos(value windowInfosType) (changed bool) { - if !v.WindowInfos.Equal(value) { - v.WindowInfos = value - v.emitPropChangedWindowInfos(value) - return true - } - return false -} - -func (v *AppEntry) emitPropChangedWindowInfos(value windowInfosType) error { - return v.service.EmitPropertyChanged(v, "WindowInfos", value) -} diff --git a/dock/dock_manager.go b/dock/dock_manager.go deleted file mode 100644 index 54ab222cc..000000000 --- a/dock/dock_manager.go +++ /dev/null @@ -1,592 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "encoding/json" - "errors" - "fmt" - "os" - "strings" - "sync" - "time" - - "github.com/godbus/dbus" - libApps "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.apps" - kwayland "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.kwayland" - kwin "github.com/linuxdeepin/go-dbus-factory/org.kde.kwin" - launcher "github.com/linuxdeepin/go-dbus-factory/com.deepin.dde.daemon.launcher" - libDDELauncher "github.com/linuxdeepin/go-dbus-factory/com.deepin.dde.launcher" - sessionmanager "github.com/linuxdeepin/go-dbus-factory/com.deepin.sessionmanager" - wm "github.com/linuxdeepin/go-dbus-factory/com.deepin.wm" - wmswitcher "github.com/linuxdeepin/go-dbus-factory/com.deepin.wmswitcher" - configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" - "github.com/linuxdeepin/go-gir/gio-2.0" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/dbusutil/gsprop" - "github.com/linuxdeepin/go-lib/dbusutil/proxy" - x "github.com/linuxdeepin/go-x11-client" - - "github.com/linuxdeepin/dde-daemon/common/dsync" -) - -type Manager struct { - PropsMu sync.RWMutex - Entries AppEntries - HideMode gsprop.Enum `prop:"access:rw"` - DisplayMode gsprop.Enum `prop:"access:rw"` - Position gsprop.Enum `prop:"access:rw"` - IconSize gsprop.Uint `prop:"access:rw"` - ShowTimeout gsprop.Uint `prop:"access:rw"` - HideTimeout gsprop.Uint `prop:"access:rw"` - WindowSizeEfficient gsprop.Uint `prop:"access:rw"` - WindowSizeFashion gsprop.Uint `prop:"access:rw"` - DockedApps gsprop.Strv - Opacity gsprop.Double - HideState HideStateType - FrontendWindowRect *Rect - - service *dbusutil.Service - sysService *dbusutil.Service - sessionSigLoop *dbusutil.SignalLoop - sysSigLoop *dbusutil.SignalLoop - syncConfig *dsync.Config - clientList windowSlice - clientListInitEnd bool - windowInfoMap map[x.Window]WindowInfoImp - windowInfoMapMutex sync.RWMutex - settings *gio.Settings - appearanceSettings *gio.Settings - pluginSettings *pluginSettingsStorage - - entryDealChan chan func() - rootWindow x.Window - activeWindow WindowInfoImp - activeWindowOld WindowInfoImp - activeWindowMu sync.Mutex - - waylandManager *WaylandManager - - ddeLauncherVisible bool - ddeLauncherVisibleMu sync.Mutex - - smartHideModeTimer *time.Timer - smartHideModeMutex sync.Mutex - - entryCount uint - identifyWindowFuns []*IdentifyWindowFunc - identifyKWindowFuns []*IdentifyKWindowFunc - windowPatterns WindowPatterns - - forceQuitAppStatus forceQuitAppType - windowActMu sync.Mutex - hideRequestDockAndUndockByNameList []string - - // dbus objects: - launcher launcher.Launcher - ddeLauncher libDDELauncher.Launcher - wm wm.Wm - appsObj libApps.Apps - startManager sessionmanager.StartManager - wmSwitcher wmswitcher.WMSwitcher - waylandWM kwayland.WindowManager - kwin kwin.KWin - wmName string - isWaylandSession bool - isMultiTaskViewShow bool - //nolint - signals *struct { - ServiceRestarted struct{} - EntryAdded struct { - path dbus.ObjectPath - index int32 - } - - EntryRemoved struct { - entryId string - } - - PluginSettingsSynced struct{} - DockAppSettingsSynced struct{} - } -} - -const ( - dockSchema = "com.deepin.dde.dock" - appearanceSchema = "com.deepin.dde.appearance" - settingKeyHideMode = "hide-mode" - settingKeyDisplayMode = "display-mode" - settingKeyPosition = "position" - settingKeyIconSize = "icon-size" - settingKeyDockedApps = "docked-apps" - settingKeyShowTimeout = "show-timeout" - settingKeyHideTimeout = "hide-timeout" - settingKeyWindowSizeFashion = "window-size-fashion" - settingKeyWindowSizeEfficient = "window-size-efficient" - settingKeyWinIconPreferredApps = "win-icon-preferred-apps" - settingKeyOpacity = "opacity" - settingKeyPluginSettings = "plugin-settings" - settingKeyForceQuitApp = "force-quit-app" - - frontendWindowWmClass = "dde-dock" - - dbusServiceName = "com.deepin.dde.daemon.Dock" - dbusPath = "/com/deepin/dde/daemon/Dock" - dbusInterface = dbusServiceName -) - -const ( - DSettingsAppID = "org.deepin.dde.daemon" - DSettingsDockName = "org.deepin.dde.daemon.dock" - DSettingsKeyHideRequestDockAndUndockByName = "hideRequestDockAndUndockByName" -) - -func newManager(service *dbusutil.Service) (*Manager, error) { - m := new(Manager) - m.service = service - var err error - m.sysService, err = dbusutil.NewSystemService() - if err != nil { - return nil, err - } - err = m.init() - if err != nil { - return nil, err - } - return m, nil -} - -func (m *Manager) GetInterfaceName() string { - return dbusInterface -} - -func (m *Manager) destroy() { - if m.smartHideModeTimer != nil { - m.smartHideModeTimer.Stop() - m.smartHideModeTimer = nil - } - - if m.settings != nil { - m.settings.Unref() - m.settings = nil - } - - m.launcher.RemoveHandler(proxy.RemoveAllHandlers) - m.ddeLauncher.RemoveHandler(proxy.RemoveAllHandlers) - m.sessionSigLoop.Stop() - m.sysSigLoop.Stop() - m.syncConfig.Destroy() - - err := m.service.StopExport(m) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) launch(desktopFile string, timestamp uint32, files []string) { - err := m.startManager.LaunchApp(dbus.FlagNoAutoStart, desktopFile, timestamp, files) - if err != nil { - logger.Warningf("launch %q failed: %v", desktopFile, err) - } -} - -// ActivateWindow会激活给定id的窗口,被激活的窗口通常会成为焦点窗口。 -func (m *Manager) ActivateWindow(win uint32) *dbus.Error { - winInfo, err := m.getWindowInfo(x.Window(win)) - if err != nil { - return dbusutil.ToError(err) - } - - err = winInfo.activate() - - if err != nil { - logger.Warning("Activate window failed:", err) - return dbusutil.ToError(err) - } - return nil -} - -// CloseWindow会将传入id的窗口关闭。 -func (m *Manager) CloseWindow(win uint32) *dbus.Error { - winInfo, err := m.getWindowInfo(x.Window(win)) - if err != nil { - return dbusutil.ToError(err) - } - - err = winInfo.activate() - if err != nil { - logger.Warning("Activate window failed:", err) - return dbusutil.ToError(err) - } - - err = winInfo.close(0) - if err != nil { - logger.Warning("Close window failed:", err) - return dbusutil.ToError(err) - } - - return nil -} - -func (m *Manager) MaximizeWindow(win uint32) *dbus.Error { - winInfo, err := m.getWindowInfo(x.Window(win)) - if err != nil { - return dbusutil.ToError(err) - } - - err = winInfo.activate() - if err != nil { - logger.Warning("active window failed:", err) - return dbusutil.ToError(err) - } - - err = winInfo.maximize() - - if err != nil { - logger.Warning("maximize window failed:", err) - return dbusutil.ToError(err) - } - return nil -} - -func (m *Manager) MinimizeWindow(win uint32) *dbus.Error { - winInfo, err := m.getWindowInfo(x.Window(win)) - if err != nil { - return dbusutil.ToError(err) - } - - err = winInfo.minimize() - if err != nil { - logger.Warning("minimize window failed:", err) - return dbusutil.ToError(err) - } - return nil -} - -func (m *Manager) MakeWindowAbove(win uint32) *dbus.Error { - winInfo, err := m.getWindowInfo(x.Window(win)) - if err != nil { - return dbusutil.ToError(err) - } - - err = winInfo.activate() - if err != nil { - logger.Warning("active window failed:", err) - return dbusutil.ToError(err) - } - - err = winInfo.makeWindowAbove() - - if err != nil { - logger.Warning("make window above failed:", err) - return dbusutil.ToError(err) - } - return nil -} - -func (m *Manager) MoveWindow(win uint32) *dbus.Error { - err := m.ActivateWindow(win) - if err != nil { - return err - } - - err1 := moveWindow(x.Window(win)) - if err1 != nil { - logger.Warning("move window failed:", err) - return dbusutil.ToError(err1) - } - return nil -} - -func (m *Manager) PreviewWindow(win uint32) *dbus.Error { - err := m.wm.PreviewWindow(dbus.FlagNoAutoStart, win) - return dbusutil.ToError(err) -} - -func (m *Manager) CancelPreviewWindow() *dbus.Error { - err := m.wm.CancelPreviewWindow(dbus.FlagNoAutoStart) - return dbusutil.ToError(err) -} - -// for debug -func (m *Manager) GetEntryIDs() (list []string, busErr *dbus.Error) { - entries := &m.Entries - entries.mu.RLock() - list = make([]string, 0, len(entries.items)) - for _, entry := range entries.items { - var appId string - if entry.appInfo != nil { - appId = entry.appInfo.GetId() - } else { - appId = entry.innerId - } - list = append(list, appId) - } - entries.mu.RUnlock() - return list, nil -} - -func (m *Manager) SetFrontendWindowRect(x, y int32, width, height uint32) *dbus.Error { - if m.FrontendWindowRect.X == x && - m.FrontendWindowRect.Y == y && - m.FrontendWindowRect.Width == width && - m.FrontendWindowRect.Height == height { - logger.Debug("SetFrontendWindowRect no changed") - return nil - } - m.FrontendWindowRect.X = x - m.FrontendWindowRect.Y = y - m.FrontendWindowRect.Width = width - m.FrontendWindowRect.Height = height - err := m.service.EmitPropertyChanged(m, "FrontendWindowRect", m.FrontendWindowRect) - if err != nil { - logger.Warning("EmitPropertyChanged error:", err) - } - m.updateHideState(false) - return nil -} - -func (m *Manager) IsDocked(desktopFile string) (docked bool, busErr *dbus.Error) { - desktopFile = toLocalPath(desktopFile) - entry, err := m.getDockedAppEntryByDesktopFilePath(desktopFile) - if err != nil { - return false, dbusutil.ToError(err) - } - return entry != nil, nil -} - -func (m *Manager) requestDock(desktopFile string, index int32) (bool, error) { - logger.Debug("requestDock", desktopFile, index) - desktopFile = toLocalPath(desktopFile) - appInfo := NewAppInfoFromFile(desktopFile) - if appInfo == nil { - return false, errors.New("invalid desktopFilePath") - } - var newlyCreated bool - entry := m.Entries.GetByInnerId(appInfo.innerId) - if entry == nil { - entry = newAppEntry(m, appInfo.innerId, appInfo) - newlyCreated = true - } - - docked, err := m.dockEntry(entry) - if err != nil { - return false, err - } - - if newlyCreated { - err = m.exportAppEntry(entry) - if err != nil { - return false, err - } - m.Entries.Insert(entry, int(index)) - } - - if docked { - // need to save after insert - m.saveDockedApps() - } - return docked, nil -} - -func (m *Manager) RequestDock(desktopFile string, index int32) (docked bool, busErr *dbus.Error) { - docked, err := m.requestDock(desktopFile, index) - return docked, dbusutil.ToError(err) -} - -func (m *Manager) RequestUndock(desktopFile string) (undocked bool, busErr *dbus.Error) { - undocked, err := m.requestUndock(desktopFile) - return undocked, dbusutil.ToError(err) -} - -func (m *Manager) requestUndock(desktopFile string) (bool, error) { - desktopFile = toLocalPath(desktopFile) - entry, err := m.getDockedAppEntryByDesktopFilePath(desktopFile) - if err != nil { - return false, err - } - if entry == nil { - return false, nil - } - m.undockEntry(entry) - return true, nil -} - -func (m *Manager) MoveEntry(index, newIndex int32) *dbus.Error { - err := m.Entries.Move(int(index), int(newIndex)) - if err != nil { - logger.Warning("MoveEntry failed:", err) - return dbusutil.ToError(err) - } - logger.Debug("MoveEntry ok") - m.saveDockedApps() - return nil -} - -func (m *Manager) IsOnDock(desktopFile string) (onDock bool, busErr *dbus.Error) { - desktopFile = toLocalPath(desktopFile) - entry, err := m.Entries.GetByDesktopFilePath(desktopFile) - if err != nil { - return false, dbusutil.ToError(err) - } - return entry != nil, nil -} - -func (m *Manager) QueryWindowIdentifyMethod(wid uint32) (method string, busErr *dbus.Error) { - m.Entries.mu.RLock() - defer m.Entries.mu.RUnlock() - - for _, entry := range m.Entries.items { - winInfo, ok := entry.windows[x.Window(wid)] - if ok { - appInfo := winInfo.getAppInfo() - if appInfo != nil { - return appInfo.identifyMethod, nil - } else { - return "Failed", nil - } - } - } - return "", dbusutil.ToError(fmt.Errorf("window %d not found", wid)) -} - -func (m *Manager) GetDockedAppsDesktopFiles() (desktopFiles []string, busErr *dbus.Error) { - for _, entry := range m.Entries.FilterDocked() { - if entry.appInfo != nil { - desktopFiles = append(desktopFiles, entry.appInfo.GetFileName()) - } - } - return desktopFiles, nil -} - -func (m *Manager) GetPluginSettings() (jsonStr string, busErr *dbus.Error) { - jsonStr, err := m.pluginSettings.getJsonStr() - if err != nil { - return "", dbusutil.ToError(err) - } - return jsonStr, nil -} - -func (m *Manager) SetPluginSettings(jsonStr string) *dbus.Error { - var v pluginSettings - err := json.Unmarshal([]byte(jsonStr), &v) - if err != nil { - return dbusutil.ToError(err) - } - m.pluginSettings.set(v) - return nil -} - -func (m *Manager) MergePluginSettings(jsonStr string) *dbus.Error { - var v pluginSettings - err := json.Unmarshal([]byte(jsonStr), &v) - if err != nil { - return dbusutil.ToError(err) - } - - m.pluginSettings.merge(v) - return nil -} - -func (m *Manager) RemovePluginSettings(key1 string, key2List []string) *dbus.Error { - m.pluginSettings.remove(key1, key2List) - return nil -} - -// 在Dock添加上添加图标的时候,有时候windowInfo不完整 -// 会重复尝试10次,为了避免阻塞其他功能,放在goroutine里处理 -// 窗口的增加和减少是有顺序的,在这个单独的goroutine里处理 -func (m *Manager) accessEntries() { - for { - fun := <-m.entryDealChan - fun() - } -} - -func (m *Manager) findWindowByXidX(win x.Window) (winInfo WindowInfoImp) { - m.windowInfoMapMutex.RLock() - winInfo, ok := m.windowInfoMap[win] - m.windowInfoMapMutex.RUnlock() - if ok { - val, ret := (winInfo).(*WindowInfo) - if ret { - return val - } - } - return nil -} - -func (m *Manager) findWindowByXidK(win x.Window) (winInfo WindowInfoImp) { - m.waylandManager.mu.Lock() - for _, windowInfo := range m.waylandManager.windows { - if windowInfo.getXid() == win { - m.waylandManager.mu.Unlock() - return windowInfo - } - } - m.waylandManager.mu.Unlock() - return nil -} - -func (m *Manager) findWindowByXid(win x.Window) (winInfo WindowInfoImp) { - winInfo = m.findWindowByXidX(win) - if winInfo != nil { - return winInfo - } - - sessionType := os.Getenv("XDG_SESSION_TYPE") - if strings.Contains(sessionType, "wayland") { - return m.findWindowByXidK(win) - } - return -} - -func (m *Manager) findXWindowInfo(win x.Window) *WindowInfo { - m.windowInfoMapMutex.RLock() - winInfo := m.windowInfoMap[win] - m.windowInfoMapMutex.RUnlock() - val, ok := (winInfo).(*WindowInfo) - if ok { - return val - } - return nil -} - -func (m *Manager) initDSettings(conn *dbus.Conn) { - ds := configManager.NewConfigManager(conn) - dsPath, err := ds.AcquireManager(0, DSettingsAppID, DSettingsDockName, "") - if err != nil { - logger.Warning(err) - return - } - dockDS, err := configManager.NewManager(conn, dsPath) - if err != nil { - logger.Warning(err) - return - } - getHideRequestDockAndUndockByNameList := func() { - v, err := dockDS.Value(0, DSettingsKeyHideRequestDockAndUndockByName) - if err != nil { - logger.Warning(err) - return - } - itemList := v.Value().([]dbus.Variant) - for _, i := range itemList { - m.hideRequestDockAndUndockByNameList = append(m.hideRequestDockAndUndockByNameList, i.Value().(string)) - } - } - getHideRequestDockAndUndockByNameList() - dockDS.InitSignalExt(m.sysSigLoop, true) - // 监听dsg配置变化 - _, err = dockDS.ConnectValueChanged(func(key string) { - switch key { - case DSettingsKeyHideRequestDockAndUndockByName: - getHideRequestDockAndUndockByNameList() - } - }) - if err != nil { - logger.Warning(err) - } -} diff --git a/dock/dock_manager_dock_app.go b/dock/dock_manager_dock_app.go deleted file mode 100644 index ca5051059..000000000 --- a/dock/dock_manager_dock_app.go +++ /dev/null @@ -1,230 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "errors" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strings" - - dutils "github.com/linuxdeepin/go-lib/utils" -) - -const dockedItemTemplate string = `[Desktop Entry] -Name=%s -Exec=%s -Icon=%s -Type=Application -Terminal=false -StartupNotify=false -` - -type dockedItemInfo struct { - Name, Icon, Exec string -} - -func createScratchDesktopFile(id, title, icon, cmd string) (string, error) { - logger.Debugf("create scratch file for %q", id) - filename := filepath.Join(scratchDir, addDesktopExt(id)) - dockedItem := dockedItemInfo{title, icon, cmd} - logger.Debugf("dockedItem: %#v", dockedItem) - content := fmt.Sprintf(dockedItemTemplate, dockedItem.Name, dockedItem.Exec, dockedItem.Icon) - // #nosec G306 - err := ioutil.WriteFile(filename, []byte(content), 0644) - if err != nil { - return "", err - } - return filename, nil -} - -func removeScratchFiles(desktopFile string) { - fileNoExt := trimDesktopExt(desktopFile) - logger.Debug("removeScratchFiles", fileNoExt) - extList := []string{".desktop", ".sh", ".png"} - for _, ext := range extList { - file := fileNoExt + ext - if dutils.IsFileExist(file) { - logger.Debugf("remove scratch file %q", file) - err := os.Remove(file) - if err != nil { - logger.Warningf("failed to remove scratch file %q: %v", file, err) - } - } - } -} - -func createScratchDesktopFileWithAppEntry(entry *AppEntry) (string, error) { - // #nosec G301 - err := os.MkdirAll(scratchDir, 0755) - if err != nil { - return "", err - } - - if entry.appInfo != nil { - desktopFile := entry.appInfo.GetFileName() - newDesktopFile := filepath.Join(scratchDir, entry.appInfo.innerId+".desktop") - err := copyFileContents(desktopFile, newDesktopFile) - if err != nil { - return "", err - } - return newDesktopFile, nil - } - - if entry.current == nil { - return "", errors.New("entry.current is nil") - } - appId := entry.current.getInnerId() - title := entry.current.getDisplayName() - // icon - icon := entry.current.getIcon() - if strings.HasPrefix(icon, "data:image") { - path, err := dataUriToFile(icon, filepath.Join(scratchDir, appId+".png")) - if err != nil { - logger.Warning(err) - icon = "" - } else { - icon = path - } - } - if icon == "" { - icon = "application-default-icon" - } - - // cmd - scriptContent := entry.getExec(false) - scriptFile := filepath.Join(scratchDir, appId+".sh") - // #nosec G306 - err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0744) - if err != nil { - return "", err - } - cmd := scriptFile + " %U" - - file, err := createScratchDesktopFile(appId, title, icon, cmd) - if err != nil { - return "", err - } - return file, nil -} - -func (m *Manager) getDockedAppEntryByDesktopFilePath(desktopFilePath string) (*AppEntry, error) { - return getByDesktopFilePath(m.Entries.FilterDocked(), desktopFilePath) -} - -func (m *Manager) saveDockedApps() { - var list []string - for _, entry := range m.Entries.FilterDocked() { - path := entry.appInfo.GetFileName() - list = append(list, zipDesktopPath(path)) - } - m.DockedApps.Set(list) -} - -func needScratchDesktop(appInfo *AppInfo) bool { - if appInfo == nil { - logger.Debug("needScratchDesktop: yes, appInfo is nil") - return true - } - if appInfo.IsInstalled() { - logger.Debug("needScratchDesktop: no, desktop is installed") - return false - } - file := appInfo.GetFileName() - if isFileInDir(file, scratchDir) { - logger.Debug("needScratchDesktop: no, desktop in scratchDir") - return false - } - logger.Debug("needScratchDesktop: yes") - return true -} - -func (m *Manager) dockEntry(entry *AppEntry) (bool, error) { - entry.PropsMu.Lock() - - if entry.IsDocked { - logger.Warningf("dockEntry failed: entry %v is docked", entry.Id) - entry.PropsMu.Unlock() - return false, nil - } - if needScratchDesktop(entry.appInfo) { - file, err := createScratchDesktopFileWithAppEntry(entry) - if err != nil { - logger.Warning("createScratchDesktopFileWithAppEntry failed", err) - entry.PropsMu.Unlock() - return false, err - } - logger.Debug("dockEntry: createScratchDesktopFile successfully", file) - appInfo := NewAppInfoFromFile(file) - entry.setAppInfo(appInfo) - entry.updateIcon() - entry.innerId = entry.appInfo.innerId - } - - entry.setPropIsDocked(true) - entry.updateMenu() - entry.PropsMu.Unlock() - return true, nil -} - -func isFileInDir(file, dir string) bool { - fileDir := filepath.Dir(file) - return fileDir == dir -} - -func (m *Manager) undockEntry(entry *AppEntry) { - entry.PropsMu.RLock() - if !entry.IsDocked { - logger.Warningf("undockEntry failed: entry %v is not docked", entry.Id) - entry.PropsMu.RUnlock() - return - } - - if entry.appInfo == nil { - logger.Warning("undockEntry failed: entry.appInfo is nil") - entry.PropsMu.RUnlock() - return - } - desktop := entry.appInfo.GetFileName() - logger.Debugf("undockEntry desktop: %q", desktop) - isDesktopInScratchDir := false - if isFileInDir(desktop, scratchDir) { - isDesktopInScratchDir = true - removeScratchFiles(entry.appInfo.GetFileName()) - } - - hasWin := entry.hasWindow() - entry.PropsMu.RUnlock() - - if !hasWin { - m.removeAppEntry(entry) - } else { - entry.PropsMu.Lock() - - if isDesktopInScratchDir && entry.current != nil { - if strings.HasPrefix(filepath.Base(desktop), windowHashPrefix) { - // desktop base starts with w: - // 由于有 Pid 识别方法在,在这里不能用 m.identifyWindow 再次识别 - entry.innerId = entry.current.getInnerId() - entry.setAppInfo(nil) - } else { - // desktop base starts with d: - var newAppInfo *AppInfo - logger.Debug("re-identify window", entry.current.getInnerId()) - entry.innerId, newAppInfo = m.identifyWindow(entry.current) - entry.setAppInfo(newAppInfo) - } - } - entry.updateIcon() - entry.setPropIsDocked(false) - entry.updateName() - entry.updateMenu() - - entry.PropsMu.Unlock() - } - m.saveDockedApps() -} diff --git a/dock/dock_manager_entries.go b/dock/dock_manager_entries.go deleted file mode 100644 index 79aa44423..000000000 --- a/dock/dock_manager_entries.go +++ /dev/null @@ -1,187 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "fmt" - "sort" - - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/go-x11-client/util/wm/ewmh" - "github.com/linuxdeepin/dde-daemon/session/common" -) - -func (m *Manager) allocEntryId() string { - m.PropsMu.Lock() - - num := m.entryCount - m.entryCount++ - - m.PropsMu.Unlock() - - return fmt.Sprintf("e%dT%x", num, getCurrentTimestamp()) -} - -func (m *Manager) markAppLaunched(appInfo *AppInfo) { - if !m.clientListInitEnd || appInfo == nil { - return - } - file := appInfo.GetFileName() - logger.Debug("markAppLaunched", file) - - go func() { - err := common.ActivateSysDaemonService(m.appsObj.ServiceName_()) - if err != nil { - logger.Warning(err) - } - - err = m.appsObj.LaunchedRecorder().MarkLaunched(0, file) - if err != nil { - logger.Debug(err) - } - }() -} - -func (m *Manager) shouldShowOnDock(winInfo WindowInfoImp) bool { - switch winInfo.(type) { - case *WindowInfo: - win := winInfo.getXid() - isReg := m.isWindowRegistered(win) - clientListContains := m.clientList.Contains(win) - shouldSkip := winInfo.shouldSkip() - isGood := isGoodWindow(win) - logger.Debugf("isReg: %v, client list contains: %v, shouldSkip: %v, isGood: %v", - isReg, clientListContains, shouldSkip, isGood) - - showOnDock := isReg && clientListContains && isGood && !shouldSkip - return showOnDock - - case *KWindowInfo: - return !winInfo.shouldSkip() - default: - return false - } -} - -func (m *Manager) attachOrDetachWindow(winInfo WindowInfoImp) { - win := winInfo.getXid() - showOnDock := m.shouldShowOnDock(winInfo) - logger.Debugf("win %v showOnDock? %v", win, showOnDock) - - // attach 或 detach 操作顺序执行 - m.windowActMu.Lock() - defer m.windowActMu.Unlock() - - entry := winInfo.getEntry() - if entry != nil { - if !showOnDock { - m.detachWindow(winInfo) - } else { - logger.Debugf("win %v nothing to do", win) - } - } else { - if winInfo.getEntryInnerId() == "" { - logger.Debugf("winInfo.entryInnerId is empty, call identifyWindow, win: %d", winInfo.getXid()) - entryInnerId, appInfo := m.identifyWindow(winInfo) - winInfo.setEntryInnerId(entryInnerId) - winInfo.setAppInfo(appInfo) - m.markAppLaunched(appInfo) - } else { - logger.Debugf("win %v identified", win) - } - - // winInfo初始化后影响判断是否在任务栏显示图标 - if m.shouldShowOnDock(winInfo) { - m.attachWindow(winInfo) - } - } -} - -func (m *Manager) initClientList() { - clientList, err := ewmh.GetClientList(globalXConn).Reply(globalXConn) - if err != nil { - logger.Warning("Get client list failed:", err) - return - } - winSlice := windowSlice(clientList) - sort.Sort(winSlice) - m.clientList = winSlice - for _, win := range winSlice { - winInfo := m.registerWindow(win) - m.attachOrDetachWindow(winInfo) - } -} - -func (m *Manager) initDockedApps() { - dockedApps := uniqStrSlice(m.DockedApps.Get()) - for _, app := range dockedApps { - m.appendDockedApp(app) - } - m.saveDockedApps() -} - -func (m *Manager) exportAppEntry(e *AppEntry) error { - err := m.service.Export(dbus.ObjectPath(entryDBusObjPathPrefix+e.Id), e) - if err != nil { - logger.Warning("failed to export AppEntry:", err) - return err - } - return nil -} - -func (m *Manager) appendDockedApp(app string) { - logger.Debugf("appendDockedApp %q", app) - appInfo := NewDockedAppInfo(app) - if appInfo == nil { - logger.Warning("appendDockedApp failed: appInfo is nil") - return - } - - entry := newAppEntry(m, appInfo.innerId, appInfo) - entry.setPropIsDocked(true) - entry.updateMenu() - err := m.exportAppEntry(entry) - if err == nil { - m.Entries.Append(entry) - } -} - -func (m *Manager) removeAppEntry(e *AppEntry) { - if e == nil { - return - } - logger.Info("removeAppEntry id:", e.Id) - m.Entries.Remove(e) -} - -func (m *Manager) attachWindow(winInfo WindowInfoImp) { - entry := m.Entries.GetByInnerId(winInfo.getEntryInnerId()) - - if entry != nil { - // existed - entry.attachWindow(winInfo) - } else { - entry = newAppEntry(m, winInfo.getEntryInnerId(), winInfo.getAppInfo()) - ok := entry.attachWindow(winInfo) - if ok { - err := m.exportAppEntry(entry) - if err == nil { - m.Entries.Append(entry) - } - } - } -} - -func (m *Manager) detachWindow(winInfo WindowInfoImp) { - entry := m.Entries.getByWindowId(winInfo.getXid()) - if entry == nil { - logger.Warningf("entry of window %d is nil", winInfo.getXid()) - return - } - needRemove := entry.detachWindow(winInfo) - if needRemove { - m.removeAppEntry(entry) - } -} diff --git a/dock/dock_manager_hide_state.go b/dock/dock_manager_hide_state.go deleted file mode 100644 index 0e505fb48..000000000 --- a/dock/dock_manager_hide_state.go +++ /dev/null @@ -1,387 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "errors" - "time" - - x "github.com/linuxdeepin/go-x11-client" - "github.com/linuxdeepin/go-x11-client/util/wm/ewmh" -) - -func max(a, b int) int { - if a < b { - return b - } - return a -} - -func min(a, b int) int { - if a < b { - return a - } - return b -} - -func hasIntersection(rectA, rectB *Rect) bool { - if rectA == nil || rectB == nil { - logger.Warning("hasIntersection rectA or rectB is nil") - return false - } - x, y, w, h := rectA.Pieces() - x1, y1, w1, h1 := rectB.Pieces() - ax := max(x, x1) - ay := max(y, y1) - bx := min(x+w, x1+w1) - by := min(y+h, y1+h1) - return ax < bx && ay < by -} - -func (m *Manager) hasIntersectionK(rectA, rectB *Rect) bool { - if rectA == nil || rectB == nil { - logger.Warning("hasIntersectionK rectA or rectB is nil") - return false - } - x, y, w, h := rectA.Pieces() - x1, y1, w1, h1 := rectB.Pieces() - ax := max(x, x1) - ay := max(y, y1) - bx := min(x+w, x1+w1) - by := min(y+h, y1+h1) - positionVal := m.Position.Get() - logger.Debug("positionVal=", positionVal) - if positionVal == int32(positionRight) || positionVal == int32(positionLeft) { - return ax <= bx && ay < by - } else if positionVal == int32(positionTop) || positionVal == int32(positionBottom) { - return ax < bx && ay <= by - } else { - return ax < bx && ay < by - } -} - -func (m *Manager) getActiveWinGroup(activeWin x.Window) (ret []x.Window) { - - ret = []x.Window{activeWin} - - list, err := ewmh.GetClientListStacking(globalXConn).Reply(globalXConn) - if err != nil { - logger.Warning(err) - return - } - - idx := -1 - for i, win := range list { - if win == activeWin { - idx = i - break - } - } - if idx == -1 { - logger.Warning("getActiveWinGroup: not found active window in clientListStacking") - return - } else if idx == 0 { - return - } - - aPid := getWmPid(activeWin) - aLeaderWin, _ := getWmClientLeader(activeWin) - - for i := idx - 1; i >= 0; i-- { - win := list[i] - pid := getWmPid(win) - if aPid != 0 && pid == aPid { - // ok - ret = append(ret, win) - continue - } - - wmClass, _ := getWmClass(win) - if wmClass != nil && wmClass.Class == frontendWindowWmClass { - // skip over frontend window - continue - } - - leaderWin, _ := getWmClientLeader(win) - if aLeaderWin != 0 && leaderWin == aLeaderWin { - // ok - ret = append(ret, win) - continue - } - - aboveWin := list[i+1] - aboveWinTransientFor, _ := getWmTransientFor(aboveWin) - if aboveWinTransientFor != 0 && aboveWinTransientFor == win { - // ok - ret = append(ret, win) - continue - } - - break - } - return -} - -func (m *Manager) isWindowDockOverlap(win x.Window) (bool, error) { - // overlap condition: - // window type is not desktop - // window opacity is not zero - // window showing and on current workspace, - // window dock rect has intersection - - windowType, err := ewmh.GetWMWindowType(globalXConn, win).Reply(globalXConn) - - if err == nil && atomsContains(windowType, atomNetWmWindowTypeDesktop) { - return false, nil - } - - opacity, err := getWmWindowOpacity(win) - if err == nil && opacity == 0 { - return false, nil - } - - if isHiddenPre(win) || (!onCurrentWorkspacePre(win)) { - logger.Debugf("window %v is hidden or not on current workspace", win) - return false, nil - } - - winRect, err := getWindowGeometry(globalXConn, win) - if err != nil { - logger.Warning("Get target window geometry failed", err) - return false, err - } - - // 与dock区域完全重合的情况认为就是dock本身 - if winRect.X == m.FrontendWindowRect.X && - winRect.Y == m.FrontendWindowRect.Y && - winRect.Height == m.FrontendWindowRect.Height && - winRect.Width == m.FrontendWindowRect.Width { - logger.Warning("FrontendWindowRect' geometry is the same as winRect' geometry") - return false, nil - } - logger.Debug("window rect:", winRect) - logger.Debug("dock rect:", m.FrontendWindowRect) - return hasIntersection(winRect, m.FrontendWindowRect), nil -} - -const ( - ddeLauncherWMClass = "dde-launcher" -) - -func isDDELauncher(win x.Window) (bool, error) { - winClass, err := getWmClass(win) - if err != nil { - return false, err - } - return winClass.Instance == ddeLauncherWMClass, nil -} - -func (m *Manager) getActiveWindow() (activeWin WindowInfoImp) { - m.activeWindowMu.Lock() - if m.activeWindow == nil { - activeWin = m.activeWindowOld - } else { - activeWin = m.activeWindow - } - m.activeWindowMu.Unlock() - return -} - -func (m *Manager) shouldHideOnSmartHideModeX(activeWin x.Window) (bool, error) { - isLauncher, err := isDDELauncher(activeWin) - if err != nil { - logger.Warning(err) - } - if isLauncher { - // dde launcher is invisible, but it is still active window - logger.Debug("shouldHideOnSmartHideMode: active window is dde launcher") - return false, nil - } - - isShowDesktop, err := ewmh.GetShowingDesktop(globalXConn).Reply(globalXConn) - if err != nil { - logger.Warning(err) - } - - // 当显示桌面时,不去隐藏任务栏 - if isShowDesktop { - return false, nil - } - - list, err := ewmh.GetClientListStacking(globalXConn).Reply(globalXConn) - if err != nil { - logger.Warning(err) - } - - logger.Debug("shouldHideOnSmartHideMode: current window stack list", list) - - // 当激活的窗口有变化时,去遍历当前的窗口栈中的窗口,而不只是激活的窗口,看是否有窗口和任务栏显示有重叠 - for _, win := range list { - over, err := m.isWindowDockOverlap(win) - if err != nil { - logger.Warning(err) - } - logger.Debugf("shouldHideOnSmartHideMode: win %d dock overlap %v", win, over) - if over { - return true, nil - } - } - return false, nil -} - -func (m *Manager) shouldHideOnSmartHideModeK(activeWin *KWindowInfo) (bool, error) { - // 向窗管小伙伴讨教了一下,这里的currentDesktop - 1 后才和wayland下通过kwayland拿到的virtualDesktop相等 - currentDesktop, _ := m.kwin.CurrentDesktop(0) - - isShowDesktop, err := m.wm.GetIsShowDesktop(0) - if err != nil { - logger.Warning(err) - } - if isShowDesktop { - return false, nil - } - - for _, winInfo := range m.waylandManager.windows { - // 最小化的窗口不用关心 - minimized, err := winInfo.winObj.IsMinimized(0) - - // 非当前工作区的窗口不用关心 - virtualDesktop, _ := winInfo.winObj.VirtualDesktop(0) - - // 一些置顶的窗口过滤掉,例如输入法的小窗口 - isKeepAbove, _ := winInfo.winObj.IsKeepAbove(0) - if err != nil { - logger.Warning(err) - continue - } - - if minimized || virtualDesktop != uint32(currentDesktop-1) || isKeepAbove { - logger.Debugf("window %v is hidden or keepAbove or not on current workspace", winInfo.appId) - continue - } - - hide, _ := m.isWindowDockOverlapK(winInfo) - if hide { - return true, nil - } - } - - return false, nil -} - -func (m *Manager) shouldHideOnSmartHideMode() (bool, error) { - if m.isMultiTaskViewShow { - logger.Debug("shouldHideOnSmartHideMode: multitaskview is visible") - return true, nil - } - - activeWinInfo := m.getActiveWindow() - if activeWinInfo == nil { - logger.Debug("shouldHideOnSmartHideMode: activeWinInfo is nil") - return false, errors.New("activeWinInfo is nil") - } - if m.isDDELauncherVisible() { - logger.Debug("shouldHideOnSmartHideMode: dde launcher is visible") - return false, nil - } - - switch winInfo := activeWinInfo.(type) { - case *WindowInfo: - activeWin := winInfo.getXid() - return m.shouldHideOnSmartHideModeX(activeWin) - case *KWindowInfo: - return m.shouldHideOnSmartHideModeK(winInfo) - default: - return false, errors.New("invalid type WindowInfo") - } -} - -func (m *Manager) smartHideModeTimerExpired() { - logger.Debug("smartHideModeTimer expired!") - shouldHide, err := m.shouldHideOnSmartHideMode() - if err != nil { - logger.Warning(err) - m.setPropHideState(HideStateUnknown) - return - } - - if shouldHide { - m.setPropHideState(HideStateHide) - } else { - m.setPropHideState(HideStateShow) - } -} - -func (m *Manager) resetSmartHideModeTimer(delay time.Duration) { - m.smartHideModeMutex.Lock() - defer m.smartHideModeMutex.Unlock() - - m.smartHideModeTimer.Reset(delay) - logger.Debug("reset smart hide mode timer ", delay) -} - -func (m *Manager) updateHideState(delay bool) { - if m.isDDELauncherVisible() { - logger.Debug("updateHideState: dde launcher is visible, show dock") - m.setPropHideState(HideStateShow) - return - } - - hideMode := HideModeType(m.HideMode.Get()) - logger.Debug("updateHideState: mode is", hideMode) - switch hideMode { - case HideModeKeepShowing: - m.setPropHideState(HideStateShow) - - case HideModeKeepHidden: - m.setPropHideState(HideStateHide) - - case HideModeSmartHide: - if delay { - m.resetSmartHideModeTimer(time.Millisecond * 400) - } else { - m.resetSmartHideModeTimer(0) - } - } -} - -func (m *Manager) setPropHideState(hideState HideStateType) { - logger.Debug("setPropHideState", hideState) - if hideState == HideStateUnknown { - logger.Warning("try setPropHideState to Unknown") - return - } - - m.PropsMu.Lock() - if m.HideState != hideState { - logger.Debugf("HideState %v => %v", m.HideState, hideState) - m.HideState = hideState - _ = m.service.EmitPropertyChanged(m, "HideState", m.HideState) - } - m.PropsMu.Unlock() -} - -func (m *Manager) isWindowDockOverlapK(winInfo *KWindowInfo) (bool, error) { - geo := winInfo.geometry - winRect := &Rect{ - X: geo.X, - Y: geo.Y, - Width: uint32(geo.Width), - Height: uint32(geo.Height), - } - logger.Debugf("window [%s] rect: %v", winInfo.appId, winRect) - logger.Debug("dock rect:", m.FrontendWindowRect) - - if winInfo.appId == "dde-desktop" || - winInfo.appId == "dde-lock" || - winInfo.appId == "dde-shutdown" || - winInfo.appId == "reset-password-dialog" || - winInfo.appId == "deepin-screen-recorder" { - logger.Debug("Active Window is dde-desktop/dde-lock/dde-shutdowm/deepin-screen-recorder && return isWindowDockOverlapK false") - return false, nil - } - - return m.hasIntersectionK(winRect, m.FrontendWindowRect), nil -} diff --git a/dock/dock_manager_hide_state_test.go b/dock/dock_manager_hide_state_test.go deleted file mode 100644 index 7aaff05c4..000000000 --- a/dock/dock_manager_hide_state_test.go +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_hasIntersection(t *testing.T) { - rect1 := Rect{0, 0, 100, 100} - rect2 := Rect{0, 0, 50, 50} - rect3 := Rect{1, 1, 30, 30} - rect4 := Rect{32, 1, 15, 20} - rect5 := Rect{32, 22, 15, 15} - - assert.True(t, hasIntersection(&rect2, &rect1)) - assert.True(t, hasIntersection(&rect3, &rect1)) - assert.True(t, hasIntersection(&rect3, &rect2)) - assert.True(t, hasIntersection(&rect4, &rect1)) - assert.True(t, hasIntersection(&rect4, &rect2)) - assert.False(t, hasIntersection(&rect4, &rect3)) - assert.True(t, hasIntersection(&rect5, &rect1)) - assert.True(t, hasIntersection(&rect5, &rect2)) - assert.False(t, hasIntersection(&rect5, &rect3)) - assert.False(t, hasIntersection(&rect5, &rect4)) -} diff --git a/dock/dock_manager_init.go b/dock/dock_manager_init.go deleted file mode 100644 index 5664c9fc3..000000000 --- a/dock/dock_manager_init.go +++ /dev/null @@ -1,361 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "os" - "strings" - "time" - - "github.com/godbus/dbus" - libApps "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.apps" - kwayland "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.kwayland" - kwin "github.com/linuxdeepin/go-dbus-factory/org.kde.kwin" - launcher "github.com/linuxdeepin/go-dbus-factory/com.deepin.dde.daemon.launcher" - libDDELauncher "github.com/linuxdeepin/go-dbus-factory/com.deepin.dde.launcher" - sessionmanager "github.com/linuxdeepin/go-dbus-factory/com.deepin.sessionmanager" - wm "github.com/linuxdeepin/go-dbus-factory/com.deepin.wm" - wmswitcher "github.com/linuxdeepin/go-dbus-factory/com.deepin.wmswitcher" - gio "github.com/linuxdeepin/go-gir/gio-2.0" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/gsettings" - x "github.com/linuxdeepin/go-x11-client" - - "github.com/linuxdeepin/dde-daemon/common/dsync" -) - -const ( - ddeDataDir = "/usr/share/dde/data" - windowPatternsFile = ddeDataDir + "/window_patterns.json" -) - -func (m *Manager) initEntries() { - m.initDockedApps() - m.Entries.insertCb = func(entry *AppEntry, index int) { - entryObjPath := dbus.ObjectPath(entryDBusObjPathPrefix + entry.Id) - logger.Debug("entry added", entry.Id, index) - _ = m.service.Emit(m, "EntryAdded", entryObjPath, int32(index)) - } - m.Entries.removeCb = func(entry *AppEntry) { - _ = m.service.Emit(m, "EntryRemoved", entry.Id) - go func() { - time.Sleep(time.Second) - err := m.service.StopExport(entry) - if err != nil { - logger.Warning("StopExport error:", err) - } - }() - } - - if m.isWaylandSession { - m.initWaylandWindows() - } else { - m.initClientList() - } - - m.clientListInitEnd = true -} - -func (m *Manager) connectSettingKeyChanged(key string, handler func(key string)) { - gsettings.ConnectChanged(dockSchema, key, handler) -} - -func (m *Manager) listenSettingsChanged() { - // listen hide mode change - m.connectSettingKeyChanged(settingKeyHideMode, func(key string) { - mode := HideModeType(m.settings.GetEnum(key)) - logger.Debug(key, "changed to", mode) - m.updateHideState(false) - }) - - // listen display mode change - m.connectSettingKeyChanged(settingKeyDisplayMode, func(key string) { - mode := DisplayModeType(m.settings.GetEnum(key)) - logger.Debug(key, "changed to", mode) - }) - - // listen position change - m.connectSettingKeyChanged(settingKeyPosition, func(key string) { - position := positionType(m.settings.GetEnum(key)) - logger.Debug(key, "changed to", position) - }) - - // listen force quit - m.connectSettingKeyChanged(settingKeyForceQuitApp, func(key string) { - m.forceQuitAppStatus = forceQuitAppType(m.settings.GetEnum(key)) - logger.Debug(key, "changed to", m.forceQuitAppStatus) - - m.Entries.mu.Lock() - for _, entry := range m.Entries.items { - entry.updateMenu() - } - m.Entries.mu.Unlock() - }) -} - -func (m *Manager) listenWMSwitcherSignal() { - m.wmSwitcher.InitSignalExt(m.sessionSigLoop, true) - _, err := m.wmSwitcher.ConnectWMChanged(func(wmName string) { - m.PropsMu.Lock() - m.wmName = wmName - m.PropsMu.Unlock() - logger.Debugf("wm changed %q", wmName) - }) - if err != nil { - logger.Warning(err) - } -} - -const ( - wmName3D = "deepin wm" - wmName2D = "deepin metacity" -) - -func (m *Manager) listenKWinSignal() { - m.kwin.InitSignalExt(m.sessionSigLoop, true) - _, err := m.kwin.ConnectMultitaskStateChanged(func(state bool) { - m.isMultiTaskViewShow = state - m.updateHideState(false) - }) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) listenWMSignal() { - m.wm.InitSignalExt(m.sessionSigLoop, true) - _, err := m.wm.ConnectCompositingEnabledChanged(func(enabled bool) { - m.PropsMu.Lock() - defer m.PropsMu.Unlock() - if enabled { - m.wmName = wmName3D - } else { - m.wmName = wmName2D - } - }) - if err != nil { - logger.Warning(err) - } -} - -// 代码逻辑源自startdde wm_kwin.go -func (m *Manager) currentWM() string { - enabled, err := m.wm.CompositingEnabled().Get(0) - if err != nil { - logger.Warning(err) - return "" - } - - wmName := wmName2D - if enabled { - wmName = wmName3D - } - return wmName -} - -func (m *Manager) is3DWM() bool { - m.PropsMu.Lock() - defer m.PropsMu.Unlock() - if m.wmName == "" { - m.wmName = m.currentWM() - } - return m.wmName == wmName3D -} - -func (m *Manager) handleLauncherItemDeleted(itemInfo launcher.ItemInfo) { - dockedEntries := m.Entries.FilterDocked() - for _, entry := range dockedEntries { - file := entry.appInfo.GetFileName() - if file == itemInfo.Path { - m.undockEntry(entry) - return - } - } -} - -func (m *Manager) handleLauncherItemCreated(itemInfo launcher.ItemInfo) { - -} - -// 在收到 launcher item 更新的信号后,需要更新相关信息,包括 appInfo、innerId、名称、图标、菜单。 -func (m *Manager) handleLauncherItemUpdated(itemInfo launcher.ItemInfo) { - desktopFile := toLocalPath(itemInfo.Path) - entry, err := m.Entries.GetByDesktopFilePath(desktopFile) - if err != nil { - logger.Warning(err) - return - } - if entry == nil { - return - } - - appInfo := NewAppInfoFromFile(desktopFile) - if appInfo == nil { - logger.Warningf("failed to new app info from file %q: %v", desktopFile, err) - return - } - entry.setAppInfo(appInfo) - entry.innerId = appInfo.innerId - entry.updateName() - entry.updateMenu() - entry.forceUpdateIcon() // 可能存在Icon图片改变,但Icon名称未改变的情况,因此强制发Icon的属性改变信号 -} - -func (m *Manager) listenLauncherSignal() { - m.launcher.InitSignalExt(m.sessionSigLoop, true) - _, err := m.launcher.ConnectItemChanged(func(status string, itemInfo launcher.ItemInfo, - categoryID int64) { - logger.Debugf("launcher item changed status: %s, itemInfo: %#v", - status, itemInfo) - switch status { - case "deleted": - m.handleLauncherItemDeleted(itemInfo) - case "created": - m.handleLauncherItemCreated(itemInfo) - case "updated": - m.handleLauncherItemUpdated(itemInfo) - } - }) - if err != nil { - logger.Warning(err) - } - - m.ddeLauncher.InitSignalExt(m.sessionSigLoop, true) - _, err = m.ddeLauncher.ConnectVisibleChanged(func(visible bool) { - logger.Debug("dde-launcher visible changed", visible) - m.ddeLauncherVisibleMu.Lock() - m.ddeLauncherVisible = visible - m.ddeLauncherVisibleMu.Unlock() - - m.updateHideState(false) - }) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) isDDELauncherVisible() bool { - m.ddeLauncherVisibleMu.Lock() - result := m.ddeLauncherVisible - m.ddeLauncherVisibleMu.Unlock() - return result -} - -func (m *Manager) getWinIconPreferredApps() []string { - return m.settings.GetStrv(settingKeyWinIconPreferredApps) -} - -func (m *Manager) init() error { - m.rootWindow = globalXConn.GetDefaultScreen().Root - - var err error - m.settings = gio.NewSettings(dockSchema) - m.HideMode.Bind(m.settings, settingKeyHideMode) - m.DisplayMode.Bind(m.settings, settingKeyDisplayMode) - m.Position.Bind(m.settings, settingKeyPosition) - m.IconSize.Bind(m.settings, settingKeyIconSize) - m.ShowTimeout.Bind(m.settings, settingKeyShowTimeout) - m.HideTimeout.Bind(m.settings, settingKeyHideTimeout) - m.WindowSizeEfficient.Bind(m.settings, settingKeyWindowSizeEfficient) - m.WindowSizeFashion.Bind(m.settings, settingKeyWindowSizeFashion) - m.DockedApps.Bind(m.settings, settingKeyDockedApps) - m.appearanceSettings = gio.NewSettings(appearanceSchema) - m.Opacity.Bind(m.appearanceSettings, settingKeyOpacity) - - m.forceQuitAppStatus = forceQuitAppType(m.settings.GetEnum(settingKeyForceQuitApp)) - - m.FrontendWindowRect = NewRect() - m.smartHideModeTimer = time.AfterFunc(10*time.Second, m.smartHideModeTimerExpired) - m.smartHideModeTimer.Stop() - - m.listenSettingsChanged() - - m.windowInfoMap = make(map[x.Window]WindowInfoImp) - m.windowPatterns, err = loadWindowPatterns(windowPatternsFile) - if err != nil { - logger.Warning("loadWindowPatterns failed:", err) - } - - sessionBus := m.service.Conn() - m.wm = wm.NewWm(sessionBus) - - systemBus, err := dbus.SystemBus() - if err != nil { - return err - } - m.appsObj = libApps.NewApps(systemBus) - m.launcher = launcher.NewLauncher(sessionBus) - m.ddeLauncher = libDDELauncher.NewLauncher(sessionBus) - m.startManager = sessionmanager.NewStartManager(sessionBus) - m.wmSwitcher = wmswitcher.NewWMSwitcher(sessionBus) - m.kwin = kwin.NewKWin(sessionBus) - - sessionType := os.Getenv("XDG_SESSION_TYPE") - if strings.Contains(sessionType, "wayland") { - m.isWaylandSession = true - } - - if m.isWaylandSession { - m.waylandWM = kwayland.NewWindowManager(sessionBus) - m.waylandManager = newWaylandManager() - } - - m.sessionSigLoop = dbusutil.NewSignalLoop(m.service.Conn(), 10) - m.sessionSigLoop.Start() - m.sysSigLoop = dbusutil.NewSignalLoop(m.sysService.Conn(), 10) - m.sysSigLoop.Start() - m.listenLauncherSignal() - m.listenWMSwitcherSignal() - m.listenWMSignal() - m.listenKWinSignal() - - if strings.Contains(sessionType, "wayland") { - m.listenWaylandWMSignals() - } - m.initDSettings(m.sysService.Conn()) - //systemd拉起bamfdaemon可能会失败,导致阻塞,手动拉一遍 - err = m.startBAMFDaemon(sessionBus) - if err != nil { - logger.Warning("startBAMFDaemon failed") - } - - if m.isWaylandSession { - m.registerIdentifyKWindowFuncs() - } else { - m.registerIdentifyWindowFuncs() - } - - m.initEntries() - m.pluginSettings = newPluginSettingsStorage(m) - - m.syncConfig = dsync.NewConfig("dock", &syncConfig{m: m}, m.sessionSigLoop, - dbusPath, logger) - - // 强制将 ClassicMode 转为 EfficientMode - if m.DisplayMode.Get() == int32(DisplayModeClassicMode) { - m.DisplayMode.Set(int32(DisplayModeEfficientMode)) - } - - m.entryDealChan = make(chan func(), 64) - go m.accessEntries() - - if strings.Contains(sessionType, "x11") { - go m.eventHandleLoop() - m.listenRootWindowXEvent() - } - return nil -} - -func (m *Manager) startBAMFDaemon(bus *dbus.Conn) error { - systemdUser := bus.Object("org.freedesktop.systemd1", "/org/freedesktop/systemd1") - var jobPath dbus.ObjectPath - err := systemdUser.Call("org.freedesktop.systemd1.Manager.StartUnit", - dbus.FlagNoAutoStart, "bamfdaemon.service", "replace").Store(&jobPath) - if err != nil { - logger.Warning("failed to start bamfdaemon.service:", err) - return err - } - return nil -} diff --git a/dock/dock_manager_xevent.go b/dock/dock_manager_xevent.go deleted file mode 100644 index 695b0a3ef..000000000 --- a/dock/dock_manager_xevent.go +++ /dev/null @@ -1,436 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "fmt" - "sort" - "strings" - "time" - - x "github.com/linuxdeepin/go-x11-client" - "github.com/linuxdeepin/go-x11-client/util/wm/ewmh" -) - -func (m *Manager) registerWindow(win x.Window) WindowInfoImp { - logger.Debug("register window", win) - - m.windowInfoMapMutex.RLock() - winInfo, ok := m.windowInfoMap[win] - m.windowInfoMapMutex.RUnlock() - if ok { - logger.Debugf("register window %v failed, window existed", win) - return winInfo - } - - xwinInfo := NewWindowInfo(win) - m.listenWindowXEvent(xwinInfo) - - m.windowInfoMapMutex.Lock() - m.windowInfoMap[win] = xwinInfo - m.windowInfoMapMutex.Unlock() - return xwinInfo -} - -func (m *Manager) isWindowRegistered(win x.Window) bool { - m.windowInfoMapMutex.RLock() - _, ok := m.windowInfoMap[win] - m.windowInfoMapMutex.RUnlock() - return ok -} - -func (m *Manager) unregisterWindow(win x.Window) { - logger.Debugf("unregister window %v", win) - m.windowInfoMapMutex.Lock() - delete(m.windowInfoMap, win) - m.windowInfoMapMutex.Unlock() -} - -func (m *Manager) handleClientListChanged() { - clientList, err := ewmh.GetClientList(globalXConn).Reply(globalXConn) - if err != nil { - logger.Warning("Get client list failed:", err) - return - } - newClientList := windowSlice(clientList) - sort.Sort(newClientList) - add, remove := diffSortedWindowSlice(m.clientList, newClientList) - m.clientList = newClientList - - if len(add) > 0 { - for _, win := range add { - window0 := win - addFunc := func() { - logger.Debugf("client list add: %d", window0) - winInfo := m.registerWindow(window0) - repeatCount := 0 - for { - if repeatCount > 10 { - logger.Debugf("give up identify window %d", window0) - return - } - good := isGoodWindow(window0) - if !good { - return - } - pid := getWmPid(window0) - wmClass, _ := getWmClass(window0) - wmName := getWmName(window0) - wmCmd, _ := getWmCommand(window0) - if pid != 0 || wmClass != nil || wmName != "" || strings.Join(wmCmd, "") != "" { - m.attachOrDetachWindow(winInfo) - return - } - repeatCount++ - time.Sleep(100 * time.Millisecond) - } - } - m.entryDealChan <- addFunc - } - } - - if len(remove) > 0 { - for _, win := range remove { - window0 := win - removeFunc := func() { - logger.Debugf("client list remove: %d", window0) - m.windowInfoMapMutex.RLock() - winInfo := m.windowInfoMap[window0] - m.windowInfoMapMutex.RUnlock() - if winInfo != nil { - m.detachWindow(winInfo) - winInfo.setEntryInnerId("") - } else { - logger.Warningf("window info of %d is nil", window0) - entry := m.Entries.getByWindowId(window0) - if entry != nil { - entry.PropsMu.RLock() - if !entry.IsDocked { - m.removeAppEntry(entry) - } - entry.PropsMu.RUnlock() - } - } - } - m.entryDealChan <- removeFunc - } - } -} - -func (m *Manager) handleActiveWindowChangedX() { - activeWindow, err := ewmh.GetActiveWindow(globalXConn).Reply(globalXConn) - if err != nil { - logger.Warning(err) - return - } - winInfo := m.findWindowByXid(activeWindow) - - logger.Debug("Active window changed X", activeWindow) - m.handleActiveWindowChanged(winInfo) -} - -func (m *Manager) handleActiveWindowChanged(activeWindow WindowInfoImp) { - m.activeWindowMu.Lock() - if activeWindow == nil { - m.activeWindowOld = m.activeWindow - m.activeWindow = nil - m.activeWindowMu.Unlock() - return - } - - m.activeWindow = activeWindow - m.activeWindowMu.Unlock() - - activeWinXid := activeWindow.getXid() - - m.Entries.mu.RLock() - for _, entry := range m.Entries.items { - entry.PropsMu.Lock() - - winInfo, ok := entry.windows[activeWinXid] - if ok { - entry.setPropIsActive(true) - entry.setCurrentWindowInfo(winInfo) - entry.updateName() - entry.updateIcon() - } else { - entry.setPropIsActive(false) - } - - entry.PropsMu.Unlock() - } - m.Entries.mu.RUnlock() - - isShowDesktop := false - var err error - - switch activeWindow.(type) { - case *WindowInfo: - isShowDesktop, err = ewmh.GetShowingDesktop(globalXConn).Reply(globalXConn) - case *KWindowInfo: - isShowDesktop, err = m.wm.GetIsShowDesktop(0) - default: - logger.Warning("invalid type WindowInfo") - } - - if err != nil { - logger.Warning(err) - } - - m.updateHideState(!isShowDesktop) -} - -func (m *Manager) listenRootWindowXEvent() { - const eventMask = x.EventMaskPropertyChange | x.EventMaskSubstructureNotify - err := x.ChangeWindowAttributesChecked(globalXConn, m.rootWindow, x.CWEventMask, - []uint32{eventMask}).Check(globalXConn) - if err != nil { - logger.Warning(err) - } - m.handleActiveWindowChangedX() - m.handleClientListChanged() -} - -func (m *Manager) listenWindowXEvent(winInfo *WindowInfo) { - const eventMask = x.EventMaskPropertyChange | x.EventMaskStructureNotify | x.EventMaskVisibilityChange - err := x.ChangeWindowAttributesChecked(globalXConn, winInfo.xid, x.CWEventMask, - []uint32{eventMask}).Check(globalXConn) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) handleDestroyNotifyEvent(ev *x.DestroyNotifyEvent) { - logger.Debug("DestroyNotifyEvent window:", ev.Window) - winInfo, err := m.getWindowInfo(ev.Window) - if err == nil { - m.detachWindow(winInfo) - } - - m.unregisterWindow(ev.Window) -} - -func (m *Manager) handleMapNotifyEvent(ev *x.MapNotifyEvent) { - logger.Debug("MapNotifyEvent window:", ev.Window) - winInfo := m.registerWindow(ev.Window) - time.AfterFunc(2*time.Second, func() { - logger.Warningf("mapNotifyEvent after 2s, call identifyWindow, win: %d", winInfo.getXid()) - _, appInfo := m.identifyWindow(winInfo) - m.markAppLaunched(appInfo) - }) -} - -func (m *Manager) getWindowInfo(win x.Window) (WindowInfoImp, error) { - m.windowInfoMapMutex.RLock() - v, ok := m.windowInfoMap[win] - if !ok { - err := fmt.Errorf("can not get %d window info", win) - m.windowInfoMapMutex.RUnlock() - return nil, err - } - - m.windowInfoMapMutex.RUnlock() - return v, nil -} - -func (m *Manager) handleConfigureNotifyEvent(ev *x.ConfigureNotifyEvent) { - winInfo := m.findXWindowInfo(ev.Window) - if winInfo == nil { - return - } - - if HideModeType(m.HideMode.Get()) != HideModeSmartHide { - return - } - if winInfo.wmClass != nil && winInfo.wmClass.Class == frontendWindowWmClass { - // ignore frontend window ConfigureNotify event - return - } - - winInfo.mu.Lock() - winInfo.lastConfigureNotifyEvent = ev - winInfo.mu.Unlock() - - const configureNotifyDelay = 100 * time.Millisecond - if winInfo.updateConfigureTimer != nil { - winInfo.updateConfigureTimer.Reset(configureNotifyDelay) - } else { - winInfo.updateConfigureTimer = time.AfterFunc(configureNotifyDelay, func() { - logger.Debug("ConfigureNotify: updateConfigureTimer expired") - - winInfo.mu.Lock() - ev := winInfo.lastConfigureNotifyEvent - winInfo.mu.Unlock() - - logger.Debugf("in closure: configure notify ev: %#v", ev) - isXYWHChange := false - if winInfo.x != ev.X { - winInfo.x = ev.X - isXYWHChange = true - } - - if winInfo.y != ev.Y { - winInfo.y = ev.Y - isXYWHChange = true - } - - if winInfo.width != ev.Width { - winInfo.width = ev.Width - isXYWHChange = true - } - - if winInfo.height != ev.Height { - winInfo.height = ev.Height - isXYWHChange = true - } - logger.Debug("isXYWHChange", isXYWHChange) - // if xywh changed ,update hide state without delay - m.updateHideState(!isXYWHChange) - }) - } - -} - -func (m *Manager) handleRootWindowPropertyNotifyEvent(ev *x.PropertyNotifyEvent) { - switch ev.Atom { - case atomNetClientList: - m.handleClientListChanged() - case atomNetActiveWindow: - m.handleActiveWindowChangedX() - case atomNetShowingDesktop: - m.updateHideState(false) - } -} - -func (m *Manager) handlePropertyNotifyEvent(ev *x.PropertyNotifyEvent) { - if ev.Window == m.rootWindow { - m.handleRootWindowPropertyNotifyEvent(ev) - return - } - - winInfo := m.findXWindowInfo(ev.Window) - if winInfo == nil { - return - } - - var newInnerId string - var needAttachOrDetach bool - - switch ev.Atom { - case atomNetWMState: - winInfo.updateWmState() - needAttachOrDetach = true - - case atomGtkApplicationId: - winInfo.gtkAppId = getWindowGtkApplicationId(winInfo.xid) - newInnerId = genInnerId(winInfo) - - case atomNetWmPid: - winInfo.updateProcessInfo() - newInnerId = genInnerId(winInfo) - - case atomNetWMName: - winInfo.updateWmName() - newInnerId = genInnerId(winInfo) - - case atomNetWMIcon: - winInfo.updateIcon() - - case atomNetWmAllowedActions: - winInfo.updateWmAllowedActions() - - case atomMotifWmHints: - winInfo.updateMotifWmHints() - - case x.AtomWMClass: - winInfo.updateWmClass() - newInnerId = genInnerId(winInfo) - needAttachOrDetach = true - - case atomXEmbedInfo: - winInfo.updateHasXEmbedInfo() - needAttachOrDetach = true - - case atomNetWMWindowType: - winInfo.updateWmWindowType() - needAttachOrDetach = true - - case x.AtomWMTransientFor: - winInfo.updateHasWmTransientFor() - needAttachOrDetach = true - } - - if winInfo.updateCalled && newInnerId != "" && winInfo.innerId != newInnerId { - // winInfo.innerId changed - logger.Debugf("window %v innerId changed to %s", winInfo.xid, newInnerId) - m.detachWindow(winInfo) - winInfo.innerId = newInnerId - winInfo.entryInnerId = "" - needAttachOrDetach = true - } - - if needAttachOrDetach { - m.attachOrDetachWindow(winInfo) - } - - entry := m.Entries.getByWindowId(ev.Window) - if entry == nil { - return - } - - entry.PropsMu.Lock() - defer entry.PropsMu.Unlock() - - switch ev.Atom { - case atomNetWMState: - entry.updateWindowInfos() - - case atomNetWMIcon: - if entry.current == winInfo { - entry.updateIcon() - } - - case atomNetWMName: - if entry.current == winInfo { - entry.updateName() - } - entry.updateWindowInfos() - - case atomNetWmAllowedActions, atomMotifWmHints: - entry.updateMenu() - } -} - -func (m *Manager) eventHandleLoop() { - eventChan := make(chan x.GenericEvent, 500) - globalXConn.AddEventChan(eventChan) - - for ev := range eventChan { - switch ev.GetEventCode() { - case x.MapNotifyEventCode: - event, _ := x.NewMapNotifyEvent(ev) - m.handleMapNotifyEvent(event) - - case x.DestroyNotifyEventCode: - event, _ := x.NewDestroyNotifyEvent(ev) - m.handleDestroyNotifyEvent(event) - - case x.ConfigureNotifyEventCode: - event, _ := x.NewConfigureNotifyEvent(ev) - m.handleConfigureNotifyEvent(event) - - case x.PropertyNotifyEventCode: - event, _ := x.NewPropertyNotifyEvent(ev) - m.handlePropertyNotifyEvent(event) - } - } -} - -func (m *Manager) isActiveWindow(winInfo WindowInfoImp) bool { - if winInfo == nil { - return false - } - return winInfo == m.getActiveWindow() -} diff --git a/dock/exported_methods_auto.go b/dock/exported_methods_auto.go deleted file mode 100644 index 33cb94bc3..000000000 --- a/dock/exported_methods_auto.go +++ /dev/null @@ -1,170 +0,0 @@ -// Code generated by "dbusutil-gen em -type AppEntry,Manager"; DO NOT EDIT. - -package dock - -import ( - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (v *AppEntry) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "Activate", - Fn: v.Activate, - InArgs: []string{"timestamp"}, - }, - { - Name: "Check", - Fn: v.Check, - }, - { - Name: "ForceQuit", - Fn: v.ForceQuit, - }, - { - Name: "GetAllowedCloseWindows", - Fn: v.GetAllowedCloseWindows, - OutArgs: []string{"windows"}, - }, - { - Name: "HandleDragDrop", - Fn: v.HandleDragDrop, - InArgs: []string{"timestamp", "files"}, - }, - { - Name: "HandleMenuItem", - Fn: v.HandleMenuItem, - InArgs: []string{"timestamp", "id"}, - }, - { - Name: "NewInstance", - Fn: v.NewInstance, - InArgs: []string{"timestamp"}, - }, - { - Name: "PresentWindows", - Fn: v.PresentWindows, - }, - { - Name: "RequestDock", - Fn: v.RequestDock, - }, - { - Name: "RequestUndock", - Fn: v.RequestUndock, - }, - } -} -func (v *Manager) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "ActivateWindow", - Fn: v.ActivateWindow, - InArgs: []string{"win"}, - }, - { - Name: "CancelPreviewWindow", - Fn: v.CancelPreviewWindow, - }, - { - Name: "CloseWindow", - Fn: v.CloseWindow, - InArgs: []string{"win"}, - }, - { - Name: "GetDockedAppsDesktopFiles", - Fn: v.GetDockedAppsDesktopFiles, - OutArgs: []string{"desktopFiles"}, - }, - { - Name: "GetEntryIDs", - Fn: v.GetEntryIDs, - OutArgs: []string{"list"}, - }, - { - Name: "GetPluginSettings", - Fn: v.GetPluginSettings, - OutArgs: []string{"jsonStr"}, - }, - { - Name: "IsDocked", - Fn: v.IsDocked, - InArgs: []string{"desktopFile"}, - OutArgs: []string{"docked"}, - }, - { - Name: "IsOnDock", - Fn: v.IsOnDock, - InArgs: []string{"desktopFile"}, - OutArgs: []string{"onDock"}, - }, - { - Name: "MakeWindowAbove", - Fn: v.MakeWindowAbove, - InArgs: []string{"win"}, - }, - { - Name: "MaximizeWindow", - Fn: v.MaximizeWindow, - InArgs: []string{"win"}, - }, - { - Name: "MergePluginSettings", - Fn: v.MergePluginSettings, - InArgs: []string{"jsonStr"}, - }, - { - Name: "MinimizeWindow", - Fn: v.MinimizeWindow, - InArgs: []string{"win"}, - }, - { - Name: "MoveEntry", - Fn: v.MoveEntry, - InArgs: []string{"index", "newIndex"}, - }, - { - Name: "MoveWindow", - Fn: v.MoveWindow, - InArgs: []string{"win"}, - }, - { - Name: "PreviewWindow", - Fn: v.PreviewWindow, - InArgs: []string{"win"}, - }, - { - Name: "QueryWindowIdentifyMethod", - Fn: v.QueryWindowIdentifyMethod, - InArgs: []string{"wid"}, - OutArgs: []string{"method"}, - }, - { - Name: "RemovePluginSettings", - Fn: v.RemovePluginSettings, - InArgs: []string{"key1", "key2List"}, - }, - { - Name: "RequestDock", - Fn: v.RequestDock, - InArgs: []string{"desktopFile", "index"}, - OutArgs: []string{"docked"}, - }, - { - Name: "RequestUndock", - Fn: v.RequestUndock, - InArgs: []string{"desktopFile"}, - OutArgs: []string{"undocked"}, - }, - { - Name: "SetFrontendWindowRect", - Fn: v.SetFrontendWindowRect, - InArgs: []string{"x", "y", "width", "height"}, - }, - { - Name: "SetPluginSettings", - Fn: v.SetPluginSettings, - InArgs: []string{"jsonStr"}, - }, - } -} diff --git a/dock/identify_window.go b/dock/identify_window.go deleted file mode 100644 index 8ede55e54..000000000 --- a/dock/identify_window.go +++ /dev/null @@ -1,638 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "fmt" - "path/filepath" - "strconv" - "strings" - "time" - - "github.com/linuxdeepin/go-lib/appinfo/desktopappinfo" - - "github.com/linuxdeepin/go-lib/procfs" -) - -type IdentifyWindowFunc struct { - Name string - Fn _IdentifyWindowFunc -} - -type _IdentifyWindowFunc func(*Manager, *WindowInfo) (string, *AppInfo) - -func (m *Manager) registerIdentifyWindowFuncs() { - m.registerIdentifyWindowFunc("DSGVirtualApp", identifyWindowDSGVirtualApp) - m.registerIdentifyWindowFunc("Android", identifyWindowAndroid) - m.registerIdentifyWindowFunc("PidEnv", func(m *Manager, winInfo *WindowInfo) (string, *AppInfo) { - return identifyWindowByPidEnv(m, &winInfo.baseWindowInfo) - }) - m.registerIdentifyWindowFunc("CmdlineTurboBooster", identifyWindowByCmdlineTurboBooster) - m.registerIdentifyWindowFunc("Cmdline-XWalk", identifyWindowByCmdlineXWalk) - m.registerIdentifyWindowFunc("FlatpakAppID", identifyWindowByFlatpakAppID) - m.registerIdentifyWindowFunc("CrxId", identifyWindowByCrxId) - m.registerIdentifyWindowFunc("Rule", identifyWindowByRule) - m.registerIdentifyWindowFunc("Pid", identifyWindowByPid) - m.registerIdentifyWindowFunc("Scratch", identifyWindowByScratch) - m.registerIdentifyWindowFunc("GtkAppId", identifyWindowByGtkAppId) - m.registerIdentifyWindowFunc("WmClass", identifyWindowByWmClass) - m.registerIdentifyWindowFunc("Bamf", func(m *Manager, winInfo *WindowInfo) (string, *AppInfo) { - return identifyWindowByBamf(m, &winInfo.baseWindowInfo) - }) -} - -func (m *Manager) registerIdentifyWindowFunc(name string, fn _IdentifyWindowFunc) { - m.identifyWindowFuns = append(m.identifyWindowFuns, &IdentifyWindowFunc{ - Name: name, - Fn: fn, - }) -} - -type IdentifyKWindowFunc struct { - Name string - Fn _IdentifyKWindowFunc -} - -type _IdentifyKWindowFunc func(*Manager, *KWindowInfo) (string, *AppInfo) - -func (m *Manager) registerIdentifyKWindowFuncs() { - m.registerIdentifyKWindowFunc("DSGVirtualApp", identifyKWindowDSGVirtualApp) - m.registerIdentifyKWindowFunc("PidEnv", func(m *Manager, winInfo *KWindowInfo) (string, *AppInfo) { - return identifyWindowByPidEnv(m, &winInfo.baseWindowInfo) - }) - m.registerIdentifyKWindowFunc("Bamf", func(m *Manager, winInfo *KWindowInfo) (string, *AppInfo) { - return identifyWindowByBamf(m, &winInfo.baseWindowInfo) - }) - m.registerIdentifyKWindowFunc("ExeEnv", identifyKwindowByExeEnv) - m.registerIdentifyKWindowFunc("WmClass", identifyKWindowByWMClass) -} - -func (m *Manager) registerIdentifyKWindowFunc(name string, fn _IdentifyKWindowFunc) { - m.identifyKWindowFuns = append(m.identifyKWindowFuns, &IdentifyKWindowFunc{ - Name: name, - Fn: fn, - }) -} - -func (m *Manager) identifyWindow(winInfo WindowInfoImp) (innerId string, appInfo *AppInfo) { - switch winType := winInfo.(type) { - case *WindowInfo: - return m.identifyWindowX(winType) - case *KWindowInfo: - return m.identifyWindowK(winType) - default: - return "", nil - } -} - -func identifyKWindowByWMClass(m *Manager, winInfo *KWindowInfo) (innerId string, appInfo *AppInfo) { - wmClass, _ := getWmClass(winInfo.xid) - if wmClass != nil { - instance := wmClass.Instance - if instance != "" { - appInfo = NewAppInfo("org.deepin.flatdeb." + strings.ToLower(instance)) - if appInfo != nil { - innerId = appInfo.innerId - return - } - - appInfo = NewAppInfo(instance) - if appInfo != nil { - innerId = appInfo.innerId - return - } - } - - class := wmClass.Class - if class != "" { - appInfo = NewAppInfo(class) - if appInfo != nil { - innerId = appInfo.innerId - return - } - } - } - - return -} - -func (m *Manager) identifyWindowK(winInfo *KWindowInfo) (innerId string, appInfo *AppInfo) { - // TODO: 对桌面调起的文管应用做规避处理,需要在此处添加,因为初始化时appId和title为空 - if winInfo.appId == "dde-desktop" && m.shouldShowOnDock(winInfo) { - winInfo.appId = "dde-file-manager" - } - appId := winInfo.appId - // TODO: 对于appId为空的情况,使用title过滤,此项修改针对浏览器下载窗口 - title := winInfo.getTitle() - if title == "下载" { - appId = "uos-browser" - } - - // wayland环境下,如果是Wine应用(微信,企业微信等),appId为wine,根据进程环境变量去需要获取具体应用的appId - if appId == "wine" { - if winInfo.process != nil { - launchedDesktopFile := winInfo.process.environ.Get("GIO_LAUNCHED_DESKTOP_FILE") - logger.Debugf("%s launchedDesktopFile: %s", appId, launchedDesktopFile) - - parts := strings.Split(launchedDesktopFile, "/") - partsLen := len(parts) - if partsLen >= 1 { - appId = parts[partsLen-1] - logger.Debugf("identifyWindowK: actual wine application appid: %s", appId) - } - } - } - - // 先使用appId获取appInfo,如果不能成功再通过定义的识别窗口机制去识别 - appInfo = NewAppInfo(appId) - if appInfo == nil { - for idx, item := range m.identifyKWindowFuns { - name := item.Name - logger.Debugf("identifyWindowK: try %s:%d", name, idx) - innerId, appInfo = item.Fn(m, winInfo) - if innerId != "" { - // success - logger.Debugf("identifyWindowK by %s success, innerId: %q", - name, innerId) - - // NOTE: if name == "Pid", appInfo may be nil - if appInfo != nil { - fixedAppInfo := fixAutostartAppInfo(appInfo) - if fixedAppInfo != nil { - appInfo = fixedAppInfo - appInfo.identifyMethod = name + "+FixAutostart" - innerId = fixedAppInfo.innerId - } else { - appInfo.identifyMethod = name - } - } - return - } - } - } else { - innerId = appInfo.innerId - fixedAppInfo := fixAutostartAppInfo(appInfo) - if fixedAppInfo != nil { - appInfo = fixedAppInfo - appInfo.identifyMethod = "FixAutostart" - innerId = fixedAppInfo.innerId - } - - logger.Debugf("identifyWindowK by %s success, innerId: %q, appInfo: %v", - "AppId", innerId, appInfo) - return - } - - // fail - logger.Debugf("identifyWindowK: failed") - return winInfo.appId, nil -} - -func (m *Manager) identifyWindowX(winInfo *WindowInfo) (innerId string, appInfo *AppInfo) { - logger.Debugf("identifyWindow: window id: %v, window innerId: %q", - winInfo.xid, winInfo.innerId) - if winInfo.innerId == "" { - logger.Debug("identifyWindow: winInfo.innerId is empty") - return - } - - for idx, item := range m.identifyWindowFuns { - name := item.Name - logger.Debugf("identifyWindow: try %s:%d", name, idx) - innerId, appInfo = item.Fn(m, winInfo) - if innerId != "" { - // success - logger.Debugf("identifyWindow by %s success, innerId: %q, appInfo: %v", - name, innerId, appInfo) - // NOTE: if name == "Pid", appInfo may be nil - if appInfo != nil { - fixedAppInfo := fixAutostartAppInfo(appInfo) - if fixedAppInfo != nil { - appInfo = fixedAppInfo - appInfo.identifyMethod = name + "+FixAutostart" - innerId = fixedAppInfo.innerId - } else { - appInfo.identifyMethod = name - } - } - return - } - } - // fail - logger.Debugf("identifyWindow: failed") - return winInfo.innerId, nil -} - -func fixAutostartAppInfo(appInfo *AppInfo) *AppInfo { - file := appInfo.GetFileName() - if isInAutostartDir(file) { - logger.Debug("file is in autostart dir") - base := filepath.Base(file) - return NewAppInfo(base) - } - return nil -} - -func identifyWindowByScratch(m *Manager, winInfo *WindowInfo) (string, *AppInfo) { - msgPrefix := fmt.Sprintf("identifyWindowByScratch win: %d ", winInfo.xid) - desktopFile := filepath.Join(scratchDir, addDesktopExt(winInfo.innerId)) - logger.Debugf("%s try scratch desktop file: %q", msgPrefix, desktopFile) - appInfo := NewAppInfoFromFile(desktopFile) - if appInfo != nil { - // success - return appInfo.innerId, appInfo - } - // fail - return "", nil -} - -func identifyWindowByPid(m *Manager, winInfo *WindowInfo) (string, *AppInfo) { - msgPrefix := fmt.Sprintf("identifyWindowByPid win: %d ", winInfo.xid) - if winInfo.pid > 10 { - logger.Debugf("%s pid: %d", msgPrefix, winInfo.pid) - entry := m.Entries.GetByWindowPid(winInfo.pid) - if entry != nil { - // success - return entry.innerId, entry.appInfo - } - } - // fail - return "", nil -} - -func identifyWindowByGtkAppId(m *Manager, winInfo *WindowInfo) (string, *AppInfo) { - msgPrefix := fmt.Sprintf("identifyWindowByGtkAppId win: %d ", winInfo.xid) - gtkAppId := winInfo.gtkAppId - logger.Debugf("%s gtkAppId: %q", msgPrefix, gtkAppId) - if gtkAppId != "" { - appInfo := NewAppInfo(gtkAppId) - if appInfo != nil { - // success - return appInfo.innerId, appInfo - } - } - // fail - return "", nil -} - -func identifyWindowByFlatpakAppID(m *Manager, winInfo *WindowInfo) (string, *AppInfo) { - msgPrefix := fmt.Sprintf("identifyWindowByFlatpakAppID win: %d ", winInfo.xid) - flatpakRef := winInfo.flatpakAppID - logger.Debugf("%s flatpak ref is %q", msgPrefix, flatpakRef) - if strings.HasPrefix(flatpakRef, "app/") { - parts := strings.Split(flatpakRef, "/") - if len(parts) > 1 { - appID := parts[1] - appInfo := NewAppInfo(appID) - if appInfo != nil { - // success - return appInfo.innerId, appInfo - } - } - } - // fail - return "", nil -} - -var crxAppIdMap = map[string]string{ - "crx_onfalgmmmaighfmjgegnamdjmhpjpgpi": "apps.com.aiqiyi", - "crx_gfhkopakpiiaeocgofdpcpjpdiglpkjl": "apps.cn.kugou.hd", - "crx_gaoopbnflngfkoobibfgbhobdeiipcgh": "apps.cn.kuwo.kwmusic", - "crx_jajaphleehpmpblokgighfjneejapnok": "apps.com.evernote", - "crx_ebhffdbfjilfhahiinoijchmlceailfn": "apps.com.letv", - "crx_almpoflgiciaanepplakjdkiaijmklld": "apps.com.tongyong.xxbox", - "crx_heaphplipeblmpflpdcedfllmbehonfo": "apps.com.peashooter", - "crx_dbngidmdhcooejaggjiochbafiaefndn": "apps.com.rovio.angrybirdsseasons", - "crx_chfeacahlaknlmjhiagghobhkollfhip": "apps.com.sina.weibo", - "crx_cpbmecbkmjjfemjiekledmejoakfkpec": "apps.com.openapp", - "crx_lalomppgkdieklbppclocckjpibnlpjc": "apps.com.baidutieba", - "crx_gejbkhjjmicgnhcdpgpggboldigfhgli": "apps.com.zhuishushenqi", - "crx_gglenfcpioacendmikabbkecnfpanegk": "apps.com.duokan", - "crx_nkmmgdfgabhefacpfdabadjfnpffhpio": "apps.com.zhihu.daily", - "crx_ajkogonhhcighbinfgcgnjiadodpdicb": "apps.com.netease.newsreader", - "crx_hgggjnaaklhemplabjhgpodlcnndhppo": "apps.com.baidu.music.pad", - "crx_ebmgfebnlgilhandilnbmgadajhkkmob": "apps.cn.ibuka", - "crx_nolebplcbgieabkblgiaacdpgehlopag": "apps.com.tianqitong", - "crx_maghncnmccfbmkekccpmkjjfcmdnnlip": "apps.com.youjoy.strugglelandlord", - "crx_heliimhfjgfabpgfecgdhackhelmocic": "apps.cn.emoney", - "crx_jkgmneeafmgjillhgmjbaipnakfiidpm": "apps.com.instagram", - "crx_cdbkhmfmikobpndfhiphdbkjklbmnakg": "apps.com.easymindmap", - "crx_djflcciklfljleibeinjmjdnmenkciab": "apps.com.lgj.thunderbattle", - "crx_ffdgbolnndgeflkapnmoefhjhkeilfff": "apps.com.qianlong", - "crx_fmpniepgiofckbfgahajldgoelogdoap": "apps.com.windhd", - "crx_dokjmallmkihbgefmladclcdcinjlnpj": "apps.com.youdao.hanyu", - "crx_dicimeimfmbfcklbjdpnlmjgegcfilhm": "apps.com.ibookstar", - "crx_cokkcjnpjfffianjbpjbcgjefningkjm": "apps.com.yidianzixun", - "crx_ehflkacdpmeehailmcknlnkmjalehdah": "apps.com.xplane", - "crx_iedokjbbjejfinokgifgecmboncmkbhb": "apps.com.wedevote", - "crx_eaefcagiihjpndconigdpdmcbpcamaok": "apps.com.tongwei.blockbreaker", - "crx_mkjjfibpccammnliaalefmlekiiikikj": "apps.com.dayima", - "crx_gflkpppiigdigkemnjlonilmglokliol": "apps.com.cookpad", - "crx_jfhpkchgedddadekfeganigbenbfaohe": "apps.com.issuu", - "crx_ggkmfnbkldhmkehabgcbnmlccfbnoldo": "apps.bible.cbol", - "crx_phlhkholfcljapmcidanddmhpcphlfng": "apps.com.kanjian.radio", - "crx_bjgfcighhaahojkibojkdmpdihhcehfm": "apps.de.danoeh.antennapod", - "crx_kldipknjommdfkifomkmcpbcnpmcnbfi": "apps.com.asoftmurmur", - "crx_jfhlegimcipljdcionjbipealofoncmd": "apps.com.tencentnews", - "crx_aikgmfkpmmclmpooohngmcdimgcocoaj": "apps.com.tonghuashun", - "crx_ifimglalpdeoaffjmmihoofapmpflkad": "apps.com.letv.lecloud.disk", - "crx_pllcekmbablpiogkinogefpdjkmgicbp": "apps.com.hwadzanebook", - "crx_ohcknkkbjmgdfcejpbmhjbohnepcagkc": "apps.com.douban.radio", -} - -func identifyWindowByCrxId(m *Manager, winInfo *WindowInfo) (string, *AppInfo) { - msgPrefix := fmt.Sprintf("identifyWindowByCrxId win: %d ", winInfo.xid) - if winInfo.wmClass != nil && - strings.EqualFold(winInfo.wmClass.Class, "chromium-browser") && - strings.HasPrefix(winInfo.wmClass.Instance, "crx_") { - - appId, ok := crxAppIdMap[winInfo.wmClass.Instance] - logger.Debug(msgPrefix, "appId:", appId) - if ok { - appInfo := NewAppInfo(appId) - if appInfo != nil { - // success - return appInfo.innerId, appInfo - } - } - } - // fail - return "", nil -} - -func identifyWindowByCmdlineTurboBooster(m *Manager, winInfo *WindowInfo) (string, *AppInfo) { - msgPrefix := fmt.Sprintf("identifyWindowByCmdlineTurboBooster win: %d ", winInfo.xid) - pid := winInfo.pid - process := winInfo.process - if process != nil && pid != 0 { - if len(process.cmdline) >= 0 { - var desktopFile string - if strings.HasSuffix(process.cmdline[0], desktopExt) { - desktopFile = process.cmdline[0] - } else if strings.Contains(process.cmdline[0], "/applications/") { - matches, err := filepath.Glob(process.cmdline[0] + "*") - if err != nil { - logger.Warning(msgPrefix, "filepath.Glob err:", err) - return "", nil - } - if len(matches) > 0 && strings.HasSuffix(matches[0], desktopExt) { - desktopFile = matches[0] - } - } - - if desktopFile != "" { - logger.Debugf("%s desktopFile: %s", msgPrefix, desktopFile) - appInfo := NewAppInfoFromFile(desktopFile) - if appInfo != nil { - // success - return appInfo.innerId, appInfo - } - } - } - } - - // fail - return "", nil -} - -func identifyWindowDSGVirtualApp(m *Manager, winInfo *WindowInfo) (string, *AppInfo) { - desktop := getDSGVirtualAppDesktop(winInfo.xid) - if "" != desktop { - deskappInfo, _ := desktopappinfo.NewDesktopAppInfoFromFile(desktop) - if deskappInfo == nil { - logger.Info("Not Exist DesktopFile") - return "", nil - } - - appInfo := newAppInfo(deskappInfo) - appInfo.identifyMethod = "DSGVirtualApp" - - return appInfo.innerId, appInfo - } - - return "", nil -} - -func identifyKWindowDSGVirtualApp(m *Manager, winInfo *KWindowInfo) (string, *AppInfo) { - desktop := getDSGVirtualAppDesktop(winInfo.xid) - if "" != desktop { - deskappInfo, _ := desktopappinfo.NewDesktopAppInfoFromFile(desktop) - if deskappInfo == nil { - logger.Info("Not Exist DesktopFile") - return "", nil - } - - appInfo := newAppInfo(deskappInfo) - appInfo.identifyMethod = "DSGVirtualApp" - - return appInfo.innerId, appInfo - } - - return "", nil -} - -func identifyWindowAndroid(m *Manager, winInfo *WindowInfo) (string, *AppInfo) { - androidId := getAndroidUengineId(winInfo.xid) - androidName := getAndroidUengineName(winInfo.xid) - if -1 != androidId && "" != androidName { - desktopPath := "/usr/share/applications/" + "uengine." + androidName + ".desktop" - deskappInfo, _ := desktopappinfo.NewDesktopAppInfoFromFile(desktopPath) - if deskappInfo == nil { - logger.Info("Not Exist DesktopFile") - return "", nil - } - - appInfo := newAppInfo(deskappInfo) - appInfo.identifyMethod = "Android" - - return appInfo.innerId, appInfo - } - - return "", nil -} - -func identifyWindowByPidEnv(m *Manager, winInfo *baseWindowInfo) (string, *AppInfo) { - msgPrefix := fmt.Sprintf("identifyWindowByPidEnv win: %d ", winInfo.xid) - pid := winInfo.pid - process := winInfo.process - if process != nil && pid != 0 { - launchedDesktopFile := process.environ.Get("GIO_LAUNCHED_DESKTOP_FILE") - launchedDesktopFilePid, _ := strconv.ParseUint( - process.environ.Get("GIO_LAUNCHED_DESKTOP_FILE_PID"), 10, 32) - - logger.Debugf("%s launchedDesktopFile: %q, pid: %d", - msgPrefix, launchedDesktopFile, launchedDesktopFilePid) - - // 以下 2 种情况下,才能信任环境变量 GIO_LAUNCHED_DESKTOP_FILE。 - // 1. 当窗口 pid 和 launchedDesktopFilePid 相同时; - // 2. 当窗口的进程的父进程 id(即 ppid)和 launchedDesktopFilePid 相同, - // 并且该父进程是 sh 或 bash 时。 - var try bool - if uint(launchedDesktopFilePid) == pid { - try = true - } else if uint(launchedDesktopFilePid) == process.ppid && process.ppid != 0 { - logger.Debug(msgPrefix, "ppid equal") - parentProcess := procfs.Process(process.ppid) - cmdline, err := parentProcess.Cmdline() - if err == nil && len(cmdline) > 0 { - logger.Debugf("%s parent process cmdline: %#v", msgPrefix, cmdline) - base := filepath.Base(cmdline[0]) - if base == "sh" || base == "bash" { - try = true - } - } - } - - if try { - appInfo := NewAppInfoFromFile(launchedDesktopFile) - if appInfo != nil { - // success - return appInfo.innerId, appInfo - } - } - } - // fail - return "", nil -} - -func identifyKwindowByExeEnv(m *Manager, winInfo *KWindowInfo) (string, *AppInfo) { - appId := winInfo.appId - msgPrefix := fmt.Sprintf("identifyKwindowByExeEnv appId: %s ", appId) - if winInfo.process == nil { - logger.Warning("identify kwindow error: process is not inited.") - return "", nil - } - process := winInfo.process - customExecName := filepath.Base(process.exe) - - // 对于一个应用对应多个pid的情况,根据process中的可执行文件名和该应用的appId去识别窗口 - if strings.Contains(customExecName, appId) { - launchedDesktopFile := process.environ.Get("GIO_LAUNCHED_DESKTOP_FILE") - logger.Debug(msgPrefix, "launchedDesktopFile: ", launchedDesktopFile) - appInfo := NewAppInfoFromFile(launchedDesktopFile) - if appInfo != nil { - // success - return appInfo.innerId, appInfo - } - } - - return "", nil -} - -func identifyWindowByRule(m *Manager, winInfo *WindowInfo) (string, *AppInfo) { - msgPrefix := fmt.Sprintf("identifyWindowByRule win: %d ", winInfo.xid) - ret := m.windowPatterns.Match(winInfo) - if ret == "" { - return "", nil - } - logger.Debug(msgPrefix, "patterns match result:", ret) - // parse ret - // id=$appId or env - var appInfo *AppInfo - if len(ret) > 4 && strings.HasPrefix(ret, "id=") { - appInfo = NewAppInfo(ret[3:]) - } else if ret == "env" { - process := winInfo.process - if process != nil { - launchedDesktopFile := process.environ.Get("GIO_LAUNCHED_DESKTOP_FILE") - if launchedDesktopFile != "" { - appInfo = NewAppInfoFromFile(launchedDesktopFile) - } - } - } else { - logger.Warningf("bad ret: %q", ret) - } - - if appInfo != nil { - return appInfo.innerId, appInfo - } - return "", nil -} - -func identifyWindowByWmClass(m *Manager, winInfo *WindowInfo) (string, *AppInfo) { - if winInfo.wmClass != nil { - instance := winInfo.wmClass.Instance - if instance != "" { - // example: - // WM_CLASS(STRING) = "Brackets", "Brackets" - // wm class instance is Brackets - // try app id org.deepin.flatdeb.brackets - appInfo := NewAppInfo("org.deepin.flatdeb." + strings.ToLower(instance)) - if appInfo != nil { - return appInfo.innerId, appInfo - } - - appInfo = NewAppInfo(instance) - if appInfo != nil { - return appInfo.innerId, appInfo - } - } - - class := winInfo.wmClass.Class - if class != "" { - appInfo := NewAppInfo(class) - if appInfo != nil { - return appInfo.innerId, appInfo - } - } - } - // fail - return "", nil -} - -func identifyWindowByBamf(m *Manager, winInfo *baseWindowInfo) (string, *AppInfo) { - msgPrefix := fmt.Sprintf("identifyWindowByBamf win: %d ", winInfo.xid) - win := winInfo.xid - desktop := "" - // 重试 bamf 识别,yozo office 的窗口经常要第二次时才能识别到。 - for i := 0; i < 3; i++ { - var err error - desktop, err = getDesktopFromWindowByBamf(win) - logger.Debugf("%s get desktop i: %d, desktop: %q", msgPrefix, i, desktop) - if err != nil { - logger.Warning(msgPrefix, "get desktop failed:", err) - } - if desktop != "" { - break - } - time.Sleep(100 * time.Millisecond) - } - - if desktop != "" { - appInfo := NewAppInfoFromFile(desktop) - if appInfo != nil { - // success - return appInfo.innerId, appInfo - } - } - return "", nil -} - -func identifyWindowByCmdlineXWalk(m *Manager, winInfo *WindowInfo) (string, *AppInfo) { - msgPrefix := fmt.Sprintf("identifyWindowByCmdlineXWalk win: %d ", winInfo.xid) - process := winInfo.process - if process == nil || winInfo.pid == 0 { - return "", nil - } - - exeBase := filepath.Base(process.exe) - args := process.args - if exeBase != "xwalk" || len(args) == 0 { - return "", nil - } - lastArg := args[len(args)-1] - logger.Debugf("%s lastArg: %q", msgPrefix, lastArg) - - if filepath.Base(lastArg) == "manifest.json" { - appId := filepath.Base(filepath.Dir(lastArg)) - appInfo := NewAppInfo(appId) - if appInfo != nil { - // success - return appInfo.innerId, appInfo - } - } - // failed - return "", nil -} diff --git a/dock/identify_window_pattern.go b/dock/identify_window_pattern.go deleted file mode 100644 index 4dc7327cc..000000000 --- a/dock/identify_window_pattern.go +++ /dev/null @@ -1,311 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "path/filepath" - "regexp" - "strings" - "sync" -) - -type WindowPatterns []WindowPattern - -type WindowPattern struct { - Rules []WindowRule `json:"rules"` - Result string `json:"ret"` - ParsedRules []*WindowRuleParsed -} - -type WindowRule [2]string -type WindowRuleParsed struct { - Key string - ValueParsed *RuleValueParsed -} - -func (rule *WindowRule) Parse() *WindowRuleParsed { - key, value := rule[0], rule[1] - return &WindowRuleParsed{ - Key: key, - ValueParsed: parseRuleValue(value), - } -} - -func loadWindowPatterns(file string) (WindowPatterns, error) { - content, err := ioutil.ReadFile(file) - if err != nil { - return nil, err - } - var patterns WindowPatterns - err = json.Unmarshal(content, &patterns) - if err != nil { - return nil, err - } - logger.Debugf("loadWindowPatterns: ok count %d", len(patterns)) - - // parse pattterns - for i := range patterns { - pattern := &patterns[i] - rules := pattern.Rules - // parse rules in pattern - pattern.ParsedRules = make([]*WindowRuleParsed, len(rules)) - for j := range rules { - rule := &rules[j] - pattern.ParsedRules[j] = rule.Parse() - } - } - - return patterns, nil -} - -func (patterns WindowPatterns) Match(winInfo *WindowInfo) string { - for i := range patterns { - pattern := &patterns[i] - rules := pattern.ParsedRules - patternOk := true - - logger.Debugf("try pattern %d", i) - for j := range rules { - rule := rules[j] - ok := rule.Match(winInfo) - if !ok { - // pattern match fail - patternOk = false - break - } - } - - if patternOk { - // pattern match success - logger.Debugf("pattern match success") - return pattern.Result - } - } - // fail - return "" -} - -func parseRuleKey(winInfo *WindowInfo, key string) string { - switch key { - case "hasPid": - if winInfo.process != nil && winInfo.process.hasPid { - return "t" - } - return "f" - case "exec": - // executable file base name - if winInfo.process != nil { - return filepath.Base(winInfo.process.exe) - } - case "arg": - // command line arguments - if winInfo.process != nil { - return strings.Join(winInfo.process.args, " ") - } - // xprop example: - // WM_CLASS(STRING) = "dman", "DManual" - // wmClass.Instance is dman - // wmClass.Class is DManual - case "wmi": - // wmClass.Instance - if winInfo.wmClass != nil { - return winInfo.wmClass.Instance - } - case "wmc": - // wmClass.Class - if winInfo.wmClass != nil { - return winInfo.wmClass.Class - } - case "wmn": - // WM_NAME - return winInfo.wmName - case "wmrole": - // WM_ROLE - return winInfo.wmRole - - default: - const envPrefix = "env." - if strings.HasPrefix(key, envPrefix) { - envName := key[len(envPrefix):] - if winInfo.process != nil { - return winInfo.process.environ.Get(envName) - } - } - } - return "" -} - -func (rule *WindowRuleParsed) Match(winInfo *WindowInfo) bool { - keyParsed := parseRuleKey(winInfo, rule.Key) - fn := rule.ValueParsed.Fn - if fn == nil { - logger.Warningf("WindowRule.Match: badRuleValue %q", rule.ValueParsed.Original) - return false - } - result := fn(keyParsed) - logger.Debugf("%s %q %v ? %v", rule.Key, keyParsed, rule.ValueParsed, result) - return result -} - -type RuleValueParsed struct { - Fn RuleMatchFunc - Type byte - Flags RuleValueParsedFlag - Original string - Value string -} -type RuleMatchFunc func(string) bool - -type RuleValueParsedFlag uint - -const ( - RuleValueParsedFlagNone RuleValueParsedFlag = 1 << iota - RuleValueParsedFlagNegative - RuleValueParsedFlagIgnoreCase -) - -func (p *RuleValueParsed) String() string { - var buf bytes.Buffer - if p.Fn == nil { - return "bad rule" - } - - if p.Flags&RuleValueParsedFlagNegative != 0 { - buf.WriteString("not ") - } - - var typeDesc string - switch p.Type { - case '=', 'e', 'E': - typeDesc = "equal" - case 'c', 'C': - typeDesc = "contains" - case 'r', 'R': - typeDesc = "match regexp " - default: - typeDesc = "" - } - buf.WriteString(typeDesc) - - if p.Flags&RuleValueParsedFlagIgnoreCase != 0 { - buf.WriteString(" (ignore case)") - } - // "$k not equal (ignore case) $p.value" - fmt.Fprintf(&buf, " %q", p.Value) - return buf.String() -} - -func negativeRule(fn RuleMatchFunc) RuleMatchFunc { - return func(k string) bool { - return !fn(k) - } -} - -var regexpCache map[string]*regexp.Regexp = make(map[string]*regexp.Regexp) -var regexpCacheMutex sync.Mutex - -func getRegexp(expr string) *regexp.Regexp { - regexpCacheMutex.Lock() - defer regexpCacheMutex.Unlock() - - reg, ok := regexpCache[expr] - if ok { - return reg - } - reg, err := regexp.Compile(expr) - if err != nil { - logger.Warning(err) - } - regexpCache[expr] = reg - return reg -} - -// "=:XXX" equal XXX -// "=!XXX" not equal XXX - -// "c:XXX" contains XXX -// "c!XXX" not contains XXX - -// "r:XXX" match regexp XXX -// "r!XXX" not match regexp XXX - -// e c r ignore case -// = E C R not ignore case -func parseRuleValue(val string) *RuleValueParsed { - var ret = &RuleValueParsed{ - Original: val, - } - if len(val) < 2 { - return ret - } - var negative bool - switch val[1] { - case ':': - case '!': - ret.Flags |= RuleValueParsedFlagNegative - negative = true - default: - return ret - } - // type - value := val[2:] - ret.Value = value - ret.Type = val[0] - - var fn RuleMatchFunc - switch val[0] { - case 'C': - fn = func(k string) bool { - return strings.Contains(k, value) - } - case 'c': - ret.Flags |= RuleValueParsedFlagIgnoreCase - fn = func(k string) bool { - return strings.Contains( - strings.ToLower(k), - strings.ToLower(value)) - } - case '=', 'E': - fn = func(k string) bool { - return k == value - } - case 'e': - ret.Flags |= RuleValueParsedFlagIgnoreCase - fn = func(k string) bool { - return strings.EqualFold(k, value) - } - - case 'R': - fn = func(k string) bool { - reg := getRegexp(value) - if reg == nil { - return false - } - return reg.MatchString(k) - } - case 'r': - ret.Flags |= RuleValueParsedFlagIgnoreCase - fn = func(k string) bool { - reg := getRegexp("(?i)" + value) - if reg == nil { - return false - } - return reg.MatchString(k) - } - - default: - return ret - } - if negative { - ret.Fn = negativeRule(fn) - } else { - ret.Fn = fn - } - return ret -} diff --git a/dock/init.go b/dock/init.go deleted file mode 100644 index 21530ca4c..000000000 --- a/dock/init.go +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "path/filepath" - - "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/go-lib/xdg/basedir" - "github.com/linuxdeepin/dde-daemon/loader" - - x "github.com/linuxdeepin/go-x11-client" -) - -func init() { - loader.Register(NewDaemon(logger)) -} - -var ( - logger = log.NewLogger("daemon/dock") - homeDir string - scratchDir string - dockManager *Manager - - globalXConn *x.Conn - - atomNetShowingDesktop x.Atom - atomNetClientList x.Atom - atomNetActiveWindow x.Atom - atomNetWMIcon x.Atom - atomNetWMName x.Atom - atomNetWMState x.Atom - atomNetWMWindowType x.Atom - atomXEmbedInfo x.Atom - atomNetFrameExtents x.Atom - atomGtkFrameExtents x.Atom - atomNetWmStateHidden x.Atom - atomWmWindowRole x.Atom - atomUTF8String x.Atom - atomString x.Atom - atomInteger x.Atom - atomFlatpakAppId x.Atom - atomGtkApplicationId x.Atom - atomNetWmWindowOpacity x.Atom - atomWmClientLeader x.Atom - atomWmCommand x.Atom - atomNetWmStateFocused x.Atom //nolint - atomNetWmWindowTypeDesktop x.Atom - atomNetWmActionMinimize x.Atom - atomWmStateDemandsAttention x.Atom - atomNetWmStateSkipTaskbar x.Atom - atomNetWmStateModal x.Atom - atomNetWmWindowTypeDialog x.Atom - atomNetWmStateMaximizedVert x.Atom - atomNetWmStateMaximizedHorz x.Atom - atomNetWmStateAbove x.Atom - atomNetWmActionClose x.Atom - atomNetWmAllowedActions x.Atom - atomNetWmPid x.Atom - atomMotifWmHints x.Atom - - atomAndroidUengineId x.Atom - atomAndroidUengineName x.Atom - atomDSGVirtualAppDesktop x.Atom -) - -func initDir() { - homeDir = basedir.GetUserHomeDir() - scratchDir = filepath.Join(basedir.GetUserConfigDir(), "dock/scratch") - logger.Debugf("scratch dir: %q", scratchDir) -} - -func initAtom() { - atomNetShowingDesktop, _ = getAtom("_NET_SHOWING_DESKTOP") - atomNetClientList, _ = getAtom("_NET_CLIENT_LIST") - atomNetActiveWindow, _ = getAtom("_NET_ACTIVE_WINDOW") - atomNetWMIcon, _ = getAtom("_NET_WM_ICON") - atomNetWMName, _ = getAtom("_NET_WM_NAME") - atomNetWMState, _ = getAtom("_NET_WM_STATE") - atomNetWMWindowType, _ = getAtom("_NET_WM_WINDOW_TYPE") - atomXEmbedInfo, _ = getAtom("_XEMBED_INFO") - atomNetFrameExtents, _ = getAtom("_NET_FRAME_EXTENTS") - atomGtkFrameExtents, _ = getAtom("_GTK_FRAME_EXTENTS") - atomNetWmStateHidden, _ = getAtom("_NET_WM_STATE_HIDDEN") - atomWmWindowRole, _ = getAtom("WM_WINDOW_ROLE") - atomUTF8String, _ = getAtom("UTF8_STRING") - atomString, _ = getAtom("STRING") - atomInteger, _ = getAtom("INTEGER") - atomFlatpakAppId, _ = getAtom("FLATPAK_APPID") - atomGtkApplicationId, _ = getAtom("_GTK_APPLICATION_ID") - atomNetWmWindowOpacity, _ = getAtom("_NET_WM_WINDOW_OPACITY") - atomWmClientLeader, _ = getAtom("WM_CLIENT_LEADER") - atomWmCommand, _ = getAtom("WM_COMMAND") - atomNetWmStateFocused, _ = getAtom("_NET_WM_STATE_FOCUSED") - atomNetWmWindowTypeDesktop, _ = getAtom("_NET_WM_WINDOW_TYPE_DESKTOP") - atomNetWmActionMinimize, _ = getAtom("_NET_WM_ACTION_MINIMIZE") - atomWmStateDemandsAttention, _ = getAtom("_NET_WM_STATE_DEMANDS_ATTENTION") - atomNetWmStateSkipTaskbar, _ = getAtom("_NET_WM_STATE_SKIP_TASKBAR") - atomNetWmStateModal, _ = getAtom("_NET_WM_STATE_MODAL") - atomNetWmWindowTypeDialog, _ = getAtom("_NET_WM_WINDOW_TYPE_DIALOG") - atomNetWmStateMaximizedVert, _ = getAtom("_NET_WM_STATE_MAXIMIZED_VERT") - atomNetWmStateMaximizedHorz, _ = getAtom("_NET_WM_STATE_MAXIMIZED_HORZ") - atomNetWmStateAbove, _ = getAtom("_NET_WM_STATE_ABOVE") - atomNetWmActionClose, _ = getAtom("_NET_WM_ACTION_CLOSE") - atomNetWmAllowedActions, _ = getAtom("_NET_WM_ALLOWED_ACTIONS") - atomNetWmPid, _ = getAtom("_NET_WM_PID") - atomMotifWmHints, _ = getAtom("_MOTIF_WM_HINTS") - atomAndroidUengineId, _ = getAtom("UENGINE_TASK_ID") - atomAndroidUengineName, _ = getAtom("UENGINE_TASK_NAME") - atomDSGVirtualAppDesktop, _ = getAtom("_DSG_NET_WM_LAUNCHED_DESKTOP_FILE") -} diff --git a/dock/kwindow_info.go b/dock/kwindow_info.go deleted file mode 100644 index 66c1baa04..000000000 --- a/dock/kwindow_info.go +++ /dev/null @@ -1,315 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "time" - - kwayland "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.kwayland" - x "github.com/linuxdeepin/go-x11-client" -) - -type WindowInfoImp interface { - getXid() x.Window - setEntry(*AppEntry) - getEntry() *AppEntry - shouldSkip() bool - getEntryInnerId() string - getInnerId() string - setEntryInnerId(string) - getAppInfo() *AppInfo - setAppInfo(*AppInfo) - print() - getDisplayName() string - getIcon() string - getTitle() string - isDemandingAttention() bool - allowClose() bool - close(timestamp uint32) error - getPid() uint - getProcess() *ProcessInfo - activate() error - minimize() error - maximize() error - makeWindowAbove() error - isMinimized() bool - killClient() error - changeXid(x.Window) bool - getCreatedTime() int64 -} - -type KWindowInfo struct { - baseWindowInfo - winObj kwayland.Window - updateCalled bool - - appId string - internalId uint32 - demandingAttention bool - closeable bool - minimized bool - geometry kwayland.Rect -} - -type baseWindowInfo struct { - xid x.Window - Title string - Icon string - pid uint - entryInnerId string - innerId string - entry *AppEntry - appInfo *AppInfo - process *ProcessInfo - createdTime int64 -} - -func (winInfo *KWindowInfo) print() { - // TODO - return -} - -func (winInfo *KWindowInfo) getDisplayName() string { - // TODO - return "" -} - -func (winInfo *KWindowInfo) shouldSkip() bool { - if !winInfo.updateCalled { - winInfo.update() - winInfo.updateCalled = true - } - - skip, err := winInfo.winObj.SkipTaskbar(0) - if err != nil { - logger.Warning(err) - return true - } - // + 添加窗口能否最小化判断,如果窗口不能最小化则隐藏任务栏图标 - canMinimize, _ := winInfo.winObj.IsMinimizeable(0) - if canMinimize == false { - skip = true - } - - if skip { - // + 白名单(临时方案,待窗口增加wayland下窗口规则后再修改): 修复类似欢迎应用没有最小化窗口,但是需要在任务栏显示图标 - for _, app := range []string{"dde-introduction"} { - if app == winInfo.appId { - skip = false - } - } - } - return skip -} - -// baseWindowInfo -func (winInfo *baseWindowInfo) getInnerId() string { - return winInfo.innerId -} - -func (winInfo *baseWindowInfo) getPid() uint { - return winInfo.pid -} - -func (winInfo *baseWindowInfo) getIcon() string { - return winInfo.Icon -} - -func (winInfo *baseWindowInfo) getTitle() string { - return winInfo.Title -} - -func (winInfo *baseWindowInfo) getProcess() *ProcessInfo { - return winInfo.process -} - -func (winInfo *baseWindowInfo) getEntry() *AppEntry { - return winInfo.entry -} - -func (winInfo *baseWindowInfo) setEntry(v *AppEntry) { - winInfo.entry = v -} - -func (winInfo *baseWindowInfo) getEntryInnerId() string { - return winInfo.entryInnerId -} - -func (winInfo *baseWindowInfo) setEntryInnerId(v string) { - winInfo.entryInnerId = v -} - -func (winInfo *baseWindowInfo) getAppInfo() *AppInfo { - return winInfo.appInfo -} - -func (winInfo *baseWindowInfo) setAppInfo(v *AppInfo) { - winInfo.appInfo = v -} - -func (winInfo *baseWindowInfo) getXid() x.Window { - return winInfo.xid -} - -func (winInfo *baseWindowInfo) getCreatedTime() int64 { - return winInfo.createdTime -} - -func newKWindowInfo(winObj kwayland.Window, xid uint32) *KWindowInfo { - winInfo := &KWindowInfo{ - winObj: winObj, - } - winInfo.xid = x.Window(xid) - winInfo.createdTime = time.Now().UnixNano() - return winInfo -} - -func (winInfo *KWindowInfo) fetchTitle() string { - title, err := winInfo.winObj.Title(0) - if err != nil { - logger.Warning(err) - return "" - } - return title -} - -func (winInfo *KWindowInfo) updateTitle() { - winInfo.Title = winInfo.fetchTitle() -} - -func (winInfo *KWindowInfo) fetchIcon() string { - icon, err := winInfo.winObj.Icon(0) - if err != nil { - logger.Warning(err) - return "" - } - return icon -} - -func (winInfo *KWindowInfo) updateIcon() { - winInfo.Icon = winInfo.fetchIcon() -} - -func (winInfo *KWindowInfo) updateGeometry() bool { - rect, err := winInfo.winObj.Geometry(0) - if err != nil { - logger.Warning(err) - return false - } - if winInfo.geometry == rect { - return false - } - winInfo.geometry = rect - return true -} - -func (winInfo *KWindowInfo) allowClose() bool { - return winInfo.closeable -} - -func (winInfo *KWindowInfo) isDemandingAttention() bool { - return winInfo.demandingAttention -} - -func (winInfo *KWindowInfo) updateAppId() { - appId, err := winInfo.winObj.AppId(0) - if err != nil { - logger.Warning(err) - } - winInfo.appId = appId -} - -func (winInfo *KWindowInfo) update() { - logger.Debug("update window info", winInfo.winObj.Path_()) - winInfo.updateInternalId() - winInfo.updateAppId() - winInfo.updateIcon() - winInfo.updateTitle() - winInfo.updateGeometry() - winInfo.updateDemandingAttention() - winInfo.updateCloseable() - winInfo.updateProcessInfo() -} - -func (winInfo *KWindowInfo) updateInternalId() { - id, err := winInfo.winObj.InternalId(0) - if err != nil { - logger.Warning(err) - } - winInfo.internalId = id -} - -func (winInfo *KWindowInfo) updateDemandingAttention() { - isDA, err := winInfo.winObj.IsDemandingAttention(0) - if err != nil { - logger.Warning(err) - } - winInfo.demandingAttention = isDA -} - -func (winInfo *KWindowInfo) updateCloseable() { - closeable, err := winInfo.winObj.IsCloseable(0) - if err != nil { - logger.Warning(err) - closeable = true - } - winInfo.closeable = closeable -} - -func (winInfo *KWindowInfo) updateMinimized() { - minimized, err := winInfo.winObj.IsMinimized(0) - if err != nil { - logger.Warning(err) - } - winInfo.minimized = minimized -} - -func (winInfo *KWindowInfo) isMinimized() bool { - return winInfo.minimized -} - -func (winInfo *KWindowInfo) updateProcessInfo() { - pid, err := winInfo.winObj.Pid(0) - if err != nil { - logger.Warning(err) - return - } - winInfo.pid = uint(pid) - winInfo.process, err = NewProcessInfo(winInfo.pid) - if err != nil { - logger.Warning(err) - return - } - logger.Debugf("process: %#v", winInfo.process) -} - -func (winInfo *KWindowInfo) activate() error { - return winInfo.winObj.RequestActivate(0) -} - -func (winInfo *KWindowInfo) minimize() error { - return winInfo.winObj.RequestToggleMinimized(0) -} - -func (winInfo *KWindowInfo) maximize() error { - return winInfo.winObj.RequestToggleMaximized(0) -} - -func (winInfo *KWindowInfo) makeWindowAbove() error { - return winInfo.winObj.RequestToggleKeepAbove(0) -} - -func (winInfo *KWindowInfo) close(timestamp uint32) error { - return winInfo.winObj.RequestClose(0) -} - -func (winInfo *KWindowInfo) killClient() error { - return winInfo.winObj.RequestClose(0) -} - -func (winInfo *KWindowInfo) changeXid(xid x.Window) bool { - winInfo.xid = xid - return true -} diff --git a/dock/menu.go b/dock/menu.go deleted file mode 100644 index 421980db6..000000000 --- a/dock/menu.go +++ /dev/null @@ -1,105 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "encoding/json" - "errors" - "strconv" -) - -/* -json sample -{ - "checkableMenu" : false, - "items" : [ - { - "itemText" : "item 1", - "isActive" : true, - "itemSubMenu" : nil, - "itemId" : "2", - "itemIconInactive" : "", - "checked" : false, - "itemIconHover" : "", - "itemIcon" : "", - "showCheckMark" : false, - "isCheckable" : false - }, - ], - "singleCheck" : false -} -*/ - -type MenuItem struct { - Id string `json:"itemId"` - Text string `json:"itemText"` - IsActive bool `json:"isActive"` - IsCheckable bool `json:"isCheckable"` - Checked bool `json:"checked"` - Icon string `json:"itemIcon"` - IconHover string `json:"itemIconHover"` - IconInactive string `json:"itemIconInactive"` - ShowCheckMark bool `json:"showCheckMark"` - SubMenu *Menu `json:"itemSubMenu"` - - hint int - action func(uint32) -} - -const menuItemHintShowAllWindows = 1 - -func NewMenuItem(name string, action func(uint32), enable bool) *MenuItem { - return &MenuItem{ - Text: name, - IsActive: enable, - action: action, - } -} - -type Menu struct { - Items []*MenuItem `json:"items"` - CheckableMenu bool `json:"checkableMenu"` - SingleCheck bool `json:"singleCheck"` - - itemCount int64 -} - -func NewMenu() *Menu { - return &Menu{} -} - -func (m *Menu) allocateId() string { - idStr := strconv.FormatInt(m.itemCount, 10) - m.itemCount++ - return idStr -} - -func (m *Menu) AppendItem(items ...*MenuItem) { - for _, item := range items { - if item.Text != "" { - item.Id = m.allocateId() - m.Items = append(m.Items, item) - } - } -} - -func (m *Menu) HandleAction(id string, timestamp uint32) error { - for _, item := range m.Items { - if id == item.Id { - item.action(timestamp) - return nil - } - } - return errors.New("invalid item id") -} - -func (m *Menu) GenerateJSON() string { - bytes, err := json.Marshal(m) - if err != nil { - logger.Warning(err) - return "" - } - return string(bytes) -} diff --git a/dock/menu_test.go b/dock/menu_test.go deleted file mode 100644 index e004321ec..000000000 --- a/dock/menu_test.go +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" -) - -func IsContainItem(items []*MenuItem, item *MenuItem) bool { - for _, i := range items { - if i.Text == item.Text && i.IsActive == item.IsActive && i.Id != "" { - return true - } - } - return false -} - -func Test_AppendItem(t *testing.T) { - menu := NewMenu() - item0 := NewMenuItem("item 0", nil, true) - item1 := NewMenuItem("item 1", nil, true) - item2 := NewMenuItem("item 2", nil, true) - item3 := NewMenuItem("item 3", nil, true) - menu.AppendItem(item0, item1, item2) - - assert.True(t, IsContainItem(menu.Items, item0)) - assert.True(t, IsContainItem(menu.Items, item1)) - assert.True(t, IsContainItem(menu.Items, item2)) - assert.False(t, IsContainItem(menu.Items, item3)) -} - -func Test_GenerateMenuJson(t *testing.T) { - menu := NewMenu() - item0 := NewMenuItem("item 0", nil, true) - item1 := NewMenuItem("item 1", nil, true) - item2 := NewMenuItem("item 2", nil, true) - menu.AppendItem(item0, item1, item2) - - menuJSON := menu.GenerateJSON() - assert.Equal(t, menuJSON, `{"items":[{"itemId":"0","itemText":"item 0","isActive":true,"isCheckable":false,"checked":false,"itemIcon":"","itemIconHover":"","itemIconInactive":"","showCheckMark":false,"itemSubMenu":null},{"itemId":"1","itemText":"item 1","isActive":true,"isCheckable":false,"checked":false,"itemIcon":"","itemIconHover":"","itemIconInactive":"","showCheckMark":false,"itemSubMenu":null},{"itemId":"2","itemText":"item 2","isActive":true,"isCheckable":false,"checked":false,"itemIcon":"","itemIconHover":"","itemIconInactive":"","showCheckMark":false,"itemSubMenu":null}],"checkableMenu":false,"singleCheck":false}`) - - var parseResult interface{} - err := json.Unmarshal([]byte(menuJSON), &parseResult) - assert.NoError(t, err) -} diff --git a/dock/plugin_settings.go b/dock/plugin_settings.go deleted file mode 100644 index bf7f27926..000000000 --- a/dock/plugin_settings.go +++ /dev/null @@ -1,136 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "encoding/json" - "reflect" - "sync" - "time" - - "github.com/linuxdeepin/go-lib/dbusutil" -) - -type pluginSettings map[string]map[string]interface{} - -type pluginSettingsStorage struct { - m *Manager - data pluginSettings - dataMu sync.Mutex - - timer *time.Timer - saving bool - saveStateMu sync.Mutex -} - -func newPluginSettingsStorage(m *Manager) *pluginSettingsStorage { - s := &pluginSettingsStorage{m: m} - - jsonStr := m.settings.GetString(settingKeyPluginSettings) - var v pluginSettings - err := json.Unmarshal([]byte(jsonStr), &v) - if err == nil { - s.data = v - } else { - logger.Warning("failed to load plugin settings:", err) - s.data = make(pluginSettings) - } - - s.timer = time.AfterFunc(3*time.Second, func() { - s.save() - s.saveStateMu.Lock() - s.saving = false - s.saveStateMu.Unlock() - }) - return s -} - -func (s *pluginSettingsStorage) requestSave() { - s.saveStateMu.Lock() - defer s.saveStateMu.Unlock() - - if s.saving { - return - } else { - s.timer.Reset(1 * time.Second) - s.saving = true - } -} - -func (s *pluginSettingsStorage) save() { - s.dataMu.Lock() - defer s.dataMu.Unlock() - - jsonData, err := json.Marshal(s.data) - if err != nil { - logger.Warning(err) - return - } - ok := s.m.settings.SetString(settingKeyPluginSettings, string(jsonData)) - if !ok { - logger.Warning("failed to save plugin settings") - } -} - -func (s *pluginSettingsStorage) getJsonStr() (string, error) { - s.dataMu.Lock() - defer s.dataMu.Unlock() - - jsonData, err := json.Marshal(s.data) - if err != nil { - return "", dbusutil.ToError(err) - } - return string(jsonData), nil -} - -func (s *pluginSettingsStorage) set(v pluginSettings) { - s.dataMu.Lock() - s.data = v - s.dataMu.Unlock() - s.requestSave() -} - -func (s *pluginSettingsStorage) merge(v pluginSettings) { - s.dataMu.Lock() - - for key1, value1 := range v { - if s.data[key1] == nil && len(value1) > 0 { - s.data[key1] = make(map[string]interface{}) - } - - for key2, value2 := range value1 { - s.data[key1][key2] = value2 - } - } - - s.dataMu.Unlock() - s.requestSave() -} - -func (s *pluginSettingsStorage) remove(key1 string, key2List []string) { - s.dataMu.Lock() - - if len(key2List) == 0 { - delete(s.data, key1) - } else { - if value1, ok := s.data[key1]; ok { - for _, key2 := range key2List { - delete(value1, key2) - } - if len(value1) == 0 { - delete(s.data, key1) - } - } - } - - s.dataMu.Unlock() - s.requestSave() -} - -func (s *pluginSettingsStorage) equal(v pluginSettings) bool { - s.dataMu.Lock() - defer s.dataMu.Unlock() - return reflect.DeepEqual(s.data, v) -} diff --git a/dock/process_info.go b/dock/process_info.go deleted file mode 100644 index 83c61d58d..000000000 --- a/dock/process_info.go +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "errors" - "fmt" - "path/filepath" - "strconv" - "strings" - - "github.com/linuxdeepin/go-lib/procfs" -) - -type ProcessInfo struct { - process procfs.Process - cmdline []string - args []string - exe string - cwd string - environ procfs.EnvVars - hasPid bool - ppid uint -} - -func NewProcessInfoWithCmdline(cmd []string) *ProcessInfo { - if len(cmd) == 0 { - return nil - } - return &ProcessInfo{ - cmdline: cmd, - args: cmd[1:], - exe: cmd[0], - } -} - -func NewProcessInfo(pid uint) (*ProcessInfo, error) { - if pid == 0 { - return nil, errors.New("pid is 0") - } - - process := procfs.Process(pid) - pInfo := &ProcessInfo{ - process: process, - hasPid: true, - } - var err error - - // exe - pInfo.exe, err = process.Exe() - if err != nil { - return nil, err - } - - // cwd - pInfo.cwd, err = process.Cwd() - if err != nil { - return nil, err - } - - // cmdline - pInfo.cmdline, err = process.Cmdline() - if err != nil { - return nil, err - } - - // args - pInfo.args = getCmdlineArgs(pInfo.exe, pInfo.cwd, pInfo.cmdline) - if err != nil { - return nil, err - } - - // environ - pInfo.environ, _ = process.Environ() - - // ppid - if status, err := process.Status(); err == nil { - pInfo.ppid, _ = status.PPid() - } - - return pInfo, nil -} - -func getCmdlineArgs(exe, cwd string, cmdline []string) []string { - ok := verifyExe(exe, cwd, cmdline[0]) - if !ok { - logger.Debug("first arg is not exe file, contains arguments") - // try again - parts := strings.Split(cmdline[0], " ") - ok = verifyExe(exe, cwd, parts[0]) - if !ok { - logger.Warningf("failed to find right exe, exe: %q, cwd: %q, cmdline: %#v", exe, cwd, cmdline) - return nil - } else { - return append(parts[1:], cmdline[1:]...) - } - } else { - return cmdline[1:] - } -} - -func verifyExe(exe, cwd, firstArg string) bool { - if filepath.Base(firstArg) == firstArg { - logger.Debug("basename equal") - return true - } - - if !filepath.IsAbs(firstArg) { - firstArg = filepath.Join(cwd, firstArg) - } - // firstArg is abs path - logger.Debugf("firstArg: %q", firstArg) - firstArgPath, err := filepath.EvalSymlinks(firstArg) - if err != nil { - logger.Warning(err) - // first arg is not exe file, contains arguments - return false - } - logger.Debugf("firstArgPath: %q", firstArgPath) - return exe == firstArgPath -} - -func (p *ProcessInfo) getJoinedExeArgs() string { - var cmdline string - cmdline = strconv.Quote(p.exe) - for _, arg := range p.args { - cmdline += " " + strconv.Quote(arg) - } - return cmdline + " $@" -} - -func (p *ProcessInfo) GetShellScriptLines() string { - cmdline := p.getJoinedExeArgs() - return fmt.Sprintf("#!/bin/sh\ncd %q\nexec %s\n", p.cwd, cmdline) -} - -func (p *ProcessInfo) GetOneCommandLine() string { - cmdline := p.getJoinedExeArgs() - return fmt.Sprintf("sh -c 'cd %q;exec %s;'", p.cwd, cmdline) -} diff --git a/dock/sync_config.go b/dock/sync_config.go deleted file mode 100644 index c47a02df0..000000000 --- a/dock/sync_config.go +++ /dev/null @@ -1,123 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "encoding/json" - "github.com/linuxdeepin/go-lib/strv" - "os" -) - -type syncConfig struct { - m *Manager -} - -func (sc *syncConfig) Get() (interface{}, error) { - var v syncData - v.Version = syncConfigVersion - v.WindowSizeEfficient = sc.m.WindowSizeEfficient.Get() - v.WindowSizeFashion = sc.m.WindowSizeFashion.Get() - v.DisplayMode = sc.m.DisplayMode.GetString() - v.HideMode = sc.m.HideMode.GetString() - v.Position = sc.m.Position.GetString() - v.DockedApps = sc.m.DockedApps.Get() - - pluginSettingsJsonStr := sc.m.settings.GetString(settingKeyPluginSettings) - err := json.Unmarshal([]byte(pluginSettingsJsonStr), &v.Plugins) - if err != nil { - logger.Warning(err) - } - - return v, nil -} - -func (sc *syncConfig) setPluginSettings(settings pluginSettings) { - m := sc.m - if m.pluginSettings.equal(settings) { - return - } - m.pluginSettings.set(settings) - // emit signal - err := m.service.Emit(m, "PluginSettingsSynced") - if err != nil { - logger.Warning(err) - } -} - -func (sc *syncConfig) setDockedApps(dockedApps []string) { - m := sc.m - added := dockedApps - removed := m.DockedApps.Get() - for _, value := range removed { - desktopFile := unzipDesktopPath(value) - _, err := m.requestUndock(desktopFile) - if err != nil { - logger.Warning(err) - } - } - - var index = 0 - for _, value := range added { - desktopFile := unzipDesktopPath(value) - _, err := os.Stat(desktopFile) - if err == nil { - _, err = m.requestDock(desktopFile, int32(index)) - if err != nil { - logger.Warning(err) - } else { - index++ - } - } - } - - // emit signal - err := m.service.Emit(m, "DockAppSettingsSynced") - if err != nil { - logger.Warning(err) - } -} - -func (sc *syncConfig) Set(data []byte) error { - var v syncData - err := json.Unmarshal(data, &v) - if err != nil { - return err - } - m := sc.m - if v.WindowSizeEfficient > 0 { - m.WindowSizeEfficient.Set(v.WindowSizeEfficient) - } - if v.WindowSizeFashion > 0 { - m.WindowSizeFashion.Set(v.WindowSizeFashion) - } - m.DisplayMode.SetString(v.DisplayMode) - m.HideMode.SetString(v.HideMode) - m.Position.SetString(v.Position) - - if !strv.Strv(m.DockedApps.Get()).Equal(v.DockedApps) { - logger.Debugf("current entries is: %+v", m.DockedApps.Get()) - logger.Debugf("ucloud entries is: %+v", v.DockedApps) - - sc.setDockedApps(v.DockedApps) - } - - sc.setPluginSettings(v.Plugins) - return nil -} - -const ( - syncConfigVersion = "1.2" -) - -type syncData struct { - Version string `json:"version"` - WindowSizeEfficient uint32 `json:"window_size_efficient"` - WindowSizeFashion uint32 `json:"window_size_fashion"` - DisplayMode string `json:"display_mode"` - HideMode string `json:"hide_mode"` - Position string `json:"position"` - DockedApps []string `json:"docked_apps"` - Plugins pluginSettings `json:"plugins"` -} diff --git a/dock/testdata/firefox.desktop b/dock/testdata/firefox.desktop deleted file mode 100644 index 8d7ef4d7a..000000000 --- a/dock/testdata/firefox.desktop +++ /dev/null @@ -1,223 +0,0 @@ -[Desktop Entry] -Version=1.0 -Name=Firefox Web Browser -Name[ar]=متصفح الويب فَيَرفُكْس -Name[ast]=Restolador web Firefox -Name[bn]=ফায়ারফক্স ওয়েব ব্রাউজার -Name[ca]=Navegador web Firefox -Name[cs]=Firefox Webový prohlížeč -Name[da]=Firefox - internetbrowser -Name[el]=Περιηγητής Firefox -Name[es]=Navegador web Firefox -Name[et]=Firefoxi veebibrauser -Name[fa]=مرورگر اینترنتی Firefox -Name[fi]=Firefox-selain -Name[fr]=Navigateur Web Firefox -Name[gl]=Navegador web Firefox -Name[he]=דפדפן האינטרנט Firefox -Name[hr]=Firefox web preglednik -Name[hu]=Firefox webböngésző -Name[it]=Firefox Browser Web -Name[ja]=Firefox ウェブ・ブラウザ -Name[ko]=Firefox 웹 브라우저 -Name[ku]=Geroka torê Firefox -Name[lt]=Firefox interneto naršyklė -Name[nb]=Firefox Nettleser -Name[nl]=Firefox webbrowser -Name[nn]=Firefox Nettlesar -Name[no]=Firefox Nettleser -Name[pl]=Przeglądarka WWW Firefox -Name[pt]=Firefox Navegador Web -Name[pt_BR]=Navegador Web Firefox -Name[ro]=Firefox – Navigator Internet -Name[ru]=Веб-браузер Firefox -Name[sk]=Firefox - internetový prehliadač -Name[sl]=Firefox spletni brskalnik -Name[sv]=Firefox webbläsare -Name[tr]=Firefox Web Tarayıcısı -Name[ug]=Firefox توركۆرگۈ -Name[uk]=Веб-браузер Firefox -Name[vi]=Trình duyệt web Firefox -Name[zh_CN]=Firefox 网络浏览器 -Name[zh_TW]=Firefox 網路瀏覽器 -Comment=Browse the World Wide Web -Comment[ar]=تصفح الشبكة العنكبوتية العالمية -Comment[ast]=Restola pela Rede -Comment[bn]=ইন্টারনেট ব্রাউজ করুন -Comment[ca]=Navegueu per la web -Comment[cs]=Prohlížení stránek World Wide Webu -Comment[da]=Surf på internettet -Comment[de]=Im Internet surfen -Comment[el]=Μπορείτε να περιηγηθείτε στο διαδίκτυο (Web) -Comment[es]=Navegue por la web -Comment[et]=Lehitse veebi -Comment[fa]=صفحات شبکه جهانی اینترنت را مرور نمایید -Comment[fi]=Selaa Internetin WWW-sivuja -Comment[fr]=Naviguer sur le Web -Comment[gl]=Navegar pola rede -Comment[he]=גלישה ברחבי האינטרנט -Comment[hr]=Pretražite web -Comment[hu]=A világháló böngészése -Comment[it]=Esplora il web -Comment[ja]=ウェブを閲覧します -Comment[ko]=웹을 돌아 다닙니다 -Comment[ku]=Li torê bigere -Comment[lt]=Naršykite internete -Comment[nb]=Surf på nettet -Comment[nl]=Verken het internet -Comment[nn]=Surf på nettet -Comment[no]=Surf på nettet -Comment[pl]=Przeglądanie stron WWW -Comment[pt]=Navegue na Internet -Comment[pt_BR]=Navegue na Internet -Comment[ro]=Navigați pe Internet -Comment[ru]=Доступ в Интернет -Comment[sk]=Prehliadanie internetu -Comment[sl]=Brskajte po spletu -Comment[sv]=Surfa på webben -Comment[tr]=İnternet'te Gezinin -Comment[ug]=دۇنيادىكى توربەتلەرنى كۆرگىلى بولىدۇ -Comment[uk]=Перегляд сторінок Інтернету -Comment[vi]=Để duyệt các trang web -Comment[zh_CN]=浏览互联网 -Comment[zh_TW]=瀏覽網際網路 -GenericName=Web Browser -GenericName[ar]=متصفح ويب -GenericName[ast]=Restolador Web -GenericName[bn]=ওয়েব ব্রাউজার -GenericName[ca]=Navegador web -GenericName[cs]=Webový prohlížeč -GenericName[da]=Webbrowser -GenericName[el]=Περιηγητής διαδικτύου -GenericName[es]=Navegador web -GenericName[et]=Veebibrauser -GenericName[fa]=مرورگر اینترنتی -GenericName[fi]=WWW-selain -GenericName[fr]=Navigateur Web -GenericName[gl]=Navegador Web -GenericName[he]=דפדפן אינטרנט -GenericName[hr]=Web preglednik -GenericName[hu]=Webböngésző -GenericName[it]=Browser web -GenericName[ja]=ウェブ・ブラウザ -GenericName[ko]=웹 브라우저 -GenericName[ku]=Geroka torê -GenericName[lt]=Interneto naršyklė -GenericName[nb]=Nettleser -GenericName[nl]=Webbrowser -GenericName[nn]=Nettlesar -GenericName[no]=Nettleser -GenericName[pl]=Przeglądarka WWW -GenericName[pt]=Navegador Web -GenericName[pt_BR]=Navegador Web -GenericName[ro]=Navigator Internet -GenericName[ru]=Веб-браузер -GenericName[sk]=Internetový prehliadač -GenericName[sl]=Spletni brskalnik -GenericName[sv]=Webbläsare -GenericName[tr]=Web Tarayıcı -GenericName[ug]=توركۆرگۈ -GenericName[uk]=Веб-браузер -GenericName[vi]=Trình duyệt Web -GenericName[zh_CN]=网络浏览器 -GenericName[zh_TW]=網路瀏覽器 -Keywords=Internet;WWW;Browser;Web;Explorer -Keywords[ar]=انترنت;إنترنت;متصفح;ويب;وب -Keywords[ast]=Internet;WWW;Restolador;Web;Esplorador -Keywords[ca]=Internet;WWW;Navegador;Web;Explorador;Explorer -Keywords[cs]=Internet;WWW;Prohlížeč;Web;Explorer -Keywords[da]=Internet;Internettet;WWW;Browser;Browse;Web;Surf;Nettet -Keywords[de]=Internet;WWW;Browser;Web;Explorer;Webseite;Site;surfen;online;browsen -Keywords[el]=Internet;WWW;Browser;Web;Explorer;Διαδίκτυο;Περιηγητής;Firefox;Φιρεφοχ;Ιντερνετ -Keywords[es]=Explorador;Internet;WWW -Keywords[fi]=Internet;WWW;Browser;Web;Explorer;selain;Internet-selain;internetselain;verkkoselain;netti;surffaa -Keywords[fr]=Internet;WWW;Browser;Web;Explorer;Fureteur;Surfer;Navigateur -Keywords[he]=דפדפן;אינטרנט;רשת;אתרים;אתר;פיירפוקס;מוזילה; -Keywords[hr]=Internet;WWW;preglednik;Web -Keywords[hu]=Internet;WWW;Böngésző;Web;Háló;Net;Explorer -Keywords[it]=Internet;WWW;Browser;Web;Navigatore -Keywords[is]=Internet;WWW;Vafri;Vefur;Netvafri;Flakk -Keywords[ja]=Internet;WWW;Web;インターネット;ブラウザ;ウェブ;エクスプローラ -Keywords[nb]=Internett;WWW;Nettleser;Explorer;Web;Browser;Nettside -Keywords[nl]=Internet;WWW;Browser;Web;Explorer;Verkenner;Website;Surfen;Online -Keywords[pt]=Internet;WWW;Browser;Web;Explorador;Navegador -Keywords[pt_BR]=Internet;WWW;Browser;Web;Explorador;Navegador -Keywords[ru]=Internet;WWW;Browser;Web;Explorer;интернет;браузер;веб;файрфокс;огнелис -Keywords[sk]=Internet;WWW;Prehliadač;Web;Explorer -Keywords[sl]=Internet;WWW;Browser;Web;Explorer;Brskalnik;Splet -Keywords[tr]=İnternet;WWW;Tarayıcı;Web;Gezgin;Web sitesi;Site;sörf;çevrimiçi;tara -Keywords[uk]=Internet;WWW;Browser;Web;Explorer;Інтернет;мережа;переглядач;оглядач;браузер;веб;файрфокс;вогнелис;перегляд -Keywords[vi]=Internet;WWW;Browser;Web;Explorer;Trình duyệt;Trang web -Keywords[zh_CN]=Internet;WWW;Browser;Web;Explorer;网页;浏览;上网;火狐;Firefox;ff;互联网;网站; -Keywords[zh_TW]=Internet;WWW;Browser;Web;Explorer;網際網路;網路;瀏覽器;上網;網頁;火狐 -Exec=firefox %u -Terminal=false -X-MultipleArgs=false -Type=Application -Icon=firefox -Categories=GNOME;GTK;Network;WebBrowser; -MimeType=text/html;text/xml;application/xhtml+xml;application/xml;application/rss+xml;application/rdf+xml;image/gif;image/jpeg;image/png;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/ftp;x-scheme-handler/chrome;video/webm;application/x-xpinstall; -StartupNotify=true -Actions=NewWindow;NewPrivateWindow; - -[Desktop Action NewWindow] -Name=Open a New Window -Name[ar]=افتح نافذة جديدة -Name[ast]=Abrir una ventana nueva -Name[bn]=Abrir una ventana nueva -Name[ca]=Obre una finestra nova -Name[cs]=Otevřít nové okno -Name[da]=Åbn et nyt vindue -Name[de]=Ein neues Fenster öffnen -Name[el]=Άνοιγμα νέου παραθύρου -Name[es]=Abrir una ventana nueva -Name[fi]=Avaa uusi ikkuna -Name[fr]=Ouvrir une nouvelle fenêtre -Name[gl]=Abrir unha nova xanela -Name[he]=פתיחת חלון חדש -Name[hr]=Otvori novi prozor -Name[hu]=Új ablak nyitása -Name[it]=Apri una nuova finestra -Name[ja]=新しいウィンドウを開く -Name[ko]=새 창 열기 -Name[ku]=Paceyeke nû veke -Name[lt]=Atverti naują langą -Name[nb]=Åpne et nytt vindu -Name[nl]=Nieuw venster openen -Name[pt]=Abrir nova janela -Name[pt_BR]=Abrir nova janela -Name[ro]=Deschide o fereastră nouă -Name[ru]=Новое окно -Name[sk]=Otvoriť nové okno -Name[sl]=Odpri novo okno -Name[sv]=Öppna ett nytt fönster -Name[tr]=Yeni pencere aç -Name[ug]=يېڭى كۆزنەك ئېچىش -Name[uk]=Відкрити нове вікно -Name[vi]=Mở cửa sổ mới -Name[zh_CN]=新建窗口 -Name[zh_TW]=開啟新視窗 -Exec=firefox -new-window -OnlyShowIn=Unity; - -[Desktop Action NewPrivateWindow] -Name=Open a New Private Window -Name[ar]=افتح نافذة جديدة للتصفح الخاص -Name[ca]=Obre una finestra nova en mode d'incògnit -Name[de]=Ein neues privates Fenster öffnen -Name[es]=Abrir una ventana privada nueva -Name[fi]=Avaa uusi yksityinen ikkuna -Name[fr]=Ouvrir une nouvelle fenêtre de navigation privée -Name[he]=פתיחת חלון גלישה פרטית חדש -Name[hu]=Új privát ablak nyitása -Name[it]=Apri una nuova finestra anonima -Name[nb]=Åpne et nytt privat vindu -Name[ru]=Новое приватное окно -Name[sl]=Odpri novo okno zasebnega brskanja -Name[tr]=Yeni bir pencere aç -Name[uk]=Відкрити нове вікно у потайливому режимі -Name[zh_TW]=開啟新隱私瀏覽視窗 -Exec=firefox -private-window -OnlyShowIn=Unity; -Name[zh_CN]=新建隐私浏览窗口 - diff --git a/dock/types.go b/dock/types.go deleted file mode 100644 index 23fc15612..000000000 --- a/dock/types.go +++ /dev/null @@ -1,114 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -type HideModeType int32 - -const ( - HideModeKeepShowing HideModeType = iota - HideModeKeepHidden - HideModeAutoHide // invalid - HideModeSmartHide -) - -func (t HideModeType) String() string { - switch t { - case HideModeKeepShowing: - return "Keep showing mode" - case HideModeKeepHidden: - return "Keep hidden mode" - case HideModeAutoHide: - return "Auto hide mode" - case HideModeSmartHide: - return "Smart hide mode" - default: - return "Unknown mode" - } -} - -type HideStateType int32 - -const ( - HideStateUnknown HideStateType = iota - HideStateShow - HideStateHide -) - -func (s HideStateType) String() string { - switch s { - case HideStateShow: - return "Show" - case HideStateHide: - return "Hide" - default: - return "Unknown" - } -} - -type DisplayModeType int32 - -const ( - DisplayModeFashionMode DisplayModeType = iota - DisplayModeEfficientMode - DisplayModeClassicMode -) - -func (t DisplayModeType) String() string { - switch t { - case DisplayModeFashionMode: - return "Fashion mode" - case DisplayModeEfficientMode: - return "Efficient mode" - case DisplayModeClassicMode: - return "Classic mode" - default: - return "Unknown mode" - } -} - -type positionType int32 - -const ( - positionTop positionType = iota - positionRight - positionBottom - positionLeft -) - -func (p positionType) String() string { - switch p { - case positionTop: - return "Top" - case positionRight: - return "Right" - case positionBottom: - return "Bottom" - case positionLeft: - return "Left" - default: - return "Unknown" - } -} - -type Rect struct { - X, Y int32 - Width, Height uint32 -} - -func NewRect() *Rect { - return &Rect{} -} - -func (r *Rect) Pieces() (int, int, int, int) { - return int(r.X), int(r.Y), int(r.Width), int(r.Height) -} - -type forceQuitAppType uint8 - -const ( - forceQuitAppEnabled forceQuitAppType = iota // 开启 - forceQuitAppDisabled // 关闭 - forceQuitAppDeactivated // 置灰 -) diff --git a/dock/util.go b/dock/util.go deleted file mode 100644 index a730ebec8..000000000 --- a/dock/util.go +++ /dev/null @@ -1,123 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "encoding/base64" - "io" - "io/ioutil" - "net/url" - "os" - "path/filepath" - "strings" - "time" - - "github.com/linuxdeepin/go-lib/xdg/basedir" -) - -var xdgAutostartDirs []string - -func init() { - configDirs := make([]string, 0, 3) - configDirs = append(configDirs, basedir.GetUserConfigDir()) - sysConfigDirs := basedir.GetSystemConfigDirs() - configDirs = append(configDirs, sysConfigDirs...) - - for idx, configDir := range configDirs { - configDirs[idx] = filepath.Join(configDir, "autostart") - } - xdgAutostartDirs = configDirs -} - -func isInAutostartDir(file string) bool { - dir := filepath.Dir(file) - for _, adir := range xdgAutostartDirs { - if adir == dir { - return true - } - } - return false -} - -func dataUriToFile(dataUri, path string) (string, error) { - // dataUri starts with string "data:image/png;base64," - commaIndex := strings.Index(dataUri, ",") - img, err := base64.StdEncoding.DecodeString(dataUri[commaIndex+1:]) - if err != nil { - return path, err - } - - return path, ioutil.WriteFile(path, img, 0644) -} - -func strSliceEqual(sa, sb []string) bool { - if len(sa) != len(sb) { - return false - } - for i, va := range sa { - vb := sb[i] - if va != vb { - return false - } - } - return true -} - -func uniqStrSlice(slice []string) []string { - newSlice := make([]string, 0) - for _, e := range slice { - if !strSliceContains(newSlice, e) { - newSlice = append(newSlice, e) - } - } - return newSlice -} - -func strSliceContains(slice []string, v string) bool { - for _, e := range slice { - if e == v { - return true - } - } - return false -} - -func copyFileContents(src, dst string) (err error) { - in, err := os.Open(src) - if err != nil { - return - } - defer in.Close() - out, err := os.Create(dst) - if err != nil { - return - } - defer func() { - cerr := out.Close() - if err == nil { - err = cerr - } - }() - if _, err = io.Copy(out, in); err != nil { - return - } - err = out.Sync() - return -} - -func getCurrentTimestamp() uint32 { - return uint32(time.Now().Unix()) -} - -func toLocalPath(in string) string { - u, err := url.Parse(in) - if err != nil { - return "" - } - if u.Scheme == "file" { - return u.Path - } - return in -} diff --git a/dock/util_test.go b/dock/util_test.go deleted file mode 100644 index 124635a26..000000000 --- a/dock/util_test.go +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_uniqStrSlice(t *testing.T) { - slice := []string{"a", "b", "c", "c", "b", "a", "c"} - slice = uniqStrSlice(slice) - assert.Equal(t, len(slice), 3) - assert.Equal(t, slice[0], "a") - assert.Equal(t, slice[1], "b") - assert.Equal(t, slice[2], "c") -} - -func Test_strSliceEqual(t *testing.T) { - sa := []string{"a", "b", "c"} - sb := []string{"a", "b", "c", "d"} - sc := sa[:] - assert.False(t, strSliceEqual(sa, sb)) - assert.True(t, strSliceEqual(sa, sc)) -} - -func Test_strSliceContains(t *testing.T) { - slice := []string{"a", "b", "c"} - assert.True(t, strSliceContains(slice, "a")) - assert.True(t, strSliceContains(slice, "b")) - assert.True(t, strSliceContains(slice, "c")) - assert.False(t, strSliceContains(slice, "d")) - assert.False(t, strSliceContains(slice, "e")) - -} diff --git a/dock/window_info.go b/dock/window_info.go deleted file mode 100644 index a0cb5a8bd..000000000 --- a/dock/window_info.go +++ /dev/null @@ -1,451 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "crypto/md5" // #nosec G501 - "encoding/hex" - "fmt" - "path/filepath" - "strings" - "sync" - "time" - "unicode/utf8" - - x "github.com/linuxdeepin/go-x11-client" - "github.com/linuxdeepin/go-x11-client/util/wm/ewmh" - "github.com/linuxdeepin/go-x11-client/util/wm/icccm" -) - -const windowHashPrefix = "w:" - -type WindowInfo struct { - baseWindowInfo - - x int16 - y int16 - width uint16 - height uint16 - lastConfigureNotifyEvent *x.ConfigureNotifyEvent - mu sync.Mutex - updateConfigureTimer *time.Timer - - wmState []x.Atom - wmWindowType []x.Atom - wmAllowedActions []x.Atom - hasXEmbedInfo bool - hasWmTransientFor bool - wmClass *icccm.WMClass - wmName string - motifWmHints *MotifWmHints - - gtkAppId string - flatpakAppID string - wmRole string - - updateCalled bool - sync.Mutex -} - -func NewWindowInfo(win x.Window) *WindowInfo { - winInfo := &WindowInfo{} - winInfo.xid = win - winInfo.createdTime = time.Now().UnixNano() - return winInfo -} - -// window type -func (winInfo *WindowInfo) updateWmWindowType() { - var err error - winInfo.wmWindowType, err = ewmh.GetWMWindowType(globalXConn, winInfo.xid).Reply(globalXConn) - if err != nil { - logger.Debugf("failed to get WMWindowType for window %d: %v", winInfo.xid, err) - } -} - -// wm allowed actions -func (winInfo *WindowInfo) updateWmAllowedActions() { - var err error - winInfo.wmAllowedActions, err = ewmh.GetWMAllowedActions(globalXConn, - winInfo.xid).Reply(globalXConn) - if err != nil { - logger.Debugf("failed to get WMAllowedActions for window %d: %v", winInfo.xid, err) - } -} - -// wm state -func (winInfo *WindowInfo) updateWmState() { - var err error - winInfo.wmState, err = ewmh.GetWMState(globalXConn, winInfo.xid).Reply(globalXConn) - if err != nil { - logger.Debugf("failed to get WMState for window %d: %v", winInfo.xid, err) - } -} - -// wm class -func (winInfo *WindowInfo) updateWmClass() { - var err error - winInfo.wmClass, err = getWmClass(winInfo.xid) - if err != nil { - logger.Debugf("failed to get wmClass for window %d: %v", winInfo.xid, err) - } -} - -func (winInfo *WindowInfo) updateMotifWmHints() { - var err error - winInfo.motifWmHints, err = getMotifWmHints(globalXConn, winInfo.xid) - if err != nil { - logger.Debugf("failed to get Motif WM Hints for window %d: %v", - winInfo.xid, err) - } -} - -// wm name -func (winInfo *WindowInfo) updateWmName() { - winInfo.wmName = getWmName(winInfo.xid) - winInfo.Title = winInfo.getTitle() -} - -func (winInfo *WindowInfo) updateIcon() { - winInfo.Icon = getIconFromWindow(winInfo.xid) -} - -// XEmbed info -// 一般 tray icon 会带有 _XEMBED_INFO 属性 -func (winInfo *WindowInfo) updateHasXEmbedInfo() { - reply, err := x.GetProperty(globalXConn, false, winInfo.xid, atomXEmbedInfo, x.AtomAny, 0, 2).Reply(globalXConn) - if err != nil { - logger.Debug(err) - return - } - if reply.Format != 0 { - // has property - winInfo.hasXEmbedInfo = true - } -} - -// WM_TRANSIENT_FOR -func (winInfo *WindowInfo) updateHasWmTransientFor() { - _, err := icccm.GetWMTransientFor(globalXConn, winInfo.xid).Reply(globalXConn) - winInfo.hasWmTransientFor = err == nil -} - -func (winInfo *WindowInfo) isActionMinimizeAllowed() bool { - logger.Debugf("wmAllowedActions: %#v", winInfo.wmAllowedActions) - return atomsContains(winInfo.wmAllowedActions, atomNetWmActionMinimize) -} - -func (winInfo *WindowInfo) hasWmStateDemandsAttention() bool { - return atomsContains(winInfo.wmState, atomWmStateDemandsAttention) -} - -func (winInfo *WindowInfo) hasWmStateSkipTaskBar() bool { - return atomsContains(winInfo.wmState, atomNetWmStateSkipTaskbar) -} - -func (winInfo *WindowInfo) hasWmStateModal() bool { - return atomsContains(winInfo.wmState, atomNetWmStateModal) -} - -func (winInfo *WindowInfo) isValidModal() bool { - return winInfo.hasWmTransientFor && winInfo.hasWmStateModal() -} - -// 通过 wmClass 判断是否需要隐藏此窗口 -func (winInfo *WindowInfo) shouldSkipWithWMClass() bool { - wmClass := winInfo.wmClass - if wmClass == nil { - return false - } - if wmClass.Instance == "explorer.exe" && wmClass.Class == "Wine" { - return true - } else if wmClass.Class == "dde-launcher" || wmClass.Class == "dde-lock" || wmClass.Class == "dde-dock" { - return true - } else if wmClass.Class == "reset-password-dialog" || wmClass.Instance == "reset-password-dialog" { - return true - } else if wmClass.Instance == "onboard" && wmClass.Class == "Onboard" { - return true - } - - return false -} - -func (winInfo *WindowInfo) getDisplayName() (name string) { - name = winInfo.getDisplayName0() - nameTitle := strings.Title(name) - // NOTE: although name is valid, nameTitle is not necessarily valid. - if utf8.ValidString(nameTitle) { - name = nameTitle - } - return -} - -func (winInfo *WindowInfo) getDisplayName0() string { - win := winInfo.xid - role := winInfo.wmRole - if !utf8.ValidString(role) { - role = "" - } - - var class, instance string - if winInfo.wmClass != nil { - class = winInfo.wmClass.Class - if !utf8.ValidString(class) { - class = "" - } - - instance = filepath.Base(winInfo.wmClass.Instance) - if !utf8.ValidString(instance) { - instance = "" - } - } - logger.Debugf("getDisplayName class: %q, instance: %q", class, instance) - - if role != "" && class != "" { - return class + " " + role - } - - if class != "" { - return class - } - - if instance != "" { - return instance - } - - wmName := winInfo.wmName - if wmName != "" { - var shortWmName string - lastIndex := strings.LastIndex(wmName, "-") - if lastIndex > 0 { - shortWmName = wmName[lastIndex:] - if shortWmName != "" && utf8.ValidString(shortWmName) { - return shortWmName - } - } - } - - if winInfo.process != nil { - exeBasename := filepath.Base(winInfo.process.exe) - if utf8.ValidString(exeBasename) { - return exeBasename - } - } - - return fmt.Sprintf("window: %v", win) -} - -func (winInfo *WindowInfo) getTitle() string { - wmName := winInfo.wmName - if wmName == "" || !utf8.ValidString(wmName) { - return winInfo.getDisplayName() - } - return wmName -} - -func (winInfo *WindowInfo) getIcon() string { - if winInfo.Icon == "" { - logger.Debug("get icon from window", winInfo.xid) - winInfo.Icon = getIconFromWindow(winInfo.xid) - } - return winInfo.Icon -} - -var skipTaskBarWindowTypes = []string{ - "_NET_WM_WINDOW_TYPE_UTILITY", - "_NET_WM_WINDOW_TYPE_COMBO", - "_NET_WM_WINDOW_TYPE_DESKTOP", - "_NET_WM_WINDOW_TYPE_DND", - "_NET_WM_WINDOW_TYPE_DOCK", - "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", - "_NET_WM_WINDOW_TYPE_MENU", - "_NET_WM_WINDOW_TYPE_NOTIFICATION", - "_NET_WM_WINDOW_TYPE_POPUP_MENU", - "_NET_WM_WINDOW_TYPE_SPLASH", - "_NET_WM_WINDOW_TYPE_TOOLBAR", - "_NET_WM_WINDOW_TYPE_TOOLTIP", -} - -func (winInfo *WindowInfo) shouldSkip() bool { - logger.Debugf("win %d shouldSkip?", winInfo.xid) - if !winInfo.updateCalled { - winInfo.update() - winInfo.updateCalled = true - } - - logger.Debugf("hasXEmbedInfo: %v", winInfo.hasXEmbedInfo) - logger.Debugf("wmWindowType: %#v", winInfo.wmWindowType) - logger.Debugf("wmState: %#v", winInfo.wmState) - logger.Debugf("wmClass: %#v", winInfo.wmClass) - - if winInfo.hasWmStateSkipTaskBar() || winInfo.isValidModal() || - winInfo.hasXEmbedInfo || winInfo.shouldSkipWithWMClass() { - return true - } - - for _, winType := range winInfo.wmWindowType { - winTypeStr, _ := getAtomName(winType) - if winType == atomNetWmWindowTypeDialog && - !winInfo.isActionMinimizeAllowed() { - return true - } else if strSliceContains(skipTaskBarWindowTypes, winTypeStr) { - return true - } - } - return false -} - -func (winInfo *WindowInfo) updateProcessInfo() { - win := winInfo.xid - winInfo.pid = getWmPid(win) - var err error - winInfo.process, err = NewProcessInfo(winInfo.pid) - if err != nil { - logger.Warning(err) - // Try WM_COMMAND - wmCommand, err := getWmCommand(win) - if err == nil { - winInfo.process = NewProcessInfoWithCmdline(wmCommand) - } else { - return - } - } - logger.Debugf("process: %#v", winInfo.process) -} - -func (winInfo *WindowInfo) update() { - win := winInfo.xid - logger.Debugf("update window %v info", win) - winInfo.updateWmClass() - winInfo.updateMotifWmHints() - winInfo.updateWmState() - winInfo.updateWmWindowType() - winInfo.updateWmAllowedActions() - if len(winInfo.wmWindowType) == 0 { - winInfo.updateHasXEmbedInfo() - } - winInfo.updateHasWmTransientFor() - winInfo.updateProcessInfo() - winInfo.wmRole = getWmWindowRole(win) - winInfo.gtkAppId = getWindowGtkApplicationId(win) - winInfo.flatpakAppID = getWindowFlatpakAppID(win) - winInfo.updateWmName() - winInfo.innerId = genInnerId(winInfo) -} - -func filterFilePath(args []string) string { - var filtered []string - for _, arg := range args { - if strings.Contains(arg, "/") || arg == "." || arg == ".." { - filtered = append(filtered, "%F") - } else { - filtered = append(filtered, arg) - } - } - return strings.Join(filtered, " ") -} - -func genInnerId(winInfo *WindowInfo) string { - win := winInfo.xid - var wmClass string - var wmInstance string - if winInfo.wmClass != nil { - wmClass = winInfo.wmClass.Class - wmInstance = filepath.Base(winInfo.wmClass.Instance) - } - var exe string - var args string - if winInfo.process != nil { - exe = winInfo.process.exe - args = filterFilePath(winInfo.process.args) - } - hasPid := winInfo.pid != 0 - - var str string - // NOTE: 不要使用 wmRole,有些程序总会改变这个值比如 GVim - if wmInstance == "" && wmClass == "" && exe == "" && winInfo.gtkAppId == "" { - if winInfo.wmName != "" { - str = fmt.Sprintf("wmName:%q", winInfo.wmName) - } else { - str = fmt.Sprintf("windowId:%v", winInfo.xid) - } - } else { - str = fmt.Sprintf("wmInstance:%q,wmClass:%q,exe:%q,args:%q,hasPid:%v,gtkAppId:%q", - wmInstance, wmClass, exe, args, hasPid, winInfo.gtkAppId) - } - // #nosec G401 - md5hash := md5.New() - _, err := md5hash.Write([]byte(str)) - if err != nil { - logger.Warning("Write error:", err) - } - innerId := windowHashPrefix + hex.EncodeToString(md5hash.Sum(nil)) - logger.Debugf("genInnerId win: %v str: %s, innerId: %s", win, str, innerId) - return innerId -} - -func (winInfo *WindowInfo) isDemandingAttention() bool { - return winInfo.hasWmStateDemandsAttention() -} - -func (winInfo *WindowInfo) isMinimized() bool { - return atomsContains(winInfo.wmState, atomNetWmStateHidden) -} - -func (winInfo *WindowInfo) activate() error { - return activateWindow(winInfo.xid) -} - -func (winInfo *WindowInfo) minimize() error { - return minimizeWindow(winInfo.xid) -} - -func (winInfo *WindowInfo) maximize() error { - return maximizeWindow(winInfo.xid) -} - -func (winInfo *WindowInfo) makeWindowAbove() error { - return makeWindowAbove(winInfo.xid) -} - -func (winInfo *WindowInfo) close(timestamp uint32) error { - return closeWindow(winInfo.xid, x.Timestamp(timestamp)) -} - -func (winInfo *WindowInfo) killClient() error { - return killClient(winInfo.xid) -} - -func (winInfo *WindowInfo) changeXid(xid x.Window) bool { - logger.Warning("XWindowInfo should not change xid!") - return false -} - -func (winInfo *WindowInfo) print() { - wmClassStr := "-" - if winInfo.wmClass != nil { - wmClassStr = fmt.Sprintf("%q %q", winInfo.wmClass.Class, winInfo.wmClass.Instance) - } - logger.Infof("id: %d, wmClass: %s, wmState: %v,"+ - " wmWindowType: %v, wmAllowedActions: %v, hasXEmbedInfo: %v, hasWmTransientFor: %v", - winInfo.xid, wmClassStr, - winInfo.wmState, winInfo.wmWindowType, winInfo.wmAllowedActions, winInfo.hasXEmbedInfo, - winInfo.hasWmTransientFor) -} - -func (winInfo *WindowInfo) allowClose() bool { - if winInfo.motifWmHints != nil { - if winInfo.motifWmHints.allowedClose() { - return true - } - } - - for _, action := range winInfo.wmAllowedActions { - if action == atomNetWmActionClose { - return true - } - } - return false -} diff --git a/dock/window_infos.go b/dock/window_infos.go deleted file mode 100644 index dc6172426..000000000 --- a/dock/window_infos.go +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - x "github.com/linuxdeepin/go-x11-client" -) - -type ExportWindowInfo struct { - Title string - Flash bool -} - -type windowInfosType map[x.Window]ExportWindowInfo - -func newWindowInfos() windowInfosType { - return make(windowInfosType) -} - -func (a windowInfosType) Equal(b windowInfosType) bool { - if len(a) != len(b) { - return false - } - for keyA, valA := range a { - valB, okB := b[keyA] - if okB { - if valA != valB { - return false - } - } else { - return false - } - } - return true -} diff --git a/dock/window_infos_test.go b/dock/window_infos_test.go deleted file mode 100644 index 9c1fb6e56..000000000 --- a/dock/window_infos_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_windowInfosTypeEqual(t *testing.T) { - wa := windowInfosType{ - 0: {"a", false}, - 1: {"b", false}, - 2: {"c", true}, - } - wb := windowInfosType{ - 2: {"c", true}, - 1: {"b", false}, - 0: {"a", false}, - } - assert.True(t, wa.Equal(wb)) - - wc := windowInfosType{ - 1: {"b", false}, - 2: {"c", false}, - } - assert.False(t, wc.Equal(wa)) - - wd := windowInfosType{ - 0: {"aa", false}, - 1: {"b", false}, - 2: {"c", false}, - } - assert.False(t, wd.Equal(wa)) - - we := windowInfosType{ - 0: {"a", false}, - 1: {"b", false}, - 3: {"c", false}, - } - assert.False(t, we.Equal(wa)) - - wf := windowInfosType{ - 0: {"a", false}, - 1: {"b", false}, - 2: {"c", false}, - } - assert.False(t, wf.Equal(wa)) -} diff --git a/dock/window_slice.go b/dock/window_slice.go deleted file mode 100644 index eb43fa3f4..000000000 --- a/dock/window_slice.go +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - x "github.com/linuxdeepin/go-x11-client" -) - -type windowSlice []x.Window - -func (a windowSlice) Len() int { return len(a) } -func (a windowSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a windowSlice) Less(i, j int) bool { return uint32(a[i]) < uint32(a[j]) } - -func (winSlice windowSlice) Contains(win x.Window) bool { - for _, window := range winSlice { - if window == win { - return true - } - } - return false -} - -// from a to b -// return [add, remove] -func diffSortedWindowSlice(a, b windowSlice) (add, remove windowSlice) { - ia := 0 - ib := 0 - lenA := len(a) - lenB := len(b) - - for ia < lenA && ib < lenB { - va := uint32(a[ia]) - vb := uint32(b[ib]) - if va == vb { - ia++ - ib++ - } else if va < vb { - // remove - remove = append(remove, a[ia]) - ia++ - } else { - // va > vb - // add - add = append(add, b[ib]) - ib++ - } - } - - for ia < lenA { - remove = append(remove, a[ia]) - ia++ - } - - for ib < lenB { - add = append(add, b[ib]) - ib++ - } - return -} diff --git a/dock/window_slice_test.go b/dock/window_slice_test.go deleted file mode 100644 index c636665e9..000000000 --- a/dock/window_slice_test.go +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_diffSortedWindowSlice(t *testing.T) { - a := windowSlice{1, 2, 3, 4} - b := windowSlice{1, 3, 5, 6, 7} - add, remove := diffSortedWindowSlice(a, b) - - assert.Equal(t, len(add), 3) - assert.Equal(t, int(add[0]), 5) - assert.Equal(t, int(add[1]), 6) - assert.Equal(t, int(add[2]), 7) - - assert.Equal(t, len(remove), 2) - assert.Equal(t, int(remove[0]), 2) - assert.Equal(t, int(remove[1]), 4) -} diff --git a/dock/wl_manager.go b/dock/wl_manager.go deleted file mode 100644 index 7b8dbfe94..000000000 --- a/dock/wl_manager.go +++ /dev/null @@ -1,281 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "os" - "strconv" - "sync" - - dbus "github.com/godbus/dbus" - kwayland "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.kwayland" - x "github.com/linuxdeepin/go-x11-client" -) - -type WaylandManager struct { - mu sync.Mutex - windows map[dbus.ObjectPath]*KWindowInfo -} - -func (wm *WaylandManager) handleActiveWindowChangedK(activeWin uint32) WindowInfoImp { - wm.mu.Lock() - defer wm.mu.Unlock() - - logger.Debug("WaylandManager.handleActiveWindowChangedK", activeWin) - - for _, winInfo := range wm.windows { - if winInfo.internalId == activeWin { - return winInfo - } - } - return nil -} - -func newWaylandManager() *WaylandManager { - m := &WaylandManager{ - windows: make(map[dbus.ObjectPath]*KWindowInfo), - } - return m -} - -func (m *Manager) listenWaylandWMSignals() { - m.waylandWM.InitSignalExt(m.sessionSigLoop, true) - - _, err := m.waylandWM.ConnectActiveWindowChanged(func() { - activeWinInternalId, err := m.waylandWM.ActiveWindow(0) - if err != nil { - logger.Warning(err) - return - } - activeWinInfo := m.waylandManager.handleActiveWindowChangedK(activeWinInternalId) - if activeWinInfo != nil { - m.handleActiveWindowChanged(activeWinInfo) - } else { - m.updateHideState(false) - } - }) - if err != nil { - logger.Warning(err) - } - - _, err = m.waylandWM.ConnectWindowCreated(func(objPathStr string) { - objPath := dbus.ObjectPath(objPathStr) - logger.Debug("window created", objPath) - m.registerWindowWayland(objPath) - }) - if err != nil { - logger.Warning(err) - } - - _, err = m.waylandWM.ConnectWindowRemove(func(objPathStr string) { - objPath := dbus.ObjectPath(objPathStr) - logger.Debug("window removed", objPath) - m.unregisterWindowWayland(objPath) - }) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) listenKWindowSignals(winInfo *KWindowInfo) { - winInfo.winObj.InitSignalExt(m.sessionSigLoop, true) - var err error - - // Title changed - _, err = winInfo.winObj.ConnectTitleChanged(func() { - winInfo.updateTitle() - entry := m.Entries.getByWindowId(winInfo.xid) - if entry == nil { - return - } - if entry.current == winInfo { - entry.updateName() - } - entry.updateWindowInfos() - }) - if err != nil { - logger.Warning(err) - } - - // Icon changed - _, err = winInfo.winObj.ConnectIconChanged(func() { - winInfo.updateIcon() - entry := m.Entries.getByWindowId(winInfo.xid) - if entry == nil { - return - } - entry.updateIcon() - }) - - // DemandingAttention changed - _, err = winInfo.winObj.ConnectDemandsAttentionChanged(func() { - winInfo.updateDemandingAttention() - entry := m.Entries.getByWindowId(winInfo.xid) - if entry == nil { - return - } - entry.updateWindowInfos() - }) - - // Geometry changed - _, err = winInfo.winObj.ConnectGeometryChanged(func() { - changed := winInfo.updateGeometry() - if !changed { - return - } - m.handleWindowGeometryChanged(winInfo) - }) -} - -func (m *Manager) handleWindowGeometryChanged(winInfo WindowInfoImp) { - if HideModeType(m.HideMode.Get()) != HideModeSmartHide { - return - } - - m.updateHideState(false) -} - -func (m *Manager) unregisterWindowWayland(objPath dbus.ObjectPath) { - logger.Debug("unregister window", objPath) - - m.waylandManager.mu.Lock() - winInfo, ok := m.waylandManager.windows[objPath] - m.waylandManager.mu.Unlock() - if !ok { - return - } - - winInfo.winObj.RemoveAllHandlers() - m.detachWindow(winInfo) - - err := globalXConn.FreeID(uint32(winInfo.xid)) - if err != nil { - logger.Warning(err) - } - - m.waylandManager.mu.Lock() - delete(m.waylandManager.windows, objPath) - m.waylandManager.mu.Unlock() - - // TODO 发现windowInfoMap中的内容没有被清除过 - // m.windowInfoMapMutex.Lock() - // delete(m.windowInfoMap, winInfo.getXid()) - // m.windowInfoMapMutex.Unlock() -} - -var globalRestrictWaylandWindow = true - -func init() { - if os.Getenv("DEEPIN_DOCK_RESTRICT_WAYLAND_WINDOW") == "0" { - globalRestrictWaylandWindow = false - } -} - -// TODO: remove it -func (m *Manager) DebugRegisterWW(id uint32) *dbus.Error { - objPath := dbus.ObjectPath("/com/deepin/daemon/KWayland/PlasmaWindow_" + strconv.Itoa(int(id))) - m.registerWindowWayland(objPath) - return nil -} - -// TODO: remove it -func (m *Manager) DebugSetActiveWindow(id uint32) *dbus.Error { - activeWinInfo := m.waylandManager.handleActiveWindowChangedK(id) - if activeWinInfo != nil { - m.handleActiveWindowChanged(activeWinInfo) - } - return nil -} - -func (m *Manager) registerWindowWayland(objPath dbus.ObjectPath) { - logger.Debug("register window", objPath) - - m.waylandManager.mu.Lock() - _, ok := m.waylandManager.windows[objPath] - m.waylandManager.mu.Unlock() - if ok { - return - } - - sessionBus := m.sessionSigLoop.Conn() - winObj, err := kwayland.NewWindow(sessionBus, objPath) - if err != nil { - logger.Warning(err) - return - } - appId, err := winObj.AppId(0) - if err != nil { - logger.Warning(err) - return - } - if appId == "dde-dock" || appId == "dde-launcher" || appId == "dde-clipboard" || - appId == "dde-osd" || appId == "dde-polkit-agent" || appId == "dde-simple-egl" || appId == "dmcs" { - return - } - - xid, err := globalXConn.AllocID() - if err != nil { - logger.Warning(err) - return - } - - realWid, err := winObj.WindowId(0) - if err != nil { - logger.Warning(err) - realWid = 0 - } - if realWid != 0 { - xid = realWid - } - - winInfo := newKWindowInfo(winObj, xid) - m.listenKWindowSignals(winInfo) - - m.waylandManager.mu.Lock() - m.waylandManager.windows[objPath] = winInfo - m.waylandManager.mu.Unlock() - - m.attachOrDetachWindow(winInfo) - - if realWid != 0 { - m.windowInfoMapMutex.Lock() - m.windowInfoMap[x.Window(realWid)] = winInfo - m.windowInfoMapMutex.Unlock() - } -} - -func (m *Manager) registerKWaylandInfo(winInfo WindowInfoImp) { - switch winInfo.(type) { - case *KWindowInfo: - break - default: - logger.Warningf("registerKWaylandInfo, not wayland, wid=%d", winInfo.getXid()) - return - } - - m.windowInfoMapMutex.RLock() - defer m.windowInfoMapMutex.RUnlock() - - winInfo, ok := m.windowInfoMap[winInfo.getXid()] - if ok { - logger.Warningf("registerKWaylandInfo, already registered, wid=%d", winInfo.getXid()) - return - } - m.windowInfoMap[winInfo.getXid()] = winInfo -} - -func (m *Manager) initWaylandWindows() { - windowPaths, err := m.waylandWM.Windows(0) - if err != nil { - logger.Warning(err) - } - for _, objPath := range windowPaths { - objPathStr, ok := objPath.Value().(string) - if !ok { - continue - } - m.registerWindowWayland(dbus.ObjectPath(objPathStr)) - } -} diff --git a/dock/xutils.go b/dock/xutils.go deleted file mode 100644 index 0b58e09dc..000000000 --- a/dock/xutils.go +++ /dev/null @@ -1,661 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package dock - -import ( - "bytes" - "encoding/base64" - "errors" - "image" - "image/png" - "math" - "strings" - "time" - - "github.com/nfnt/resize" - - x "github.com/linuxdeepin/go-x11-client" - "github.com/linuxdeepin/go-x11-client/util/wm/ewmh" - "github.com/linuxdeepin/go-x11-client/util/wm/icccm" -) - -func atomsContains(slice []x.Atom, atom x.Atom) bool { - for _, a := range slice { - if a == atom { - return true - } - } - return false -} - -func getWmClass(win x.Window) (*icccm.WMClass, error) { - wmClass, err := icccm.GetWMClass(globalXConn, win).Reply(globalXConn) - if err != nil { - return nil, err - } - return &wmClass, nil -} - -func getAtomName(atom x.Atom) (string, error) { - return globalXConn.GetAtomName(atom) -} - -func getAtom(name string) (x.Atom, error) { - return globalXConn.GetAtom(name) -} - -func maximizeWindow(win x.Window) error { - return ewmh.RequestChangeWMState(globalXConn, win, ewmh.WMStateAdd, atomNetWmStateMaximizedVert, atomNetWmStateMaximizedHorz, 2).Check(globalXConn) -} - -func minimizeWindow(win x.Window) error { - logger.Debug("minimizeWindow", win) - return icccm.RequestChangeWMState(globalXConn, win, icccm.StateIconic).Check(globalXConn) -} - -func makeWindowAbove(win x.Window) error { - return ewmh.RequestChangeWMState(globalXConn, win, ewmh.WMStateAdd, atomNetWmStateAbove, - 0, 2).Check(globalXConn) -} - -func moveWindow(win x.Window) error { - // TODO: - //return ewmh.WmMoveresize(xu, win, ewmh.MoveKeyboard) - //ewmh.RequestWMMoveResize(win, ) - return nil -} - -func closeWindow(win x.Window, ts x.Timestamp) error { - return ewmh.RequestCloseWindow(globalXConn, win, ts, 2).Check(globalXConn) -} - -type windowFrameExtents struct { - Left, Right, Top, Bottom uint -} - -func getWindowFrameExtents(xConn *x.Conn, win x.Window) (*windowFrameExtents, error) { - reply, err := x.GetProperty(xConn, false, win, atomNetFrameExtents, x.AtomCardinal, - 0, 4).Reply(xConn) - if err != nil || reply.Format == 0 { - // try _GTK_FRAME_EXTENTS - reply, err = x.GetProperty(xConn, false, win, atomGtkFrameExtents, x.AtomCardinal, - 0, 4).Reply(xConn) - if err != nil { - return nil, err - } - } - - return getFrameExtentsFromReply(reply) -} - -func getCardinalsFromReply(r *x.GetPropertyReply) ([]uint32, error) { - if r.Format != 32 { - return nil, errors.New("bad reply") - } - count := len(r.Value) / 4 - ret := make([]uint32, count) - rdr := x.NewReaderFromData(r.Value) - for i := 0; i < count; i++ { - ret[i] = uint32(rdr.Read4b()) - } - return ret, nil -} - -func getFrameExtentsFromReply(reply *x.GetPropertyReply) (*windowFrameExtents, error) { - list, err := getCardinalsFromReply(reply) - if err != nil { - return nil, err - } - - if len(list) != 4 { - return nil, errors.New("length of list is not 4") - } - return &windowFrameExtents{ - Left: uint(list[0]), - Right: uint(list[1]), - Top: uint(list[2]), - Bottom: uint(list[3]), - }, nil -} - -func getMotifWmHints(xConn *x.Conn, win x.Window) (*MotifWmHints, error) { - reply, err := x.GetProperty(xConn, false, win, atomMotifWmHints, - atomMotifWmHints, 0, 5).Reply(xConn) - if err != nil { - return nil, err - } - return getMotifWmHintsFromReply(reply) -} - -func getMotifWmHintsFromReply(reply *x.GetPropertyReply) (*MotifWmHints, error) { - list, err := getCardinalsFromReply(reply) - if err != nil { - return nil, err - } - if len(list) != 5 { - return nil, errors.New("length of list is not 5") - } - return &MotifWmHints{ - Flags: list[0], - Functions: list[1], - Decorations: list[2], - InputMode: int32(list[3]), - Status: list[4], - }, nil -} - -type MotifWmHints struct { - Flags uint32 - Functions uint32 - Decorations uint32 - InputMode int32 - Status uint32 -} - -const ( - MotifHintFunctions = 1 << iota - MotifHintDecorations - MotifHintInputMode - MotifHintStatus -) - -const ( - MotifFunctionAll = 1 << iota - MotifFunctionResize - MotifFunctionMove - MotifFunctionMinimize - MotifFunctionMaximize - MotifFunctionClose - MotifFunctionNone = 0 -) - -func (h *MotifWmHints) allowedClose() bool { - // 允许关闭的条件: - // 1. 不设置 Functions 字段,即 h.Flags 没有设置 MotifHintFunctions 标志位; - // 2. 或者设置了 Functions 字段并且 h.Functions 设置了 MotifFunctionAll 标志位; - // 3. 或者设置了 Functions 字段并且 h.Functions 设置了 MotifFunctionClose 标志位。 - // 相关定义在 motif-2.3.8/lib/Xm/MwmUtil.h 。 - return h.Flags&MotifHintFunctions == 0 || - h.Functions&MotifFunctionAll != 0 || - h.Functions&MotifFunctionClose != 0 -} - -func getWindowGeometry(xConn *x.Conn, win x.Window) (*Rect, error) { - rect, err := getGeometry(xConn, win) - if err != nil { - return nil, err - } - - root := xConn.GetDefaultScreen().Root - coord, err := x.TranslateCoordinates(xConn, win, root, 0, 0).Reply(xConn) - if err != nil { - return nil, err - } - rect.X = int32(coord.DstX) - rect.Y = int32(coord.DstY) - - dWin, err := getDecorativeWindow(xConn, win) - if err != nil { - return nil, err - } - - dRect, err := getGeometry(xConn, dWin) - if err != nil { - return nil, err - } - - if rect.X == dRect.X && rect.Y == dRect.Y { - // 无标题栏的窗口,比如 deepin-editor, dconf-editor - frameExtents, _ := getWindowFrameExtents(xConn, win) - if frameExtents != nil { - X := rect.X + int32(frameExtents.Left) - y := rect.Y + int32(frameExtents.Top) - w := rect.Width - uint32(frameExtents.Left+frameExtents.Right) - h := rect.Height - uint32(frameExtents.Top+frameExtents.Bottom) - return &Rect{X, y, w, h}, nil - } - return rect, nil - } - // else 普通的有标题栏的窗口,比如 xev, 返回装饰窗口的位置和大小。 - return dRect, nil -} - -func getDecorativeWindow(conn *x.Conn, win x.Window) (x.Window, error) { - count := 0 - for { - count++ - reply, err := x.QueryTree(conn, win).Reply(conn) - if err != nil { - return 0, err - } - - if reply.Root == reply.Parent { - return win, nil - } - if count > 10 { - return 0, errors.New("getDecorateWindow: exceeded the loop iteration limit") - } - win = reply.Parent - } -} - -func getGeometry(xConn *x.Conn, win x.Window) (*Rect, error) { - geo, err := x.GetGeometry(xConn, x.Drawable(win)).Reply(xConn) - if err != nil { - return nil, err - } - return &Rect{ - X: int32(geo.X), - Y: int32(geo.Y), - Width: uint32(geo.Width), - Height: uint32(geo.Height), - }, nil -} - -func getWmName(win x.Window) string { - // get _NET_WM_NAME - name, err := ewmh.GetWMName(globalXConn, win).Reply(globalXConn) - if err != nil || name == "" { - // get WM_NAME - nameTp, _ := icccm.GetWMName(globalXConn, win).Reply(globalXConn) - name, _ = nameTp.GetStr() - } - - return strings.Replace(name, "\x00", "", -1) -} - -func getWmPid(win x.Window) uint { - pid, _ := ewmh.GetWMPid(globalXConn, win).Reply(globalXConn) - return uint(pid) -} - -// WM_CLIENT_LEADER -func getWmClientLeader(win x.Window) (x.Window, error) { - reply, err := x.GetProperty(globalXConn, false, win, atomWmClientLeader, atomUTF8String, - 0, 1).Reply(globalXConn) - if err != nil { - return 0, err - } - leader, err := getWindowFromReply(reply) - if err != nil { - return 0, err - } - return leader, nil -} - -// WM_TRANSIENT_FOR -func getWmTransientFor(win x.Window) (x.Window, error) { - return icccm.GetWMTransientFor(globalXConn, win).Reply(globalXConn) -} - -// _NET_WM_WINDOW_OPACITY -func getWmWindowOpacity(win x.Window) (uint, error) { - reply, err := x.GetProperty(globalXConn, false, win, atomNetWmWindowOpacity, atomUTF8String, - 0, 1).Reply(globalXConn) - if err != nil { - return 0, err - } - - opacity, err := getCardinalFromReply(reply) - if err != nil { - return 0, err - } - - return uint(opacity), nil -} - -func getWmCommand(win x.Window) ([]string, error) { - reply, err := x.GetProperty(globalXConn, false, win, atomWmCommand, atomUTF8String, - 0, lengthMax).Reply(globalXConn) - if err != nil { - return nil, err - } - return getUTF8StrsFromReply(reply) -} - -func getWindowGtkApplicationId(win x.Window) string { - gtkAppId, _ := getWindowPropertyString(win, atomGtkApplicationId) - return gtkAppId -} - -func getWindowFlatpakAppID(win x.Window) string { - id, _ := getWindowPropertyString(win, atomFlatpakAppId) - return id -} - -func getAndroidUengineId(win x.Window) int32 { - atom := atomAndroidUengineId - - reply, err := x.GetProperty(globalXConn, false, win, - atom, atomInteger, 0, lengthMax).Reply(globalXConn) - - if err != nil || reply.ValueLen == 0 { - return -1 - } - - return int32(x.Get32(reply.Value)) -} - -func getAndroidUengineName(win x.Window) string { - reply, err := x.GetProperty(globalXConn, false, win, - atomAndroidUengineName, atomString, 0, lengthMax).Reply(globalXConn) - if err != nil { - return "" - } - - name := string(reply.Value) - return name -} - -func getDSGVirtualAppDesktop(win x.Window) string { - reply, err := x.GetProperty(globalXConn, false, win, - atomDSGVirtualAppDesktop, atomString, 0, lengthMax).Reply(globalXConn) - if err != nil { - return "" - } - - name := string(reply.Value) - return name -} - -const lengthMax = 0xffff - -func getWmWindowRole(win x.Window) string { - role, _ := getWindowPropertyString(win, atomWmWindowRole) - return role -} - -func getWindowPropertyString(win x.Window, atom x.Atom) (string, error) { - reply, err := x.GetProperty(globalXConn, false, win, atom, atomUTF8String, - 0, lengthMax).Reply(globalXConn) - if err != nil { - return "", err - } - return getUTF8StrFromReply(reply) -} - -func getCardinalFromReply(r *x.GetPropertyReply) (uint32, error) { - if r.Format != 32 || len(r.Value) != 4 { - return 0, errors.New("bad reply") - } - return uint32(x.Get32(r.Value)), nil -} - -func getWindowFromReply(r *x.GetPropertyReply) (x.Window, error) { - if r.Format != 32 || len(r.Value) != 4 { - return 0, errors.New("bad reply") - } - return x.Window(x.Get32(r.Value)), nil -} - -func getUTF8StrFromReply(reply *x.GetPropertyReply) (string, error) { - if reply.Format != 8 { - return "", errors.New("bad reply") - } - - return string(reply.Value), nil -} - -func getUTF8StrsFromReply(reply *x.GetPropertyReply) ([]string, error) { - if reply.Format != 8 { - return nil, errors.New("bad reply") - } - - data := reply.Value - var strs []string - sstart := 0 - for i, c := range data { - if c == 0 { - strs = append(strs, string(data[sstart:i])) - sstart = i + 1 - } - } - if sstart < len(data) { - strs = append(strs, string(data[sstart:])) - } - return strs, nil -} - -const bestIconSize = 48 - -func getIconFromWindow(win x.Window) string { - img, err := findIconEwmh(win) - if err != nil { - logger.Warning(err) - // try icccm - img, err = findIconIcccm(win) - if err != nil { - logger.Warning(err) - // get icon failed - return "" - } - } - - img = resize.Thumbnail(bestIconSize, bestIconSize, img, resize.NearestNeighbor) - - // encode image to png, then to base64 string - var buf bytes.Buffer - if err := png.Encode(&buf, img); err != nil { - logger.Warning(err) - return "" - } - return "data:image/png;base64," + base64.StdEncoding.EncodeToString(buf.Bytes()) -} - -func findIconEwmh(win x.Window) (image.Image, error) { - icon, err := getBestEwmhIcon(win) - if err != nil { - return nil, err - } - return NewNRGBAImageFromEwmhIcon(icon), nil -} - -// findIconIcccm helps FindIcon by trying to return an icccm-style icon. -func findIconIcccm(wid x.Window) (image.Image, error) { - // TODO - return nil, errors.New("todo") - //hints, err := icccm.WmHintsGet(xu, wid) - //if err != nil { - // return nil, err - //} - // - //// Only continue if the WM_HINTS flags say an icon is specified and - //// if at least one of icon pixmap or icon mask is non-zero. - //if hints.Flags&icccm.HintIconPixmap == 0 || - // (hints.IconPixmap == 0 && hints.IconMask == 0) { - // - // return nil, errors.New("No icon found in WM_HINTS.") - //} - // - //return xgraphics.NewIcccmIcon(xu, hints.IconPixmap, hints.IconMask) -} - -func getBestEwmhIcon(win x.Window) (*ewmh.WMIcon, error) { - icons, err := ewmh.GetWMIcon(globalXConn, win).Reply(globalXConn) - if err != nil { - return nil, err - } - - best := findBestEwmhIcon(bestIconSize, bestIconSize, icons) - if best == nil { - return nil, errors.New("ewmh icon not found") - } - return best, nil -} - -// findBestEwmhIcon takes width/height dimensions and a slice of *ewmh.WmIcon -// and finds the best matching icon of the bunch. We always prefer bigger. -// If no icons are bigger than the preferred dimensions, use the biggest -// available. Otherwise, use the smallest icon that is greater than or equal -// to the preferred dimensions. The preferred dimensions is essentially -// what you'll likely scale the resulting icon to. -// If width and height are 0, then the largest icon found will be returned. -func findBestEwmhIcon(width, height int, icons []ewmh.WMIcon) *ewmh.WMIcon { - // nada nada limonada - if len(icons) == 0 { - return nil - } - - parea := width * height // preferred size - best := -1 - - // If zero area, set it to the largest possible. - if parea == 0 { - parea = math.MaxInt32 - } - - var bestArea, iconArea int - - for i, icon := range icons { - // the first valid icon we've seen; use it! - if best == -1 { - best = i - continue - } - - // load areas for comparison - bestArea = int(icons[best].Width * icons[best].Height) - iconArea = int(icon.Width * icon.Height) - - // We don't always want to accept bigger icons if our best is - // already bigger. But we always want something bigger if our best - // is insufficient. - if (iconArea >= parea && iconArea <= bestArea) || - (bestArea < parea && iconArea > bestArea) { - best = i - } - } - - if best > -1 { - return &icons[best] - } - return nil -} - -func NewNRGBAImageFromEwmhIcon(icon *ewmh.WMIcon) *image.NRGBA { - img := image.NewNRGBA(image.Rect(0, 0, int(icon.Width), int(icon.Height))) - // icon.Data []uint8 BGRA - // img.Pix []uint8 RGBA - - for i := 0; i < len(icon.Data); i += 4 { - b := icon.Data[i] - g := icon.Data[i+1] - r := icon.Data[i+2] - a := icon.Data[i+3] - - img.Pix[i] = r - img.Pix[i+1] = g - img.Pix[i+2] = b - img.Pix[i+3] = a - } - return img -} - -func getWindowUserTime(win x.Window) (uint, error) { - timestamp, err := ewmh.GetWMUserTime(globalXConn, win).Reply(globalXConn) - if err != nil { - userTimeWindow, err := ewmh.GetWMUserTimeWindow(globalXConn, win).Reply(globalXConn) - if err != nil { - return 0, err - } - - timestamp, err = ewmh.GetWMUserTime(globalXConn, userTimeWindow).Reply(globalXConn) - if err != nil { - return 0, err - } - } - return uint(timestamp), nil -} - -func changeCurrentWorkspaceToWindowWorkspace(win x.Window) error { - winWorkspace, err := ewmh.GetWMDesktop(globalXConn, win).Reply(globalXConn) - if err != nil { - return err - } - - currentWorkspace, err := ewmh.GetCurrentDesktop(globalXConn).Reply(globalXConn) - if err != nil { - return err - } - - if currentWorkspace == winWorkspace { - logger.Debugf("No need to change workspace, the current desktop is already %v", currentWorkspace) - return nil - } - logger.Debug("Change workspace") - - winUserTime, err := getWindowUserTime(win) - logger.Debug("window user time:", winUserTime) - if err != nil { - // only warning not return - logger.Warning("getWindowUserTime failed:", err) - } - _ = ewmh.RequestChangeCurrentDesktop(globalXConn, winWorkspace, - x.Timestamp(winUserTime)).Check(globalXConn) - - return nil -} - -func activateWindow(win x.Window) error { - logger.Debug("activateWindow", win) - err := changeCurrentWorkspaceToWindowWorkspace(win) - if err != nil { - return err - } - err = ewmh.RequestChangeActiveWindow(globalXConn, win, - 2, 0, 0).Check(globalXConn) - if err != nil { - return err - } - - time.AfterFunc(50*time.Millisecond, func() { - err := ewmh.RequestRestackWindow(globalXConn, win, 0, - x.StackModeAbove).Check(globalXConn) - if err != nil { - logger.Warning(err) - } - }) - - return nil -} - -func isHiddenPre(win x.Window) bool { - state, _ := ewmh.GetWMState(globalXConn, win).Reply(globalXConn) - return atomsContains(state, atomNetWmStateHidden) -} - -// works for new deepin wm. -func isWindowOnCurrentWorkspace(win x.Window) (bool, error) { - winWorkspace, err := ewmh.GetWMDesktop(globalXConn, win).Reply(globalXConn) - if err != nil { - return false, err - } - - currentWorkspace, err := ewmh.GetCurrentDesktop(globalXConn).Reply(globalXConn) - if err != nil { - return false, err - } - - return winWorkspace == currentWorkspace, nil -} - -func onCurrentWorkspacePre(win x.Window) bool { - isOnCurrentWorkspace, err := isWindowOnCurrentWorkspace(win) - if err != nil { - logger.Warning(err) - // 也许是窗口跳过窗口管理器了,如 dde-control-center - return true - } - return isOnCurrentWorkspace -} - -func isGoodWindow(win x.Window) bool { - _, err := x.GetGeometry(globalXConn, x.Drawable(win)).Reply(globalXConn) - return err == nil -} - -func killClient(win x.Window) error { - return x.KillClientChecked(globalXConn, uint32(win)).Check(globalXConn) -} diff --git a/docs/aireplane-mode.md b/docs/aireplane-mode.md index 568b2e53f..aabb5c72a 100644 --- a/docs/aireplane-mode.md +++ b/docs/aireplane-mode.md @@ -1,8 +1,8 @@ # airplane mode 模块 -在 system bus 上提供服务,服务名 com.deepin.daemon.AirplaneMode, 只有一个对象 /com/deepin/daemon/AirplaneMode,这个对象只有一个接口 com.deepin.daemon.AirplaneMode。 +在 system bus 上提供服务,服务名 org.deepin.dde.AirplaneMode1, 只有一个对象 /org/deepin/dde/AirplaneMode1,这个对象只有一个接口 org.deepin.dde.AirplaneMode1。 -## 接口 com.deepin.daemon.AirplaneMode +## 接口 org.deepin.dde.AirplaneMode1 ### 属性 Enabled bool 飞行模式是否打开 diff --git a/docs/authority.md b/docs/authority.md index 9a781ad1b..23f52c200 100644 --- a/docs/authority.md +++ b/docs/authority.md @@ -1,4 +1,4 @@ -# com.deepin.daemon.Authority 服务 +# org.deepin.dde.Authority1 服务 这是个在 system bus 上的 DBus 服务,提供给 UI 界面统一的认证服务。可以支持 登录界面、锁屏界面和 policykit 权限认证框的认证。 @@ -8,9 +8,9 @@ ## Authority 入口对象 -对象路径:/com/deepin/daemon/Authority +对象路径:/org/deepin/dde/Authority1 -### com.deepin.daemon.Authority 接口 +### org.deepin.dde.Authority1 接口 #### 方法 @@ -38,9 +38,9 @@ CheckCookie(String user, String cookie) -> (Bool result) ## 认证事务 -对象路径:/com/deepin/daemon/Authority/TranscationN +对象路径:/org/deepin/dde/Authority1/TranscationN -### com.deepin.daemon.Authority.Transcation 接口 +### org.deepin.dde.Authority1.Transcation 接口 #### 方法 @@ -69,9 +69,9 @@ Authenticating Bool 表示是否正在进行认证 ## Agent 对象 -UI 程序在 system bus 上导出一个对象,这个对象实现 com.deepin.daemon.Authority.Agent 接口,把对象的路径作为 com.deepin.daemon.Authority.Start 方法的 agentObj 参数。 +UI 程序在 system bus 上导出一个对象,这个对象实现 org.deepin.dde.Authority1.Agent 接口,把对象的路径作为 org.deepin.dde.Authority1.Start 方法的 agentObj 参数。 -### com.deepin.daemon.Authority.Agent 接口 +### org.deepin.dde.Authority1.Agent 接口 #### 方法 diff --git a/docs/calendar/ifc.md b/docs/calendar/ifc.md index 5e5fc0867..48ccbc6ed 100644 --- a/docs/calendar/ifc.md +++ b/docs/calendar/ifc.md @@ -1,10 +1,10 @@ Bus 类型:session bus -服务名称:com.deepin.daemon.Calendar +服务名称:org.deepin.dde.Calendar1 -对象路径:/com/deepin/daemon/Calendar/Scheduler +对象路径:/org/deepin/dde/Calendar1/Scheduler -接口名称:com.deepin.daemon.Calendar.Scheduler +接口名称:org.deepin.dde.Calendar1.Scheduler # 方法 diff --git a/docs/service_trigger.md b/docs/service_trigger.md index 9465c6434..7ef915e32 100644 --- a/docs/service_trigger.md +++ b/docs/service_trigger.md @@ -27,9 +27,9 @@ "Type": "DBus", "DBus": { "BusType": "System", - "Sender": "com.deepin.daemon.Apps", - "Interface": "com.deepin.daemon.Apps.LaunchedRecorder", - "Path": "/com/deepin/daemon/Apps", + "Sender": "org.deepin.dde.Apps1", + "Interface": "org.deepin.dde.Apps1.LaunchedRecorder", + "Path": "/org/deepin/dde/Apps1", "Signal": "StatusSaved" } }, @@ -40,7 +40,7 @@ } ``` -这样会让 service_trigger 监听 system bus 的 com.deepin.daemon.Apps 服务的 /com/deepin/daemon/Apps 对象的 com.deepin.daemon.Apps.LaunchedRecorder 接口的 StatusSaved 信号,如果收到将执行 echo 命令输出信号参数。 +这样会让 service_trigger 监听 system bus 的 org.deepin.dde.Apps 服务的 /org/deepin/dde/Apps1 对象的 org.deepin.dde.Apps1.LaunchedRecorder 接口的 StatusSaved 信号,如果收到将执行 echo 命令输出信号参数。 ### 详述 Name 名称,字符串,必填; diff --git a/docs/session-power.md b/docs/session-power.md index 795bf10be..8f026bc72 100644 --- a/docs/session-power.md +++ b/docs/session-power.md @@ -1,10 +1,10 @@ -# com.deepin.daemon.Power 服务 +# org.deepin.dde.Power1 服务 这是个在 Session Bus 上的服务 ## Power 入口对象 -对象路径:/com/deepin/daemon/Power +对象路径:/org/deepin/dde/Power1 ## 属性: diff --git a/fprintd/device.go b/fprintd/device.go deleted file mode 100644 index 04f3a5bff..000000000 --- a/fprintd/device.go +++ /dev/null @@ -1,234 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package fprintd - -import ( - "errors" - "path" - "strings" - - "github.com/godbus/dbus" - fprint "github.com/linuxdeepin/go-dbus-factory/net.reactivated.fprint" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/dbusutil/proxy" -) - -const ( - actionIdEnroll = "com.deepin.daemon.fprintd.enroll" - actionIdDelete = "com.deepin.daemon.fprintd.delete-enrolled-fingers" -) - -type IDevice interface { - destroy() - getCorePath() dbus.ObjectPath - getPath() dbus.ObjectPath - dbusutil.Implementer - - isFree() (bool, error) -} - -type Device struct { - service *dbusutil.Service - core fprint.Device - - ScanType string -} - -type Devices []IDevice - -func newDevice(objPath dbus.ObjectPath, service *dbusutil.Service, - systemSigLoop *dbusutil.SignalLoop) *Device { - var dev Device - dev.service = service - dev.core, _ = fprint.NewDevice(systemSigLoop.Conn(), objPath) - dev.ScanType, _ = dev.core.ScanType().Get(0) - dev.listenDBusSignals(systemSigLoop) - return &dev -} - -func (dev *Device) listenDBusSignals(sigLoop *dbusutil.SignalLoop) { - dev.core.InitSignalExt(sigLoop, true) - _, err := dev.core.ConnectEnrollStatus(func(status string, ok bool) { - err := dev.service.Emit(dev, "EnrollStatus", status, ok) - if err != nil { - logger.Warning(err) - } - }) - if err != nil { - logger.Warning(err) - } - - _, err = dev.core.ConnectVerifyStatus(func(status string, ok bool) { - err := dev.service.Emit(dev, "VerifyStatus", status, ok) - if err != nil { - logger.Warning(err) - } - }) - if err != nil { - logger.Warning(err) - } - - _, err = dev.core.ConnectVerifyFingerSelected(func(finger string) { - err := dev.service.Emit(dev, "VerifyFingerSelected", finger) - if err != nil { - logger.Warning(err) - } - }) - if err != nil { - logger.Warning(err) - } -} - -func (dev *Device) destroy() { - dev.core.RemoveHandler(proxy.RemoveAllHandlers) - err := dev.service.StopExport(dev) - if err != nil { - logger.Warning(err) - } -} - -func (dev *Device) isFree() (bool, error) { - err := dev.core.Claim(0, "root") - if err == nil { - err = dev.core.Release(dbus.FlagNoAutoStart) - if err != nil { - logger.Warningf("failed to release device %q: %v", dev.getCorePath(), err) - } - return true, nil - - } else { - if strings.Contains(err.Error(), "already claimed") { - return false, nil - } - return false, err - } -} - -func (dev *Device) Claim(username string) *dbus.Error { - err := dev.core.Claim(0, username) - return dbusutil.ToError(err) -} - -func (dev *Device) Release() *dbus.Error { - err := dev.core.Release(0) - return dbusutil.ToError(err) -} - -func (dev *Device) EnrollStart(sender dbus.Sender, finger string) *dbus.Error { - err := checkAuth(actionIdEnroll, string(sender)) - if err != nil { - return dbusutil.ToError(err) - } - - err = dev.core.EnrollStart(0, finger) - return dbusutil.ToError(err) -} - -func (dev *Device) EnrollStop(sender dbus.Sender) *dbus.Error { - err := dev.core.EnrollStop(0) - return dbusutil.ToError(err) -} - -func (dev *Device) VerifyStart(finger string) *dbus.Error { - err := dev.core.VerifyStart(0, finger) - return dbusutil.ToError(err) -} - -func (dev *Device) VerifyStop() *dbus.Error { - err := dev.core.VerifyStop(0) - return dbusutil.ToError(err) -} - -func (dev *Device) DeleteEnrolledFingers(sender dbus.Sender, username string) *dbus.Error { - err := checkAuth(actionIdDelete, string(sender)) - if err != nil { - return dbusutil.ToError(err) - } - - err = dev.core.DeleteEnrolledFingers(0, username) - return dbusutil.ToError(err) -} - -func (dev *Device) DeleteEnrolledFinger(sender dbus.Sender, username string, finger string) *dbus.Error { - return dbusutil.ToError(errors.New("can not delete fprintd single finger")) -} - -func (dev *Device) GetCapabilities() (caps []string, dbusErr *dbus.Error) { - return nil, nil -} - -func (dev *Device) ClaimForce(sender dbus.Sender, username string) *dbus.Error { - return dbusutil.ToError(errors.New("can not claim force")) -} - -func (dev *Device) ListEnrolledFingers(username string) (fingers []string, busErr *dbus.Error) { - fingers, err := dev.core.ListEnrolledFingers(0, username) - if err != nil { - return nil, dbusutil.ToError(err) - } - return fingers, nil -} - -func (*Device) GetInterfaceName() string { - return dbusDeviceInterface -} - -func (dev *Device) getPath() dbus.ObjectPath { - return convertFPrintPath(dev.core.Path_()) -} - -func (dev *Device) getCorePath() dbus.ObjectPath { - return dev.core.Path_() -} - -func destroyDevices(list Devices) { - for _, dev := range list { - dev.destroy() - } -} - -func (devList Devices) Add(objPath dbus.ObjectPath, service *dbusutil.Service, - systemSigLoop *dbusutil.SignalLoop) Devices { - var v = newDevice(objPath, service, systemSigLoop) - err := service.Export(v.getPath(), v) - if err != nil { - logger.Warning("failed to export:", objPath) - return devList - } - - devList = append(devList, v) - return devList -} - -func (devList Devices) Get(objPath dbus.ObjectPath) IDevice { - for _, dev := range devList { - if dev.getCorePath() == objPath { - return dev - } - } - return nil -} - -func (devList Devices) Delete(objPath dbus.ObjectPath) Devices { - var ( - list Devices - v IDevice - ) - for _, dev := range devList { - if dev.getCorePath() == objPath { - v = dev - continue - } - list = append(list, dev) - } - if v != nil { - v.destroy() - } - return list -} - -func convertFPrintPath(objPath dbus.ObjectPath) dbus.ObjectPath { - return dbus.ObjectPath(dbusPath + "/Device/" + path.Base(string(objPath))) -} diff --git a/fprintd/exported_methods_auto.go b/fprintd/exported_methods_auto.go deleted file mode 100644 index e38594cb3..000000000 --- a/fprintd/exported_methods_auto.go +++ /dev/null @@ -1,144 +0,0 @@ -// Code generated by "dbusutil-gen em -type Manager,HuaweiDevice,Device"; DO NOT EDIT. - -package fprintd - -import ( - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (v *Device) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "Claim", - Fn: v.Claim, - InArgs: []string{"username"}, - }, - { - Name: "ClaimForce", - Fn: v.ClaimForce, - InArgs: []string{"username"}, - }, - { - Name: "DeleteEnrolledFinger", - Fn: v.DeleteEnrolledFinger, - InArgs: []string{"username", "finger"}, - }, - { - Name: "DeleteEnrolledFingers", - Fn: v.DeleteEnrolledFingers, - InArgs: []string{"username"}, - }, - { - Name: "EnrollStart", - Fn: v.EnrollStart, - InArgs: []string{"finger"}, - }, - { - Name: "EnrollStop", - Fn: v.EnrollStop, - }, - { - Name: "GetCapabilities", - Fn: v.GetCapabilities, - OutArgs: []string{"caps"}, - }, - { - Name: "ListEnrolledFingers", - Fn: v.ListEnrolledFingers, - InArgs: []string{"username"}, - OutArgs: []string{"fingers"}, - }, - { - Name: "Release", - Fn: v.Release, - }, - { - Name: "VerifyStart", - Fn: v.VerifyStart, - InArgs: []string{"finger"}, - }, - { - Name: "VerifyStop", - Fn: v.VerifyStop, - }, - } -} -func (v *HuaweiDevice) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "Claim", - Fn: v.Claim, - InArgs: []string{"username"}, - }, - { - Name: "ClaimForce", - Fn: v.ClaimForce, - InArgs: []string{"username"}, - }, - { - Name: "DeleteEnrolledFinger", - Fn: v.DeleteEnrolledFinger, - InArgs: []string{"username", "finger"}, - }, - { - Name: "DeleteEnrolledFingers", - Fn: v.DeleteEnrolledFingers, - InArgs: []string{"username"}, - }, - { - Name: "EnrollStart", - Fn: v.EnrollStart, - InArgs: []string{"finger"}, - }, - { - Name: "EnrollStop", - Fn: v.EnrollStop, - }, - { - Name: "GetCapabilities", - Fn: v.GetCapabilities, - OutArgs: []string{"caps"}, - }, - { - Name: "ListEnrolledFingers", - Fn: v.ListEnrolledFingers, - InArgs: []string{"username"}, - OutArgs: []string{"fingers"}, - }, - { - Name: "Release", - Fn: v.Release, - }, - { - Name: "VerifyStart", - Fn: v.VerifyStart, - InArgs: []string{"finger"}, - }, - { - Name: "VerifyStop", - Fn: v.VerifyStop, - }, - } -} -func (v *Manager) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "GetDefaultDevice", - Fn: v.GetDefaultDevice, - OutArgs: []string{"device"}, - }, - { - Name: "GetDevices", - Fn: v.GetDevices, - OutArgs: []string{"devices"}, - }, - { - Name: "PreAuthEnroll", - Fn: v.PreAuthEnroll, - }, - { - Name: "TriggerUDevEvent", - Fn: v.TriggerUDevEvent, - }, - } -} diff --git a/fprintd/manager.go b/fprintd/manager.go deleted file mode 100644 index 2d2bc5bb2..000000000 --- a/fprintd/manager.go +++ /dev/null @@ -1,420 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package fprintd - -import ( - "errors" - "strings" - "sync" - "time" - - "github.com/godbus/dbus" - huawei_fprint "github.com/linuxdeepin/go-dbus-factory/com.huawei.fingerprint" - fprint "github.com/linuxdeepin/go-dbus-factory/net.reactivated.fprint" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" - polkit "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.policykit1" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/strv" - "golang.org/x/xerrors" -) - -const ( - dbusServiceName = "com.deepin.daemon.Fprintd" - dbusPath = "/com/deepin/daemon/Fprintd" - dbusInterface = dbusServiceName - dbusDeviceInterface = dbusServiceName + ".Device" - - systemdDBusServiceName = "org.freedesktop.systemd1" - systemdDBusPath = "/org/freedesktop/systemd1" - systemdDBusInterface = systemdDBusServiceName + ".Manager" -) - -//go:generate dbusutil-gen -type Manager -import github.com/godbus/dbus manager.go -//go:generate dbusutil-gen em -type Manager,HuaweiDevice,Device - -type Manager struct { - service *dbusutil.Service - sysSigLoop *dbusutil.SignalLoop - fprintManager fprint.Manager - huaweiFprint huawei_fprint.Fingerprint - huaweiDevice *HuaweiDevice - dbusDaemon ofdbus.DBus - devices Devices - devicesMu sync.Mutex - fprintCh chan struct{} - - PropsMu sync.RWMutex - // dbusutil-gen: equal=nil - Devices []dbus.ObjectPath -} - -func newManager(service *dbusutil.Service) (*Manager, error) { - systemConn, err := dbus.SystemBus() - if err != nil { - return nil, err - } - - return &Manager{ - service: service, - fprintManager: fprint.NewManager(systemConn), - huaweiFprint: huawei_fprint.NewFingerprint(systemConn), - dbusDaemon: ofdbus.NewDBus(systemConn), - sysSigLoop: dbusutil.NewSignalLoop(systemConn, 10), - }, nil -} - -func (m *Manager) getDefaultDeviceInter() (IDevice, error) { - if m.huaweiDevice != nil { - return m.huaweiDevice, nil - } - - objPath, err := m.fprintManager.GetDefaultDevice(0) - if err != nil { - return nil, err - } - return m.devices.Get(objPath), nil -} - -func (m *Manager) GetDefaultDevice() (device dbus.ObjectPath, busErr *dbus.Error) { - err := m.refreshDeviceHuawei() - if err != nil { - logger.Warning(err) - } - - if m.huaweiDevice != nil { - return huaweiDevicePath, nil - } - - objPath, err := m.fprintManager.GetDefaultDevice(0) - if err != nil { - logger.Debug("failed to get default device:", err) - return "/", dbusutil.ToError(err) - } - m.addDevice(objPath) - return convertFPrintPath(objPath), nil -} - -func (m *Manager) GetDevices() (devices []dbus.ObjectPath, busErr *dbus.Error) { - m.refreshDevices() - m.PropsMu.Lock() - devices = m.Devices - m.PropsMu.Unlock() - return devices, nil -} - -func (m *Manager) refreshDevicesFprintd() error { - devicePaths, err := m.fprintManager.GetDevices(0) - if err != nil { - return err - } - - if m.huaweiDevice != nil { - devicePaths = append(devicePaths, huaweiDevicePath) - } - - var needDelete []dbus.ObjectPath - var needAdd []dbus.ObjectPath - - m.devicesMu.Lock() - - // 在 m.devList 但不在 devicePaths 中的记录在 needDelete - for _, d := range m.devices { - found := false - for _, devPath := range devicePaths { - if d.getCorePath() == devPath { - found = true - break - } - } - if !found { - needDelete = append(needDelete, d.getCorePath()) - } - } - - // 在 devicePaths 但不在 m.devList 中的记录在 needAdd - for _, devPath := range devicePaths { - found := false - for _, d := range m.devices { - if d.getCorePath() == devPath { - found = true - break - } - } - if !found { - needAdd = append(needAdd, devPath) - } - } - - for _, devPath := range needDelete { - m.devices = m.devices.Delete(devPath) - } - for _, devPath := range needAdd { - m.devices = m.devices.Add(devPath, m.service, m.sysSigLoop) - } - m.devicesMu.Unlock() - - m.updatePropDevices() - return nil -} - -func (m *Manager) refreshDeviceHuawei() error { - if m.huaweiDevice != nil { - return nil - } - - has, err := m.hasHuaweiDevice() - if err != nil { - return err - } - - if has { - m.addHuaweiDevice() - m.updatePropDevices() - } - return nil -} - -func (m *Manager) refreshDevices() { - err := m.refreshDeviceHuawei() - if err != nil { - logger.Warning(err) - } - err = m.refreshDevicesFprintd() - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) updatePropDevices() { - m.devicesMu.Lock() - paths := make([]dbus.ObjectPath, len(m.devices)) - for idx, d := range m.devices { - paths[idx] = d.getPath() - } - m.devicesMu.Unlock() - - m.PropsMu.Lock() - m.setPropDevices(paths) - m.PropsMu.Unlock() -} - -func (*Manager) GetInterfaceName() string { - return dbusInterface -} - -func (m *Manager) hasHuaweiDevice() (has bool, err error) { - activatableNames, err := m.dbusDaemon.ListActivatableNames(0) - if err != nil { - return false, err - } - if !strv.Strv(activatableNames).Contains(m.huaweiFprint.ServiceName_()) { - return false, nil - } - - has, err = m.huaweiFprint.SearchDevice(0) - return -} - -func (m *Manager) init() { - m.sysSigLoop.Start() - m.fprintCh = make(chan struct{}, 1) - m.listenDBusSignals() - - paths, err := m.fprintManager.GetDevices(0) - if err != nil { - logger.Warning("Failed to get fprint devices:", err) - return - } - for _, devPath := range paths { - m.addDevice(devPath) - } - m.updatePropDevices() -} - -func (m *Manager) addHuaweiDevice() { - logger.Debug("add huawei device") - d := &HuaweiDevice{ - service: m.service, - core: m.huaweiFprint, - ScanType: "press", - } - - // listen dbus signals - m.huaweiFprint.InitSignalExt(m.sysSigLoop, true) - _, err := m.huaweiFprint.ConnectEnrollStatus(func(progress int32, result int32) { - d.handleSignalEnrollStatus(progress, result) - }) - if err != nil { - logger.Warning(err) - } - - _, err = m.huaweiFprint.ConnectIdentifyStatus(func(result int32) { - d.handleSignalIdentifyStatus(result) - }) - if err != nil { - logger.Warning(err) - } - - err = m.service.Export(huaweiDevicePath, d) - if err != nil { - logger.Warning(err) - return - } - - m.huaweiDevice = d - - m.devicesMu.Lock() - m.devices = append(m.devices, d) - m.devicesMu.Unlock() -} - -func (m *Manager) listenDBusSignals() { - m.dbusDaemon.InitSignalExt(m.sysSigLoop, true) - _, err := m.dbusDaemon.ConnectNameOwnerChanged(func(name string, oldOwner string, newOwner string) { - fprintDBusServiceName := m.fprintManager.ServiceName_() - if name == fprintDBusServiceName && newOwner != "" { - select { - case m.fprintCh <- struct{}{}: - default: - } - } - if newOwner == "" && - oldOwner != "" && - name == oldOwner && - strings.HasPrefix(name, ":") { - // uniq name lost - - if m.huaweiDevice != nil { - m.huaweiDevice.handleNameLost(name) - } - } - }) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) addDevice(objPath dbus.ObjectPath) { - logger.Debug("add device:", objPath) - m.devicesMu.Lock() - defer m.devicesMu.Unlock() - - d := m.devices.Get(objPath) - if d != nil { - return - } - m.devices = m.devices.Add(objPath, m.service, m.sysSigLoop) -} - -func (m *Manager) destroy() { - destroyDevices(m.devices) - m.sysSigLoop.Stop() -} - -var errAuthFailed = errors.New("authentication failed") - -func checkAuth(actionId string, busName string) error { - systemBus, err := dbus.SystemBus() - if err != nil { - return err - } - authority := polkit.NewAuthority(systemBus) - subject := polkit.MakeSubject(polkit.SubjectKindSystemBusName) - subject.SetDetail("name", busName) - - ret, err := authority.CheckAuthorization(0, subject, - actionId, nil, - polkit.CheckAuthorizationFlagsAllowUserInteraction, "") - if err != nil { - return err - } - - if ret.IsAuthorized { - return nil - } - return errAuthFailed -} - -func (m *Manager) TriggerUDevEvent(sender dbus.Sender) *dbus.Error { - uid, err := m.service.GetConnUID(string(sender)) - if err != nil { - return dbusutil.ToError(err) - } - if uid != 0 { - err = errors.New("not root user") - return dbusutil.ToError(err) - } - - logger.Debug("udev event") - - select { - case <-m.fprintCh: - default: - } - - err = restartSystemdService("fprintd.service", "replace") - if err != nil { - return dbusutil.ToError(err) - } - - select { - case <-m.fprintCh: - logger.Debug("fprintd started") - case <-time.After(5 * time.Second): - logger.Warning("wait fprintd restart timed out!") - } - - err = m.refreshDevicesFprintd() - if err != nil { - return dbusutil.ToError(err) - } - return nil -} - -func restartSystemdService(name, mode string) error { - sysBus, err := dbus.SystemBus() - if err != nil { - return err - } - obj := sysBus.Object(systemdDBusServiceName, systemdDBusPath) - var jobPath dbus.ObjectPath - err = obj.Call(systemdDBusInterface+".RestartUnit", dbus.FlagNoAutoStart, name, mode).Store(&jobPath) - return err -} - -func (m *Manager) PreAuthEnroll(sender dbus.Sender) *dbus.Error { - logger.Debug("PreAuthEnroll sender:", sender) - err := checkAuth(actionIdEnroll, string(sender)) - if err != nil { - return dbusutil.ToError(err) - } - - var dev IDevice - dev, err = m.getDefaultDeviceInter() - if err != nil { - return dbusutil.ToError(xerrors.Errorf("failed to get default device: %w", err)) - } - if dev == nil { - logger.Warning("PreAuthEnroll dev is nil") - return nil - } - - // wait device free, timeout 4s - for i := 0; i < 20; i++ { - free, err := dev.isFree() - if err != nil { - logger.Warning("dev isFree err:", err) - return dbusutil.ToError(err) - } - if free { - logger.Debug("PreAuthEnroll default device is free now") - return nil - } - time.Sleep(200 * time.Millisecond) - } - logger.Warning("wait for the default device to become free timed out") - - return nil -} diff --git a/fprintd/common/common.go b/fprintd1/common/common.go similarity index 87% rename from fprintd/common/common.go rename to fprintd1/common/common.go index 6781f21be..3f81184a2 100644 --- a/fprintd/common/common.go +++ b/fprintd1/common/common.go @@ -10,9 +10,9 @@ import ( "os" "path/filepath" - dbus "github.com/godbus/dbus" - huawei_fprint "github.com/linuxdeepin/go-dbus-factory/com.huawei.fingerprint" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" + dbus "github.com/godbus/dbus/v5" + huawei_fprint "github.com/linuxdeepin/go-dbus-factory/system/com.huawei.fingerprint" + ofdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.dbus" ) const ( diff --git a/fprintd1/device.go b/fprintd1/device.go new file mode 100644 index 000000000..73746a3ed --- /dev/null +++ b/fprintd1/device.go @@ -0,0 +1,234 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package fprintd1 + +import ( + "errors" + "path" + "strings" + + "github.com/godbus/dbus/v5" + fprint "github.com/linuxdeepin/go-dbus-factory/system/net.reactivated.fprint" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/dbusutil/proxy" +) + +const ( + actionIdEnroll = "org.deepin.dde.fprintd1.enroll" + actionIdDelete = "org.deepin.dde.fprintd1.delete-enrolled-fingers" +) + +type IDevice interface { + destroy() + getCorePath() dbus.ObjectPath + getPath() dbus.ObjectPath + dbusutil.Implementer + + isFree() (bool, error) +} + +type Device struct { + service *dbusutil.Service + core fprint.Device + + ScanType string +} + +type Devices []IDevice + +func newDevice(objPath dbus.ObjectPath, service *dbusutil.Service, + systemSigLoop *dbusutil.SignalLoop) *Device { + var dev Device + dev.service = service + dev.core, _ = fprint.NewDevice(systemSigLoop.Conn(), objPath) + dev.ScanType, _ = dev.core.ScanType().Get(0) + dev.listenDBusSignals(systemSigLoop) + return &dev +} + +func (dev *Device) listenDBusSignals(sigLoop *dbusutil.SignalLoop) { + dev.core.InitSignalExt(sigLoop, true) + _, err := dev.core.ConnectEnrollStatus(func(status string, ok bool) { + err := dev.service.Emit(dev, "EnrollStatus", status, ok) + if err != nil { + logger.Warning(err) + } + }) + if err != nil { + logger.Warning(err) + } + + _, err = dev.core.ConnectVerifyStatus(func(status string, ok bool) { + err := dev.service.Emit(dev, "VerifyStatus", status, ok) + if err != nil { + logger.Warning(err) + } + }) + if err != nil { + logger.Warning(err) + } + + _, err = dev.core.ConnectVerifyFingerSelected(func(finger string) { + err := dev.service.Emit(dev, "VerifyFingerSelected", finger) + if err != nil { + logger.Warning(err) + } + }) + if err != nil { + logger.Warning(err) + } +} + +func (dev *Device) destroy() { + dev.core.RemoveHandler(proxy.RemoveAllHandlers) + err := dev.service.StopExport(dev) + if err != nil { + logger.Warning(err) + } +} + +func (dev *Device) isFree() (bool, error) { + err := dev.core.Claim(0, "root") + if err == nil { + err = dev.core.Release(dbus.FlagNoAutoStart) + if err != nil { + logger.Warningf("failed to release device %q: %v", dev.getCorePath(), err) + } + return true, nil + + } else { + if strings.Contains(err.Error(), "already claimed") { + return false, nil + } + return false, err + } +} + +func (dev *Device) Claim(username string) *dbus.Error { + err := dev.core.Claim(0, username) + return dbusutil.ToError(err) +} + +func (dev *Device) Release() *dbus.Error { + err := dev.core.Release(0) + return dbusutil.ToError(err) +} + +func (dev *Device) EnrollStart(sender dbus.Sender, finger string) *dbus.Error { + err := checkAuth(actionIdEnroll, string(sender)) + if err != nil { + return dbusutil.ToError(err) + } + + err = dev.core.EnrollStart(0, finger) + return dbusutil.ToError(err) +} + +func (dev *Device) EnrollStop(sender dbus.Sender) *dbus.Error { + err := dev.core.EnrollStop(0) + return dbusutil.ToError(err) +} + +func (dev *Device) VerifyStart(finger string) *dbus.Error { + err := dev.core.VerifyStart(0, finger) + return dbusutil.ToError(err) +} + +func (dev *Device) VerifyStop() *dbus.Error { + err := dev.core.VerifyStop(0) + return dbusutil.ToError(err) +} + +func (dev *Device) DeleteEnrolledFingers(sender dbus.Sender, username string) *dbus.Error { + err := checkAuth(actionIdDelete, string(sender)) + if err != nil { + return dbusutil.ToError(err) + } + + err = dev.core.DeleteEnrolledFingers(0, username) + return dbusutil.ToError(err) +} + +func (dev *Device) DeleteEnrolledFinger(sender dbus.Sender, username string, finger string) *dbus.Error { + return dbusutil.ToError(errors.New("can not delete fprintd single finger")) +} + +func (dev *Device) GetCapabilities() (caps []string, dbusErr *dbus.Error) { + return nil, nil +} + +func (dev *Device) ClaimForce(sender dbus.Sender, username string) *dbus.Error { + return dbusutil.ToError(errors.New("can not claim force")) +} + +func (dev *Device) ListEnrolledFingers(username string) (fingers []string, busErr *dbus.Error) { + fingers, err := dev.core.ListEnrolledFingers(0, username) + if err != nil { + return nil, dbusutil.ToError(err) + } + return fingers, nil +} + +func (*Device) GetInterfaceName() string { + return dbusDeviceInterface +} + +func (dev *Device) getPath() dbus.ObjectPath { + return convertFPrintPath(dev.core.Path_()) +} + +func (dev *Device) getCorePath() dbus.ObjectPath { + return dev.core.Path_() +} + +func destroyDevices(list Devices) { + for _, dev := range list { + dev.destroy() + } +} + +func (devList Devices) Add(objPath dbus.ObjectPath, service *dbusutil.Service, + systemSigLoop *dbusutil.SignalLoop) Devices { + var v = newDevice(objPath, service, systemSigLoop) + err := service.Export(v.getPath(), v) + if err != nil { + logger.Warning("failed to export:", objPath) + return devList + } + + devList = append(devList, v) + return devList +} + +func (devList Devices) Get(objPath dbus.ObjectPath) IDevice { + for _, dev := range devList { + if dev.getCorePath() == objPath { + return dev + } + } + return nil +} + +func (devList Devices) Delete(objPath dbus.ObjectPath) Devices { + var ( + list Devices + v IDevice + ) + for _, dev := range devList { + if dev.getCorePath() == objPath { + v = dev + continue + } + list = append(list, dev) + } + if v != nil { + v.destroy() + } + return list +} + +func convertFPrintPath(objPath dbus.ObjectPath) dbus.ObjectPath { + return dbus.ObjectPath(dbusPath + "/Device/" + path.Base(string(objPath))) +} diff --git a/fprintd1/exported_methods_auto.go b/fprintd1/exported_methods_auto.go new file mode 100644 index 000000000..67012f1dc --- /dev/null +++ b/fprintd1/exported_methods_auto.go @@ -0,0 +1,144 @@ +// Code generated by "dbusutil-gen em -type Manager,HuaweiDevice,Device"; DO NOT EDIT. + +package fprintd1 + +import ( + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (v *Device) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "Claim", + Fn: v.Claim, + InArgs: []string{"username"}, + }, + { + Name: "ClaimForce", + Fn: v.ClaimForce, + InArgs: []string{"username"}, + }, + { + Name: "DeleteEnrolledFinger", + Fn: v.DeleteEnrolledFinger, + InArgs: []string{"username", "finger"}, + }, + { + Name: "DeleteEnrolledFingers", + Fn: v.DeleteEnrolledFingers, + InArgs: []string{"username"}, + }, + { + Name: "EnrollStart", + Fn: v.EnrollStart, + InArgs: []string{"finger"}, + }, + { + Name: "EnrollStop", + Fn: v.EnrollStop, + }, + { + Name: "GetCapabilities", + Fn: v.GetCapabilities, + OutArgs: []string{"caps"}, + }, + { + Name: "ListEnrolledFingers", + Fn: v.ListEnrolledFingers, + InArgs: []string{"username"}, + OutArgs: []string{"fingers"}, + }, + { + Name: "Release", + Fn: v.Release, + }, + { + Name: "VerifyStart", + Fn: v.VerifyStart, + InArgs: []string{"finger"}, + }, + { + Name: "VerifyStop", + Fn: v.VerifyStop, + }, + } +} +func (v *HuaweiDevice) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "Claim", + Fn: v.Claim, + InArgs: []string{"username"}, + }, + { + Name: "ClaimForce", + Fn: v.ClaimForce, + InArgs: []string{"username"}, + }, + { + Name: "DeleteEnrolledFinger", + Fn: v.DeleteEnrolledFinger, + InArgs: []string{"username", "finger"}, + }, + { + Name: "DeleteEnrolledFingers", + Fn: v.DeleteEnrolledFingers, + InArgs: []string{"username"}, + }, + { + Name: "EnrollStart", + Fn: v.EnrollStart, + InArgs: []string{"finger"}, + }, + { + Name: "EnrollStop", + Fn: v.EnrollStop, + }, + { + Name: "GetCapabilities", + Fn: v.GetCapabilities, + OutArgs: []string{"caps"}, + }, + { + Name: "ListEnrolledFingers", + Fn: v.ListEnrolledFingers, + InArgs: []string{"username"}, + OutArgs: []string{"fingers"}, + }, + { + Name: "Release", + Fn: v.Release, + }, + { + Name: "VerifyStart", + Fn: v.VerifyStart, + InArgs: []string{"finger"}, + }, + { + Name: "VerifyStop", + Fn: v.VerifyStop, + }, + } +} +func (v *Manager) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "GetDefaultDevice", + Fn: v.GetDefaultDevice, + OutArgs: []string{"device"}, + }, + { + Name: "GetDevices", + Fn: v.GetDevices, + OutArgs: []string{"devices"}, + }, + { + Name: "PreAuthEnroll", + Fn: v.PreAuthEnroll, + }, + { + Name: "TriggerUDevEvent", + Fn: v.TriggerUDevEvent, + }, + } +} diff --git a/fprintd/fprintd.go b/fprintd1/fprintd.go similarity index 98% rename from fprintd/fprintd.go rename to fprintd1/fprintd.go index 279b83096..49b305e6c 100644 --- a/fprintd/fprintd.go +++ b/fprintd1/fprintd.go @@ -2,11 +2,11 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package fprintd +package fprintd1 import ( - "github.com/linuxdeepin/go-lib/log" "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" ) var ( diff --git a/fprintd/fprintd_dbusutil.go b/fprintd1/fprintd_dbusutil.go similarity index 88% rename from fprintd/fprintd_dbusutil.go rename to fprintd1/fprintd_dbusutil.go index 3c554bda1..bdb156913 100644 --- a/fprintd/fprintd_dbusutil.go +++ b/fprintd1/fprintd_dbusutil.go @@ -1,9 +1,9 @@ // Code generated by "dbusutil-gen -type Manager -import github.com/godbus/dbus manager.go"; DO NOT EDIT. -package fprintd +package fprintd1 import ( - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" ) func (v *Manager) setPropDevices(value []dbus.ObjectPath) { diff --git a/fprintd/huawei_device.go b/fprintd1/huawei_device.go similarity index 98% rename from fprintd/huawei_device.go rename to fprintd1/huawei_device.go index a7f742c05..a06641208 100644 --- a/fprintd/huawei_device.go +++ b/fprintd1/huawei_device.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package fprintd +package fprintd1 import ( "errors" @@ -11,12 +11,12 @@ import ( "path/filepath" "sync" - dbus "github.com/godbus/dbus" - accounts "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.accounts" - huawei_fprint "github.com/linuxdeepin/go-dbus-factory/com.huawei.fingerprint" + dbus "github.com/godbus/dbus/v5" + fprintd_common "github.com/linuxdeepin/dde-daemon/fprintd1/common" + huawei_fprint "github.com/linuxdeepin/go-dbus-factory/system/com.huawei.fingerprint" + accounts "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.accounts1" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/strv" - fprintd_common "github.com/linuxdeepin/dde-daemon/fprintd/common" ) const ( diff --git a/fprintd1/manager.go b/fprintd1/manager.go new file mode 100644 index 000000000..0d4ba3c27 --- /dev/null +++ b/fprintd1/manager.go @@ -0,0 +1,420 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package fprintd1 + +import ( + "errors" + "strings" + "sync" + "time" + + "github.com/godbus/dbus/v5" + huawei_fprint "github.com/linuxdeepin/go-dbus-factory/system/com.huawei.fingerprint" + fprint "github.com/linuxdeepin/go-dbus-factory/system/net.reactivated.fprint" + ofdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.dbus" + polkit "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.policykit1" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/strv" + "golang.org/x/xerrors" +) + +const ( + dbusServiceName = "org.deepin.dde.Fprintd1" + dbusPath = "/org/deepin/dde/Fprintd1" + dbusInterface = dbusServiceName + dbusDeviceInterface = dbusServiceName + ".Device" + + systemdDBusServiceName = "org.freedesktop.systemd1" + systemdDBusPath = "/org/freedesktop/systemd1" + systemdDBusInterface = systemdDBusServiceName + ".Manager" +) + +//go:generate dbusutil-gen -type Manager -import github.com/godbus/dbus manager.go +//go:generate dbusutil-gen em -type Manager,HuaweiDevice,Device + +type Manager struct { + service *dbusutil.Service + sysSigLoop *dbusutil.SignalLoop + fprintManager fprint.Manager + huaweiFprint huawei_fprint.Fingerprint + huaweiDevice *HuaweiDevice + dbusDaemon ofdbus.DBus + devices Devices + devicesMu sync.Mutex + fprintCh chan struct{} + + PropsMu sync.RWMutex + // dbusutil-gen: equal=nil + Devices []dbus.ObjectPath +} + +func newManager(service *dbusutil.Service) (*Manager, error) { + systemConn, err := dbus.SystemBus() + if err != nil { + return nil, err + } + + return &Manager{ + service: service, + fprintManager: fprint.NewManager(systemConn), + huaweiFprint: huawei_fprint.NewFingerprint(systemConn), + dbusDaemon: ofdbus.NewDBus(systemConn), + sysSigLoop: dbusutil.NewSignalLoop(systemConn, 10), + }, nil +} + +func (m *Manager) getDefaultDeviceInter() (IDevice, error) { + if m.huaweiDevice != nil { + return m.huaweiDevice, nil + } + + objPath, err := m.fprintManager.GetDefaultDevice(0) + if err != nil { + return nil, err + } + return m.devices.Get(objPath), nil +} + +func (m *Manager) GetDefaultDevice() (device dbus.ObjectPath, busErr *dbus.Error) { + err := m.refreshDeviceHuawei() + if err != nil { + logger.Warning(err) + } + + if m.huaweiDevice != nil { + return huaweiDevicePath, nil + } + + objPath, err := m.fprintManager.GetDefaultDevice(0) + if err != nil { + logger.Debug("failed to get default device:", err) + return "/", dbusutil.ToError(err) + } + m.addDevice(objPath) + return convertFPrintPath(objPath), nil +} + +func (m *Manager) GetDevices() (devices []dbus.ObjectPath, busErr *dbus.Error) { + m.refreshDevices() + m.PropsMu.Lock() + devices = m.Devices + m.PropsMu.Unlock() + return devices, nil +} + +func (m *Manager) refreshDevicesFprintd() error { + devicePaths, err := m.fprintManager.GetDevices(0) + if err != nil { + return err + } + + if m.huaweiDevice != nil { + devicePaths = append(devicePaths, huaweiDevicePath) + } + + var needDelete []dbus.ObjectPath + var needAdd []dbus.ObjectPath + + m.devicesMu.Lock() + + // 在 m.devList 但不在 devicePaths 中的记录在 needDelete + for _, d := range m.devices { + found := false + for _, devPath := range devicePaths { + if d.getCorePath() == devPath { + found = true + break + } + } + if !found { + needDelete = append(needDelete, d.getCorePath()) + } + } + + // 在 devicePaths 但不在 m.devList 中的记录在 needAdd + for _, devPath := range devicePaths { + found := false + for _, d := range m.devices { + if d.getCorePath() == devPath { + found = true + break + } + } + if !found { + needAdd = append(needAdd, devPath) + } + } + + for _, devPath := range needDelete { + m.devices = m.devices.Delete(devPath) + } + for _, devPath := range needAdd { + m.devices = m.devices.Add(devPath, m.service, m.sysSigLoop) + } + m.devicesMu.Unlock() + + m.updatePropDevices() + return nil +} + +func (m *Manager) refreshDeviceHuawei() error { + if m.huaweiDevice != nil { + return nil + } + + has, err := m.hasHuaweiDevice() + if err != nil { + return err + } + + if has { + m.addHuaweiDevice() + m.updatePropDevices() + } + return nil +} + +func (m *Manager) refreshDevices() { + err := m.refreshDeviceHuawei() + if err != nil { + logger.Warning(err) + } + err = m.refreshDevicesFprintd() + if err != nil { + logger.Warning(err) + } +} + +func (m *Manager) updatePropDevices() { + m.devicesMu.Lock() + paths := make([]dbus.ObjectPath, len(m.devices)) + for idx, d := range m.devices { + paths[idx] = d.getPath() + } + m.devicesMu.Unlock() + + m.PropsMu.Lock() + m.setPropDevices(paths) + m.PropsMu.Unlock() +} + +func (*Manager) GetInterfaceName() string { + return dbusInterface +} + +func (m *Manager) hasHuaweiDevice() (has bool, err error) { + activatableNames, err := m.dbusDaemon.ListActivatableNames(0) + if err != nil { + return false, err + } + if !strv.Strv(activatableNames).Contains(m.huaweiFprint.ServiceName_()) { + return false, nil + } + + has, err = m.huaweiFprint.SearchDevice(0) + return +} + +func (m *Manager) init() { + m.sysSigLoop.Start() + m.fprintCh = make(chan struct{}, 1) + m.listenDBusSignals() + + paths, err := m.fprintManager.GetDevices(0) + if err != nil { + logger.Warning("Failed to get fprint devices:", err) + return + } + for _, devPath := range paths { + m.addDevice(devPath) + } + m.updatePropDevices() +} + +func (m *Manager) addHuaweiDevice() { + logger.Debug("add huawei device") + d := &HuaweiDevice{ + service: m.service, + core: m.huaweiFprint, + ScanType: "press", + } + + // listen dbus signals + m.huaweiFprint.InitSignalExt(m.sysSigLoop, true) + _, err := m.huaweiFprint.ConnectEnrollStatus(func(progress int32, result int32) { + d.handleSignalEnrollStatus(progress, result) + }) + if err != nil { + logger.Warning(err) + } + + _, err = m.huaweiFprint.ConnectIdentifyStatus(func(result int32) { + d.handleSignalIdentifyStatus(result) + }) + if err != nil { + logger.Warning(err) + } + + err = m.service.Export(huaweiDevicePath, d) + if err != nil { + logger.Warning(err) + return + } + + m.huaweiDevice = d + + m.devicesMu.Lock() + m.devices = append(m.devices, d) + m.devicesMu.Unlock() +} + +func (m *Manager) listenDBusSignals() { + m.dbusDaemon.InitSignalExt(m.sysSigLoop, true) + _, err := m.dbusDaemon.ConnectNameOwnerChanged(func(name string, oldOwner string, newOwner string) { + fprintDBusServiceName := m.fprintManager.ServiceName_() + if name == fprintDBusServiceName && newOwner != "" { + select { + case m.fprintCh <- struct{}{}: + default: + } + } + if newOwner == "" && + oldOwner != "" && + name == oldOwner && + strings.HasPrefix(name, ":") { + // uniq name lost + + if m.huaweiDevice != nil { + m.huaweiDevice.handleNameLost(name) + } + } + }) + if err != nil { + logger.Warning(err) + } +} + +func (m *Manager) addDevice(objPath dbus.ObjectPath) { + logger.Debug("add device:", objPath) + m.devicesMu.Lock() + defer m.devicesMu.Unlock() + + d := m.devices.Get(objPath) + if d != nil { + return + } + m.devices = m.devices.Add(objPath, m.service, m.sysSigLoop) +} + +func (m *Manager) destroy() { + destroyDevices(m.devices) + m.sysSigLoop.Stop() +} + +var errAuthFailed = errors.New("authentication failed") + +func checkAuth(actionId string, busName string) error { + systemBus, err := dbus.SystemBus() + if err != nil { + return err + } + authority := polkit.NewAuthority(systemBus) + subject := polkit.MakeSubject(polkit.SubjectKindSystemBusName) + subject.SetDetail("name", busName) + + ret, err := authority.CheckAuthorization(0, subject, + actionId, nil, + polkit.CheckAuthorizationFlagsAllowUserInteraction, "") + if err != nil { + return err + } + + if ret.IsAuthorized { + return nil + } + return errAuthFailed +} + +func (m *Manager) TriggerUDevEvent(sender dbus.Sender) *dbus.Error { + uid, err := m.service.GetConnUID(string(sender)) + if err != nil { + return dbusutil.ToError(err) + } + if uid != 0 { + err = errors.New("not root user") + return dbusutil.ToError(err) + } + + logger.Debug("udev event") + + select { + case <-m.fprintCh: + default: + } + + err = restartSystemdService("fprintd.service", "replace") + if err != nil { + return dbusutil.ToError(err) + } + + select { + case <-m.fprintCh: + logger.Debug("fprintd started") + case <-time.After(5 * time.Second): + logger.Warning("wait fprintd restart timed out!") + } + + err = m.refreshDevicesFprintd() + if err != nil { + return dbusutil.ToError(err) + } + return nil +} + +func restartSystemdService(name, mode string) error { + sysBus, err := dbus.SystemBus() + if err != nil { + return err + } + obj := sysBus.Object(systemdDBusServiceName, systemdDBusPath) + var jobPath dbus.ObjectPath + err = obj.Call(systemdDBusInterface+".RestartUnit", dbus.FlagNoAutoStart, name, mode).Store(&jobPath) + return err +} + +func (m *Manager) PreAuthEnroll(sender dbus.Sender) *dbus.Error { + logger.Debug("PreAuthEnroll sender:", sender) + err := checkAuth(actionIdEnroll, string(sender)) + if err != nil { + return dbusutil.ToError(err) + } + + var dev IDevice + dev, err = m.getDefaultDeviceInter() + if err != nil { + return dbusutil.ToError(xerrors.Errorf("failed to get default device: %w", err)) + } + if dev == nil { + logger.Warning("PreAuthEnroll dev is nil") + return nil + } + + // wait device free, timeout 4s + for i := 0; i < 20; i++ { + free, err := dev.isFree() + if err != nil { + logger.Warning("dev isFree err:", err) + return dbusutil.ToError(err) + } + if free { + logger.Debug("PreAuthEnroll default device is free now") + return nil + } + time.Sleep(200 * time.Millisecond) + } + logger.Warning("wait for the default device to become free timed out") + + return nil +} diff --git a/gesture/config.go b/gesture/config.go deleted file mode 100644 index bfbd4db79..000000000 --- a/gesture/config.go +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package gesture - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "path/filepath" - - "github.com/linuxdeepin/go-lib/xdg/basedir" -) - -const ( - ActionTypeShortcut = "shortcut" - ActionTypeCommandline = "commandline" - ActionTypeBuiltin = "built-in" -) - -var ( - configUserPath = filepath.Join(basedir.GetUserConfigDir(), "deepin/dde-daemon/gesture.json") -) - -const ( - configSystemPath = "/usr/share/dde-daemon/gesture.json" - - gestureSchemaId = "com.deepin.dde.gesture" - gsKeyTouchPadEnabled = "touch-pad-enabled" - gsKeyTouchScreenEnabled = "touch-screen-enabled" - - configManagerId = "org.desktopspec.ConfigManager" -) - -type ActionInfo struct { - Type string - Action string -} - -type EventInfo struct { - Name string - Direction string - Fingers int32 -} - -type gestureInfo struct { - Event EventInfo - Action ActionInfo -} -type gestureInfos []*gestureInfo - -func (action ActionInfo) toString() string { - return fmt.Sprintf("Type:%s, Action=%s", action.Type, action.Action) -} - -func (evInfo EventInfo) toString() string { - return fmt.Sprintf("Name=%s, Direction=%s, Fingers=%d", evInfo.Name, evInfo.Direction, evInfo.Fingers) -} - -func (infos gestureInfos) Get(evInfo EventInfo) *gestureInfo { - for _, info := range infos { - if info.Event == evInfo { - return info - } - } - return nil -} - -func (infos gestureInfos) Set(evInfo EventInfo, action ActionInfo) error { - info := infos.Get(evInfo) - if info == nil { - return fmt.Errorf("not found gesture info for: %s, %s, %d", evInfo.Name, evInfo.Direction, evInfo.Fingers) - } - info.Action = action - return nil -} - -func newGestureInfosFromFile(filename string) (gestureInfos, error) { - content, err := ioutil.ReadFile(filepath.Clean(filename)) - if err != nil { - return nil, err - } - - if len(content) == 0 { - return nil, fmt.Errorf("file '%s' is empty", filename) - } - - var infos gestureInfos - err = json.Unmarshal(content, &infos) - if err != nil { - return nil, err - } - return infos, nil -} diff --git a/gesture/config_test.go b/gesture/config_test.go deleted file mode 100644 index dd3792d8f..000000000 --- a/gesture/config_test.go +++ /dev/null @@ -1,109 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package gesture - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -var ( - configPath = "testdata/gesture" -) - -// 查找手势信息 -func findGestureInfo(evInfo EventInfo, infos gestureInfos) bool { - for _, info := range infos { - if info.Event == evInfo { - return true - } - } - return false -} - -// 测试: 从文件读取手势信息 -func Test_newGestureInfosFromFile(t *testing.T) { - infos, err := newGestureInfosFromFile(configPath) - assert.NoError(t, err) - - assert.True(t, findGestureInfo(EventInfo{Name:"swipe", Direction:"up", Fingers:3}, infos)) - assert.True(t, findGestureInfo(EventInfo{Name:"swipe", Direction:"down", Fingers:3}, infos)) - assert.True(t, findGestureInfo(EventInfo{Name:"swipe", Direction:"left", Fingers:3}, infos)) - assert.True(t, findGestureInfo(EventInfo{Name:"swipe", Direction:"right", Fingers:3}, infos)) - assert.True(t, findGestureInfo(EventInfo{Name:"swipe", Direction:"up", Fingers:4}, infos)) - assert.True(t, findGestureInfo(EventInfo{Name:"swipe", Direction:"down", Fingers:4}, infos)) - assert.True(t, findGestureInfo(EventInfo{Name:"swipe", Direction:"left", Fingers:4}, infos)) - assert.True(t, findGestureInfo(EventInfo{Name:"swipe", Direction:"right", Fingers:4}, infos)) - assert.True(t, findGestureInfo(EventInfo{Name:"swipe", Direction:"up", Fingers:5}, infos)) - assert.True(t, findGestureInfo(EventInfo{Name:"swipe", Direction:"down", Fingers:5}, infos)) - assert.True(t, findGestureInfo(EventInfo{Name:"swipe", Direction:"left", Fingers:5}, infos)) - assert.True(t, findGestureInfo(EventInfo{Name:"swipe", Direction:"right", Fingers:5}, infos)) -} - -// 测试:Get接口 -func Test_Get(t *testing.T) { - infos, err := newGestureInfosFromFile(configPath) - assert.NoError(t, err) - - // for touch long press - infos = append(infos, &gestureInfo{ - Event: EventInfo{ - Name: "touch right button", - Direction: "down", - Fingers: 0, - }, - Action: ActionInfo{ - Type: ActionTypeCommandline, - Action: "xdotool mousedown 3", - }, - }) - infos = append(infos, &gestureInfo{ - Event: EventInfo{ - Name: "touch right button", - Direction: "up", - Fingers: 0, - }, - Action: ActionInfo{ - Type: ActionTypeCommandline, - Action: "xdotool mouseup 3", - }, - }) - - assert.NoError(t, err) - assert.NotNil(t, infos.Get(EventInfo{Name:"touch right button", Direction:"down", Fingers:0})) - assert.NotNil(t, infos.Get(EventInfo{Name:"touch right button", Direction:"up", Fingers:0}),) - assert.NotNil(t, infos.Get(EventInfo{Name:"swipe", Direction:"up", Fingers:3})) - assert.NotNil(t, infos.Get(EventInfo{Name:"swipe", Direction:"down", Fingers:3})) - assert.NotNil(t, infos.Get(EventInfo{Name:"swipe", Direction:"left", Fingers:3})) - assert.NotNil(t, infos.Get(EventInfo{Name:"swipe", Direction:"right", Fingers:3})) - assert.NotNil(t, infos.Get(EventInfo{Name:"swipe", Direction:"up", Fingers:4})) - assert.NotNil(t, infos.Get(EventInfo{Name:"swipe", Direction:"down", Fingers:4})) - assert.NotNil(t, infos.Get(EventInfo{Name:"swipe", Direction:"left", Fingers:4})) - assert.NotNil(t, infos.Get(EventInfo{Name:"swipe", Direction:"right", Fingers:4})) - assert.NotNil(t, infos.Get(EventInfo{Name:"swipe", Direction:"up", Fingers:5})) - assert.NotNil(t, infos.Get(EventInfo{Name:"swipe", Direction:"down", Fingers:5})) - assert.NotNil(t, infos.Get(EventInfo{Name:"swipe", Direction:"left", Fingers:5})) - assert.NotNil(t, infos.Get(EventInfo{Name:"swipe", Direction:"right", Fingers:5})) -} - -// 测试:Set接口 -func Test_Set(t *testing.T) { - infos, err := newGestureInfosFromFile(configPath) - assert.NoError(t, err) - - action1 := ActionInfo{ - Type: "shortcut", - Action: "ctrl+minus", - } - action2 := ActionInfo{ - Type: "shortcut", - Action: "ctrl+find", - } - assert.NotNil(t, infos.Set(EventInfo{Name:"pinch", Direction:"in", Fingers:2}, action1)) - assert.NotNil(t, infos.Set(EventInfo{Name:"pinch", Direction:"out", Fingers:2}, action1)) - assert.Nil(t, infos.Set(EventInfo{Name:"swipe", Direction:"up", Fingers:3}, action2)) - assert.Nil(t, infos.Set(EventInfo{Name:"swipe", Direction:"down", Fingers:3}, action2)) -} diff --git a/gesture/daemon.go b/gesture/daemon.go deleted file mode 100644 index 3ffabe054..000000000 --- a/gesture/daemon.go +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package gesture - -import ( - "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/dde-daemon/loader" -) - -type Daemon struct { - *loader.ModuleBase - manager *Manager -} - -const ( - dbusServiceName = "com.deepin.daemon.Gesture" - dbusServicePath = "/com/deepin/daemon/Gesture" - dbusServiceIFC = dbusServiceName -) - -var ( - logger = log.NewLogger("gesture") -) - -func NewDaemon() *Daemon { - daemon := new(Daemon) - daemon.ModuleBase = loader.NewModuleBase("gesture", daemon, logger) - return daemon -} - -func init() { - loader.Register(NewDaemon()) -} - -func (*Daemon) GetDependencies() []string { - return []string{} -} - -func (d *Daemon) Start() error { - if d.manager != nil { - return nil - } - - var err error - d.manager, err = newManager() - if err != nil { - logger.Error("failed to initialize gesture manager:", err) - return err - } - - service := loader.GetService() - err = service.Export(dbusServicePath, d.manager) - if err != nil { - logger.Error("failed to export gesture:", err) - return err - } - - err = service.RequestName(dbusServiceName) - if err != nil { - logger.Error("failed to request gesture name:", err) - d.manager.destroy() - err1 := service.StopExport(d.manager) - if err1 != nil { - logger.Error("failed to StopExport:", err1) - } - return err - } - - d.manager.init() - - return nil -} - -func (d *Daemon) Stop() error { - if xconn != nil { - xconn.Close() - xconn = nil - } - - if d.manager == nil { - return nil - } - - d.manager.destroy() - d.manager = nil - return nil -} diff --git a/gesture/exported_methods_auto.go b/gesture/exported_methods_auto.go deleted file mode 100644 index 24364c292..000000000 --- a/gesture/exported_methods_auto.go +++ /dev/null @@ -1,42 +0,0 @@ -// Code generated by "dbusutil-gen em -type Manager"; DO NOT EDIT. - -package gesture - -import ( - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (v *Manager) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "GetEdgeMoveStopDuration", - Fn: v.GetEdgeMoveStopDuration, - OutArgs: []string{"duration"}, - }, - { - Name: "GetLongPressDuration", - Fn: v.GetLongPressDuration, - OutArgs: []string{"duration"}, - }, - { - Name: "GetShortPressDuration", - Fn: v.GetShortPressDuration, - OutArgs: []string{"duration"}, - }, - { - Name: "SetEdgeMoveStopDuration", - Fn: v.SetEdgeMoveStopDuration, - InArgs: []string{"duration"}, - }, - { - Name: "SetLongPressDuration", - Fn: v.SetLongPressDuration, - InArgs: []string{"duration"}, - }, - { - Name: "SetShortPressDuration", - Fn: v.SetShortPressDuration, - InArgs: []string{"duration"}, - }, - } -} diff --git a/gesture/manager.go b/gesture/manager.go deleted file mode 100644 index 0d2c5bfa1..000000000 --- a/gesture/manager.go +++ /dev/null @@ -1,801 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package gesture - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "math" - "os" - "os/exec" - "path/filepath" - "strings" - "sync" - - "github.com/godbus/dbus" - daemon "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.daemon" - display "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.display" - gesture "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.gesture" - sessionwatcher "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.sessionwatcher" - clipboard "github.com/linuxdeepin/go-dbus-factory/com.deepin.dde.clipboard" - dock "github.com/linuxdeepin/go-dbus-factory/com.deepin.dde.daemon.dock" - notification "github.com/linuxdeepin/go-dbus-factory/com.deepin.dde.notification" - sessionmanager "github.com/linuxdeepin/go-dbus-factory/com.deepin.sessionmanager" - wm "github.com/linuxdeepin/go-dbus-factory/com.deepin.wm" - gio "github.com/linuxdeepin/go-gir/gio-2.0" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/dbusutil/proxy" - "github.com/linuxdeepin/go-lib/gsettings" - dutils "github.com/linuxdeepin/go-lib/utils" -) - -//go:generate dbusutil-gen em -type Manager - -const ( - tsSchemaID = "com.deepin.dde.touchscreen" - tsSchemaKeyLongPress = "longpress-duration" - tsSchemaKeyShortPress = "shortpress-duration" - tsSchemaKeyEdgeMoveStop = "edgemovestop-duration" - tsSchemaKeyBlacklist = "longpress-blacklist" -) - -type deviceType int32 // 设备类型(触摸屏,触摸板) - -const ( - deviceTouchPad deviceType = iota - deviceTouchScreen -) - -var _useWayland bool - -func setUseWayland(value bool) { - _useWayland = value -} - -type Manager struct { - wm wm.Wm - sysDaemon daemon.Daemon - systemSigLoop *dbusutil.SignalLoop - mu sync.RWMutex - userFile string - builtinSets map[string]func() error - gesture gesture.Gesture - dock dock.Dock - display display.Display - setting *gio.Settings - tsSetting *gio.Settings - touchPadEnabled bool - touchScreenEnabled bool - Infos gestureInfos - sessionmanager sessionmanager.SessionManager - clipboard clipboard.Clipboard - notification notification.Notification - - longPressEnable bool - oneFingerBottomEnable bool - oneFingerLeftEnable bool - oneFingerRightEnable bool - configManagerPath dbus.ObjectPath - sessionWatcher sessionwatcher.SessionWatcher -} - -func newManager() (*Manager, error) { - setUseWayland(len(os.Getenv("WAYLAND_DISPLAY")) != 0) - sessionConn, err := dbus.SessionBus() - if err != nil { - return nil, err - } - - systemConn, err := dbus.SystemBus() - if err != nil { - return nil, err - } - - var filename = configUserPath - if !dutils.IsFileExist(configUserPath) { - filename = configSystemPath - } - - infos, err := newGestureInfosFromFile(filename) - if err != nil { - return nil, err - } - // for touch long press - infos = append(infos, &gestureInfo{ - Event: EventInfo{ - Name: "touch right button", - Direction: "down", - Fingers: 0, - }, - Action: ActionInfo{ - Type: ActionTypeCommandline, - Action: "xdotool mousedown 3", - }, - }) - infos = append(infos, &gestureInfo{ - Event: EventInfo{ - Name: "touch right button", - Direction: "up", - Fingers: 0, - }, - Action: ActionInfo{ - Type: ActionTypeCommandline, - Action: "xdotool mouseup 3", - }, - }) - - setting, err := dutils.CheckAndNewGSettings(gestureSchemaId) - if err != nil { - return nil, err - } - - tsSetting, err := dutils.CheckAndNewGSettings(tsSchemaID) - if err != nil { - return nil, err - } - - m := &Manager{ - userFile: configUserPath, - Infos: infos, - setting: setting, - tsSetting: tsSetting, - touchPadEnabled: setting.GetBoolean(gsKeyTouchPadEnabled), - touchScreenEnabled: setting.GetBoolean(gsKeyTouchScreenEnabled), - wm: wm.NewWm(sessionConn), - dock: dock.NewDock(sessionConn), - display: display.NewDisplay(sessionConn), - sysDaemon: daemon.NewDaemon(systemConn), - sessionmanager: sessionmanager.NewSessionManager(sessionConn), - clipboard: clipboard.NewClipboard(sessionConn), - notification: notification.NewNotification(sessionConn), - } - - systemConnObj := systemConn.Object(configManagerId, "/") - err = systemConnObj.Call(configManagerId+".acquireManager", 0, "org.deepin.dde.daemon", "org.deepin.dde.daemon.gesture", "").Store(&m.configManagerPath) - if err != nil { - logger.Warning(err) - } - m.longPressEnable = m.getGestureConfigValue("longPressEnable") - m.oneFingerBottomEnable = m.getGestureConfigValue("oneFingerBottomEnable") - m.oneFingerLeftEnable = m.getGestureConfigValue("oneFingerLeftEnable") - m.oneFingerRightEnable = m.getGestureConfigValue("oneFingerRightEnable") - - if _useWayland { - setLongPressEnable(m.longPressEnable) - } - - m.gesture = gesture.NewGesture(systemConn) - m.systemSigLoop = dbusutil.NewSignalLoop(systemConn, 10) - - if _useWayland { - m.sessionWatcher = sessionwatcher.NewSessionWatcher(sessionConn) - } - return m, nil -} - -func setLongPressEnable(enable bool) { - sessionBus, err := dbus.SessionBus() - if err != nil { - logger.Warning(err) - return - } - Obj := sessionBus.Object("org.kde.KWin", "/KWin") - err = Obj.Call("org.kde.KWin.setEnableTouchLongPress", 0, enable).Err - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) getGestureConfigValue(key string) bool { - systemConn, err := dbus.SystemBus() - if err != nil { - return true - } - systemConnObj := systemConn.Object("org.desktopspec.ConfigManager", m.configManagerPath) - var val bool - err = systemConnObj.Call("org.desktopspec.ConfigManager.Manager.value", 0, key).Store(&val) - if err != nil { - logger.Warning(err) - return true - } - return val -} - -func (m *Manager) destroy() { - m.gesture.RemoveHandler(proxy.RemoveAllHandlers) - m.systemSigLoop.Stop() - m.setting.Unref() -} - -func (m *Manager) init() { - m.initBuiltinSets() - err := m.sysDaemon.SetLongPressDuration(0, uint32(m.tsSetting.GetInt(tsSchemaKeyLongPress))) - if err != nil { - logger.Warning("call SetLongPressDuration failed:", err) - } - err = m.gesture.SetShortPressDuration(0, uint32(m.tsSetting.GetInt(tsSchemaKeyShortPress))) - if err != nil { - logger.Warning("call SetShortPressDuration failed:", err) - } - err = m.gesture.SetEdgeMoveStopDuration(0, uint32(m.tsSetting.GetInt(tsSchemaKeyEdgeMoveStop))) - if err != nil { - logger.Warning("call SetEdgeMoveStopDuration failed:", err) - } - - systemConn, err := dbus.SystemBus() - if err != nil { - logger.Error(err) - } - err = dbusutil.NewMatchRuleBuilder().Type("signal"). - PathNamespace(string(m.configManagerPath)). - Interface("org.desktopspec.ConfigManager.Manager"). - Member("valueChanged").Build().AddTo(systemConn) - if err != nil { - logger.Warning(err) - } - - m.systemSigLoop.Start() - m.gesture.InitSignalExt(m.systemSigLoop, true) - _, err = m.gesture.ConnectEvent(func(name string, direction string, fingers int32) { - should, err := m.shouldHandleEvent(deviceTouchPad) - if err != nil { - logger.Error("shouldHandleEvent failed:", err) - return - } - if !should { - return - } - - err = m.Exec(EventInfo{ - Name: name, - Direction: direction, - Fingers: fingers, - }) - if err != nil { - logger.Error("Exec failed:", err) - } - }) - - m.systemSigLoop.AddHandler(&dbusutil.SignalRule{ - Name: "org.desktopspec.ConfigManager.Manager.valueChanged", - }, func(sig *dbus.Signal) { - if strings.Contains(sig.Name, "org.desktopspec.ConfigManager.Manager.valueChanged") && - strings.Contains(string(sig.Path), "org_deepin_dde_daemon_gesture") && len(sig.Body) >= 1 { - key, ok := sig.Body[0].(string) - if !ok { - logger.Warning("Get key of body failed.") - return - } - switch key { - case "oneFingerBottomEnable": - m.oneFingerBottomEnable = m.getGestureConfigValue("oneFingerBottomEnable") - logger.Info("DConfig of oneFingerBottomEnable : ", m.oneFingerBottomEnable) - case "longPressEnable": - m.longPressEnable = m.getGestureConfigValue("longPressEnable") - logger.Info("DConfig of longPressEnable : ", m.longPressEnable) - if _useWayland { - setLongPressEnable(m.longPressEnable) - } - case "oneFingerLeftEnable": - m.oneFingerLeftEnable = m.getGestureConfigValue("oneFingerLeftEnable") - logger.Info("DConfig of oneFingerLeftEnable : ", m.oneFingerLeftEnable) - case "oneFingerRightEnable": - m.oneFingerRightEnable = m.getGestureConfigValue("oneFingerRightEnable") - logger.Info("DConfig of oneFingerRightEnable : ", m.oneFingerRightEnable) - default: - logger.Warning("Not use key : ", key) - } - } - }) - - if err != nil { - logger.Error("connect gesture event failed:", err) - } - - _, err = m.gesture.ConnectTouchEdgeMoveStopLeave(func(direction string, scaleX float64, scaleY float64, duration int32) { - should, err := m.shouldHandleEvent(deviceTouchScreen) - if err != nil { - logger.Error("shouldHandleEvent failed:", err) - return - } - if !should { - return - } - - context, pointFn, err := m.getTouchScreenRotationContext() - if err != nil { - logger.Error("getTouchScreenRotationContext failed:", err) - } - p := &point{X: scaleX, Y: scaleY} - pointFn(p) - - err = m.handleTouchEdgeMoveStopLeave(context, direction, p, duration) - if err != nil { - logger.Error("handleTouchEdgeMoveStopLeave failed:", err) - } - }) - if err != nil { - logger.Error("connect TouchEdgeMoveStopLeave failed:", err) - } - - _, err = m.gesture.ConnectTouchEdgeEvent(func(direction string, scaleX float64, scaleY float64) { - should, err := m.shouldHandleEvent(deviceTouchScreen) - if err != nil { - logger.Error("shouldHandleEvent failed:", err) - return - } - if !should { - return - } - context, pointFn, err := m.getTouchScreenRotationContext() - if err != nil { - logger.Error("getTouchScreenRotationContext failed:", err) - } - p := &point{X: scaleX, Y: scaleY} - pointFn(p) - err = m.handleTouchEdgeEvent(context, direction, p) - if err != nil { - logger.Error("handleTouchEdgeEvent failed:", err) - } - }) - if err != nil { - logger.Error("connect handleTouchEdgeEvent failed:", err) - } - - _, err = m.gesture.ConnectTouchMovementEvent(func(direction string, fingers int32, startScaleX float64, startScaleY float64, endScaleX float64, endScaleY float64) { - should, err := m.shouldHandleEvent(deviceTouchScreen) - if err != nil { - logger.Error("shouldHandleEvent failed:", err) - return - } - if !should { - return - } - - context, pointFn, err := m.getTouchScreenRotationContext() - if err != nil { - logger.Error("getTouchScreenRotationContext failed:", err) - } - - startP := &point{X: startScaleX, Y: startScaleY} - endP := &point{X: endScaleX, Y: endScaleY} - pointFn(startP) - pointFn(endP) - - err = m.handleTouchMovementEvent(context, direction, fingers, startP, endP) - if err != nil { - logger.Error("handleTouchMovementEvent failed:", err) - } - }) - if err != nil { - logger.Error("connect handleTouchMovementEvent failed:", err) - } - m.listenGSettingsChanged() -} - -func (m *Manager) shouldIgnoreGesture(info *gestureInfo) bool { - // allow right button up when kbd grabbed - if (info.Event.Name != "touch right button" || info.Event.Direction != "up") && isKbdAlreadyGrabbed() { - // 多任务窗口下,不应该忽略手势操作 - isShowMultiTask, err := m.wm.GetMultiTaskingStatus(0) - if err != nil { - logger.Warning(err) - } else if isShowMultiTask && info.Event.Name == "swipe" { - logger.Debug("should not ignore swipe event, because we are in multi task") - return false - } - logger.Debug("another process grabbed keyboard, not exec action") - return true - } - - // TODO(jouyouyun): improve touch right button handler - if info.Event.Name == "touch right button" { - // filter google chrome - if isInWindowBlacklist(getCurrentActionWindowCmd(), m.tsSetting.GetStrv(tsSchemaKeyBlacklist)) { - logger.Debug("the current active window in blacklist") - return true - } - } else if strings.HasPrefix(info.Event.Name, "touch") { - return true - } - - return false -} - -func (m *Manager) Exec(evInfo EventInfo) error { - if _useWayland { - if !isSessionActive("/org/freedesktop/login1/session/self") { - active, err := m.sessionWatcher.IsActive().Get(0) - if err != nil || !active { - logger.Debug("Gesture had been disabled or session inactive") - return nil - } - } - } - - info := m.Infos.Get(evInfo) - if info == nil { - logger.Infof("[Exec]: not found event info: %s", evInfo.toString()) - return nil - } - - logger.Debugf("[Exec]: event info:%s action info:%s", info.Event.toString(), info.Action.toString()) - if m.shouldIgnoreGesture(info) { - return nil - } - - if (!m.longPressEnable || _useWayland) && strings.Contains(string(info.Event.Name), "touch right button") { - return nil - } - - var cmd = info.Action.Action - switch info.Action.Type { - case ActionTypeCommandline: - break - case ActionTypeShortcut: - cmd = fmt.Sprintf("xdotool key %s", cmd) - case ActionTypeBuiltin: - return m.handleBuiltinAction(cmd) - default: - return fmt.Errorf("invalid action type: %s", info.Action.Type) - } - - // #nosec G204 - out, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput() - if err != nil { - return fmt.Errorf("%s", string(out)) - } - return nil -} - -func (m *Manager) Write() error { - m.mu.Lock() - defer m.mu.Unlock() - - // #nosec G301 - err := os.MkdirAll(filepath.Dir(m.userFile), 0755) - if err != nil { - return err - } - data, err := json.Marshal(m.Infos) - if err != nil { - return err - } - // #nosec G306 - return ioutil.WriteFile(m.userFile, data, 0644) -} - -func (m *Manager) listenGSettingsChanged() { - gsettings.ConnectChanged(gestureSchemaId, gsKeyTouchPadEnabled, func(key string) { - m.mu.Lock() - m.touchPadEnabled = m.setting.GetBoolean(key) - m.mu.Unlock() - }) - - gsettings.ConnectChanged(gestureSchemaId, gsKeyTouchScreenEnabled, func(key string) { - m.mu.Lock() - m.touchScreenEnabled = m.setting.GetBoolean(key) - m.mu.Unlock() - }) -} - -func (m *Manager) handleBuiltinAction(cmd string) error { - fn := m.builtinSets[cmd] - if fn == nil { - return fmt.Errorf("invalid built-in action %q", cmd) - } - return fn() -} - -func (*Manager) GetInterfaceName() string { - return dbusServiceIFC -} - -type TouchScreensRotation uint16 - -// counterclockwise -const ( - Normal TouchScreensRotation = 1 - Rotation_90 TouchScreensRotation = 2 - Rotation_180 TouchScreensRotation = 4 - Rotation_270 TouchScreensRotation = 8 -) - -// 获取触摸屏的旋转 -func (m *Manager) getTouchScreenRotation() (display.Monitor, TouchScreensRotation) { - // 读取触屏列表,取第一个触屏(目前触摸手势事件中不包含所属屏幕,因此不支持多个触摸屏) - touchScreens, err := m.display.TouchscreensV2().Get(0) - if err != nil { - logger.Warning(err) - } - - // 读取触摸屏映射 - touchMap, err := m.display.TouchMap().Get(0) - if err != nil { - logger.Warning(err) - } - - // 读取触摸屏的名字 - var touchScreen string - if len(touchScreens) > 0 && len(touchMap) > 0 { - touchScreen = touchMap[touchScreens[0].UUID] - } - - // 读取失败,把主屏当做触摸屏 - if touchScreen == "" { - logger.Warning("failed to find the touch screen, assume the primary as the touch screen") - touchScreen, err = m.display.Primary().Get(0) - if err != nil { - logger.Warning(err) - } - } - - // 遍历显示器,查找触摸屏的旋转角度 - monitors, err := m.display.Monitors().Get(0) - if err != nil { - logger.Warning(err) - } - sessionBus, err := dbus.SessionBus() - if err != nil { - logger.Warning(err) - return nil, Normal - } - for _, path := range monitors { - monitor, err := display.NewMonitor(sessionBus, path) - if err != nil { - logger.Warning(err) - continue - } - - name, err := monitor.Name().Get(0) - if err != nil { - logger.Warning(err) - continue - } - - if name == touchScreen { - rotation, err := monitor.Rotation().Get(0) - if err != nil { - logger.Warning(err) - break - } - return monitor, TouchScreensRotation(rotation) - } - } - - // 查找失败,当做没有旋转 - return nil, Normal -} - -// struct point represents a point on a touchScreen -// X is a float64 in [0,1], which is the horizontal index -// Y is a float64 in [0,1], which is the vertical index -// left-top corner represents in struct point is{X:0,Y:0} -type point struct { - X float64 - Y float64 -} - -// struct touchEventContext is a struct try to handle the context of touchScreen Gesture after rotation -// for example after Rotation_90 context.top is "left", and context.screenHeight is always the vertical height of screen -// see func getTouchScreenRotationContext for details -type touchEventContext struct { - top, bot, left, right string - screenWidth, screenHeight uint16 -} - -// func getTouchScreenRotationContext return a context represents the current touchScreen's rotation, and a func to transform point -func (m *Manager) getTouchScreenRotationContext() (context *touchEventContext, pointTransformFn func(*point), err error) { - monitor, rotation := m.getTouchScreenRotation() - - var screenWidth, screenHeight uint16 - if monitor == nil { // 如果获取失败则当作用户只有一个显示屏, 直接使用 x 的画布大小当作触摸屏大小 - screenWidth, err = m.display.ScreenWidth().Get(0) - if err != nil { - logger.Error("get display.ScreenWidth failed:", err) - return - } - screenHeight, err = m.display.ScreenHeight().Get(0) - if err != nil { - logger.Error("get display.ScreenWidth failed:", err) - return - } - } else { - screenWidth, err = monitor.Width().Get(0) - if err != nil { - logger.Error("get monitor.Width failed:", err) - return - } - screenHeight, err = monitor.Height().Get(0) - if err != nil { - logger.Error("get monitor.Height failed:", err) - return - } - } - - pointFn := func(p *point) {} - top, bot, left, right := "top", "bot", "left", "right" - switch rotation { - case Rotation_90: - top, bot, left, right = "left", "right", "bot", "top" - screenHeight, screenWidth = screenWidth, screenHeight - pointFn = func(p *point) { - p.X, p.Y = 1-p.Y, p.X - } - case Rotation_180: - top, bot, left, right = "bot", "top", "right", "left" - pointFn = func(p *point) { - p.X, p.Y = 1-p.X, 1-p.Y - } - case Rotation_270: - top, bot, left, right = "right", "left", "top", "bot" - screenHeight, screenWidth = screenWidth, screenHeight - pointFn = func(p *point) { - p.X, p.Y = p.Y, 1-p.X - } - } - context = &touchEventContext{ - screenWidth: screenWidth, - screenHeight: screenHeight, - top: top, - bot: bot, - left: left, - right: right, - } - pointTransformFn = pointFn - return -} - -//param @edge: swipe to touchscreen edge -// edge: 该手势来自屏幕的哪条边 -// p: 该手势的终点 -func (m *Manager) handleTouchEdgeMoveStopLeave(context *touchEventContext, edge string, p *point, duration int32) error { - logger.Debugf("handleTouchEdgeMoveStopLeave: context:%+v edge:%s p: %+v", *context, edge, *p) - - if edge == context.bot && m.oneFingerBottomEnable { - position, err := m.dock.Position().Get(0) - if err != nil { - logger.Error("get dock.Position failed:", err) - return err - } - - if position >= 0 { - rect, err := m.dock.FrontendWindowRect().Get(0) - if err != nil { - logger.Error("get dock.FrontendWindowRect failed:", err) - return err - } - - var dockPly uint32 = 0 - if position == positionTop || position == positionBottom { - dockPly = rect.Height - } else if position == positionRight || position == positionLeft { - dockPly = rect.Width - } - - if (1-p.Y)*float64(context.screenHeight) > float64(dockPly) { - logger.Debug("show work space") - return m.handleBuiltinAction("ShowWorkspace") - } - } - } - return nil -} - -// edge: 该手势来自屏幕的哪条边 -// p: 该手势的终点 -func (m *Manager) handleTouchEdgeEvent(context *touchEventContext, edge string, p *point) error { - logger.Debugf("handleTouchEdgeEvent: context:%+v edge:%s p:%+v", *context, edge, *p) - switch edge { - case context.left: - if p.X*float64(context.screenHeight) > 100 && m.oneFingerLeftEnable { - return m.clipboard.Show(0) - } - case context.right: - if (1-p.X)*float64(context.screenWidth) > 100 && m.oneFingerRightEnable { - return m.notification.Show(0) - } - } - return nil -} - -// direction: 该手势的方向 -// fingers: 手指的数量 -// startP: 该手势的起点 -// endP: 该手势的终点 -func (m *Manager) handleTouchMovementEvent(context *touchEventContext, direction string, fingers int32, startP *point, endP *point) error { - logger.Debugf("handleTouchMovementEvent: context:%+v direction:%s startP:%+v endP:%+v", *context, direction, *startP, *endP) - - if fingers == 1 { - // sensitivity check - // TODO maybe write a function for this - sensitivityThreshold := 0.05 - - if math.Abs(startP.X-endP.X) < sensitivityThreshold { - logger.Debug("sensitivity check fail, gesture will not be triggered") - return nil - } - - switch direction { - case context.left: - if m.oneFingerLeftEnable { - return m.clipboard.Hide(0) - } - case context.right: - if m.oneFingerRightEnable { - return m.notification.Hide(0) - } - } - } - - return nil -} - -//touchpad double click down -func (m *Manager) handleDbclickDown(fingers int32) error { - if fingers == 3 { - return m.wm.TouchToMove(0, 0, 0) - } - return nil -} - -//touchpad swipe move -func (m *Manager) handleSwipeMoving(fingers int32, accelX float64, accelY float64) error { - if fingers == 3 { - return m.wm.TouchToMove(0, int32(accelX), int32(accelY)) - } - return nil -} - -//touchpad swipe stop or interrupted -func (m *Manager) handleSwipeStop(fingers int32) error { - if fingers == 3 { - return m.wm.ClearMoveStatus(0) - } - return nil -} - -// 多用户存在,防止非当前用户响应触摸屏手势 -func (m *Manager) shouldHandleEvent(devType deviceType) (bool, error) { - m.mu.RLock() - defer m.mu.RUnlock() - - switch devType { - case deviceTouchPad: - if !m.touchPadEnabled { - logger.Debug("touch pad is disabled, do not handle touchpad gesture event") - return false, nil - } - case deviceTouchScreen: - if !m.touchScreenEnabled { - logger.Debug("touch screen is disabled, do not handle touchscreen gesture event") - return false, nil - } - default: - logger.Warningf("Unknown device type: %v, do not handle gesture event", devType) - return false, nil - } - - isLocked, err := m.sessionmanager.Locked().Get(0) - if err != nil { - return false, fmt.Errorf("get login1 session locked failed: %v", err) - } - - if isLocked { - return false, nil - } - - currentSessionPath, err := m.sessionmanager.CurrentSessionPath().Get(0) - if err != nil { - return false, fmt.Errorf("get login1 session path failed: %v", err) - } - - if !isSessionActive(currentSessionPath) { - return false, nil - } - - return true, nil -} diff --git a/gesture/manager_ifc.go b/gesture/manager_ifc.go deleted file mode 100644 index 0268ca9fa..000000000 --- a/gesture/manager_ifc.go +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package gesture - -import ( - "github.com/godbus/dbus" - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (m *Manager) SetLongPressDuration(duration uint32) *dbus.Error { - if m.tsSetting.GetInt(tsSchemaKeyLongPress) == int32(duration) { - return nil - } - err := m.sysDaemon.SetLongPressDuration(0, duration) - if err != nil { - return dbusutil.ToError(err) - } - m.tsSetting.SetInt(tsSchemaKeyLongPress, int32(duration)) - return nil -} - -func (m *Manager) GetLongPressDuration() (duration uint32, busErr *dbus.Error) { - return uint32(m.tsSetting.GetInt(tsSchemaKeyLongPress)), nil -} - -func (m *Manager) SetShortPressDuration(duration uint32) *dbus.Error { - if m.tsSetting.GetInt(tsSchemaKeyShortPress) == int32(duration) { - return nil - } - err := m.gesture.SetShortPressDuration(0, duration) - if err != nil { - return dbusutil.ToError(err) - } - m.tsSetting.SetInt(tsSchemaKeyShortPress, int32(duration)) - return nil -} - -func (m *Manager) GetShortPressDuration() (duration uint32, busErr *dbus.Error) { - return uint32(m.tsSetting.GetInt(tsSchemaKeyShortPress)), nil -} - -func (m *Manager) SetEdgeMoveStopDuration(duration uint32) *dbus.Error { - if m.tsSetting.GetInt(tsSchemaKeyShortPress) == int32(duration) { - return nil - } - err := m.gesture.SetEdgeMoveStopDuration(0, duration) - if err != nil { - return dbusutil.ToError(err) - } - m.tsSetting.SetInt(tsSchemaKeyEdgeMoveStop, int32(duration)) - return nil -} - -func (m *Manager) GetEdgeMoveStopDuration() (duration uint32, busErr *dbus.Error) { - return uint32(m.tsSetting.GetInt(tsSchemaKeyEdgeMoveStop)), nil -} diff --git a/gesture/utils.go b/gesture/utils.go deleted file mode 100644 index 245bd5495..000000000 --- a/gesture/utils.go +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package gesture - -import ( - "fmt" - "io/ioutil" - "strings" - - "github.com/godbus/dbus" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" - x "github.com/linuxdeepin/go-x11-client" - "github.com/linuxdeepin/go-x11-client/util/keybind" - "github.com/linuxdeepin/go-x11-client/util/wm/ewmh" -) - -var ( - xconn *x.Conn - _dconn *dbus.Conn - _self login1.Session -) - -const ( - positionTop int32 = iota - positionRight - positionBottom - positionLeft -) - -type Rect struct { - X, Y int32 - Width, Height uint32 -} - -func isKbdAlreadyGrabbed() bool { - if getX11Conn() == nil { - return false - } - - var grabWin x.Window - - // 如果是防止安全问题只抓取rootWin就可以了,抓取激活窗口会导致多任务等窗口响应失效。 - rootWin := xconn.GetDefaultScreen().Root - grabWin = rootWin - - err := keybind.GrabKeyboard(xconn, grabWin) - if err == nil { - // grab keyboard successful - _ = keybind.UngrabKeyboard(xconn) - return false - } - - logger.Warningf("GrabKeyboard win %d failed: %v", grabWin, err) - - gkErr, ok := err.(keybind.GrabKeyboardError) - if ok && gkErr.Status == x.GrabStatusAlreadyGrabbed { - return true - } - return false -} - -func getCurrentActionWindowCmd() string { - win, err := ewmh.GetActiveWindow(xconn).Reply(xconn) - if err != nil { - logger.Warning("Failed to get current active window:", err) - return "" - } - pid, err := ewmh.GetWMPid(xconn, win).Reply(xconn) - if err != nil { - logger.Warning("Failed to get current window pid:", err) - return "" - } - data, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pid)) - if err != nil { - logger.Warning("Failed to read cmdline:", err) - return "" - } - return string(data) -} - -func isSessionActive(sessionPath dbus.ObjectPath) bool { - if _dconn == nil { - conn, err := dbus.SystemBus() - if err != nil { - logger.Error("Failed to new system bus:", err) - return false - } - _dconn = conn - } - - if _self == nil { - self, err := login1.NewSession(_dconn, sessionPath) - if err != nil { - logger.Error("Failed to connect self session:", err) - return false - } - _self = self - } - - active, err := _self.Active().Get(dbus.FlagNoAutoStart) - if err != nil { - logger.Error("Failed to get self active:", err) - return false - } - return active -} - -func getX11Conn() *x.Conn { - if xconn == nil { - conn, err := x.NewConn() - if err != nil { - return nil - } - xconn = conn - } - return xconn -} - -func isInWindowBlacklist(cmd string, list []string) bool { - for _, v := range list { - if strings.Contains(cmd, v) { - return true - } - } - return false -} diff --git a/gesture/utils_test.go b/gesture/utils_test.go deleted file mode 100644 index 7a53d5333..000000000 --- a/gesture/utils_test.go +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package gesture - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_isInWindowBlacklist(t *testing.T) { - slice := []string{"window1", "window2", "window3"} - assert.True(t, isInWindowBlacklist("window1", slice)) - assert.True(t, isInWindowBlacklist("window2", slice)) - assert.True(t, isInWindowBlacklist("window3", slice)) - assert.False(t,isInWindowBlacklist("window4", slice)) -} diff --git a/gesture/built-in.go b/gesture1/built-in.go similarity index 99% rename from gesture/built-in.go rename to gesture1/built-in.go index e77045003..b44d18cd6 100644 --- a/gesture/built-in.go +++ b/gesture1/built-in.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package gesture +package gesture1 import ( "os/exec" diff --git a/gesture1/config.go b/gesture1/config.go new file mode 100644 index 000000000..5051a3f06 --- /dev/null +++ b/gesture1/config.go @@ -0,0 +1,95 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package gesture1 + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "path/filepath" + + "github.com/linuxdeepin/go-lib/xdg/basedir" +) + +const ( + ActionTypeShortcut = "shortcut" + ActionTypeCommandline = "commandline" + ActionTypeBuiltin = "built-in" +) + +var ( + configUserPath = filepath.Join(basedir.GetUserConfigDir(), "deepin/dde-daemon/gesture.json") +) + +const ( + configSystemPath = "/usr/share/dde-daemon/gesture.json" + + gestureSchemaId = "com.deepin.dde.gesture" + gsKeyTouchPadEnabled = "touch-pad-enabled" + gsKeyTouchScreenEnabled = "touch-screen-enabled" + + configManagerId = "org.desktopspec.ConfigManager" +) + +type ActionInfo struct { + Type string + Action string +} + +type EventInfo struct { + Name string + Direction string + Fingers int32 +} + +type gestureInfo struct { + Event EventInfo + Action ActionInfo +} +type gestureInfos []*gestureInfo + +func (action ActionInfo) toString() string { + return fmt.Sprintf("Type:%s, Action=%s", action.Type, action.Action) +} + +func (evInfo EventInfo) toString() string { + return fmt.Sprintf("Name=%s, Direction=%s, Fingers=%d", evInfo.Name, evInfo.Direction, evInfo.Fingers) +} + +func (infos gestureInfos) Get(evInfo EventInfo) *gestureInfo { + for _, info := range infos { + if info.Event == evInfo { + return info + } + } + return nil +} + +func (infos gestureInfos) Set(evInfo EventInfo, action ActionInfo) error { + info := infos.Get(evInfo) + if info == nil { + return fmt.Errorf("not found gesture info for: %s, %s, %d", evInfo.Name, evInfo.Direction, evInfo.Fingers) + } + info.Action = action + return nil +} + +func newGestureInfosFromFile(filename string) (gestureInfos, error) { + content, err := ioutil.ReadFile(filepath.Clean(filename)) + if err != nil { + return nil, err + } + + if len(content) == 0 { + return nil, fmt.Errorf("file '%s' is empty", filename) + } + + var infos gestureInfos + err = json.Unmarshal(content, &infos) + if err != nil { + return nil, err + } + return infos, nil +} diff --git a/gesture1/config_test.go b/gesture1/config_test.go new file mode 100644 index 000000000..25be2ad2b --- /dev/null +++ b/gesture1/config_test.go @@ -0,0 +1,109 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package gesture1 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +var ( + configPath = "testdata/gesture" +) + +// 查找手势信息 +func findGestureInfo(evInfo EventInfo, infos gestureInfos) bool { + for _, info := range infos { + if info.Event == evInfo { + return true + } + } + return false +} + +// 测试: 从文件读取手势信息 +func Test_newGestureInfosFromFile(t *testing.T) { + infos, err := newGestureInfosFromFile(configPath) + assert.NoError(t, err) + + assert.True(t, findGestureInfo(EventInfo{Name: "swipe", Direction: "up", Fingers: 3}, infos)) + assert.True(t, findGestureInfo(EventInfo{Name: "swipe", Direction: "down", Fingers: 3}, infos)) + assert.True(t, findGestureInfo(EventInfo{Name: "swipe", Direction: "left", Fingers: 3}, infos)) + assert.True(t, findGestureInfo(EventInfo{Name: "swipe", Direction: "right", Fingers: 3}, infos)) + assert.True(t, findGestureInfo(EventInfo{Name: "swipe", Direction: "up", Fingers: 4}, infos)) + assert.True(t, findGestureInfo(EventInfo{Name: "swipe", Direction: "down", Fingers: 4}, infos)) + assert.True(t, findGestureInfo(EventInfo{Name: "swipe", Direction: "left", Fingers: 4}, infos)) + assert.True(t, findGestureInfo(EventInfo{Name: "swipe", Direction: "right", Fingers: 4}, infos)) + assert.True(t, findGestureInfo(EventInfo{Name: "swipe", Direction: "up", Fingers: 5}, infos)) + assert.True(t, findGestureInfo(EventInfo{Name: "swipe", Direction: "down", Fingers: 5}, infos)) + assert.True(t, findGestureInfo(EventInfo{Name: "swipe", Direction: "left", Fingers: 5}, infos)) + assert.True(t, findGestureInfo(EventInfo{Name: "swipe", Direction: "right", Fingers: 5}, infos)) +} + +// 测试:Get接口 +func Test_Get(t *testing.T) { + infos, err := newGestureInfosFromFile(configPath) + assert.NoError(t, err) + + // for touch long press + infos = append(infos, &gestureInfo{ + Event: EventInfo{ + Name: "touch right button", + Direction: "down", + Fingers: 0, + }, + Action: ActionInfo{ + Type: ActionTypeCommandline, + Action: "xdotool mousedown 3", + }, + }) + infos = append(infos, &gestureInfo{ + Event: EventInfo{ + Name: "touch right button", + Direction: "up", + Fingers: 0, + }, + Action: ActionInfo{ + Type: ActionTypeCommandline, + Action: "xdotool mouseup 3", + }, + }) + + assert.NoError(t, err) + assert.NotNil(t, infos.Get(EventInfo{Name: "touch right button", Direction: "down", Fingers: 0})) + assert.NotNil(t, infos.Get(EventInfo{Name: "touch right button", Direction: "up", Fingers: 0})) + assert.NotNil(t, infos.Get(EventInfo{Name: "swipe", Direction: "up", Fingers: 3})) + assert.NotNil(t, infos.Get(EventInfo{Name: "swipe", Direction: "down", Fingers: 3})) + assert.NotNil(t, infos.Get(EventInfo{Name: "swipe", Direction: "left", Fingers: 3})) + assert.NotNil(t, infos.Get(EventInfo{Name: "swipe", Direction: "right", Fingers: 3})) + assert.NotNil(t, infos.Get(EventInfo{Name: "swipe", Direction: "up", Fingers: 4})) + assert.NotNil(t, infos.Get(EventInfo{Name: "swipe", Direction: "down", Fingers: 4})) + assert.NotNil(t, infos.Get(EventInfo{Name: "swipe", Direction: "left", Fingers: 4})) + assert.NotNil(t, infos.Get(EventInfo{Name: "swipe", Direction: "right", Fingers: 4})) + assert.NotNil(t, infos.Get(EventInfo{Name: "swipe", Direction: "up", Fingers: 5})) + assert.NotNil(t, infos.Get(EventInfo{Name: "swipe", Direction: "down", Fingers: 5})) + assert.NotNil(t, infos.Get(EventInfo{Name: "swipe", Direction: "left", Fingers: 5})) + assert.NotNil(t, infos.Get(EventInfo{Name: "swipe", Direction: "right", Fingers: 5})) +} + +// 测试:Set接口 +func Test_Set(t *testing.T) { + infos, err := newGestureInfosFromFile(configPath) + assert.NoError(t, err) + + action1 := ActionInfo{ + Type: "shortcut", + Action: "ctrl+minus", + } + action2 := ActionInfo{ + Type: "shortcut", + Action: "ctrl+find", + } + assert.NotNil(t, infos.Set(EventInfo{Name: "pinch", Direction: "in", Fingers: 2}, action1)) + assert.NotNil(t, infos.Set(EventInfo{Name: "pinch", Direction: "out", Fingers: 2}, action1)) + assert.Nil(t, infos.Set(EventInfo{Name: "swipe", Direction: "up", Fingers: 3}, action2)) + assert.Nil(t, infos.Set(EventInfo{Name: "swipe", Direction: "down", Fingers: 3}, action2)) +} diff --git a/gesture1/daemon.go b/gesture1/daemon.go new file mode 100644 index 000000000..b2021008b --- /dev/null +++ b/gesture1/daemon.go @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package gesture1 + +import ( + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" +) + +type Daemon struct { + *loader.ModuleBase + manager *Manager +} + +const ( + dbusServiceName = "org.deepin.dde.Gesture1" + dbusServicePath = "/org/deepin/dde/Gesture1" + dbusServiceIFC = dbusServiceName +) + +var ( + logger = log.NewLogger("gesture") +) + +func NewDaemon() *Daemon { + daemon := new(Daemon) + daemon.ModuleBase = loader.NewModuleBase("gesture", daemon, logger) + return daemon +} + +func init() { + loader.Register(NewDaemon()) +} + +func (*Daemon) GetDependencies() []string { + return []string{} +} + +func (d *Daemon) Start() error { + if d.manager != nil { + return nil + } + + var err error + d.manager, err = newManager() + if err != nil { + logger.Error("failed to initialize gesture manager:", err) + return err + } + + service := loader.GetService() + err = service.Export(dbusServicePath, d.manager) + if err != nil { + logger.Error("failed to export gesture:", err) + return err + } + + err = service.RequestName(dbusServiceName) + if err != nil { + logger.Error("failed to request gesture name:", err) + d.manager.destroy() + err1 := service.StopExport(d.manager) + if err1 != nil { + logger.Error("failed to StopExport:", err1) + } + return err + } + + d.manager.init() + + return nil +} + +func (d *Daemon) Stop() error { + if xconn != nil { + xconn.Close() + xconn = nil + } + + if d.manager == nil { + return nil + } + + d.manager.destroy() + d.manager = nil + return nil +} diff --git a/gesture1/exported_methods_auto.go b/gesture1/exported_methods_auto.go new file mode 100644 index 000000000..3e114736d --- /dev/null +++ b/gesture1/exported_methods_auto.go @@ -0,0 +1,42 @@ +// Code generated by "dbusutil-gen em -type Manager"; DO NOT EDIT. + +package gesture1 + +import ( + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (v *Manager) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "GetEdgeMoveStopDuration", + Fn: v.GetEdgeMoveStopDuration, + OutArgs: []string{"duration"}, + }, + { + Name: "GetLongPressDuration", + Fn: v.GetLongPressDuration, + OutArgs: []string{"duration"}, + }, + { + Name: "GetShortPressDuration", + Fn: v.GetShortPressDuration, + OutArgs: []string{"duration"}, + }, + { + Name: "SetEdgeMoveStopDuration", + Fn: v.SetEdgeMoveStopDuration, + InArgs: []string{"duration"}, + }, + { + Name: "SetLongPressDuration", + Fn: v.SetLongPressDuration, + InArgs: []string{"duration"}, + }, + { + Name: "SetShortPressDuration", + Fn: v.SetShortPressDuration, + InArgs: []string{"duration"}, + }, + } +} diff --git a/gesture1/manager.go b/gesture1/manager.go new file mode 100644 index 000000000..77d0c5d92 --- /dev/null +++ b/gesture1/manager.go @@ -0,0 +1,802 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package gesture1 + +import ( + "encoding/json" + "fmt" + + "io/ioutil" + "math" + "os" + "os/exec" + "path/filepath" + "strings" + "sync" + + "github.com/godbus/dbus/v5" + dock "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.dde.daemon.dock" + notification "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.dde.notification" + wm "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.wm" + clipboard "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.clipboard1" + display "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.display1" + sessionmanager "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.sessionmanager1" + sessionwatcher "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.sessionwatcher1" + daemon "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.daemon1" + gesture "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.gesture1" + gio "github.com/linuxdeepin/go-gir/gio-2.0" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/dbusutil/proxy" + "github.com/linuxdeepin/go-lib/gsettings" + dutils "github.com/linuxdeepin/go-lib/utils" +) + +//go:generate dbusutil-gen em -type Manager + +const ( + tsSchemaID = "com.deepin.dde.touchscreen" + tsSchemaKeyLongPress = "longpress-duration" + tsSchemaKeyShortPress = "shortpress-duration" + tsSchemaKeyEdgeMoveStop = "edgemovestop-duration" + tsSchemaKeyBlacklist = "longpress-blacklist" +) + +type deviceType int32 // 设备类型(触摸屏,触摸板) + +const ( + deviceTouchPad deviceType = iota + deviceTouchScreen +) + +var _useWayland bool + +func setUseWayland(value bool) { + _useWayland = value +} + +type Manager struct { + wm wm.Wm + sysDaemon daemon.Daemon + systemSigLoop *dbusutil.SignalLoop + mu sync.RWMutex + userFile string + builtinSets map[string]func() error + gesture gesture.Gesture + dock dock.Dock + display display.Display + setting *gio.Settings + tsSetting *gio.Settings + touchPadEnabled bool + touchScreenEnabled bool + Infos gestureInfos + sessionmanager sessionmanager.SessionManager + clipboard clipboard.Clipboard + notification notification.Notification + + longPressEnable bool + oneFingerBottomEnable bool + oneFingerLeftEnable bool + oneFingerRightEnable bool + configManagerPath dbus.ObjectPath + sessionWatcher sessionwatcher.SessionWatcher +} + +func newManager() (*Manager, error) { + setUseWayland(len(os.Getenv("WAYLAND_DISPLAY")) != 0) + sessionConn, err := dbus.SessionBus() + if err != nil { + return nil, err + } + + systemConn, err := dbus.SystemBus() + if err != nil { + return nil, err + } + + var filename = configUserPath + if !dutils.IsFileExist(configUserPath) { + filename = configSystemPath + } + + infos, err := newGestureInfosFromFile(filename) + if err != nil { + return nil, err + } + // for touch long press + infos = append(infos, &gestureInfo{ + Event: EventInfo{ + Name: "touch right button", + Direction: "down", + Fingers: 0, + }, + Action: ActionInfo{ + Type: ActionTypeCommandline, + Action: "xdotool mousedown 3", + }, + }) + infos = append(infos, &gestureInfo{ + Event: EventInfo{ + Name: "touch right button", + Direction: "up", + Fingers: 0, + }, + Action: ActionInfo{ + Type: ActionTypeCommandline, + Action: "xdotool mouseup 3", + }, + }) + + setting, err := dutils.CheckAndNewGSettings(gestureSchemaId) + if err != nil { + return nil, err + } + + tsSetting, err := dutils.CheckAndNewGSettings(tsSchemaID) + if err != nil { + return nil, err + } + + m := &Manager{ + userFile: configUserPath, + Infos: infos, + setting: setting, + tsSetting: tsSetting, + touchPadEnabled: setting.GetBoolean(gsKeyTouchPadEnabled), + touchScreenEnabled: setting.GetBoolean(gsKeyTouchScreenEnabled), + wm: wm.NewWm(sessionConn), + dock: dock.NewDock(sessionConn), + display: display.NewDisplay(sessionConn), + sysDaemon: daemon.NewDaemon(systemConn), + sessionmanager: sessionmanager.NewSessionManager(sessionConn), + clipboard: clipboard.NewClipboard(sessionConn), + notification: notification.NewNotification(sessionConn), + } + + systemConnObj := systemConn.Object(configManagerId, "/") + err = systemConnObj.Call(configManagerId+".acquireManager", 0, "org.deepin.dde.daemon", "org.deepin.dde.daemon.gesture", "").Store(&m.configManagerPath) + if err != nil { + logger.Warning(err) + } + m.longPressEnable = m.getGestureConfigValue("longPressEnable") + m.oneFingerBottomEnable = m.getGestureConfigValue("oneFingerBottomEnable") + m.oneFingerLeftEnable = m.getGestureConfigValue("oneFingerLeftEnable") + m.oneFingerRightEnable = m.getGestureConfigValue("oneFingerRightEnable") + + if _useWayland { + setLongPressEnable(m.longPressEnable) + } + + m.gesture = gesture.NewGesture(systemConn) + m.systemSigLoop = dbusutil.NewSignalLoop(systemConn, 10) + + if _useWayland { + m.sessionWatcher = sessionwatcher.NewSessionWatcher(sessionConn) + } + return m, nil +} + +func setLongPressEnable(enable bool) { + sessionBus, err := dbus.SessionBus() + if err != nil { + logger.Warning(err) + return + } + Obj := sessionBus.Object("org.kde.KWin", "/KWin") + err = Obj.Call("org.kde.KWin.setEnableTouchLongPress", 0, enable).Err + if err != nil { + logger.Warning(err) + } +} + +func (m *Manager) getGestureConfigValue(key string) bool { + systemConn, err := dbus.SystemBus() + if err != nil { + return true + } + systemConnObj := systemConn.Object("org.desktopspec.ConfigManager", m.configManagerPath) + var val bool + err = systemConnObj.Call("org.desktopspec.ConfigManager.Manager.value", 0, key).Store(&val) + if err != nil { + logger.Warning(err) + return true + } + return val +} + +func (m *Manager) destroy() { + m.gesture.RemoveHandler(proxy.RemoveAllHandlers) + m.systemSigLoop.Stop() + m.setting.Unref() +} + +func (m *Manager) init() { + m.initBuiltinSets() + err := m.sysDaemon.SetLongPressDuration(0, uint32(m.tsSetting.GetInt(tsSchemaKeyLongPress))) + if err != nil { + logger.Warning("call SetLongPressDuration failed:", err) + } + err = m.gesture.SetShortPressDuration(0, uint32(m.tsSetting.GetInt(tsSchemaKeyShortPress))) + if err != nil { + logger.Warning("call SetShortPressDuration failed:", err) + } + err = m.gesture.SetEdgeMoveStopDuration(0, uint32(m.tsSetting.GetInt(tsSchemaKeyEdgeMoveStop))) + if err != nil { + logger.Warning("call SetEdgeMoveStopDuration failed:", err) + } + + systemConn, err := dbus.SystemBus() + if err != nil { + logger.Error(err) + } + err = dbusutil.NewMatchRuleBuilder().Type("signal"). + PathNamespace(string(m.configManagerPath)). + Interface("org.desktopspec.ConfigManager.Manager"). + Member("valueChanged").Build().AddTo(systemConn) + if err != nil { + logger.Warning(err) + } + + m.systemSigLoop.Start() + m.gesture.InitSignalExt(m.systemSigLoop, true) + _, err = m.gesture.ConnectEvent(func(name string, direction string, fingers int32) { + should, err := m.shouldHandleEvent(deviceTouchPad) + if err != nil { + logger.Error("shouldHandleEvent failed:", err) + return + } + if !should { + return + } + + err = m.Exec(EventInfo{ + Name: name, + Direction: direction, + Fingers: fingers, + }) + if err != nil { + logger.Error("Exec failed:", err) + } + }) + + m.systemSigLoop.AddHandler(&dbusutil.SignalRule{ + Name: "org.desktopspec.ConfigManager.Manager.valueChanged", + }, func(sig *dbus.Signal) { + if strings.Contains(sig.Name, "org.desktopspec.ConfigManager.Manager.valueChanged") && + strings.Contains(string(sig.Path), "org_deepin_dde_daemon_gesture") && len(sig.Body) >= 1 { + key, ok := sig.Body[0].(string) + if !ok { + logger.Warning("Get key of body failed.") + return + } + switch key { + case "oneFingerBottomEnable": + m.oneFingerBottomEnable = m.getGestureConfigValue("oneFingerBottomEnable") + logger.Info("DConfig of oneFingerBottomEnable : ", m.oneFingerBottomEnable) + case "longPressEnable": + m.longPressEnable = m.getGestureConfigValue("longPressEnable") + logger.Info("DConfig of longPressEnable : ", m.longPressEnable) + if _useWayland { + setLongPressEnable(m.longPressEnable) + } + case "oneFingerLeftEnable": + m.oneFingerLeftEnable = m.getGestureConfigValue("oneFingerLeftEnable") + logger.Info("DConfig of oneFingerLeftEnable : ", m.oneFingerLeftEnable) + case "oneFingerRightEnable": + m.oneFingerRightEnable = m.getGestureConfigValue("oneFingerRightEnable") + logger.Info("DConfig of oneFingerRightEnable : ", m.oneFingerRightEnable) + default: + logger.Warning("Not use key : ", key) + } + } + }) + + if err != nil { + logger.Error("connect gesture event failed:", err) + } + + _, err = m.gesture.ConnectTouchEdgeMoveStopLeave(func(direction string, scaleX float64, scaleY float64, duration int32) { + should, err := m.shouldHandleEvent(deviceTouchScreen) + if err != nil { + logger.Error("shouldHandleEvent failed:", err) + return + } + if !should { + return + } + + context, pointFn, err := m.getTouchScreenRotationContext() + if err != nil { + logger.Error("getTouchScreenRotationContext failed:", err) + } + p := &point{X: scaleX, Y: scaleY} + pointFn(p) + + err = m.handleTouchEdgeMoveStopLeave(context, direction, p, duration) + if err != nil { + logger.Error("handleTouchEdgeMoveStopLeave failed:", err) + } + }) + if err != nil { + logger.Error("connect TouchEdgeMoveStopLeave failed:", err) + } + + _, err = m.gesture.ConnectTouchEdgeEvent(func(direction string, scaleX float64, scaleY float64) { + should, err := m.shouldHandleEvent(deviceTouchScreen) + if err != nil { + logger.Error("shouldHandleEvent failed:", err) + return + } + if !should { + return + } + context, pointFn, err := m.getTouchScreenRotationContext() + if err != nil { + logger.Error("getTouchScreenRotationContext failed:", err) + } + p := &point{X: scaleX, Y: scaleY} + pointFn(p) + err = m.handleTouchEdgeEvent(context, direction, p) + if err != nil { + logger.Error("handleTouchEdgeEvent failed:", err) + } + }) + if err != nil { + logger.Error("connect handleTouchEdgeEvent failed:", err) + } + + _, err = m.gesture.ConnectTouchMovementEvent(func(direction string, fingers int32, startScaleX float64, startScaleY float64, endScaleX float64, endScaleY float64) { + should, err := m.shouldHandleEvent(deviceTouchScreen) + if err != nil { + logger.Error("shouldHandleEvent failed:", err) + return + } + if !should { + return + } + + context, pointFn, err := m.getTouchScreenRotationContext() + if err != nil { + logger.Error("getTouchScreenRotationContext failed:", err) + } + + startP := &point{X: startScaleX, Y: startScaleY} + endP := &point{X: endScaleX, Y: endScaleY} + pointFn(startP) + pointFn(endP) + + err = m.handleTouchMovementEvent(context, direction, fingers, startP, endP) + if err != nil { + logger.Error("handleTouchMovementEvent failed:", err) + } + }) + if err != nil { + logger.Error("connect handleTouchMovementEvent failed:", err) + } + m.listenGSettingsChanged() +} + +func (m *Manager) shouldIgnoreGesture(info *gestureInfo) bool { + // allow right button up when kbd grabbed + if (info.Event.Name != "touch right button" || info.Event.Direction != "up") && isKbdAlreadyGrabbed() { + // 多任务窗口下,不应该忽略手势操作 + isShowMultiTask, err := m.wm.GetMultiTaskingStatus(0) + if err != nil { + logger.Warning(err) + } else if isShowMultiTask && info.Event.Name == "swipe" { + logger.Debug("should not ignore swipe event, because we are in multi task") + return false + } + logger.Debug("another process grabbed keyboard, not exec action") + return true + } + + // TODO(jouyouyun): improve touch right button handler + if info.Event.Name == "touch right button" { + // filter google chrome + if isInWindowBlacklist(getCurrentActionWindowCmd(), m.tsSetting.GetStrv(tsSchemaKeyBlacklist)) { + logger.Debug("the current active window in blacklist") + return true + } + } else if strings.HasPrefix(info.Event.Name, "touch") { + return true + } + + return false +} + +func (m *Manager) Exec(evInfo EventInfo) error { + if _useWayland { + if !isSessionActive("/org/freedesktop/login1/session/self") { + active, err := m.sessionWatcher.IsActive().Get(0) + if err != nil || !active { + logger.Debug("Gesture had been disabled or session inactive") + return nil + } + } + } + + info := m.Infos.Get(evInfo) + if info == nil { + logger.Infof("[Exec]: not found event info: %s", evInfo.toString()) + return nil + } + + logger.Debugf("[Exec]: event info:%s action info:%s", info.Event.toString(), info.Action.toString()) + if m.shouldIgnoreGesture(info) { + return nil + } + + if (!m.longPressEnable || _useWayland) && strings.Contains(string(info.Event.Name), "touch right button") { + return nil + } + + var cmd = info.Action.Action + switch info.Action.Type { + case ActionTypeCommandline: + break + case ActionTypeShortcut: + cmd = fmt.Sprintf("xdotool key %s", cmd) + case ActionTypeBuiltin: + return m.handleBuiltinAction(cmd) + default: + return fmt.Errorf("invalid action type: %s", info.Action.Type) + } + + // #nosec G204 + out, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput() + if err != nil { + return fmt.Errorf("%s", string(out)) + } + return nil +} + +func (m *Manager) Write() error { + m.mu.Lock() + defer m.mu.Unlock() + + // #nosec G301 + err := os.MkdirAll(filepath.Dir(m.userFile), 0755) + if err != nil { + return err + } + data, err := json.Marshal(m.Infos) + if err != nil { + return err + } + // #nosec G306 + return ioutil.WriteFile(m.userFile, data, 0644) +} + +func (m *Manager) listenGSettingsChanged() { + gsettings.ConnectChanged(gestureSchemaId, gsKeyTouchPadEnabled, func(key string) { + m.mu.Lock() + m.touchPadEnabled = m.setting.GetBoolean(key) + m.mu.Unlock() + }) + + gsettings.ConnectChanged(gestureSchemaId, gsKeyTouchScreenEnabled, func(key string) { + m.mu.Lock() + m.touchScreenEnabled = m.setting.GetBoolean(key) + m.mu.Unlock() + }) +} + +func (m *Manager) handleBuiltinAction(cmd string) error { + fn := m.builtinSets[cmd] + if fn == nil { + return fmt.Errorf("invalid built-in action %q", cmd) + } + return fn() +} + +func (*Manager) GetInterfaceName() string { + return dbusServiceIFC +} + +type TouchScreensRotation uint16 + +// counterclockwise +const ( + Normal TouchScreensRotation = 1 + Rotation_90 TouchScreensRotation = 2 + Rotation_180 TouchScreensRotation = 4 + Rotation_270 TouchScreensRotation = 8 +) + +// 获取触摸屏的旋转 +func (m *Manager) getTouchScreenRotation() (display.Monitor, TouchScreensRotation) { + // 读取触屏列表,取第一个触屏(目前触摸手势事件中不包含所属屏幕,因此不支持多个触摸屏) + touchScreens, err := m.display.TouchscreensV2().Get(0) + if err != nil { + logger.Warning(err) + } + + // 读取触摸屏映射 + touchMap, err := m.display.TouchMap().Get(0) + if err != nil { + logger.Warning(err) + } + + // 读取触摸屏的名字 + var touchScreen string + if len(touchScreens) > 0 && len(touchMap) > 0 { + touchScreen = touchMap[touchScreens[0].UUID] + } + + // 读取失败,把主屏当做触摸屏 + if touchScreen == "" { + logger.Warning("failed to find the touch screen, assume the primary as the touch screen") + touchScreen, err = m.display.Primary().Get(0) + if err != nil { + logger.Warning(err) + } + } + + // 遍历显示器,查找触摸屏的旋转角度 + monitors, err := m.display.Monitors().Get(0) + if err != nil { + logger.Warning(err) + } + sessionBus, err := dbus.SessionBus() + if err != nil { + logger.Warning(err) + return nil, Normal + } + for _, path := range monitors { + monitor, err := display.NewMonitor(sessionBus, path) + if err != nil { + logger.Warning(err) + continue + } + + name, err := monitor.Name().Get(0) + if err != nil { + logger.Warning(err) + continue + } + + if name == touchScreen { + rotation, err := monitor.Rotation().Get(0) + if err != nil { + logger.Warning(err) + break + } + return monitor, TouchScreensRotation(rotation) + } + } + + // 查找失败,当做没有旋转 + return nil, Normal +} + +// struct point represents a point on a touchScreen +// X is a float64 in [0,1], which is the horizontal index +// Y is a float64 in [0,1], which is the vertical index +// left-top corner represents in struct point is{X:0,Y:0} +type point struct { + X float64 + Y float64 +} + +// struct touchEventContext is a struct try to handle the context of touchScreen Gesture after rotation +// for example after Rotation_90 context.top is "left", and context.screenHeight is always the vertical height of screen +// see func getTouchScreenRotationContext for details +type touchEventContext struct { + top, bot, left, right string + screenWidth, screenHeight uint16 +} + +// func getTouchScreenRotationContext return a context represents the current touchScreen's rotation, and a func to transform point +func (m *Manager) getTouchScreenRotationContext() (context *touchEventContext, pointTransformFn func(*point), err error) { + monitor, rotation := m.getTouchScreenRotation() + + var screenWidth, screenHeight uint16 + if monitor == nil { // 如果获取失败则当作用户只有一个显示屏, 直接使用 x 的画布大小当作触摸屏大小 + screenWidth, err = m.display.ScreenWidth().Get(0) + if err != nil { + logger.Error("get display.ScreenWidth failed:", err) + return + } + screenHeight, err = m.display.ScreenHeight().Get(0) + if err != nil { + logger.Error("get display.ScreenWidth failed:", err) + return + } + } else { + screenWidth, err = monitor.Width().Get(0) + if err != nil { + logger.Error("get monitor.Width failed:", err) + return + } + screenHeight, err = monitor.Height().Get(0) + if err != nil { + logger.Error("get monitor.Height failed:", err) + return + } + } + + pointFn := func(p *point) {} + top, bot, left, right := "top", "bot", "left", "right" + switch rotation { + case Rotation_90: + top, bot, left, right = "left", "right", "bot", "top" + screenHeight, screenWidth = screenWidth, screenHeight + pointFn = func(p *point) { + p.X, p.Y = 1-p.Y, p.X + } + case Rotation_180: + top, bot, left, right = "bot", "top", "right", "left" + pointFn = func(p *point) { + p.X, p.Y = 1-p.X, 1-p.Y + } + case Rotation_270: + top, bot, left, right = "right", "left", "top", "bot" + screenHeight, screenWidth = screenWidth, screenHeight + pointFn = func(p *point) { + p.X, p.Y = p.Y, 1-p.X + } + } + context = &touchEventContext{ + screenWidth: screenWidth, + screenHeight: screenHeight, + top: top, + bot: bot, + left: left, + right: right, + } + pointTransformFn = pointFn + return +} + +// param @edge: swipe to touchscreen edge +// edge: 该手势来自屏幕的哪条边 +// p: 该手势的终点 +func (m *Manager) handleTouchEdgeMoveStopLeave(context *touchEventContext, edge string, p *point, duration int32) error { + logger.Debugf("handleTouchEdgeMoveStopLeave: context:%+v edge:%s p: %+v", *context, edge, *p) + + if edge == context.bot && m.oneFingerBottomEnable { + position, err := m.dock.Position().Get(0) + if err != nil { + logger.Error("get dock.Position failed:", err) + return err + } + + if position >= 0 { + rect, err := m.dock.FrontendWindowRect().Get(0) + if err != nil { + logger.Error("get dock.FrontendWindowRect failed:", err) + return err + } + + var dockPly uint32 = 0 + if position == positionTop || position == positionBottom { + dockPly = rect.Height + } else if position == positionRight || position == positionLeft { + dockPly = rect.Width + } + + if (1-p.Y)*float64(context.screenHeight) > float64(dockPly) { + logger.Debug("show work space") + return m.handleBuiltinAction("ShowWorkspace") + } + } + } + return nil +} + +// edge: 该手势来自屏幕的哪条边 +// p: 该手势的终点 +func (m *Manager) handleTouchEdgeEvent(context *touchEventContext, edge string, p *point) error { + logger.Debugf("handleTouchEdgeEvent: context:%+v edge:%s p:%+v", *context, edge, *p) + switch edge { + case context.left: + if p.X*float64(context.screenHeight) > 100 && m.oneFingerLeftEnable { + return m.clipboard.Show(0) + } + case context.right: + if (1-p.X)*float64(context.screenWidth) > 100 && m.oneFingerRightEnable { + return m.notification.Show(0) + } + } + return nil +} + +// direction: 该手势的方向 +// fingers: 手指的数量 +// startP: 该手势的起点 +// endP: 该手势的终点 +func (m *Manager) handleTouchMovementEvent(context *touchEventContext, direction string, fingers int32, startP *point, endP *point) error { + logger.Debugf("handleTouchMovementEvent: context:%+v direction:%s startP:%+v endP:%+v", *context, direction, *startP, *endP) + + if fingers == 1 { + // sensitivity check + // TODO maybe write a function for this + sensitivityThreshold := 0.05 + + if math.Abs(startP.X-endP.X) < sensitivityThreshold { + logger.Debug("sensitivity check fail, gesture will not be triggered") + return nil + } + + switch direction { + case context.left: + if m.oneFingerLeftEnable { + return m.clipboard.Hide(0) + } + case context.right: + if m.oneFingerRightEnable { + return m.notification.Hide(0) + } + } + } + + return nil +} + +// touchpad double click down +func (m *Manager) handleDbclickDown(fingers int32) error { + if fingers == 3 { + return m.wm.TouchToMove(0, 0, 0) + } + return nil +} + +// touchpad swipe move +func (m *Manager) handleSwipeMoving(fingers int32, accelX float64, accelY float64) error { + if fingers == 3 { + return m.wm.TouchToMove(0, int32(accelX), int32(accelY)) + } + return nil +} + +// touchpad swipe stop or interrupted +func (m *Manager) handleSwipeStop(fingers int32) error { + if fingers == 3 { + return m.wm.ClearMoveStatus(0) + } + return nil +} + +// 多用户存在,防止非当前用户响应触摸屏手势 +func (m *Manager) shouldHandleEvent(devType deviceType) (bool, error) { + m.mu.RLock() + defer m.mu.RUnlock() + + switch devType { + case deviceTouchPad: + if !m.touchPadEnabled { + logger.Debug("touch pad is disabled, do not handle touchpad gesture event") + return false, nil + } + case deviceTouchScreen: + if !m.touchScreenEnabled { + logger.Debug("touch screen is disabled, do not handle touchscreen gesture event") + return false, nil + } + default: + logger.Warningf("Unknown device type: %v, do not handle gesture event", devType) + return false, nil + } + + isLocked, err := m.sessionmanager.Locked().Get(0) + if err != nil { + return false, fmt.Errorf("get login1 session locked failed: %v", err) + } + + if isLocked { + return false, nil + } + + currentSessionPath, err := m.sessionmanager.CurrentSessionPath().Get(0) + if err != nil { + return false, fmt.Errorf("get login1 session path failed: %v", err) + } + + if !isSessionActive(currentSessionPath) { + return false, nil + } + + return true, nil +} diff --git a/gesture1/manager_ifc.go b/gesture1/manager_ifc.go new file mode 100644 index 000000000..60a23b1d6 --- /dev/null +++ b/gesture1/manager_ifc.go @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package gesture1 + +import ( + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (m *Manager) SetLongPressDuration(duration uint32) *dbus.Error { + if m.tsSetting.GetInt(tsSchemaKeyLongPress) == int32(duration) { + return nil + } + err := m.sysDaemon.SetLongPressDuration(0, duration) + if err != nil { + return dbusutil.ToError(err) + } + m.tsSetting.SetInt(tsSchemaKeyLongPress, int32(duration)) + return nil +} + +func (m *Manager) GetLongPressDuration() (duration uint32, busErr *dbus.Error) { + return uint32(m.tsSetting.GetInt(tsSchemaKeyLongPress)), nil +} + +func (m *Manager) SetShortPressDuration(duration uint32) *dbus.Error { + if m.tsSetting.GetInt(tsSchemaKeyShortPress) == int32(duration) { + return nil + } + err := m.gesture.SetShortPressDuration(0, duration) + if err != nil { + return dbusutil.ToError(err) + } + m.tsSetting.SetInt(tsSchemaKeyShortPress, int32(duration)) + return nil +} + +func (m *Manager) GetShortPressDuration() (duration uint32, busErr *dbus.Error) { + return uint32(m.tsSetting.GetInt(tsSchemaKeyShortPress)), nil +} + +func (m *Manager) SetEdgeMoveStopDuration(duration uint32) *dbus.Error { + if m.tsSetting.GetInt(tsSchemaKeyShortPress) == int32(duration) { + return nil + } + err := m.gesture.SetEdgeMoveStopDuration(0, duration) + if err != nil { + return dbusutil.ToError(err) + } + m.tsSetting.SetInt(tsSchemaKeyEdgeMoveStop, int32(duration)) + return nil +} + +func (m *Manager) GetEdgeMoveStopDuration() (duration uint32, busErr *dbus.Error) { + return uint32(m.tsSetting.GetInt(tsSchemaKeyEdgeMoveStop)), nil +} diff --git a/gesture/testdata/gesture b/gesture1/testdata/gesture similarity index 92% rename from gesture/testdata/gesture rename to gesture1/testdata/gesture index a790fa1a2..14db6803e 100644 --- a/gesture/testdata/gesture +++ b/gesture1/testdata/gesture @@ -106,7 +106,7 @@ }, "Action": { "Type": "commandline", - "Action": "dbus-send --type=method_call --dest=com.deepin.dde.Launcher /com/deepin/dde/Launcher com.deepin.dde.Launcher.Toggle" + "Action": "dbus-send --type=method_call --dest=org.deepin.dde.Launcher1 /org/deepin/dde/Launcher1 org.deepin.dde.Launcher1.Toggle" } }, { @@ -161,7 +161,7 @@ }, "Action": { "Type": "commandline", - "Action": "dbus-send --type=method_call --dest=com.deepin.dde.Launcher /com/deepin/dde/Launcher com.deepin.dde.Launcher.Toggle" + "Action": "dbus-send --type=method_call --dest=org.deepin.dde.Launcher1 /org/deepin/dde/Launcher1 org.deepin.dde.Launcher1.Toggle" } } ] diff --git a/gesture1/utils.go b/gesture1/utils.go new file mode 100644 index 000000000..50d2813cc --- /dev/null +++ b/gesture1/utils.go @@ -0,0 +1,128 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package gesture1 + +import ( + "fmt" + "io/ioutil" + "strings" + + "github.com/godbus/dbus/v5" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" + x "github.com/linuxdeepin/go-x11-client" + "github.com/linuxdeepin/go-x11-client/util/keybind" + "github.com/linuxdeepin/go-x11-client/util/wm/ewmh" +) + +var ( + xconn *x.Conn + _dconn *dbus.Conn + _self login1.Session +) + +const ( + positionTop int32 = iota + positionRight + positionBottom + positionLeft +) + +type Rect struct { + X, Y int32 + Width, Height uint32 +} + +func isKbdAlreadyGrabbed() bool { + if getX11Conn() == nil { + return false + } + + var grabWin x.Window + + // 如果是防止安全问题只抓取rootWin就可以了,抓取激活窗口会导致多任务等窗口响应失效。 + rootWin := xconn.GetDefaultScreen().Root + grabWin = rootWin + + err := keybind.GrabKeyboard(xconn, grabWin) + if err == nil { + // grab keyboard successful + _ = keybind.UngrabKeyboard(xconn) + return false + } + + logger.Warningf("GrabKeyboard win %d failed: %v", grabWin, err) + + gkErr, ok := err.(keybind.GrabKeyboardError) + if ok && gkErr.Status == x.GrabStatusAlreadyGrabbed { + return true + } + return false +} + +func getCurrentActionWindowCmd() string { + win, err := ewmh.GetActiveWindow(xconn).Reply(xconn) + if err != nil { + logger.Warning("Failed to get current active window:", err) + return "" + } + pid, err := ewmh.GetWMPid(xconn, win).Reply(xconn) + if err != nil { + logger.Warning("Failed to get current window pid:", err) + return "" + } + data, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pid)) + if err != nil { + logger.Warning("Failed to read cmdline:", err) + return "" + } + return string(data) +} + +func isSessionActive(sessionPath dbus.ObjectPath) bool { + if _dconn == nil { + conn, err := dbus.SystemBus() + if err != nil { + logger.Error("Failed to new system bus:", err) + return false + } + _dconn = conn + } + + if _self == nil { + self, err := login1.NewSession(_dconn, sessionPath) + if err != nil { + logger.Error("Failed to connect self session:", err) + return false + } + _self = self + } + + active, err := _self.Active().Get(dbus.FlagNoAutoStart) + if err != nil { + logger.Error("Failed to get self active:", err) + return false + } + return active +} + +func getX11Conn() *x.Conn { + if xconn == nil { + conn, err := x.NewConn() + if err != nil { + return nil + } + xconn = conn + } + return xconn +} + +func isInWindowBlacklist(cmd string, list []string) bool { + for _, v := range list { + if strings.Contains(cmd, v) { + return true + } + } + return false +} diff --git a/gesture1/utils_test.go b/gesture1/utils_test.go new file mode 100644 index 000000000..2e29daee0 --- /dev/null +++ b/gesture1/utils_test.go @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package gesture1 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_isInWindowBlacklist(t *testing.T) { + slice := []string{"window1", "window2", "window3"} + assert.True(t, isInWindowBlacklist("window1", slice)) + assert.True(t, isInWindowBlacklist("window2", slice)) + assert.True(t, isInWindowBlacklist("window3", slice)) + assert.False(t, isInWindowBlacklist("window4", slice)) +} diff --git a/go.mod b/go.mod new file mode 100644 index 000000000..6aad7309d --- /dev/null +++ b/go.mod @@ -0,0 +1,47 @@ +module github.com/linuxdeepin/dde-daemon + +go 1.20 + +require ( + github.com/Lofanmi/pinyin-golang v0.0.0-20211114132645-1db892057f20 + github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 + github.com/davecgh/go-spew v1.1.1 + github.com/fsnotify/fsnotify v1.7.0 + github.com/godbus/dbus/v5 v5.1.0 + github.com/gosexy/gettext v0.0.0-20160830220431-74466a0a0c4a + github.com/jouyouyun/hardware v0.1.8 + github.com/linuxdeepin/dde-api v0.0.0-20240902063014-bac87797f4c3 + github.com/linuxdeepin/go-dbus-factory v0.0.0-20240903071359-9b78726cee9a + github.com/linuxdeepin/go-gir v0.0.0-20230710064042-bd15f0549c87 + github.com/linuxdeepin/go-lib v0.0.0-20240105075242-dddda54ea9f0 + github.com/linuxdeepin/go-x11-client v0.0.0-20240415051504-c8e43d028ff9 + github.com/mdlayher/netlink v1.7.2 + github.com/msteinert/pam v1.2.0 + github.com/rickb777/date v1.21.1 + github.com/stretchr/testify v1.9.0 + golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 + google.golang.org/protobuf v1.34.2 + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c + gopkg.in/yaml.v2 v2.4.0 +) + +require ( + github.com/google/go-cmp v0.6.0 // indirect + github.com/josharian/native v1.1.0 // indirect + github.com/kr/pretty v0.2.1 // indirect + github.com/kr/text v0.1.0 // indirect + github.com/mdlayher/socket v0.4.1 // indirect + github.com/mozillazg/go-pinyin v0.19.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rickb777/plural v1.4.2 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/youpy/go-riff v0.1.0 // indirect + github.com/youpy/go-wav v0.3.2 // indirect + github.com/zaf/g711 v0.0.0-20220109202201-cf0017bf0359 // indirect + golang.org/x/image v0.10.0 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.17.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 000000000..c0172ed8e --- /dev/null +++ b/go.sum @@ -0,0 +1,144 @@ +github.com/Lofanmi/pinyin-golang v0.0.0-20211114132645-1db892057f20 h1:QUwRV0ZgSjXBJnKOJh0T5rqe1jLWxlR5AvBLWSYJ7qg= +github.com/Lofanmi/pinyin-golang v0.0.0-20211114132645-1db892057f20/go.mod h1:J7A5UW8HA8b8lsEO/OshykiGGfmdQEnbDE53D23JsXE= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ= +github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gosexy/gettext v0.0.0-20160830220431-74466a0a0c4a h1:N2b2mb4Gki1SlF3WuhR9P1YHOpl7oy/b+xxX4A3iM2E= +github.com/gosexy/gettext v0.0.0-20160830220431-74466a0a0c4a/go.mod h1:IEJaV4/6J0VpoQ33kFCUUP6umRjrcBVEbOva6XCub/Q= +github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= +github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/jouyouyun/hardware v0.1.8 h1:AMYS9AMindRzSIL204OC9paLRpKZdnaoe5d/aJcg3r4= +github.com/jouyouyun/hardware v0.1.8/go.mod h1:euf5y8Zl/iC5YoBS+ELD1jrCN3K+D0CAz+vFtuzDGho= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/linuxdeepin/dde-api v0.0.0-20240902063014-bac87797f4c3 h1:SlPsz953m6CeFoawhtL5S/3huF0s4PtPxiTeIp7CKIw= +github.com/linuxdeepin/dde-api v0.0.0-20240902063014-bac87797f4c3/go.mod h1:Ms92CRDOjzkDmX1x0x6+b0vQSYHJ7Ab9jQMY2JYWiio= +github.com/linuxdeepin/go-dbus-factory v0.0.0-20240903071359-9b78726cee9a h1:y4efdtW6HfewiXayG9mRRGekkGECQDhgzmsSbkOkdoY= +github.com/linuxdeepin/go-dbus-factory v0.0.0-20240903071359-9b78726cee9a/go.mod h1:iIlTR50SA8MJ9ORPyMOpKWMF4g+AUorbER5AX0RD9Jk= +github.com/linuxdeepin/go-gir v0.0.0-20230331033513-a8d7a9e89f9b/go.mod h1:a0tox5vepTQu5iO6rdKc4diGT+fkyXZlRROM8ULEvaI= +github.com/linuxdeepin/go-gir v0.0.0-20230710064042-bd15f0549c87 h1:ga3ioifiDJJDfWv0ZJPX8e//fQNIzINXxJb4BMQofOo= +github.com/linuxdeepin/go-gir v0.0.0-20230710064042-bd15f0549c87/go.mod h1:a0tox5vepTQu5iO6rdKc4diGT+fkyXZlRROM8ULEvaI= +github.com/linuxdeepin/go-lib v0.0.0-20240105075242-dddda54ea9f0 h1:GKCg/0gMMMbQUBvZiGFeEp/xeFTWmBeee+a77viyO3I= +github.com/linuxdeepin/go-lib v0.0.0-20240105075242-dddda54ea9f0/go.mod h1:yNoMFao1mE45M8zW6i83eaGpT9eriCWsXEdcVNQswpw= +github.com/linuxdeepin/go-x11-client v0.0.0-20220830090948-78fe92b727bb/go.mod h1:KwpmRZ47A/0a2l9V0V6aTlkuNaqy5j1fOqMFJONuIMY= +github.com/linuxdeepin/go-x11-client v0.0.0-20240415051504-c8e43d028ff9 h1:GbhdC1TMi+V5yMRlfl16Y2gT/nhJn2OJalw6sVbFRHQ= +github.com/linuxdeepin/go-x11-client v0.0.0-20240415051504-c8e43d028ff9/go.mod h1:KwpmRZ47A/0a2l9V0V6aTlkuNaqy5j1fOqMFJONuIMY= +github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= +github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= +github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= +github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/mozillazg/go-pinyin v0.19.0 h1:p+J8/kjJ558KPvVGYLvqBhxf8jbZA2exSLCs2uUVN8c= +github.com/mozillazg/go-pinyin v0.19.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc= +github.com/msteinert/pam v1.2.0 h1:mYfjlvN2KYs2Pb9G6nb/1f/nPfAttT/Jee5Sq9r3bGE= +github.com/msteinert/pam v1.2.0/go.mod h1:d2n0DCUK8rGecChV3JzvmsDjOY4R7AYbsNxAT+ftQl0= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rickb777/date v1.21.1 h1:tUcQS8riIRoYK5kUAv5aevllFEYUEk2x8OYDyoldOn4= +github.com/rickb777/date v1.21.1/go.mod h1:gnDexsbXViZr2fCKMrY3m6IfAF5U2vSkEaiGJcNFaLQ= +github.com/rickb777/plural v1.4.2 h1:Kl/syFGLFZ5EbuV8c9SVud8s5HI2HpCCtOMw2U1kS+A= +github.com/rickb777/plural v1.4.2/go.mod h1:kdmXUpmKBJTS0FtG/TFumd//VBWsNTD7zOw7x4umxNw= +github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/youpy/go-riff v0.1.0 h1:vZO/37nI4tIET8tQI0Qn0Y79qQh99aEpponTPiPut7k= +github.com/youpy/go-riff v0.1.0/go.mod h1:83nxdDV4Z9RzrTut9losK7ve4hUnxUR8ASSz4BsKXwQ= +github.com/youpy/go-wav v0.3.2 h1:NLM8L/7yZ0Bntadw/0h95OyUsen+DQIVf9gay+SUsMU= +github.com/youpy/go-wav v0.3.2/go.mod h1:0FCieAXAeSdcxFfwLpRuEo0PFmAoc+8NU34h7TUvk50= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zaf/g711 v0.0.0-20190814101024-76a4a538f52b/go.mod h1:T2h1zV50R/q0CVYnsQOQ6L7P4a2ZxH47ixWcMXFGyx8= +github.com/zaf/g711 v0.0.0-20220109202201-cf0017bf0359 h1:P9yeMx2iNJxJqXEwLtMjSwWcD2a0AlFmFByeosMZhLM= +github.com/zaf/g711 v0.0.0-20220109202201-cf0017bf0359/go.mod h1:ySLGJD8AQluMQuu5JDvfJrwsBra+8iX1jFsKS8KfB2I= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/image v0.10.0 h1:gXjUUtwtx5yOE0VKWq1CH4IJAClq4UGgUA3i+rpON9M= +golang.org/x/image v0.10.0/go.mod h1:jtrku+n79PfroUbvDdeUWMAI+heR786BofxrbiSF+J0= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk= +golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= diff --git a/grub2/edit_auth_ifc.go b/grub2/edit_auth_ifc.go index cac3bac64..db3407b53 100644 --- a/grub2/edit_auth_ifc.go +++ b/grub2/edit_auth_ifc.go @@ -9,7 +9,7 @@ import ( "strings" "unicode" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" ) diff --git a/grub2/fstart_ifc.go b/grub2/fstart_ifc.go index deeff8097..d0a0cca0e 100644 --- a/grub2/fstart_ifc.go +++ b/grub2/fstart_ifc.go @@ -7,7 +7,7 @@ package grub2 import ( "errors" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" ) @@ -18,7 +18,7 @@ const ( const ( deepinFstartFile = "/etc/default/grub.d/15_deepin_fstart.cfg" - deepinFstart = "DEEPIN_FSTART"; + deepinFstart = "DEEPIN_FSTART" ) func (*Fstart) GetInterfaceName() string { @@ -43,7 +43,7 @@ func (f *Fstart) SkipGrub(sender dbus.Sender, enabled bool) *dbus.Error { return nil } err = setFstartState(enabled) - if err != nil{ + if err != nil { return dbusutil.ToError(err) } diff --git a/grub2/grub2.go b/grub2/grub2.go index 36f0d6ce9..fdeee4e0b 100644 --- a/grub2/grub2.go +++ b/grub2/grub2.go @@ -17,9 +17,9 @@ import ( "sync" "unicode" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-daemon/grub_common" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" + ofdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.dbus" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/log" "github.com/linuxdeepin/go-lib/procfs" @@ -705,7 +705,7 @@ func setFstartState(state bool) error { if strings.Trim(strings.TrimSpace(line[strings.Index(line, "=")+1:]), "\"") != arg { lines[lineNum] = "export " + deepinFstart + "=\"" + arg + "\"" err := ioutil.WriteFile(deepinFstartFile, []byte(strings.Join(lines, "\n")), 0644) - if err != nil{ + if err != nil { return dbusutil.ToError(err) } } diff --git a/grub2/grub2_ifc.go b/grub2/grub2_ifc.go index 7dd488fac..67f98b00f 100644 --- a/grub2/grub2_ifc.go +++ b/grub2/grub2_ifc.go @@ -9,19 +9,19 @@ import ( "io/ioutil" "strings" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-daemon/grub_common" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/procfs" ) const ( - dbusServiceName = "com.deepin.daemon.Grub2" - dbusPath = "/com/deepin/daemon/Grub2" - dbusInterface = "com.deepin.daemon.Grub2" + dbusServiceName = "org.deepin.dde.Grub2" + dbusPath = "/org/deepin/dde/Grub2" + dbusInterface = dbusServiceName - polikitActionIdCommon = "com.deepin.daemon.Grub2" - polikitActionIdPrepareGfxmodeDetect = "com.deepin.daemon.grub2.prepare-gfxmode-detect" + polikitActionIdCommon = "org.deepin.dde.Grub2" + polikitActionIdPrepareGfxmodeDetect = "org.deepin.dde.grub2.prepare-gfxmode-detect" timeoutMax = 10 ) diff --git a/grub2/inhibitor.go b/grub2/inhibitor.go index 4a6ad4c79..58799cc7c 100644 --- a/grub2/inhibitor.go +++ b/grub2/inhibitor.go @@ -7,8 +7,8 @@ package grub2 import ( "syscall" - "github.com/godbus/dbus" - "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" ) func (m *Grub2) enableShutdown() { diff --git a/grub2/theme_ifc.go b/grub2/theme_ifc.go index 454c00977..a7d0ab11f 100644 --- a/grub2/theme_ifc.go +++ b/grub2/theme_ifc.go @@ -11,7 +11,7 @@ import ( "path/filepath" "strings" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/utils" dutils "github.com/linuxdeepin/go-lib/utils" diff --git a/grub2/utils.go b/grub2/utils.go index 0e7281aea..4f5a770d6 100644 --- a/grub2/utils.go +++ b/grub2/utils.go @@ -14,9 +14,9 @@ import ( "strconv" "strings" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-daemon/grub_common" - polkit "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.policykit1" + polkit "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.policykit1" ) func quoteString(str string) string { diff --git a/grub_gfx/main.go b/grub_gfx/main.go index d2e1392d3..e758ffa04 100644 --- a/grub_gfx/main.go +++ b/grub_gfx/main.go @@ -5,9 +5,9 @@ package grub_gfx import ( - "github.com/godbus/dbus" - ofd "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-daemon/grub_common" + ofd "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.dbus" ) func detectChange() { @@ -97,7 +97,7 @@ func startSysGrubService() error { } sysBusDaemon := ofd.NewDBus(sysBus) _, err = sysBusDaemon.StartServiceByName(dbus.FlagNoAutoStart, - "com.deepin.daemon.Grub2", 0) + "org.deepin.dde.Grub2", 0) return err } @@ -107,7 +107,7 @@ func getSysGrubObj() (dbus.BusObject, error) { return nil, err } - obj := sysBus.Object("com.deepin.daemon.Grub2", "/com/deepin/daemon/Grub2") + obj := sysBus.Object("org.deepin.dde.Grub2", "/org/deepin/dde/Grub2") return obj, nil } @@ -118,5 +118,5 @@ func prepareGfxmodeDetect() error { return err } - return sysGrubObj.Call("com.deepin.daemon.Grub2.PrepareGfxmodeDetect", 0).Err + return sysGrubObj.Call("org.deepin.dde.Grub2.PrepareGfxmodeDetect", 0).Err } diff --git a/housekeeping/init.go b/housekeeping/init.go index 62b6c5e82..b328286d5 100644 --- a/housekeeping/init.go +++ b/housekeeping/init.go @@ -8,12 +8,12 @@ import ( "os" "time" - "github.com/godbus/dbus" - notifications "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.notifications" + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/loader" + notifications "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.notifications" . "github.com/linuxdeepin/go-lib/gettext" "github.com/linuxdeepin/go-lib/log" "github.com/linuxdeepin/go-lib/utils" - "github.com/linuxdeepin/dde-daemon/loader" ) const ( @@ -61,21 +61,12 @@ func (d *Daemon) Start() error { return } - fs, err := utils.QueryFilesytemInfo(os.Getenv("HOME")) - if err != nil { - logger.Error("Failed to get filesystem info:", err) + if !d.checkSpace("HOME", true) { break } - logger.Debug("Home filesystem info(total, free, avail):", - fs.TotalSize, fs.FreeSize, fs.AvailSize) - if fs.AvailSize > fsMinLeftSpace { + if !d.checkSpace("/tmp", false) { break } - err = sendNotify("dialog-warning", "", - Tr("Insufficient disk space, please clean up in time!")) - if err != nil { - logger.Warning(err) - } case <-d.stopChan: logger.Debug("Stop housekeeping") if d.ticker != nil { @@ -108,3 +99,47 @@ func sendNotify(icon, summary, body string) error { nil, nil, -1) return err } + +func sendNotify2(icon, summary, body, action, call string, timeout int32) error { + sessionBus, err := dbus.SessionBus() + if err != nil { + return err + } + notifier := notifications.NewNotifications(sessionBus) + _, err = notifier.Notify(0, "dde-control-center", 0, + icon, summary, body, + []string{"_dbus", action}, + map[string]dbus.Variant{ + "x-deepin-action-_dbus": dbus.MakeVariant(call), + "x-deepin-ClickToDisappear": dbus.MakeVariant(false), + "x-deepin-DisappearAfterLock": dbus.MakeVariant(false), + }, timeout) + return err +} + +func (d *Daemon) checkSpace(dir string, state bool) bool { + if state { + dir = os.Getenv(dir) + } + fs, err := utils.QueryFilesytemInfo(dir) + if err != nil { + logger.Error("Failed to get filesystem info for :", dir, err) + return false + } + + if fs.AvailSize > fsMinLeftSpace { + logger.Debug("Sufficient space for:", dir) + return true + } + logger.Info("checkSpace fs.AvailSize(M) : ", dir, fs.AvailSize/1024/1024) + err = sendNotify2("dialog-warning", "", + Tr("Insufficient disk space, please clean up in time!"), + Tr("Go to clean up"), + "dbus-send,--type=method_call,--dest=com.deepin.defender.hmiscreen,/com/deepin/defender/hmiscreen,com.deepin.defender.hmiscreen.ShowModule,string:diskcleaner", + 5000, + ) + if err != nil { + logger.Warning("Failed to send notification for", dir, ":", err) + } + return false +} diff --git a/image_effect/module.go b/image_effect/module.go deleted file mode 100644 index 9ee3ae1df..000000000 --- a/image_effect/module.go +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package image_effect - -import ( - "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/dde-daemon/loader" -) - -func init() { - loader.Register(newModule()) -} - -type Module struct { - *loader.ModuleBase - ie *ImageEffect -} - -func (m *Module) GetDependencies() []string { - return nil -} - -func (m *Module) Start() error { - if m.ie != nil { - return nil - } - - var err error - m.ie, err = start() - if err != nil { - return err - } - - return nil -} - -func (m *Module) Stop() error { - // TODO - return nil -} - -const moduleName = "image_effect" - -var logger = log.NewLogger("daemon/" + moduleName) - -func newModule() *Module { - m := &Module{} - m.ModuleBase = loader.NewModuleBase(moduleName, m, logger) - return m -} - -func start() (*ImageEffect, error) { - logger.Debug("module image_effect start") - ie := newImageEffect() - service := loader.GetService() - ie.service = service - err := service.Export(dbusPath, ie) - if err != nil { - return nil, err - } - - err = service.RequestName(dbusServiceName) - if err != nil { - return nil, err - } - - return ie, nil -} diff --git a/image_effect/exported_methods_auto.go b/image_effect1/exported_methods_auto.go similarity index 100% rename from image_effect/exported_methods_auto.go rename to image_effect1/exported_methods_auto.go diff --git a/image_effect/image_effect.go b/image_effect1/image_effect.go similarity index 98% rename from image_effect/image_effect.go rename to image_effect1/image_effect.go index 2bb4be993..653af4072 100644 --- a/image_effect/image_effect.go +++ b/image_effect1/image_effect.go @@ -14,7 +14,7 @@ import ( "sync" "time" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/procfs" "golang.org/x/xerrors" @@ -23,9 +23,9 @@ import ( //go:generate dbusutil-gen em -type ImageEffect const ( - dbusServiceName = "com.deepin.daemon.ImageEffect" + dbusServiceName = "org.deepin.dde.ImageEffect1" dbusInterface = dbusServiceName - dbusPath = "/com/deepin/daemon/ImageEffect" + dbusPath = "/org/deepin/dde/ImageEffect1" cacheDir = "/var/cache/deepin/dde-daemon/image-effect" effectPixmix = "pixmix" diff --git a/image_effect1/module.go b/image_effect1/module.go new file mode 100644 index 000000000..74ee334fa --- /dev/null +++ b/image_effect1/module.go @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package image_effect + +import ( + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" +) + +func init() { + loader.Register(newModule()) +} + +type Module struct { + *loader.ModuleBase + ie *ImageEffect +} + +func (m *Module) GetDependencies() []string { + return nil +} + +func (m *Module) Start() error { + if m.ie != nil { + return nil + } + + var err error + m.ie, err = start() + if err != nil { + return err + } + + return nil +} + +func (m *Module) Stop() error { + // TODO + return nil +} + +const moduleName = "image_effect" + +var logger = log.NewLogger("daemon/" + moduleName) + +func newModule() *Module { + m := &Module{} + m.ModuleBase = loader.NewModuleBase(moduleName, m, logger) + return m +} + +func start() (*ImageEffect, error) { + logger.Debug("module image_effect start") + ie := newImageEffect() + service := loader.GetService() + ie.service = service + err := service.Export(dbusPath, ie) + if err != nil { + return nil, err + } + + err = service.RequestName(dbusServiceName) + if err != nil { + return nil, err + } + + return ie, nil +} diff --git a/image_effect/utils.go b/image_effect1/utils.go similarity index 100% rename from image_effect/utils.go rename to image_effect1/utils.go diff --git a/inputdevices/ifc.go b/inputdevices/ifc.go deleted file mode 100644 index 8adc701c0..000000000 --- a/inputdevices/ifc.go +++ /dev/null @@ -1,114 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package inputdevices - -import ( - "github.com/godbus/dbus" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/dde-daemon/langselector" -) - -func (m *Mouse) Reset() *dbus.Error { - for _, key := range m.setting.ListKeys() { - m.setting.Reset(key) - } - return nil -} - -func (tp *TrackPoint) Reset() *dbus.Error { - for _, key := range tp.setting.ListKeys() { - tp.setting.Reset(key) - } - return nil -} - -func (tpad *Touchpad) Reset() *dbus.Error { - for _, key := range tpad.setting.ListKeys() { - tpad.setting.Reset(key) - } - return nil -} - -func (w *Wacom) Reset() *dbus.Error { - for _, key := range w.setting.ListKeys() { - w.setting.Reset(key) - } - for _, key := range w.stylusSetting.ListKeys() { - w.stylusSetting.Reset(key) - } - for _, key := range w.eraserSetting.ListKeys() { - w.eraserSetting.Reset(key) - } - return nil -} - -func (kbd *Keyboard) Reset() *dbus.Error { - for _, key := range kbd.setting.ListKeys() { - kbd.setting.Reset(key) - } - return nil -} - -func (kbd *Keyboard) LayoutList() (map[string]string, *dbus.Error) { - locales := langselector.GetLocales() - result := kbd.layoutMap.filterByLocales(locales) - - kbd.PropsMu.RLock() - for _, layout := range kbd.UserLayoutList { - layoutDetail := kbd.layoutMap[layout] - result[layout] = layoutDetail.Description - } - kbd.PropsMu.RUnlock() - - return result, nil -} - -func (kbd *Keyboard) GetLayoutDesc(layout string) (string, *dbus.Error) { - if len(layout) == 0 { - return "", nil - } - - value, ok := kbd.layoutMap[layout] - if !ok { - return "", nil - } - - return value.Description, nil -} - -func (kbd *Keyboard) AddUserLayout(layout string) *dbus.Error { - err := kbd.checkLayout(layout) - if err != nil { - return dbusutil.ToError(errInvalidLayout) - } - - kbd.addUserLayout(layout) - return nil -} - -func (kbd *Keyboard) DeleteUserLayout(layout string) *dbus.Error { - kbd.delUserLayout(layout) - return nil -} - -func (kbd *Keyboard) AddLayoutOption(option string) *dbus.Error { - kbd.addUserOption(option) - return nil -} - -func (kbd *Keyboard) DeleteLayoutOption(option string) *dbus.Error { - kbd.delUserOption(option) - return nil -} - -func (kbd *Keyboard) ClearLayoutOption() *dbus.Error { - kbd.UserOptionList.Set([]string{}) - return nil -} - -func (kbd *Keyboard) ToggleNextLayout() *dbus.Error { - kbd.toggleNextLayout() - return nil -} diff --git a/inputdevices/manager.go b/inputdevices/manager.go deleted file mode 100644 index 20383cc72..000000000 --- a/inputdevices/manager.go +++ /dev/null @@ -1,201 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package inputdevices - -import ( - "bufio" - "fmt" - "os" - "os/exec" - "path/filepath" - - "github.com/linuxdeepin/dde-daemon/common/dsync" - kwin "github.com/linuxdeepin/go-dbus-factory/org.kde.kwin" - "github.com/linuxdeepin/go-gir/gio-2.0" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/dbusutil/gsprop" - "github.com/linuxdeepin/go-lib/xdg/basedir" -) - -const ( - gsSchemaInputDevices = "com.deepin.dde.inputdevices" - gsKeyWheelSpeed = "wheel-speed" - imWheelBin = "imwheel" -) - -type devicePathInfo struct { - Path string - Type string -} -type devicePathInfos []*devicePathInfo - -type Manager struct { - Infos devicePathInfos // readonly - WheelSpeed gsprop.Uint `prop:"access:rw"` - - settings *gio.Settings - imWheelConfigFile string - - kbd *Keyboard - mouse *Mouse - trackPoint *TrackPoint - tpad *Touchpad - wacom *Wacom - - kwinManager kwin.InputDeviceManager - kwinIdList []dbusutil.SignalHandlerId - - sessionSigLoop *dbusutil.SignalLoop - syncConfig *dsync.Config -} - -func NewManager(service *dbusutil.Service) *Manager { - var m = new(Manager) - m.imWheelConfigFile = filepath.Join(basedir.GetUserHomeDir(), ".imwheelrc") - - m.Infos = devicePathInfos{ - &devicePathInfo{ - Path: kbdDBusInterface, - Type: "keyboard", - }, - &devicePathInfo{ - Path: mouseDBusInterface, - Type: "mouse", - }, - &devicePathInfo{ - Path: trackPointDBusInterface, - Type: "trackpoint", - }, - &devicePathInfo{ - Path: touchPadDBusInterface, - Type: "touchpad", - }, - } - - m.settings = gio.NewSettings(gsSchemaInputDevices) - m.WheelSpeed.Bind(m.settings, gsKeyWheelSpeed) - - m.kbd = newKeyboard(service) - m.wacom = newWacom(service) - - m.tpad = newTouchpad(service) - - m.mouse = newMouse(service, m.tpad) - - m.trackPoint = newTrackPoint(service) - - m.kwinManager = kwin.NewInputDeviceManager(service.Conn()) - - m.sessionSigLoop = dbusutil.NewSignalLoop(service.Conn(), 10) - m.syncConfig = dsync.NewConfig("peripherals", &syncConfig{m: m}, - m.sessionSigLoop, dbusPath, logger) - - return m -} - -func (m *Manager) setWheelSpeed() { - speed := m.settings.GetUint(gsKeyWheelSpeed) - // speed range is [1,100] - logger.Debug("setWheelSpeed", speed) - - // 为了避免imwheel对kwin影响,先杀死imwheel - err := exec.Command("pkill", "-ef", imWheelBin).Run() - if err != nil { - logger.Warning(err) - } - - err = m.setWaylandWheelSpeed(speed) - if err == nil { - logger.Info("set Wayland WheelSpeed finish") - return - } - - logger.Info("can not set WheelSpeed by Wayland interface, use imwheel") - // 通过kwin设置wheel speed失败时候才通过命令设置 - err = writeImWheelConfig(m.imWheelConfigFile, speed) - if err != nil { - logger.Warning("failed to write imwheel config file:", err) - return - } - - err = controlImWheel(speed) - if err != nil { - logger.Warning("failed to control imwheel:", err) - return - } -} - -func controlImWheel(speed uint32) error { - if speed == 1 { - // quit - return exec.Command(imWheelBin, "-k", "-q").Run() - } - // restart - return exec.Command(imWheelBin, "-k", "-b", "4 5").Run() -} - -func writeImWheelConfig(file string, speed uint32) error { - logger.Debugf("writeImWheelConfig file:%q, speed: %d", file, speed) - - const header = `# written by ` + dbusServiceName + ` -".*" -Control_L,Up,Control_L|Button4 -Control_R,Up,Control_R|Button4 -Control_L,Down,Control_L|Button5 -Control_R,Down,Control_R|Button5 -Shift_L,Up,Shift_L|Button4 -Shift_R,Up,Shift_R|Button4 -Shift_L,Down,Shift_L|Button5 -Shift_R,Down,Shift_R|Button5 -` - fh, err := os.Create(file) - if err != nil { - return err - } - defer fh.Close() - writer := bufio.NewWriter(fh) - - _, err = writer.Write([]byte(header)) - if err != nil { - return err - } - - // Delay Before Next KeyPress Event - delay := 240000 / speed - _, err = fmt.Fprintf(writer, "None,Up,Button4,%d,0,%d\n", speed, delay) - if err != nil { - return err - } - - _, err = fmt.Fprintf(writer, "None,Down,Button5,%d,0,%d\n", speed, delay) - if err != nil { - return err - } - - err = writer.Flush() - if err != nil { - return err - } - - return fh.Sync() -} - -func (m *Manager) init() { - m.kbd.init() - m.kbd.handleGSettings() - m.wacom.init() - m.wacom.handleGSettings() - m.tpad.init() - m.tpad.handleGSettings() - m.mouse.init() - m.mouse.handleGSettings() - m.trackPoint.init() - m.trackPoint.handleGSettings() - - m.setWheelSpeed() - m.handleGSettings() - - m.sessionSigLoop.Start() -} diff --git a/inputdevices/stub.go b/inputdevices/stub.go deleted file mode 100644 index 0b6cb1252..000000000 --- a/inputdevices/stub.go +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package inputdevices - -const ( - dbusServiceName = "com.deepin.daemon.InputDevices" - dbusPath = "/com/deepin/daemon/InputDevices" - dbusInterface = dbusServiceName - - kbdDBusPath = "/com/deepin/daemon/InputDevice/Keyboard" - kbdDBusInterface = "com.deepin.daemon.InputDevice.Keyboard" - - mouseDBusPath = "/com/deepin/daemon/InputDevice/Mouse" - mouseDBusInterface = "com.deepin.daemon.InputDevice.Mouse" - trackPointDBusInterface = "com.deepin.daemon.InputDevice.TrackPoint" - - touchPadDBusPath = "/com/deepin/daemon/InputDevice/TouchPad" - touchPadDBusInterface = "com.deepin.daemon.InputDevice.TouchPad" - - wacomDBusPath = "/com/deepin/daemon/InputDevice/Wacom" - wacomDBusInterface = "com.deepin.daemon.InputDevice.Wacom" -) - -func (*Manager) GetInterfaceName() string { - return dbusInterface -} - -func (*Keyboard) GetInterfaceName() string { - return kbdDBusInterface -} - -func (*Mouse) GetInterfaceName() string { - return mouseDBusInterface -} - -func (*TrackPoint) GetInterfaceName() string { - return trackPointDBusInterface -} - -func (*Touchpad) GetInterfaceName() string { - return touchPadDBusInterface -} - -func (*Wacom) GetInterfaceName() string { - return wacomDBusInterface -} diff --git a/inputdevices/touchpad.go b/inputdevices/touchpad.go deleted file mode 100644 index 9677e0f08..000000000 --- a/inputdevices/touchpad.go +++ /dev/null @@ -1,510 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package inputdevices - -import ( - "fmt" - "io/ioutil" - "os" - "os/exec" - "strconv" - "strings" - "sync" - - "github.com/godbus/dbus" - inputdevices "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.inputdevices" - power "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.power" - configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" - "github.com/linuxdeepin/go-gir/gio-2.0" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/dbusutil/gsprop" - "github.com/linuxdeepin/go-lib/strv" - dutils "github.com/linuxdeepin/go-lib/utils" -) - -const ( - tpadSchema = "com.deepin.dde.touchpad" - - tpadKeyEnabled = "touchpad-enabled" - tpadKeyLeftHanded = "left-handed" - tpadKeyDisableWhileTyping = "disable-while-typing" - tpadKeyNaturalScroll = "natural-scroll" - tpadKeyEdgeScroll = "edge-scroll-enabled" - tpadKeyHorizScroll = "horiz-scroll-enabled" - tpadKeyVertScroll = "vert-scroll-enabled" - tpadKeyAcceleration = "motion-acceleration" - tpadKeyThreshold = "motion-threshold" - tpadKeyScaling = "motion-scaling" - tpadKeyTapClick = "tap-to-click" - tpadKeyScrollDelta = "delta-scroll" - tpadKeyWhileTypingCmd = "disable-while-typing-cmd" - tpadKeyPalmDetect = "palm-detect" - tpadKeyPalmMinWidth = "palm-min-width" - tpadKeyPalmMinZ = "palm-min-pressure" - - dsettingsAppID = "org.deepin.dde.daemon" - dsettingsInputdevices = "org.deepin.dde.daemon.inputdevices" - dsettingsData = "ps2MouseAsTouchPadEnabled" -) - -const ( - syndaemonPidFile = "/tmp/syndaemon.pid" -) - -type Touchpad struct { - service *dbusutil.Service - PropsMu sync.RWMutex - Exist bool - DeviceList string - - // dbusutil-gen: ignore-below - TPadEnable gsprop.Bool `prop:"access:rw"` - LeftHanded gsprop.Bool `prop:"access:rw"` - DisableIfTyping gsprop.Bool `prop:"access:rw"` - NaturalScroll gsprop.Bool `prop:"access:rw"` - EdgeScroll gsprop.Bool `prop:"access:rw"` - HorizScroll gsprop.Bool `prop:"access:rw"` - VertScroll gsprop.Bool `prop:"access:rw"` - TapClick gsprop.Bool `prop:"access:rw"` - PalmDetect gsprop.Bool `prop:"access:rw"` - - MotionAcceleration gsprop.Double `prop:"access:rw"` - MotionThreshold gsprop.Double `prop:"access:rw"` - MotionScaling gsprop.Double `prop:"access:rw"` - - DoubleClick gsprop.Int `prop:"access:rw"` - DragThreshold gsprop.Int `prop:"access:rw"` - DeltaScroll gsprop.Int `prop:"access:rw"` - PalmMinWidth gsprop.Int `prop:"access:rw"` - PalmMinZ gsprop.Int `prop:"access:rw"` - - devInfos Touchpads - setting *gio.Settings - mouseSetting *gio.Settings - - systemConn *dbus.Conn - systemSigLoop *dbusutil.SignalLoop -} - -func newTouchpad(service *dbusutil.Service) *Touchpad { - var tpad = new(Touchpad) - - tpad.service = service - tpad.setting = gio.NewSettings(tpadSchema) - tpad.TPadEnable.Bind(tpad.setting, tpadKeyEnabled) - tpad.LeftHanded.Bind(tpad.setting, tpadKeyLeftHanded) - tpad.DisableIfTyping.Bind(tpad.setting, tpadKeyDisableWhileTyping) - tpad.NaturalScroll.Bind(tpad.setting, tpadKeyNaturalScroll) - tpad.EdgeScroll.Bind(tpad.setting, tpadKeyEdgeScroll) - tpad.VertScroll.Bind(tpad.setting, tpadKeyVertScroll) - tpad.HorizScroll.Bind(tpad.setting, tpadKeyHorizScroll) - tpad.TapClick.Bind(tpad.setting, tpadKeyTapClick) - tpad.PalmDetect.Bind(tpad.setting, tpadKeyPalmDetect) - tpad.MotionAcceleration.Bind(tpad.setting, tpadKeyAcceleration) - tpad.MotionThreshold.Bind(tpad.setting, tpadKeyThreshold) - tpad.MotionScaling.Bind(tpad.setting, tpadKeyScaling) - tpad.DeltaScroll.Bind(tpad.setting, tpadKeyScrollDelta) - tpad.PalmMinWidth.Bind(tpad.setting, tpadKeyPalmMinWidth) - tpad.PalmMinZ.Bind(tpad.setting, tpadKeyPalmMinZ) - - tpad.mouseSetting = gio.NewSettings(mouseSchema) - tpad.DoubleClick.Bind(tpad.mouseSetting, mouseKeyDoubleClick) - tpad.DragThreshold.Bind(tpad.mouseSetting, mouseKeyDragThreshold) - - tpad.updateDXTpads() - - if conn, err := dbus.SystemBus(); err != nil { - logger.Warning(err) - } else { - tpad.systemConn = conn - tpad.systemSigLoop = dbusutil.NewSignalLoop(conn, 10) - } - - return tpad -} - -func (tpad *Touchpad) getDsgPS2MouseAsTouchPadEnable() bool { - sysBus, err := dbus.SystemBus() - if err != nil { - return false - } - ds := configManager.NewConfigManager(sysBus) - - inputdevicesPath, err := ds.AcquireManager(0, dsettingsAppID, dsettingsInputdevices, "") - if err != nil { - logger.Warning(err) - return false - } - inputdevicesDsg, err := configManager.NewManager(sysBus, inputdevicesPath) - if err != nil { - logger.Warning(err) - return false - } - value, err := inputdevicesDsg.Value(0, dsettingsData) - if err != nil { - logger.Warning(err) - return false - } - return value.Value().(bool) -} - -func (tpad *Touchpad) needCheckPS2Mouse() bool { - sysBus, err := dbus.SystemBus() - if err != nil { - logger.Warning(err) - return false - } - sysPower := power.NewPower(sysBus) - hasBattery, err := sysPower.HasBattery().Get(0) - if err != nil { - logger.Warning(err) - return false - } - - logger.Info("isPS2Mouse hasBattery : ", hasBattery) - return hasBattery && tpad.getDsgPS2MouseAsTouchPadEnable() -} - -func (tpad *Touchpad) init() { - if !tpad.Exist { - return - } - - if tpad.systemConn != nil { - sysTouchPad, err := inputdevices.NewTouchpad(tpad.systemConn, "/com/deepin/system/InputDevices/Touchpad") - if err != nil { - logger.Warning(err) - } else { - sysTouchPad.InitSignalExt(tpad.systemSigLoop, true) - sysTouchPad.Enable().ConnectChanged(func(hasValue bool, value bool) { - if !hasValue { - return - } - tpad.TPadEnable.Set(value) - tpad.enable(tpad.TPadEnable.Get()) - }) - if enabled, err := sysTouchPad.Enable().Get(0); err != nil { - logger.Warning(err) - } else { - tpad.TPadEnable.Set(enabled) - } - } - } - - tpad.enable(tpad.TPadEnable.Get()) - tpad.enableLeftHanded() - tpad.enableNaturalScroll() - tpad.enableEdgeScroll() - tpad.enableTapToClick() - tpad.enableTwoFingerScroll() - tpad.motionAcceleration() - tpad.motionThreshold() - tpad.motionScaling() - tpad.disableWhileTyping() - tpad.enablePalmDetect() - tpad.setPalmDimensions() - - if tpad.systemSigLoop != nil { - tpad.systemSigLoop.Start() - } -} - -func (tpad *Touchpad) handleDeviceChanged() { - tpad.updateDXTpads() - tpad.init() -} - -func (tpad *Touchpad) updateDXTpads() { - tpad.devInfos = Touchpads{} - for _, info := range getTPadInfos(false, tpad.needCheckPS2Mouse()) { - if !globalWayland { - tmp := tpad.devInfos.get(info.Id) - if tmp != nil { - continue - } - } - tpad.devInfos = append(tpad.devInfos, info) - } - - tpad.PropsMu.Lock() - var v string - if len(tpad.devInfos) == 0 { - tpad.setPropExist(false) - } else { - tpad.setPropExist(true) - v = tpad.devInfos.string() - } - tpad.setPropDeviceList(v) - tpad.PropsMu.Unlock() -} - -func (tpad *Touchpad) enable(enabled bool) { - if len(tpad.devInfos) > 0 { - for _, v := range tpad.devInfos { - err := v.Enable(enabled) - if err != nil { - logger.Warningf("Enable '%v - %v' failed: %v", - v.Id, v.Name, err) - } - } - } - - enableGesture(enabled) -} - -func (tpad *Touchpad) enableLeftHanded() { - enabled := tpad.LeftHanded.Get() - for _, v := range tpad.devInfos { - err := v.EnableLeftHanded(enabled) - if err != nil { - logger.Debugf("Enable left handed '%v - %v' failed: %v", - v.Id, v.Name, err) - } - } - setWMTPadBoolKey(wmTPadKeyLeftHanded, enabled) -} - -func (tpad *Touchpad) enableNaturalScroll() { - enabled := tpad.NaturalScroll.Get() - for _, v := range tpad.devInfos { - err := v.EnableNaturalScroll(enabled) - if err != nil { - logger.Debugf("Enable natural scroll '%v - %v' failed: %v", - v.Id, v.Name, err) - } - } - setWMTPadBoolKey(wmTPadKeyNaturalScroll, enabled) -} - -func (tpad *Touchpad) setScrollDistance() { - delta := tpad.DeltaScroll.Get() - for _, v := range tpad.devInfos { - err := v.SetScrollDistance(delta, delta) - if err != nil { - logger.Debugf("Set natural scroll distance '%v - %v' failed: %v", - v.Id, v.Name, err) - } - } -} - -func (tpad *Touchpad) enableEdgeScroll() { - enabled := tpad.EdgeScroll.Get() - for _, v := range tpad.devInfos { - err := v.EnableEdgeScroll(enabled) - if err != nil { - logger.Debugf("Enable edge scroll '%v - %v' failed: %v", - v.Id, v.Name, err) - } - } - setWMTPadBoolKey(wmTPadKeyEdgeScroll, enabled) -} - -func (tpad *Touchpad) enableTwoFingerScroll() { - vert := tpad.VertScroll.Get() - horiz := tpad.HorizScroll.Get() - for _, v := range tpad.devInfos { - err := v.EnableTwoFingerScroll(vert, horiz) - if err != nil { - logger.Debugf("Enable two-finger scroll '%v - %v' failed: %v", - v.Id, v.Name, err) - } - } -} - -func (tpad *Touchpad) enableTapToClick() { - enabled := tpad.TapClick.Get() - for _, v := range tpad.devInfos { - err := v.EnableTapToClick(enabled) - if err != nil { - logger.Debugf("Enable tap to click '%v - %v' failed: %v", - v.Id, v.Name, err) - } - } - setWMTPadBoolKey(wmTPadKeyTapClick, enabled) -} - -func (tpad *Touchpad) motionAcceleration() { - accel := float32(tpad.MotionAcceleration.Get()) - for _, v := range tpad.devInfos { - err := v.SetMotionAcceleration(accel) - if err != nil { - logger.Debugf("Set acceleration for '%d - %v' failed: %v", - v.Id, v.Name, err) - } - } -} - -func (tpad *Touchpad) motionThreshold() { - thres := float32(tpad.MotionThreshold.Get()) - for _, v := range tpad.devInfos { - err := v.SetMotionThreshold(thres) - if err != nil { - logger.Debugf("Set threshold for '%d - %v' failed: %v", - v.Id, v.Name, err) - } - } -} - -func (tpad *Touchpad) motionScaling() { - scaling := float32(tpad.MotionScaling.Get()) - for _, v := range tpad.devInfos { - err := v.SetMotionScaling(scaling) - if err != nil { - logger.Debugf("Set scaling for '%d - %v' failed: %v", - v.Id, v.Name, err) - } - } -} - -func (tpad *Touchpad) disableWhileTyping() { - if !tpad.Exist { - return - } - - var usedLibinput bool = false - enabled := tpad.DisableIfTyping.Get() - for _, v := range tpad.devInfos { - err := v.EnableDisableWhileTyping(enabled) - if err != nil { - continue - } - usedLibinput = true - } - if usedLibinput { - return - } - - if enabled { - tpad.startSyndaemon() - } else { - tpad.stopSyndaemon() - } -} - -func (tpad *Touchpad) startSyndaemon() { - if isSyndaemonExist(syndaemonPidFile) { - logger.Debug("Syndaemon has running") - return - } - - syncmd := tpad.setting.GetString(tpadKeyWhileTypingCmd) - if syncmd == "" { - logger.Warning("Failed to start syndaemon, because no cmd is specified") - return - } - logger.Debug("[startSyndaemon] will exec:", syncmd) - args := strings.Split(syncmd, " ") - argsLen := len(args) - var cmd *exec.Cmd - if argsLen == 1 { - // pidfile will be created only in daemon mode - cmd = exec.Command(args[0], "-d", "-p", syndaemonPidFile) - } else { - list := strv.Strv(args) - if !list.Contains("-p") { - if !list.Contains("-d") { - args = append(args, "-d") - } - args = append(args, "-p", syndaemonPidFile) - } - argsLen = len(args) - cmd = exec.Command(args[0], args[1:argsLen]...) - } - err := cmd.Start() - if err != nil { - err = os.Remove(syndaemonPidFile) - if err != nil { - logger.Warning("Remove error:", err) - } - logger.Debug("[disableWhileTyping] start syndaemon failed:", err) - return - } - - go func() { - _ = cmd.Wait() - }() -} - -func (tpad *Touchpad) stopSyndaemon() { - out, err := exec.Command("killall", "syndaemon").CombinedOutput() - if err != nil { - logger.Warning("[stopSyndaemon] failed:", string(out), err) - } - err = os.Remove(syndaemonPidFile) - if err != nil { - logger.Warning("remove error:", err) - } -} - -func (tpad *Touchpad) enablePalmDetect() { - enabled := tpad.PalmDetect.Get() - for _, dev := range tpad.devInfos { - err := dev.EnablePalmDetect(enabled) - if err != nil { - logger.Warning("[enablePalmDetect] failed to enable:", dev.Id, enabled, err) - } - } -} - -func (tpad *Touchpad) setPalmDimensions() { - width := tpad.PalmMinWidth.Get() - z := tpad.PalmMinZ.Get() - for _, dev := range tpad.devInfos { - err := dev.SetPalmDimensions(width, z) - if err != nil { - logger.Warning("[setPalmDimensions] failed to set:", dev.Id, width, z, err) - } - } -} - -func (tpad *Touchpad) destroy() { - if tpad.systemSigLoop != nil { - tpad.systemSigLoop.Stop() - } -} - -func isSyndaemonExist(pidFile string) bool { - if !dutils.IsFileExist(pidFile) { - out, err := exec.Command("pgrep", "syndaemon").CombinedOutput() - if err != nil || len(out) < 2 { - return false - } - return true - } - - context, err := ioutil.ReadFile(pidFile) - if err != nil { - return false - } - - pid, err := strconv.ParseInt(strings.TrimSpace(string(context)), 10, 64) - if err != nil { - return false - } - var file = fmt.Sprintf("/proc/%v/cmdline", pid) - return isProcessExist(file, "syndaemon") -} - -func isProcessExist(file, name string) bool { - context, err := ioutil.ReadFile(file) - if err != nil { - return false - } - - return strings.Contains(string(context), name) -} - -func enableGesture(enabled bool) { - s, err := dutils.CheckAndNewGSettings("com.deepin.dde.gesture") - if err != nil { - return - } - if s.GetBoolean("touch-pad-enabled") == enabled { - return - } - - s.SetBoolean("touch-pad-enabled", enabled) - s.Unref() -} diff --git a/inputdevices/wrapper.go b/inputdevices/wrapper.go deleted file mode 100644 index 571dad025..000000000 --- a/inputdevices/wrapper.go +++ /dev/null @@ -1,288 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package inputdevices - -// #cgo pkg-config: x11 xi -// #cgo CFLAGS: -W -Wall -fstack-protector-all -fPIC -// #cgo LDFLAGS: -lpthread -// #include "listen.h" -import "C" - -import ( - "encoding/json" - "fmt" - "os" - "strings" - - "github.com/linuxdeepin/dde-api/dxinput" - "github.com/linuxdeepin/dde-api/dxinput/common" - dxutils "github.com/linuxdeepin/dde-api/dxinput/utils" - gudev "github.com/linuxdeepin/go-gir/gudev-1.0" -) - -type mouseInfo struct { - *dxinput.Mouse - devNode string - phys string -} - -type touchpadInfo struct { - *dxinput.Touchpad - devNode string - phys string -} - -type Mouses []*mouseInfo -type Touchpads []*touchpadInfo -type dxWacoms []*dxinput.Wacom - -var ( - _devInfos common.DeviceInfos - _mouseInfos Mouses - _tpadInfos Touchpads - _wacomInfos dxWacoms - _gudevClient = gudev.NewClient([]string{"input"}) -) - -func startDeviceListener() { - C.start_device_listener() -} - -func endDeviceListener() { - C.end_device_listener() -} - -//export handleDeviceChanged -func handleDeviceChanged() { - logger.Debug("Device changed") - - getDeviceInfos(true) - - // 鼠标依赖触摸板的数据,必须在触摸板之后获取 - _tpadInfos = Touchpads{} - getTPadInfos(false, false) - _mouseInfos = Mouses{} - getMouseInfos(false) - _wacomInfos = dxWacoms{} - getWacomInfos(false) - - if _manager == nil { - logger.Warning("_manager is nil") - return - } - - _manager.tpad.handleDeviceChanged() - _manager.mouse.handleDeviceChanged() - _manager.wacom.handleDeviceChanged() - _manager.kbd.handleDeviceChanged() - - _manager.setWheelSpeed() -} - -func getDeviceInfos(force bool) common.DeviceInfos { - if force || len(_devInfos) == 0 { - _devInfos = dxutils.ListDevice() - } - - return _devInfos -} - -func getKeyboardNumber() int { - var number = 0 - for _, info := range getDeviceInfos(false) { - // TODO: Improve keyboard device detected by udev property 'ID_INPUT_KEYBOARD' - if strings.Contains(strings.ToLower(info.Name), "keyboard") { - number += 1 - } - } - return number -} - -func getExtraInfo(id int32) (devNode string, phys string) { - var devNodeBytes []byte - var length int32 - sessionType := os.Getenv("XDG_SESSION_TYPE") - isWaylandSession := strings.Contains(sessionType, "wayland") - if isWaylandSession { - devNode = fmt.Sprint("/dev/input/event", id) // id是从kwayland获取的sysname - } else { - devNodeBytes, length = dxutils.GetProperty(id, "Device Node") - if len(devNodeBytes) == 0 { - logger.Warningf("could not get DeviceNode for %d", id) - return - } - devNode = string(devNodeBytes[:length]) - } - udevDev := _gudevClient.QueryByDeviceFile(devNode) - if udevDev == nil { - logger.Warning("failed to get device of", devNode) - return - } - defer udevDev.Unref() - - phys = udevDev.GetSysfsAttr("phys") - if phys == "" { - parent := udevDev.GetParent() - if parent == nil { - logger.Warning("failed to get parent device of", devNode) - return - } - phys = parent.GetSysfsAttr("phys") - - parent.Unref() - } - - return -} - -func getTouchpadInfoByDxTouchpad(tmp *dxinput.Touchpad) *touchpadInfo { - m := &touchpadInfo{ - Touchpad: tmp, - } - - m.devNode, m.phys = getExtraInfo(tmp.Id) - - return m -} - -func getMouseInfoByDxMouse(tmp *dxinput.Mouse) *mouseInfo { - m := &mouseInfo{ - Mouse: tmp, - } - - m.devNode, m.phys = getExtraInfo(tmp.Id) - - return m -} - -func getMouseInfos(force bool) Mouses { - if !force && len(_mouseInfos) != 0 { - return _mouseInfos - } - - _mouseInfos = Mouses{} - for _, info := range getDeviceInfos(force) { - if info.Type == common.DevTypeMouse { - tmp, _ := dxinput.NewMouseFromDeviceInfo(info) - mouse := getMouseInfoByDxMouse(tmp) - - // phys 用来标识物理设备,若俩设备的 phys 相同,说明是同一物理设备, - // 若 phys 与某个触摸板的 phys 相同,说明是同一个设备(触摸板),忽略此鼠标设备 - found := false - for _, touchpad := range _tpadInfos { - logger.Warning(touchpad) - if touchpad.phys == mouse.phys { - found = true - break - } - } - - if found { - logger.Debug("mouse device ignored:", tmp.Name) - continue - } - - if mouse.phys != "" { - _mouseInfos = append(_mouseInfos, mouse) - logger.Debug("mouse device add:", mouse) - } - - } - } - - return _mouseInfos -} - -func isTPadPS2Mouse(name string) bool { - name = strings.ToLower(name) - return strings.Contains(name, "ps/2") && strings.Contains(name, "mouse") && !strings.Contains(name, "usb") -} - -func getTPadInfos(force, check bool) Touchpads { - if !force && len(_tpadInfos) != 0 { - return _tpadInfos - } - - _tpadInfos = Touchpads{} - for _, info := range getDeviceInfos(false) { - // 处理触控板被识别为PS2鼠标的情况 - if check && info.Type == common.DevTypeMouse && isTPadPS2Mouse(info.Name) { - tmp, err := dxinput.NewTouchpadFromDevInfo(info) - if err != nil { - logger.Warning(err) - } else { - _tpadInfos = append(_tpadInfos, getTouchpadInfoByDxTouchpad(tmp)) - } - continue - } - if info.Type == common.DevTypeTouchpad { - tmp, _ := dxinput.NewTouchpadFromDevInfo(info) - - _tpadInfos = append(_tpadInfos, getTouchpadInfoByDxTouchpad(tmp)) - } - } - - return _tpadInfos -} - -func getWacomInfos(force bool) dxWacoms { - if !force && len(_wacomInfos) != 0 { - return _wacomInfos - } - - _wacomInfos = dxWacoms{} - for _, info := range getDeviceInfos(false) { - if info.Type == common.DevTypeWacom { - tmp, _ := dxinput.NewWacomFromDevInfo(info) - _wacomInfos = append(_wacomInfos, tmp) - } - } - - return _wacomInfos -} - -func (infos Mouses) get(id int32) *dxinput.Mouse { - for _, info := range infos { - if info.Id == id { - return info.Mouse - } - } - return nil -} - -func (infos Mouses) string() string { - return toJSON(infos) -} - -func (infos Touchpads) get(id int32) *dxinput.Touchpad { - for _, info := range infos { - if info.Id == id { - return info.Touchpad - } - } - return nil -} - -func (infos Touchpads) string() string { - return toJSON(infos) -} - -func (infos dxWacoms) get(id int32) *dxinput.Wacom { - for _, info := range infos { - if info.Id == id { - return info - } - } - return nil -} - -func (infos dxWacoms) string() string { - return toJSON(infos) -} - -func toJSON(v interface{}) string { - data, _ := json.Marshal(v) - return string(data) -} diff --git a/inputdevices/app_layout_config.go b/inputdevices1/app_layout_config.go similarity index 100% rename from inputdevices/app_layout_config.go rename to inputdevices1/app_layout_config.go diff --git a/inputdevices/exported_methods_auto.go b/inputdevices1/exported_methods_auto.go similarity index 100% rename from inputdevices/exported_methods_auto.go rename to inputdevices1/exported_methods_auto.go diff --git a/inputdevices/handle_gsettings.go b/inputdevices1/handle_gsettings.go similarity index 100% rename from inputdevices/handle_gsettings.go rename to inputdevices1/handle_gsettings.go diff --git a/inputdevices1/ifc.go b/inputdevices1/ifc.go new file mode 100644 index 000000000..b3257ce3d --- /dev/null +++ b/inputdevices1/ifc.go @@ -0,0 +1,114 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package inputdevices + +import ( + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/langselector1" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (m *Mouse) Reset() *dbus.Error { + for _, key := range m.setting.ListKeys() { + m.setting.Reset(key) + } + return nil +} + +func (tp *TrackPoint) Reset() *dbus.Error { + for _, key := range tp.setting.ListKeys() { + tp.setting.Reset(key) + } + return nil +} + +func (tpad *Touchpad) Reset() *dbus.Error { + for _, key := range tpad.setting.ListKeys() { + tpad.setting.Reset(key) + } + return nil +} + +func (w *Wacom) Reset() *dbus.Error { + for _, key := range w.setting.ListKeys() { + w.setting.Reset(key) + } + for _, key := range w.stylusSetting.ListKeys() { + w.stylusSetting.Reset(key) + } + for _, key := range w.eraserSetting.ListKeys() { + w.eraserSetting.Reset(key) + } + return nil +} + +func (kbd *Keyboard) Reset() *dbus.Error { + for _, key := range kbd.setting.ListKeys() { + kbd.setting.Reset(key) + } + return nil +} + +func (kbd *Keyboard) LayoutList() (map[string]string, *dbus.Error) { + locales := langselector.GetLocales() + result := kbd.layoutMap.filterByLocales(locales) + + kbd.PropsMu.RLock() + for _, layout := range kbd.UserLayoutList { + layoutDetail := kbd.layoutMap[layout] + result[layout] = layoutDetail.Description + } + kbd.PropsMu.RUnlock() + + return result, nil +} + +func (kbd *Keyboard) GetLayoutDesc(layout string) (string, *dbus.Error) { + if len(layout) == 0 { + return "", nil + } + + value, ok := kbd.layoutMap[layout] + if !ok { + return "", nil + } + + return value.Description, nil +} + +func (kbd *Keyboard) AddUserLayout(layout string) *dbus.Error { + err := kbd.checkLayout(layout) + if err != nil { + return dbusutil.ToError(errInvalidLayout) + } + + kbd.addUserLayout(layout) + return nil +} + +func (kbd *Keyboard) DeleteUserLayout(layout string) *dbus.Error { + kbd.delUserLayout(layout) + return nil +} + +func (kbd *Keyboard) AddLayoutOption(option string) *dbus.Error { + kbd.addUserOption(option) + return nil +} + +func (kbd *Keyboard) DeleteLayoutOption(option string) *dbus.Error { + kbd.delUserOption(option) + return nil +} + +func (kbd *Keyboard) ClearLayoutOption() *dbus.Error { + kbd.UserOptionList.Set([]string{}) + return nil +} + +func (kbd *Keyboard) ToggleNextLayout() *dbus.Error { + kbd.toggleNextLayout() + return nil +} diff --git a/inputdevices/inputdevices.go b/inputdevices1/inputdevices.go similarity index 100% rename from inputdevices/inputdevices.go rename to inputdevices1/inputdevices.go diff --git a/inputdevices/inputdevices_dbusutil.go b/inputdevices1/inputdevices_dbusutil.go similarity index 100% rename from inputdevices/inputdevices_dbusutil.go rename to inputdevices1/inputdevices_dbusutil.go diff --git a/inputdevices/inputdevices_test.go b/inputdevices1/inputdevices_test.go similarity index 100% rename from inputdevices/inputdevices_test.go rename to inputdevices1/inputdevices_test.go diff --git a/inputdevices/iso639/auto.go b/inputdevices1/iso639/auto.go similarity index 100% rename from inputdevices/iso639/auto.go rename to inputdevices1/iso639/auto.go diff --git a/inputdevices/iso639/iso639.go b/inputdevices1/iso639/iso639.go similarity index 100% rename from inputdevices/iso639/iso639.go rename to inputdevices1/iso639/iso639.go diff --git a/inputdevices/keyboard.go b/inputdevices1/keyboard.go similarity index 99% rename from inputdevices/keyboard.go rename to inputdevices1/keyboard.go index 7f3b684f5..1aaa39fbd 100644 --- a/inputdevices/keyboard.go +++ b/inputdevices1/keyboard.go @@ -15,10 +15,10 @@ import ( "strings" "sync" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-api/dxinput" ddbus "github.com/linuxdeepin/dde-daemon/dbus" - accounts "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.accounts" + accounts "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.accounts1" "github.com/linuxdeepin/go-gir/gio-2.0" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/dbusutil/gsprop" diff --git a/inputdevices/kwayland.go b/inputdevices1/kwayland.go similarity index 97% rename from inputdevices/kwayland.go rename to inputdevices1/kwayland.go index 2c23c1d0d..f34fd1f77 100644 --- a/inputdevices/kwayland.go +++ b/inputdevices1/kwayland.go @@ -9,11 +9,11 @@ import ( "strconv" "strings" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-api/dxinput" "github.com/linuxdeepin/dde-api/dxinput/common" "github.com/linuxdeepin/dde-api/dxinput/kwayland" - kwin "github.com/linuxdeepin/go-dbus-factory/org.kde.kwin" + kwin "github.com/linuxdeepin/go-dbus-factory/session/org.kde.kwin" ) var ( @@ -81,6 +81,7 @@ func (m *Manager) setWaylandWheelSpeed(speed uint32) error { if pointer && speed != uint32(scrollFactor) { err := device.ScrollFactor().Set(0, float64(speed)) + if err != nil { logger.Warning(err) continue diff --git a/inputdevices/layout_list.go b/inputdevices1/layout_list.go similarity index 98% rename from inputdevices/layout_list.go rename to inputdevices1/layout_list.go index ef8a17819..275b0ca66 100644 --- a/inputdevices/layout_list.go +++ b/inputdevices1/layout_list.go @@ -8,10 +8,10 @@ import ( "encoding/xml" "io/ioutil" + "github.com/linuxdeepin/dde-daemon/inputdevices1/iso639" "github.com/linuxdeepin/go-lib/gettext" lib_locale "github.com/linuxdeepin/go-lib/locale" "github.com/linuxdeepin/go-lib/strv" - "github.com/linuxdeepin/dde-daemon/inputdevices/iso639" ) const ( diff --git a/inputdevices/listen.c b/inputdevices1/listen.c similarity index 100% rename from inputdevices/listen.c rename to inputdevices1/listen.c diff --git a/inputdevices/listen.h b/inputdevices1/listen.h similarity index 100% rename from inputdevices/listen.h rename to inputdevices1/listen.h diff --git a/inputdevices1/manager.go b/inputdevices1/manager.go new file mode 100644 index 000000000..115349ed6 --- /dev/null +++ b/inputdevices1/manager.go @@ -0,0 +1,201 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package inputdevices + +import ( + "bufio" + "fmt" + "os" + "os/exec" + "path/filepath" + + "github.com/linuxdeepin/dde-daemon/common/dsync" + kwin "github.com/linuxdeepin/go-dbus-factory/session/org.kde.kwin" + "github.com/linuxdeepin/go-gir/gio-2.0" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/dbusutil/gsprop" + "github.com/linuxdeepin/go-lib/xdg/basedir" +) + +const ( + gsSchemaInputDevices = "com.deepin.dde.inputdevices" + gsKeyWheelSpeed = "wheel-speed" + imWheelBin = "imwheel" +) + +type devicePathInfo struct { + Path string + Type string +} +type devicePathInfos []*devicePathInfo + +type Manager struct { + Infos devicePathInfos // readonly + WheelSpeed gsprop.Uint `prop:"access:rw"` + + settings *gio.Settings + imWheelConfigFile string + + kbd *Keyboard + mouse *Mouse + trackPoint *TrackPoint + tpad *Touchpad + wacom *Wacom + + kwinManager kwin.InputDeviceManager + kwinIdList []dbusutil.SignalHandlerId + + sessionSigLoop *dbusutil.SignalLoop + syncConfig *dsync.Config +} + +func NewManager(service *dbusutil.Service) *Manager { + var m = new(Manager) + m.imWheelConfigFile = filepath.Join(basedir.GetUserHomeDir(), ".imwheelrc") + + m.Infos = devicePathInfos{ + &devicePathInfo{ + Path: kbdDBusInterface, + Type: "keyboard", + }, + &devicePathInfo{ + Path: mouseDBusInterface, + Type: "mouse", + }, + &devicePathInfo{ + Path: trackPointDBusInterface, + Type: "trackpoint", + }, + &devicePathInfo{ + Path: touchPadDBusInterface, + Type: "touchpad", + }, + } + + m.settings = gio.NewSettings(gsSchemaInputDevices) + m.WheelSpeed.Bind(m.settings, gsKeyWheelSpeed) + + m.kbd = newKeyboard(service) + m.wacom = newWacom(service) + + m.tpad = newTouchpad(service) + + m.mouse = newMouse(service, m.tpad) + + m.trackPoint = newTrackPoint(service) + + m.kwinManager = kwin.NewInputDeviceManager(service.Conn()) + + m.sessionSigLoop = dbusutil.NewSignalLoop(service.Conn(), 10) + m.syncConfig = dsync.NewConfig("peripherals", &syncConfig{m: m}, + m.sessionSigLoop, dbusPath, logger) + + return m +} + +func (m *Manager) setWheelSpeed() { + speed := m.settings.GetUint(gsKeyWheelSpeed) + // speed range is [1,100] + logger.Debug("setWheelSpeed", speed) + + // 为了避免imwheel对kwin影响,先杀死imwheel + err := exec.Command("pkill", "-ef", imWheelBin).Run() + if err != nil { + logger.Warning(err) + } + + err = m.setWaylandWheelSpeed(speed) + if err == nil { + logger.Info("set Wayland WheelSpeed finish") + return + } + + logger.Info("can not set WheelSpeed by Wayland interface, use imwheel") + // 通过kwin设置wheel speed失败时候才通过命令设置 + err = writeImWheelConfig(m.imWheelConfigFile, speed) + if err != nil { + logger.Warning("failed to write imwheel config file:", err) + return + } + + err = controlImWheel(speed) + if err != nil { + logger.Warning("failed to control imwheel:", err) + return + } +} + +func controlImWheel(speed uint32) error { + if speed == 1 { + // quit + return exec.Command(imWheelBin, "-k", "-q").Run() + } + // restart + return exec.Command(imWheelBin, "-k", "-b", "4 5").Run() +} + +func writeImWheelConfig(file string, speed uint32) error { + logger.Debugf("writeImWheelConfig file:%q, speed: %d", file, speed) + + const header = `# written by ` + dbusServiceName + ` +".*" +Control_L,Up,Control_L|Button4 +Control_R,Up,Control_R|Button4 +Control_L,Down,Control_L|Button5 +Control_R,Down,Control_R|Button5 +Shift_L,Up,Shift_L|Button4 +Shift_R,Up,Shift_R|Button4 +Shift_L,Down,Shift_L|Button5 +Shift_R,Down,Shift_R|Button5 +` + fh, err := os.Create(file) + if err != nil { + return err + } + defer fh.Close() + writer := bufio.NewWriter(fh) + + _, err = writer.Write([]byte(header)) + if err != nil { + return err + } + + // Delay Before Next KeyPress Event + delay := 240000 / speed + _, err = fmt.Fprintf(writer, "None,Up,Button4,%d,0,%d\n", speed, delay) + if err != nil { + return err + } + + _, err = fmt.Fprintf(writer, "None,Down,Button5,%d,0,%d\n", speed, delay) + if err != nil { + return err + } + + err = writer.Flush() + if err != nil { + return err + } + + return fh.Sync() +} + +func (m *Manager) init() { + m.kbd.init() + m.kbd.handleGSettings() + m.wacom.init() + m.wacom.handleGSettings() + m.tpad.init() + m.tpad.handleGSettings() + m.mouse.init() + m.mouse.handleGSettings() + m.trackPoint.init() + m.trackPoint.handleGSettings() + + m.setWheelSpeed() + m.handleGSettings() + + m.sessionSigLoop.Start() +} diff --git a/inputdevices/mouse.go b/inputdevices1/mouse.go similarity index 100% rename from inputdevices/mouse.go rename to inputdevices1/mouse.go diff --git a/inputdevices1/stub.go b/inputdevices1/stub.go new file mode 100644 index 000000000..c18074ce5 --- /dev/null +++ b/inputdevices1/stub.go @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package inputdevices + +const ( + dbusServiceName = "org.deepin.dde.InputDevices1" + dbusPath = "/org/deepin/dde/InputDevices1" + dbusInterface = dbusServiceName + + kbdDBusPath = "/org/deepin/dde/InputDevice1/Keyboard" + kbdDBusInterface = "org.deepin.dde.InputDevice1.Keyboard" + + mouseDBusPath = "/org/deepin/dde/InputDevice1/Mouse" + mouseDBusInterface = "org.deepin.dde.InputDevice1.Mouse" + trackPointDBusInterface = "org.deepin.dde.InputDevice1.TrackPoint" + + touchPadDBusPath = "/org/deepin/dde/InputDevice1/TouchPad" + touchPadDBusInterface = "org.deepin.dde.InputDevice1.TouchPad" + + wacomDBusPath = "/org/deepin/dde/InputDevice1/Wacom" + wacomDBusInterface = "org.deepin.dde.InputDevice1.Wacom" +) + +func (*Manager) GetInterfaceName() string { + return dbusInterface +} + +func (*Keyboard) GetInterfaceName() string { + return kbdDBusInterface +} + +func (*Mouse) GetInterfaceName() string { + return mouseDBusInterface +} + +func (*TrackPoint) GetInterfaceName() string { + return trackPointDBusInterface +} + +func (*Touchpad) GetInterfaceName() string { + return touchPadDBusInterface +} + +func (*Wacom) GetInterfaceName() string { + return wacomDBusInterface +} diff --git a/inputdevices/sync_config.go b/inputdevices1/sync_config.go similarity index 100% rename from inputdevices/sync_config.go rename to inputdevices1/sync_config.go diff --git a/inputdevices/testdata/base.xml b/inputdevices1/testdata/base.xml similarity index 100% rename from inputdevices/testdata/base.xml rename to inputdevices1/testdata/base.xml diff --git a/inputdevices/testdata/dde-desktop-cmdline b/inputdevices1/testdata/dde-desktop-cmdline similarity index 100% rename from inputdevices/testdata/dde-desktop-cmdline rename to inputdevices1/testdata/dde-desktop-cmdline diff --git a/inputdevices/testdata/keyboard b/inputdevices1/testdata/keyboard similarity index 100% rename from inputdevices/testdata/keyboard rename to inputdevices1/testdata/keyboard diff --git a/inputdevices/testdata/syndaemon.pid b/inputdevices1/testdata/syndaemon.pid similarity index 100% rename from inputdevices/testdata/syndaemon.pid rename to inputdevices1/testdata/syndaemon.pid diff --git a/inputdevices/testdata/users.ini b/inputdevices1/testdata/users.ini similarity index 100% rename from inputdevices/testdata/users.ini rename to inputdevices1/testdata/users.ini diff --git a/inputdevices1/touchpad.go b/inputdevices1/touchpad.go new file mode 100644 index 000000000..6bc76bfeb --- /dev/null +++ b/inputdevices1/touchpad.go @@ -0,0 +1,510 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package inputdevices + +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "strconv" + "strings" + "sync" + + "github.com/godbus/dbus/v5" + configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" + inputdevices "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.inputdevices1" + power "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.power1" + "github.com/linuxdeepin/go-gir/gio-2.0" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/dbusutil/gsprop" + "github.com/linuxdeepin/go-lib/strv" + dutils "github.com/linuxdeepin/go-lib/utils" +) + +const ( + tpadSchema = "com.deepin.dde.touchpad" + + tpadKeyEnabled = "touchpad-enabled" + tpadKeyLeftHanded = "left-handed" + tpadKeyDisableWhileTyping = "disable-while-typing" + tpadKeyNaturalScroll = "natural-scroll" + tpadKeyEdgeScroll = "edge-scroll-enabled" + tpadKeyHorizScroll = "horiz-scroll-enabled" + tpadKeyVertScroll = "vert-scroll-enabled" + tpadKeyAcceleration = "motion-acceleration" + tpadKeyThreshold = "motion-threshold" + tpadKeyScaling = "motion-scaling" + tpadKeyTapClick = "tap-to-click" + tpadKeyScrollDelta = "delta-scroll" + tpadKeyWhileTypingCmd = "disable-while-typing-cmd" + tpadKeyPalmDetect = "palm-detect" + tpadKeyPalmMinWidth = "palm-min-width" + tpadKeyPalmMinZ = "palm-min-pressure" + + dsettingsAppID = "org.deepin.dde.daemon" + dsettingsInputdevices = "org.deepin.dde.daemon.inputdevices" + dsettingsData = "ps2MouseAsTouchPadEnabled" +) + +const ( + syndaemonPidFile = "/tmp/syndaemon.pid" +) + +type Touchpad struct { + service *dbusutil.Service + PropsMu sync.RWMutex + Exist bool + DeviceList string + + // dbusutil-gen: ignore-below + TPadEnable gsprop.Bool `prop:"access:rw"` + LeftHanded gsprop.Bool `prop:"access:rw"` + DisableIfTyping gsprop.Bool `prop:"access:rw"` + NaturalScroll gsprop.Bool `prop:"access:rw"` + EdgeScroll gsprop.Bool `prop:"access:rw"` + HorizScroll gsprop.Bool `prop:"access:rw"` + VertScroll gsprop.Bool `prop:"access:rw"` + TapClick gsprop.Bool `prop:"access:rw"` + PalmDetect gsprop.Bool `prop:"access:rw"` + + MotionAcceleration gsprop.Double `prop:"access:rw"` + MotionThreshold gsprop.Double `prop:"access:rw"` + MotionScaling gsprop.Double `prop:"access:rw"` + + DoubleClick gsprop.Int `prop:"access:rw"` + DragThreshold gsprop.Int `prop:"access:rw"` + DeltaScroll gsprop.Int `prop:"access:rw"` + PalmMinWidth gsprop.Int `prop:"access:rw"` + PalmMinZ gsprop.Int `prop:"access:rw"` + + devInfos Touchpads + setting *gio.Settings + mouseSetting *gio.Settings + + systemConn *dbus.Conn + systemSigLoop *dbusutil.SignalLoop +} + +func newTouchpad(service *dbusutil.Service) *Touchpad { + var tpad = new(Touchpad) + + tpad.service = service + tpad.setting = gio.NewSettings(tpadSchema) + tpad.TPadEnable.Bind(tpad.setting, tpadKeyEnabled) + tpad.LeftHanded.Bind(tpad.setting, tpadKeyLeftHanded) + tpad.DisableIfTyping.Bind(tpad.setting, tpadKeyDisableWhileTyping) + tpad.NaturalScroll.Bind(tpad.setting, tpadKeyNaturalScroll) + tpad.EdgeScroll.Bind(tpad.setting, tpadKeyEdgeScroll) + tpad.VertScroll.Bind(tpad.setting, tpadKeyVertScroll) + tpad.HorizScroll.Bind(tpad.setting, tpadKeyHorizScroll) + tpad.TapClick.Bind(tpad.setting, tpadKeyTapClick) + tpad.PalmDetect.Bind(tpad.setting, tpadKeyPalmDetect) + tpad.MotionAcceleration.Bind(tpad.setting, tpadKeyAcceleration) + tpad.MotionThreshold.Bind(tpad.setting, tpadKeyThreshold) + tpad.MotionScaling.Bind(tpad.setting, tpadKeyScaling) + tpad.DeltaScroll.Bind(tpad.setting, tpadKeyScrollDelta) + tpad.PalmMinWidth.Bind(tpad.setting, tpadKeyPalmMinWidth) + tpad.PalmMinZ.Bind(tpad.setting, tpadKeyPalmMinZ) + + tpad.mouseSetting = gio.NewSettings(mouseSchema) + tpad.DoubleClick.Bind(tpad.mouseSetting, mouseKeyDoubleClick) + tpad.DragThreshold.Bind(tpad.mouseSetting, mouseKeyDragThreshold) + + tpad.updateDXTpads() + + if conn, err := dbus.SystemBus(); err != nil { + logger.Warning(err) + } else { + tpad.systemConn = conn + tpad.systemSigLoop = dbusutil.NewSignalLoop(conn, 10) + } + + return tpad +} + +func (tpad *Touchpad) getDsgPS2MouseAsTouchPadEnable() bool { + sysBus, err := dbus.SystemBus() + if err != nil { + return false + } + ds := configManager.NewConfigManager(sysBus) + + inputdevicesPath, err := ds.AcquireManager(0, dsettingsAppID, dsettingsInputdevices, "") + if err != nil { + logger.Warning(err) + return false + } + inputdevicesDsg, err := configManager.NewManager(sysBus, inputdevicesPath) + if err != nil { + logger.Warning(err) + return false + } + value, err := inputdevicesDsg.Value(0, dsettingsData) + if err != nil { + logger.Warning(err) + return false + } + return value.Value().(bool) +} + +func (tpad *Touchpad) needCheckPS2Mouse() bool { + sysBus, err := dbus.SystemBus() + if err != nil { + logger.Warning(err) + return false + } + sysPower := power.NewPower(sysBus) + hasBattery, err := sysPower.HasBattery().Get(0) + if err != nil { + logger.Warning(err) + return false + } + + logger.Info("isPS2Mouse hasBattery : ", hasBattery) + return hasBattery && tpad.getDsgPS2MouseAsTouchPadEnable() +} + +func (tpad *Touchpad) init() { + if !tpad.Exist { + return + } + + if tpad.systemConn != nil { + sysTouchPad, err := inputdevices.NewTouchpad(tpad.systemConn, "/org/deepin/dde/InputDevices1/Touchpad") + if err != nil { + logger.Warning(err) + } else { + sysTouchPad.InitSignalExt(tpad.systemSigLoop, true) + sysTouchPad.Enable().ConnectChanged(func(hasValue bool, value bool) { + if !hasValue { + return + } + tpad.TPadEnable.Set(value) + tpad.enable(tpad.TPadEnable.Get()) + }) + if enabled, err := sysTouchPad.Enable().Get(0); err != nil { + logger.Warning(err) + } else { + tpad.TPadEnable.Set(enabled) + } + } + } + + tpad.enable(tpad.TPadEnable.Get()) + tpad.enableLeftHanded() + tpad.enableNaturalScroll() + tpad.enableEdgeScroll() + tpad.enableTapToClick() + tpad.enableTwoFingerScroll() + tpad.motionAcceleration() + tpad.motionThreshold() + tpad.motionScaling() + tpad.disableWhileTyping() + tpad.enablePalmDetect() + tpad.setPalmDimensions() + + if tpad.systemSigLoop != nil { + tpad.systemSigLoop.Start() + } +} + +func (tpad *Touchpad) handleDeviceChanged() { + tpad.updateDXTpads() + tpad.init() +} + +func (tpad *Touchpad) updateDXTpads() { + tpad.devInfos = Touchpads{} + for _, info := range getTPadInfos(false, tpad.needCheckPS2Mouse()) { + if !globalWayland { + tmp := tpad.devInfos.get(info.Id) + if tmp != nil { + continue + } + } + tpad.devInfos = append(tpad.devInfos, info) + } + + tpad.PropsMu.Lock() + var v string + if len(tpad.devInfos) == 0 { + tpad.setPropExist(false) + } else { + tpad.setPropExist(true) + v = tpad.devInfos.string() + } + tpad.setPropDeviceList(v) + tpad.PropsMu.Unlock() +} + +func (tpad *Touchpad) enable(enabled bool) { + if len(tpad.devInfos) > 0 { + for _, v := range tpad.devInfos { + err := v.Enable(enabled) + if err != nil { + logger.Warningf("Enable '%v - %v' failed: %v", + v.Id, v.Name, err) + } + } + } + + enableGesture(enabled) +} + +func (tpad *Touchpad) enableLeftHanded() { + enabled := tpad.LeftHanded.Get() + for _, v := range tpad.devInfos { + err := v.EnableLeftHanded(enabled) + if err != nil { + logger.Debugf("Enable left handed '%v - %v' failed: %v", + v.Id, v.Name, err) + } + } + setWMTPadBoolKey(wmTPadKeyLeftHanded, enabled) +} + +func (tpad *Touchpad) enableNaturalScroll() { + enabled := tpad.NaturalScroll.Get() + for _, v := range tpad.devInfos { + err := v.EnableNaturalScroll(enabled) + if err != nil { + logger.Debugf("Enable natural scroll '%v - %v' failed: %v", + v.Id, v.Name, err) + } + } + setWMTPadBoolKey(wmTPadKeyNaturalScroll, enabled) +} + +func (tpad *Touchpad) setScrollDistance() { + delta := tpad.DeltaScroll.Get() + for _, v := range tpad.devInfos { + err := v.SetScrollDistance(delta, delta) + if err != nil { + logger.Debugf("Set natural scroll distance '%v - %v' failed: %v", + v.Id, v.Name, err) + } + } +} + +func (tpad *Touchpad) enableEdgeScroll() { + enabled := tpad.EdgeScroll.Get() + for _, v := range tpad.devInfos { + err := v.EnableEdgeScroll(enabled) + if err != nil { + logger.Debugf("Enable edge scroll '%v - %v' failed: %v", + v.Id, v.Name, err) + } + } + setWMTPadBoolKey(wmTPadKeyEdgeScroll, enabled) +} + +func (tpad *Touchpad) enableTwoFingerScroll() { + vert := tpad.VertScroll.Get() + horiz := tpad.HorizScroll.Get() + for _, v := range tpad.devInfos { + err := v.EnableTwoFingerScroll(vert, horiz) + if err != nil { + logger.Debugf("Enable two-finger scroll '%v - %v' failed: %v", + v.Id, v.Name, err) + } + } +} + +func (tpad *Touchpad) enableTapToClick() { + enabled := tpad.TapClick.Get() + for _, v := range tpad.devInfos { + err := v.EnableTapToClick(enabled) + if err != nil { + logger.Debugf("Enable tap to click '%v - %v' failed: %v", + v.Id, v.Name, err) + } + } + setWMTPadBoolKey(wmTPadKeyTapClick, enabled) +} + +func (tpad *Touchpad) motionAcceleration() { + accel := float32(tpad.MotionAcceleration.Get()) + for _, v := range tpad.devInfos { + err := v.SetMotionAcceleration(accel) + if err != nil { + logger.Debugf("Set acceleration for '%d - %v' failed: %v", + v.Id, v.Name, err) + } + } +} + +func (tpad *Touchpad) motionThreshold() { + thres := float32(tpad.MotionThreshold.Get()) + for _, v := range tpad.devInfos { + err := v.SetMotionThreshold(thres) + if err != nil { + logger.Debugf("Set threshold for '%d - %v' failed: %v", + v.Id, v.Name, err) + } + } +} + +func (tpad *Touchpad) motionScaling() { + scaling := float32(tpad.MotionScaling.Get()) + for _, v := range tpad.devInfos { + err := v.SetMotionScaling(scaling) + if err != nil { + logger.Debugf("Set scaling for '%d - %v' failed: %v", + v.Id, v.Name, err) + } + } +} + +func (tpad *Touchpad) disableWhileTyping() { + if !tpad.Exist { + return + } + + var usedLibinput bool = false + enabled := tpad.DisableIfTyping.Get() + for _, v := range tpad.devInfos { + err := v.EnableDisableWhileTyping(enabled) + if err != nil { + continue + } + usedLibinput = true + } + if usedLibinput { + return + } + + if enabled { + tpad.startSyndaemon() + } else { + tpad.stopSyndaemon() + } +} + +func (tpad *Touchpad) startSyndaemon() { + if isSyndaemonExist(syndaemonPidFile) { + logger.Debug("Syndaemon has running") + return + } + + syncmd := tpad.setting.GetString(tpadKeyWhileTypingCmd) + if syncmd == "" { + logger.Warning("Failed to start syndaemon, because no cmd is specified") + return + } + logger.Debug("[startSyndaemon] will exec:", syncmd) + args := strings.Split(syncmd, " ") + argsLen := len(args) + var cmd *exec.Cmd + if argsLen == 1 { + // pidfile will be created only in daemon mode + cmd = exec.Command(args[0], "-d", "-p", syndaemonPidFile) + } else { + list := strv.Strv(args) + if !list.Contains("-p") { + if !list.Contains("-d") { + args = append(args, "-d") + } + args = append(args, "-p", syndaemonPidFile) + } + argsLen = len(args) + cmd = exec.Command(args[0], args[1:argsLen]...) + } + err := cmd.Start() + if err != nil { + err = os.Remove(syndaemonPidFile) + if err != nil { + logger.Warning("Remove error:", err) + } + logger.Debug("[disableWhileTyping] start syndaemon failed:", err) + return + } + + go func() { + _ = cmd.Wait() + }() +} + +func (tpad *Touchpad) stopSyndaemon() { + out, err := exec.Command("killall", "syndaemon").CombinedOutput() + if err != nil { + logger.Warning("[stopSyndaemon] failed:", string(out), err) + } + err = os.Remove(syndaemonPidFile) + if err != nil { + logger.Warning("remove error:", err) + } +} + +func (tpad *Touchpad) enablePalmDetect() { + enabled := tpad.PalmDetect.Get() + for _, dev := range tpad.devInfos { + err := dev.EnablePalmDetect(enabled) + if err != nil { + logger.Warning("[enablePalmDetect] failed to enable:", dev.Id, enabled, err) + } + } +} + +func (tpad *Touchpad) setPalmDimensions() { + width := tpad.PalmMinWidth.Get() + z := tpad.PalmMinZ.Get() + for _, dev := range tpad.devInfos { + err := dev.SetPalmDimensions(width, z) + if err != nil { + logger.Warning("[setPalmDimensions] failed to set:", dev.Id, width, z, err) + } + } +} + +func (tpad *Touchpad) destroy() { + if tpad.systemSigLoop != nil { + tpad.systemSigLoop.Stop() + } +} + +func isSyndaemonExist(pidFile string) bool { + if !dutils.IsFileExist(pidFile) { + out, err := exec.Command("pgrep", "syndaemon").CombinedOutput() + if err != nil || len(out) < 2 { + return false + } + return true + } + + context, err := ioutil.ReadFile(pidFile) + if err != nil { + return false + } + + pid, err := strconv.ParseInt(strings.TrimSpace(string(context)), 10, 64) + if err != nil { + return false + } + var file = fmt.Sprintf("/proc/%v/cmdline", pid) + return isProcessExist(file, "syndaemon") +} + +func isProcessExist(file, name string) bool { + context, err := ioutil.ReadFile(file) + if err != nil { + return false + } + + return strings.Contains(string(context), name) +} + +func enableGesture(enabled bool) { + s, err := dutils.CheckAndNewGSettings("com.deepin.dde.gesture") + if err != nil { + return + } + if s.GetBoolean("touch-pad-enabled") == enabled { + return + } + + s.SetBoolean("touch-pad-enabled", enabled) + s.Unref() +} diff --git a/inputdevices/trackpoint.go b/inputdevices1/trackpoint.go similarity index 100% rename from inputdevices/trackpoint.go rename to inputdevices1/trackpoint.go diff --git a/inputdevices/utils.go b/inputdevices1/utils.go similarity index 100% rename from inputdevices/utils.go rename to inputdevices1/utils.go diff --git a/inputdevices/utils_test.go b/inputdevices1/utils_test.go similarity index 100% rename from inputdevices/utils_test.go rename to inputdevices1/utils_test.go diff --git a/inputdevices/wacom.go b/inputdevices1/wacom.go similarity index 100% rename from inputdevices/wacom.go rename to inputdevices1/wacom.go index 6ce03293e..9825ab130 100644 --- a/inputdevices/wacom.go +++ b/inputdevices1/wacom.go @@ -10,12 +10,12 @@ import ( "sync" "time" + "github.com/linuxdeepin/dde-api/dxinput" "github.com/linuxdeepin/go-gir/gio-2.0" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/dbusutil/gsprop" x "github.com/linuxdeepin/go-x11-client" "github.com/linuxdeepin/go-x11-client/ext/randr" - "github.com/linuxdeepin/dde-api/dxinput" ) const ( diff --git a/inputdevices/wm_wrapper.go b/inputdevices1/wm_wrapper.go similarity index 100% rename from inputdevices/wm_wrapper.go rename to inputdevices1/wm_wrapper.go diff --git a/inputdevices1/wrapper.go b/inputdevices1/wrapper.go new file mode 100644 index 000000000..78f5aeaac --- /dev/null +++ b/inputdevices1/wrapper.go @@ -0,0 +1,288 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package inputdevices + +// #cgo pkg-config: x11 xi +// #cgo CFLAGS: -W -Wall -fstack-protector-all -fPIC +// #cgo LDFLAGS: -lpthread +// #include "listen.h" +import "C" + +import ( + "encoding/json" + "fmt" + "os" + "strings" + + "github.com/linuxdeepin/dde-api/dxinput" + "github.com/linuxdeepin/dde-api/dxinput/common" + dxutils "github.com/linuxdeepin/dde-api/dxinput/utils" + gudev "github.com/linuxdeepin/go-gir/gudev-1.0" +) + +type mouseInfo struct { + *dxinput.Mouse + devNode string + phys string +} + +type touchpadInfo struct { + *dxinput.Touchpad + devNode string + phys string +} + +type Mouses []*mouseInfo +type Touchpads []*touchpadInfo +type dxWacoms []*dxinput.Wacom + +var ( + _devInfos common.DeviceInfos + _mouseInfos Mouses + _tpadInfos Touchpads + _wacomInfos dxWacoms + _gudevClient = gudev.NewClient([]string{"input"}) +) + +func startDeviceListener() { + C.start_device_listener() +} + +func endDeviceListener() { + C.end_device_listener() +} + +//export handleDeviceChanged +func handleDeviceChanged() { + logger.Debug("Device changed") + + getDeviceInfos(true) + + // 鼠标依赖触摸板的数据,必须在触摸板之后获取 + _tpadInfos = Touchpads{} + getTPadInfos(false, true) + _mouseInfos = Mouses{} + getMouseInfos(false) + _wacomInfos = dxWacoms{} + getWacomInfos(false) + + if _manager == nil { + logger.Warning("_manager is nil") + return + } + + _manager.tpad.handleDeviceChanged() + _manager.mouse.handleDeviceChanged() + _manager.wacom.handleDeviceChanged() + _manager.kbd.handleDeviceChanged() + + _manager.setWheelSpeed() +} + +func getDeviceInfos(force bool) common.DeviceInfos { + if force || len(_devInfos) == 0 { + _devInfos = dxutils.ListDevice() + } + + return _devInfos +} + +func getKeyboardNumber() int { + var number = 0 + for _, info := range getDeviceInfos(false) { + // TODO: Improve keyboard device detected by udev property 'ID_INPUT_KEYBOARD' + if strings.Contains(strings.ToLower(info.Name), "keyboard") { + number += 1 + } + } + return number +} + +func getExtraInfo(id int32) (devNode string, phys string) { + var devNodeBytes []byte + var length int32 + sessionType := os.Getenv("XDG_SESSION_TYPE") + isWaylandSession := strings.Contains(sessionType, "wayland") + if isWaylandSession { + devNode = fmt.Sprint("/dev/input/event", id) // id是从kwayland获取的sysname + } else { + devNodeBytes, length = dxutils.GetProperty(id, "Device Node") + if len(devNodeBytes) == 0 { + logger.Warningf("could not get DeviceNode for %d", id) + return + } + devNode = string(devNodeBytes[:length]) + } + udevDev := _gudevClient.QueryByDeviceFile(devNode) + if udevDev == nil { + logger.Warning("failed to get device of", devNode) + return + } + defer udevDev.Unref() + + phys = udevDev.GetSysfsAttr("phys") + if phys == "" { + parent := udevDev.GetParent() + if parent == nil { + logger.Warning("failed to get parent device of", devNode) + return + } + phys = parent.GetSysfsAttr("phys") + + parent.Unref() + } + + return +} + +func getTouchpadInfoByDxTouchpad(tmp *dxinput.Touchpad) *touchpadInfo { + m := &touchpadInfo{ + Touchpad: tmp, + } + + m.devNode, m.phys = getExtraInfo(tmp.Id) + + return m +} + +func getMouseInfoByDxMouse(tmp *dxinput.Mouse) *mouseInfo { + m := &mouseInfo{ + Mouse: tmp, + } + + m.devNode, m.phys = getExtraInfo(tmp.Id) + + return m +} + +func getMouseInfos(force bool) Mouses { + if !force && len(_mouseInfos) != 0 { + return _mouseInfos + } + + _mouseInfos = Mouses{} + for _, info := range getDeviceInfos(force) { + if info.Type == common.DevTypeMouse { + tmp, _ := dxinput.NewMouseFromDeviceInfo(info) + mouse := getMouseInfoByDxMouse(tmp) + + // phys 用来标识物理设备,若俩设备的 phys 相同,说明是同一物理设备, + // 若 phys 与某个触摸板的 phys 相同,说明是同一个设备(触摸板),忽略此鼠标设备 + found := false + for _, touchpad := range _tpadInfos { + logger.Warning(touchpad) + if touchpad.phys == mouse.phys { + found = true + break + } + } + + if found { + logger.Debug("mouse device ignored:", tmp.Name) + continue + } + + if mouse.phys != "" { + _mouseInfos = append(_mouseInfos, mouse) + logger.Debug("mouse device add:", mouse) + } + + } + } + + return _mouseInfos +} + +func isTPadPS2Mouse(name string) bool { + name = strings.ToLower(name) + return strings.Contains(name, "ps/2") && strings.Contains(name, "mouse") && !strings.Contains(name, "usb") +} + +func getTPadInfos(force, check bool) Touchpads { + if !force && len(_tpadInfos) != 0 { + return _tpadInfos + } + + _tpadInfos = Touchpads{} + for _, info := range getDeviceInfos(false) { + // 处理触控板被识别为PS2鼠标的情况 + if check && info.Type == common.DevTypeMouse && isTPadPS2Mouse(info.Name) { + tmp, err := dxinput.NewTouchpadFromDevInfo(info) + if err != nil { + logger.Warning(err) + } else { + _tpadInfos = append(_tpadInfos, getTouchpadInfoByDxTouchpad(tmp)) + } + continue + } + if info.Type == common.DevTypeTouchpad { + tmp, _ := dxinput.NewTouchpadFromDevInfo(info) + + _tpadInfos = append(_tpadInfos, getTouchpadInfoByDxTouchpad(tmp)) + } + } + + return _tpadInfos +} + +func getWacomInfos(force bool) dxWacoms { + if !force && len(_wacomInfos) != 0 { + return _wacomInfos + } + + _wacomInfos = dxWacoms{} + for _, info := range getDeviceInfos(false) { + if info.Type == common.DevTypeWacom { + tmp, _ := dxinput.NewWacomFromDevInfo(info) + _wacomInfos = append(_wacomInfos, tmp) + } + } + + return _wacomInfos +} + +func (infos Mouses) get(id int32) *dxinput.Mouse { + for _, info := range infos { + if info.Id == id { + return info.Mouse + } + } + return nil +} + +func (infos Mouses) string() string { + return toJSON(infos) +} + +func (infos Touchpads) get(id int32) *dxinput.Touchpad { + for _, info := range infos { + if info.Id == id { + return info.Touchpad + } + } + return nil +} + +func (infos Touchpads) string() string { + return toJSON(infos) +} + +func (infos dxWacoms) get(id int32) *dxinput.Wacom { + for _, info := range infos { + if info.Id == id { + return info + } + } + return nil +} + +func (infos dxWacoms) string() string { + return toJSON(infos) +} + +func toJSON(v interface{}) string { + data, _ := json.Marshal(v) + return string(data) +} diff --git a/keybinding/daemon.go b/keybinding/daemon.go deleted file mode 100644 index 2459d4392..000000000 --- a/keybinding/daemon.go +++ /dev/null @@ -1,99 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package keybinding - -import ( - "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/dde-daemon/keybinding/shortcuts" - "github.com/linuxdeepin/dde-daemon/loader" -) - -func init() { - loader.Register(NewDaemon(logger)) - shortcuts.SetLogger(logger) -} - -type Daemon struct { - *loader.ModuleBase - manager *Manager -} - -var ( - logger = log.NewLogger("daemon/keybinding") -) - -func NewDaemon(logger *log.Logger) *Daemon { - var d = new(Daemon) - d.ModuleBase = loader.NewModuleBase("keybinding", d, logger) - return d -} - -func (*Daemon) GetDependencies() []string { - return []string{} -} - -func (d *Daemon) Start() error { - if d.manager != nil { - return nil - } - var err error - - service := loader.GetService() - - loadConfig() - - d.manager, err = newManager(service) - if err != nil { - return err - } - - err = service.Export(dbusPath, d.manager) - if err != nil { - d.manager.destroy() - d.manager = nil - return err - } - - err = service.RequestName(dbusServiceName) - if err != nil { - d.manager.destroy() - d.manager = nil - return err - } - - go func() { - m := d.manager - m.initHandlers() - - // listen gsettings changed event - m.listenGSettingsChanged(gsSchemaSystem, d.manager.gsSystem, shortcuts.ShortcutTypeSystem) - m.listenGSettingsChanged(gsSchemaMediaKey, d.manager.gsMediaKey, shortcuts.ShortcutTypeMedia) - m.listenGSettingsChanged(gsSchemaGnomeWM, d.manager.gsGnomeWM, shortcuts.ShortcutTypeWM) - - m.listenSystemEnableChanged() - m.listenSystemPlatformChanged() - - m.eliminateKeystrokeConflict() - m.shortcutManager.EventLoop() - }() - - return nil -} - -func (d *Daemon) Stop() error { - if d.manager == nil { - return nil - } - - service := loader.GetService() - err := service.ReleaseName(dbusServiceName) - if err != nil { - logger.Warning(err) - } - - d.manager.destroy() - d.manager = nil - return nil -} diff --git a/keybinding/exported_methods_auto.go b/keybinding/exported_methods_auto.go deleted file mode 100644 index 25bbfbbbb..000000000 --- a/keybinding/exported_methods_auto.go +++ /dev/null @@ -1,138 +0,0 @@ -// Code generated by "dbusutil-gen em -type Manager"; DO NOT EDIT. - -package keybinding - -import ( - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (v *Manager) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "Add", - Fn: v.Add, - InArgs: []string{"name", "action", "keystroke"}, - OutArgs: []string{"ret0", "ret1"}, - }, - { - Name: "AddCustomShortcut", - Fn: v.AddCustomShortcut, - InArgs: []string{"name", "action", "keystroke"}, - OutArgs: []string{"id", "type0"}, - }, - { - Name: "AddShortcutKeystroke", - Fn: v.AddShortcutKeystroke, - InArgs: []string{"id", "type0", "keystroke"}, - }, - { - Name: "CheckAvaliable", - Fn: v.CheckAvaliable, - InArgs: []string{"keystroke"}, - OutArgs: []string{"available", "shortcut"}, - }, - { - Name: "ClearShortcutKeystrokes", - Fn: v.ClearShortcutKeystrokes, - InArgs: []string{"id", "type0"}, - }, - { - Name: "Delete", - Fn: v.Delete, - InArgs: []string{"id", "type0"}, - }, - { - Name: "DeleteCustomShortcut", - Fn: v.DeleteCustomShortcut, - InArgs: []string{"id"}, - }, - { - Name: "DeleteShortcutKeystroke", - Fn: v.DeleteShortcutKeystroke, - InArgs: []string{"id", "type0", "keystroke"}, - }, - { - Name: "Disable", - Fn: v.Disable, - InArgs: []string{"id", "type0"}, - }, - { - Name: "GetCapsLockState", - Fn: v.GetCapsLockState, - OutArgs: []string{"state"}, - }, - { - Name: "GetShortcut", - Fn: v.GetShortcut, - InArgs: []string{"id", "type0"}, - OutArgs: []string{"shortcut"}, - }, - { - Name: "GrabScreen", - Fn: v.GrabScreen, - }, - { - Name: "List", - Fn: v.List, - OutArgs: []string{"shortcuts"}, - }, - { - Name: "ListAllShortcuts", - Fn: v.ListAllShortcuts, - OutArgs: []string{"shortcuts"}, - }, - { - Name: "ListShortcutsByType", - Fn: v.ListShortcutsByType, - InArgs: []string{"type0"}, - OutArgs: []string{"shortcuts"}, - }, - { - Name: "LookupConflictingShortcut", - Fn: v.LookupConflictingShortcut, - InArgs: []string{"keystroke"}, - OutArgs: []string{"shortcut"}, - }, - { - Name: "ModifiedAccel", - Fn: v.ModifiedAccel, - InArgs: []string{"id", "type0", "keystroke", "add"}, - OutArgs: []string{"ret0", "ret1"}, - }, - { - Name: "ModifyCustomShortcut", - Fn: v.ModifyCustomShortcut, - InArgs: []string{"id", "name", "cmd", "keystroke"}, - }, - { - Name: "Query", - Fn: v.Query, - InArgs: []string{"id", "type0"}, - OutArgs: []string{"shortcut"}, - }, - { - Name: "Reset", - Fn: v.Reset, - }, - { - Name: "SearchShortcuts", - Fn: v.SearchShortcuts, - InArgs: []string{"query"}, - OutArgs: []string{"shortcuts"}, - }, - { - Name: "SelectKeystroke", - Fn: v.SelectKeystroke, - }, - { - Name: "SetCapsLockState", - Fn: v.SetCapsLockState, - InArgs: []string{"state"}, - }, - { - Name: "SetNumLockState", - Fn: v.SetNumLockState, - InArgs: []string{"state"}, - }, - } -} diff --git a/keybinding/manager.go b/keybinding/manager.go deleted file mode 100644 index 05876bace..000000000 --- a/keybinding/manager.go +++ /dev/null @@ -1,1202 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package keybinding - -import ( - "encoding/json" - "os" - "os/exec" - "path/filepath" - "strings" - "time" - - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/keybinding/shortcuts" - airplanemode "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.airplanemode" - backlight "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.helper.backlight" - inputdevices "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.inputdevices" - keyevent "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.keyevent" - kwayland "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.kwayland" - network "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.network" - lockfront "github.com/linuxdeepin/go-dbus-factory/com.deepin.dde.lockfront" - shutdownfront "github.com/linuxdeepin/go-dbus-factory/com.deepin.dde.shutdownfront" - sessionmanager "github.com/linuxdeepin/go-dbus-factory/com.deepin.sessionmanager" - power "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.power" - systeminfo "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.systeminfo" - wm "github.com/linuxdeepin/go-dbus-factory/com.deepin.wm" - configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" - DisplayManager "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.DisplayManager" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" - networkmanager "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.networkmanager" - gio "github.com/linuxdeepin/go-gir/gio-2.0" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/dbusutil/gsprop" - "github.com/linuxdeepin/go-lib/dbusutil/proxy" - "github.com/linuxdeepin/go-lib/gsettings" - "github.com/linuxdeepin/go-lib/xdg/basedir" - x "github.com/linuxdeepin/go-x11-client" - "github.com/linuxdeepin/go-x11-client/util/keysyms" -) - -//go:generate dbusutil-gen em -type Manager - -const ( - // shortcut signals: - shortcutSignalChanged = "Changed" - shortcutSignalAdded = "Added" - shortcutSignalDeleted = "Deleted" - - gsSchemaKeyboard = "com.deepin.dde.keyboard" - gsKeyNumLockState = "numlock-state" - gsKeySaveNumLockState = "save-numlock-state" - gsKeyShortcutSwitchLayout = "shortcut-switch-layout" - gsKeyShowCapsLockOSD = "capslock-toggle" - gsKeyUpperLayerWLAN = "upper-layer-wlan" - - gsSchemaSystem = "com.deepin.dde.keybinding.system" - gsSchemaSystemPlatform = "com.deepin.dde.keybinding.system.platform" - gsSchemaSystemEnable = "com.deepin.dde.keybinding.system.enable" - gsSchemaMediaKey = "com.deepin.dde.keybinding.mediakey" - gsSchemaGnomeWM = "com.deepin.wrap.gnome.desktop.wm.keybindings" - gsSchemaSessionPower = "com.deepin.dde.power" - - customConfigFile = "deepin/dde-daemon/keybinding/custom.ini" - CapslockKey = 58 - NumlockKey = 69 - KeyPress = 1 -) - -const ( - DSettingsAppID = "org.deepin.dde.daemon" - DSettingsKeyBindingName = "org.deepin.dde.daemon.keybinding" - DSettingsKeyWirelessControlEnable = "wirelessControlEnable" - DSettingsKeyNeedXrandrQDevices = "need-xrandr-q-devices" -) - -const ( // power按键事件的响应 - powerActionShutdown int32 = iota - powerActionSuspend - powerActionHibernate - powerActionTurnOffScreen - powerActionShowUI -) - -var _useWayland bool - -func setUseWayland(value bool) { - _useWayland = value -} - -type Manager struct { - service *dbusutil.Service - // properties - NumLockState gsprop.Enum - ShortcutSwitchLayout gsprop.Uint `prop:"access:rw"` - - conn *x.Conn - keySymbols *keysyms.KeySymbols - - gsKeyboard *gio.Settings - gsSystem *gio.Settings - gsSystemPlatform *gio.Settings - gsSystemEnable *gio.Settings - gsMediaKey *gio.Settings - gsGnomeWM *gio.Settings - gsPower *gio.Settings - - enableListenGSettings bool - delayNetworkStateChange bool - canExcuteSuspendOrHiberate bool - prepareForSleep bool - clickNum uint32 - shortcutCmd string - shortcutKey string - shortcutKeyCmd string - customShortcutManager *shortcuts.CustomShortcutManager - - lockFront lockfront.LockFront - shutdownFront shutdownfront.ShutdownFront - - sessionSigLoop *dbusutil.SignalLoop - systemSigLoop *dbusutil.SignalLoop - startManager sessionmanager.StartManager - sessionManager sessionmanager.SessionManager - airplane airplanemode.AirplaneMode - networkmanager networkmanager.Manager - backlightHelper backlight.Backlight - keyboard inputdevices.Keyboard - keyboardLayout string - wm wm.Wm - waylandOutputMgr kwayland.OutputManagement - login1Manager login1.Manager - keyEvent keyevent.KeyEvent - displayManager DisplayManager.DisplayManager - network network.Network - specialKeycodeBindingList map[SpecialKeycodeMapKey]func() - - // controllers - audioController *AudioController - mediaPlayerController *MediaPlayerController - displayController *DisplayController - kbdLightController *KbdLightController - touchPadController *TouchPadController - - shortcutManager *shortcuts.ShortcutManager - // shortcut action handlers - handlers []shortcuts.KeyEventFunc - lastKeyEventTime time.Time - lastMethodCalledTime time.Time - delayUpdateRfTimer *time.Timer - grabScreenKeystroke *shortcuts.Keystroke - - // for switch kbd layout - switchKbdLayoutState SKLState - sklWaitQuit chan int - - // dsg config - wifiControlEnable bool - needXrandrQDevice []string - - configManagerPath dbus.ObjectPath - - dmiInfo systeminfo.DMIInfo - rfkillState bool - repeatCount int - fnLockCount int - fnLocking bool - - // nolint - signals *struct { - Added, Deleted, Changed struct { - id string - typ int32 - } - - KeyEvent struct { - pressed bool - keystroke string - } - } -} - -// SKLState Switch keyboard Layout state -type SKLState uint - -const ( - SKLStateNone SKLState = iota - SKLStateWait - SKLStateOSDShown -) - -func newManager(service *dbusutil.Service) (*Manager, error) { - setUseWayland(strings.Contains(os.Getenv("XDG_SESSION_TYPE"), "wayland")) - conn, err := x.NewConn() - if err != nil { - return nil, err - } - - sessionBus := service.Conn() - sysBus, err := dbus.SystemBus() - if err != nil { - return nil, err - } - - var m = Manager{ - service: service, - enableListenGSettings: true, - conn: conn, - keySymbols: keysyms.NewKeySymbols(conn), - handlers: make([]shortcuts.KeyEventFunc, shortcuts.ActionTypeCount), - } - - m.sessionSigLoop = dbusutil.NewSignalLoop(sessionBus, 10) - m.systemSigLoop = dbusutil.NewSignalLoop(sysBus, 10) - - if _useWayland { - m.waylandOutputMgr = kwayland.NewOutputManagement(sessionBus) - } - m.login1Manager = login1.NewManager(sysBus) - m.login1Manager.InitSignalExt(m.systemSigLoop, true) - _, err = m.login1Manager.ConnectPrepareForSleep(func(isSleep bool) { - logger.Debugf("PreparingForSleep status changed, isSleep: %v", isSleep) - m.prepareForSleep = isSleep - // 待机或休眠时,唤醒后的1秒内不响应待机和休眠操作,避免按电源键唤醒时再次进入待机或休眠 - if !isSleep { - m.canExcuteSuspendOrHiberate = false - time.AfterFunc(1*time.Second, func() { - m.canExcuteSuspendOrHiberate = true - }) - } else { - m.canExcuteSuspendOrHiberate = false - } - }) - if err != nil { - logger.Warning("failed to connect signal PrepareForSleep:", err) - } - m.prepareForSleep, _ = m.login1Manager.PreparingForSleep().Get(0) - m.displayManager = DisplayManager.NewDisplayManager(sysBus) - m.shutdownFront = shutdownfront.NewShutdownFront(sessionBus) - m.gsKeyboard = gio.NewSettings(gsSchemaKeyboard) - m.NumLockState.Bind(m.gsKeyboard, gsKeyNumLockState) - m.ShortcutSwitchLayout.Bind(m.gsKeyboard, gsKeyShortcutSwitchLayout) - m.sessionSigLoop.Start() - m.systemSigLoop.Start() - - m.initNumLockState(sysBus) - m.initDSettings(sysBus) - - m.init() - - return &m, nil -} - -func (m *Manager) init() { - sessionBus := m.service.Conn() - sysBus, _ := dbus.SystemBus() - m.delayNetworkStateChange = true - m.canExcuteSuspendOrHiberate = true - - // init settings - m.gsSystem = gio.NewSettings(gsSchemaSystem) - m.gsSystemPlatform = gio.NewSettings(gsSchemaSystemPlatform) - m.gsSystemEnable = gio.NewSettings(gsSchemaSystemEnable) - m.gsMediaKey = gio.NewSettings(gsSchemaMediaKey) - m.gsPower = gio.NewSettings(gsSchemaSessionPower) - m.wm = wm.NewWm(sessionBus) - m.keyEvent = keyevent.NewKeyEvent(sysBus) - m.network = network.NewNetwork(sessionBus) - - m.shortcutManager = shortcuts.NewShortcutManager(m.conn, m.keySymbols, m.handleKeyEvent) - - // when session is locked, we need handle some keyboard function event - m.lockFront = lockfront.NewLockFront(sessionBus) - m.lockFront.InitSignalExt(m.sessionSigLoop, true) - m.lockFront.ConnectChangKey(func(changKey string) { - m.handleKeyEventFromLockFront(changKey) - }) - - m.shutdownFront = shutdownfront.NewShutdownFront(sessionBus) - m.shutdownFront.InitSignalExt(m.sessionSigLoop, true) - m.shutdownFront.ConnectChangKey(func(changKey string) { - m.handleKeyEventFromShutdownFront(changKey) - }) - - if _useWayland { - if shouldUseDDEKwin() { - m.shortcutManager.AddSpecialToKwin(m.wm) - m.shortcutManager.AddSystemToKwin(m.gsSystem, m.wm) - m.shortcutManager.AddMediaToKwin(m.gsMediaKey, m.wm) - m.shortcutManager.AddKWinForWayland(m.wm) - } else { - m.shortcutManager.AddSpecial() - m.shortcutManager.AddSystem(m.gsSystem, m.gsSystemPlatform, m.gsSystemEnable, m.wm) - m.shortcutManager.AddMedia(m.gsMediaKey, m.wm) - m.gsGnomeWM = gio.NewSettings(gsSchemaGnomeWM) - m.shortcutManager.AddWM(m.gsGnomeWM, m.wm) - } - } else { - m.shortcutManager.AddSystem(m.gsSystem, m.gsSystemPlatform, m.gsSystemEnable, m.wm) - m.shortcutManager.AddMedia(m.gsMediaKey, m.wm) - if shouldUseDDEKwin() { - logger.Debug("Use DDE KWin") - m.shortcutManager.AddKWin(m.wm) - } else { - logger.Debug("Use gnome WM") - m.gsGnomeWM = gio.NewSettings(gsSchemaGnomeWM) - m.shortcutManager.AddWM(m.gsGnomeWM, m.wm) - } - } - - // init custom shortcuts - customConfigFilePath := filepath.Join(basedir.GetUserConfigDir(), customConfigFile) - m.customShortcutManager = shortcuts.NewCustomShortcutManager(customConfigFilePath) - m.shortcutManager.AddCustom(m.customShortcutManager, m.wm) - - // init controllers - m.backlightHelper = backlight.NewBacklight(sysBus) - m.audioController = NewAudioController(sessionBus, m.backlightHelper) - m.mediaPlayerController = NewMediaPlayerController(m.systemSigLoop, sessionBus) - - m.startManager = sessionmanager.NewStartManager(sessionBus) - m.airplane = airplanemode.NewAirplaneMode(sysBus) - m.networkmanager = networkmanager.NewManager(sysBus) - m.sessionManager = sessionmanager.NewSessionManager(sessionBus) - m.keyboard = inputdevices.NewKeyboard(sessionBus) - m.keyboard.InitSignalExt(m.sessionSigLoop, true) - err := m.keyboard.CurrentLayout().ConnectChanged(func(hasValue bool, layout string) { - if !hasValue { - return - } - if m.keyboardLayout != layout { - m.keyboardLayout = layout - logger.Debug("keyboard layout changed:", layout) - m.shortcutManager.NotifyLayoutChanged() - } - }) - - if err != nil { - logger.Warning("connect CurrentLayout property changed failed:", err) - } - - m.displayController = NewDisplayController(m.backlightHelper, sessionBus, m) - m.kbdLightController = NewKbdLightController(m.backlightHelper) - m.touchPadController = NewTouchPadController(sessionBus) - - m.initSpecialKeycodeMap() - m.keyEvent.InitSignalExt(m.systemSigLoop, true) - _, err = m.keyEvent.ConnectKeyEvent(m.handleSpecialKeycode) - if err != nil { - logger.Warning(err) - } - - sysInfo := systeminfo.NewSystemInfo(sysBus) - dmiInfo, err := sysInfo.DMIInfo().Get(0) - if err != nil { - logger.Warning(err) - } else { - m.dmiInfo = dmiInfo - } - - if _useWayland { - m.initHandlers() - m.clickNum = 0 - - go m.listenGlobalAccel(sessionBus) - go m.listenKeyboardEvent(sysBus) - } - - m.rfkillState, err = m.airplane.Enabled().Get(0) - if err != nil { - logger.Warning(err) - } else { - logger.Info("init rfkillState : ", m.rfkillState) - } -} - -func (m *Manager) initDSettings(bus *dbus.Conn) { - ds := configManager.NewConfigManager(bus) - dsPath, err := ds.AcquireManager(0, DSettingsAppID, DSettingsKeyBindingName, "") - if err != nil { - logger.Warning(err) - return - } - - keybindingDS, err := configManager.NewManager(bus, dsPath) - if err != nil { - logger.Warning(err) - return - } - - getWirelessControlEnableConfig := func() { - v, err := keybindingDS.Value(0, DSettingsKeyWirelessControlEnable) - if err != nil { - logger.Warning(err) - return - } - m.wifiControlEnable = v.Value().(bool) - } - getNeedXrandrQConfig := func() { - v, err := keybindingDS.Value(0, DSettingsKeyNeedXrandrQDevices) - if err != nil { - logger.Warning(err) - return - } - itemList := v.Value().([]dbus.Variant) - for _, i := range itemList { - m.needXrandrQDevice = append(m.needXrandrQDevice, i.Value().(string)) - } - } - - getWirelessControlEnableConfig() - getNeedXrandrQConfig() - - keybindingDS.InitSignalExt(m.systemSigLoop, true) - // 监听dsg配置变化 - _, err = keybindingDS.ConnectValueChanged(func(key string) { - switch key { - case DSettingsKeyWirelessControlEnable: - getWirelessControlEnableConfig() - case DSettingsKeyNeedXrandrQDevices: - getNeedXrandrQConfig() - } - }) - if err != nil { - logger.Warning(err) - } -} - -var kwinSysActionCmdMap = map[string]string{ - "Launcher": "launcher", // Super_L Super_R - "Terminal": "terminal", // T - "Terminal Quake Window": "terminal-quake", // - "Lock screen": "lock-screen", // super+l - "Shutdown interface": "logout", // ctrl+alt+del - "File manager": "file-manager", // super+e - "Screenshot": "screenshot", // ctrl+alt+a - "Full screenshot": "screenshot-fullscreen", // print - "Window screenshot": "screenshot-window", // alt+print - "Delay screenshot": "screenshot-delayed", // ctrl+print - "Disable Touchpad": "disable-touchpad", // - "Switch window effects": "wm-switcher", // alt+tab - "turn-off-screen": "Fast Screen Off", // L - "Deepin Picker": "color-picker", // ctrl+alt+v - "System Monitor": "system-monitor", // ctrl+alt+escape - "Screen Recorder": "deepin-screen-recorder", // deepin-screen-recorder ctrl+alt+r - "Desktop AI Assistant": "ai-assistant", // ai-assistant [Q]q - "Text to Speech": "text-to-speech", - "Speech to Text": "speech-to-text", - "Clipboard": "clipboard", - "Translation": "translation", - "Show/Hide the dock": "show-dock", - - // cmd - "Calculator": "calculator", // XF86Calculator - "Search": "search", // XF86Search - "Notification Center": "notification-center", // Meta M - - "ScreenshotScroll": "screenshot-scroll", - "ScreenshotOcr": "screenshot-ocr", - "Global Search": "global-search", - "Switch monitors": "switch-monitors", -} - -var waylandMediaIdMap = map[string]string{ - "Messenger": "messenger", // XF86Messenger - "Save": "save", // XF86Save - "New": "new", // XF86New - "WakeUp": "wake-up", // XF86WakeUp - "audio-rewind": "AudioRewind", // XF86AudioRewind - "VolumeMute": "audio-mute", // XF86AudioMute "AudioMute": - "MonBrightnessUp": "mon-brightness-up", // XF86MonBrightnessUp - "WLAN": "wlan", // XF86WLAN - "AudioMedia": "audio-media", // XF86AudioMedia - "reply": "Reply", // XF86Reply - "favorites": "Favorites", // XF86Favorites - "AudioPlay": "audio-play", // XF86AudioPlay - "AudioMicMute": "audio-mic-mute", // XF86AudioMicMute - "AudioPause": "audio-pause", // XF86AudioPause - "AudioStop": "audio-stop", // XF86AudioStop - "documents": "Documents", // XF86Documents - "game": "Game", // XF86Game - "AudioRecord": "audio-record", // XF86AudioRecord - "Display": "display", // XF86Display - "reload": "Reload", // XF86Reload - "explorer": "Explorer", // XF86Explorer - "calendar": "Calendar", // XF86Calendar - "forward": "Forward", // XF86Forward - "cut": "Cut", // XF86Cut - "MonBrightnessDown": "mon-brightness-down", // XF86MonBrightnessDown - "Copy": "copy", // XF86Copy - "Tools": "tools", // XF86Tools - "VolumeUp": "audio-raise-volume", // XF86AudioRaiseVolume "AudioRaiseVolume": "audio-raise-volume", - "media-close": "media-Close", // XF86Close - "WWW": "www", // XF86WWW - "HomePage": "home-page", // XF86HomePage - "sleep": "Sleep", // XF86Sleep - "VolumeDown": "audio-lower-volume", // XF86AudioLowerVolume "AudioLowerVolume": "audio-lower-volume", - "AudioPrev": "audio-prev", // XF86AudioPrev - "AudioNext": "audio-next", // XF86AudioNext - "Paste": "paste", // XF86Paste - "open": "Open", // XF86Open - "send": "Send", // XF86Send - "my-computer": "MyComputer", // XF86MyComputer - "Mail": "mail", // XF86Mail - "adjust-brightness": "BrightnessAdjust", // XF86BrightnessAdjust - "LogOff": "log-off", // XF86LogOff - "pictures": "Pictures", // XF86Pictures - "Terminal": "terminal", // XF86Terminal - "video": "Video", // XF86Video - "Music": "music", // XF86Music - "app-left": "ApplicationLeft", // XF86ApplicationLeft - "app-right": "ApplicationRight", // XF86ApplicationRight - "meeting": "Meeting", // XF86Meeting - "Numlock": "numlock", - "Capslock": "capslock", - "Switch kbd layout": "switch-kbd-layout", -} - -func (m *Manager) listenGlobalAccel(sessionBus *dbus.Conn) error { - err := sessionBus.Object("org.kde.kglobalaccel", - "/component/kwin").AddMatchSignal("org.kde.kglobalaccel.Component", "globalShortcutPressed").Err - if err != nil { - logger.Warning(err) - return err - } - - m.sessionSigLoop.AddHandler(&dbusutil.SignalRule{ - Name: "org.kde.kglobalaccel.Component.globalShortcutPressed", - }, func(sig *dbus.Signal) { - if len(sig.Body) > 1 { - const minKeyEventInterval = 200 * time.Millisecond - now := time.Now() - duration := now.Sub(m.lastKeyEventTime) - if 0 < duration && duration < minKeyEventInterval { - logger.Debug("ignore key event duration:", duration) - return - } - m.lastKeyEventTime = now - - m.shortcutKey = sig.Body[0].(string) - m.shortcutKeyCmd = sig.Body[1].(string) - ok := strings.Compare(string("kwin"), m.shortcutKey) - if ok == 0 { - logger.Debug("[global key] get accel sig.Body[1]", m.shortcutKeyCmd) - if m.shortcutKeyCmd == "" { - // + 把响应一次的逻辑放到协程外执行,防止协程响应延迟 - m.handleKeyEventByWayland(waylandMediaIdMap[m.shortcutKeyCmd]) - } else { - m.shortcutCmd = shortcuts.GetSystemActionCmd(kwinSysActionCmdMap[m.shortcutKeyCmd]) - if m.shortcutCmd == "" { - m.shortcutCmd = m.shortcutManager.WaylandCustomShortCutMap[m.shortcutKeyCmd] - } - logger.Debug("WaylandCustomShortCutMap", m.shortcutCmd) - if m.shortcutCmd == "" { - m.handleKeyEventByWayland(waylandMediaIdMap[m.shortcutKeyCmd]) - } else { - if strings.HasSuffix(m.shortcutCmd, ".desktop") { - err := m.runDesktopFile(m.shortcutCmd) - if err != nil { - logger.Warning(err) - } - } else { - go func() { - err := m.execCmd(m.shortcutCmd, true) - if err != nil { - logger.Warning(err) - } - }() - } - } - } - } - } - }) - - return nil -} - -func (m *Manager) listenKeyboardEvent(systemBus *dbus.Conn) { - err := systemBus.Object("com.deepin.daemon.Gesture", - "/com/deepin/daemon/Gesture").AddMatchSignal("com.deepin.daemon.Gesture", "KeyboardEvent").Err - if err != nil { - logger.Warning(err) - } - m.systemSigLoop.AddHandler(&dbusutil.SignalRule{ - Name: "com.deepin.daemon.Gesture.KeyboardEvent", - }, func(sig *dbus.Signal) { - if len(sig.Body) > 1 { - key := sig.Body[0].(uint32) - value := sig.Body[1].(uint32) - - if key == CapslockKey && value == KeyPress { - m.handleKeyEventByWayland("capslock") - } else if key == NumlockKey && value == KeyPress { - m.handleKeyEventByWayland("numlock") - } - } - }) -} - -// 初始化 NumLock 数字锁定键状态 -func (m *Manager) initNumLockState(sysBus *dbus.Conn) { - // 从 gsettings 读取相关设置 - nlState := NumLockState(m.NumLockState.Get()) - saveStateEnabled := m.gsKeyboard.GetBoolean(gsKeySaveNumLockState) - if nlState == NumLockUnknown { - // 判断是否是笔记本, 只根据电池状态,有电池则是笔记本。 - isLaptop := false - sysPower := power.NewPower(sysBus) - hasBattery, err := sysPower.HasBattery().Get(0) - if err != nil { - logger.Warning("failed to get sysPower HasBattery property:", err) - } else if hasBattery { - isLaptop = true - } - - state := NumLockUnknown - logger.Debug("isLaptop:", isLaptop) - if isLaptop { - // 笔记本,默认关闭。 - state = NumLockOff - } else { - // 台式机等,默认开启。 - state = NumLockOn - } - - if saveStateEnabled { - // 保存新状态到 gsettings - m.NumLockState.Set(int32(state)) - } - - err = setNumLockState(m.waylandOutputMgr, m.conn, m.keySymbols, state) - if err != nil { - logger.Warning("setNumLockState failed:", err) - } - } else { - if saveStateEnabled { - err := setNumLockState(m.waylandOutputMgr, m.conn, m.keySymbols, nlState) - if err != nil { - logger.Warning("setNumLockState failed:", err) - } - } - } - -} - -// 检查快捷键时间间隔,如果间隔太短返回false,不应该响应快捷键 -func (m *Manager) checkKeyEventInterval() bool { - const minKeyEventInterval = 200 * time.Millisecond - now := time.Now() - duration := now.Sub(m.lastKeyEventTime) - if 0 < duration && duration < minKeyEventInterval { - logger.Debug("handleKeyEvent ignore key event duration:", duration) - return false - } - m.lastKeyEventTime = now - return true -} - -func (m *Manager) handleKeyEventFromLockFront(changKey string) { - if !m.checkKeyEventInterval() { - return - } - logger.Debugf("Receive LockFront ChangKey Event %s", changKey) - action := shortcuts.GetAction(changKey) - - // numlock/capslock - if action.Type == shortcuts.ActionTypeShowNumLockOSD || - action.Type == shortcuts.ActionTypeShowCapsLockOSD || - action.Type == shortcuts.ActionTypeSystemShutdown { - if handler := m.handlers[int(action.Type)]; handler != nil { - handler(nil) - } else { - logger.Warning("handler is nil") - } - } else { - cmd, ok := action.Arg.(shortcuts.ActionCmd) - if !ok { - logger.Warning(errTypeAssertionFail) - } else { - if action.Type == shortcuts.ActionTypeAudioCtrl { - // audio-mute/audio-lower-volume/audio-raise-volume - if m.audioController != nil { - if err := m.audioController.ExecCmd(cmd); err != nil { - logger.Warning(m.audioController.Name(), "Controller exec cmd err:", err) - } - } - } else if action.Type == shortcuts.ActionTypeDisplayCtrl { - // mon-brightness-up/mon-brightness-down - if m.displayController != nil { - if err := m.displayController.ExecCmd(cmd); err != nil { - logger.Warning(m.displayController.Name(), "Controller exec cmd err:", err) - } - } - } else if action.Type == shortcuts.ActionTypeTouchpadCtrl { - // touchpad-toggle/touchpad-on/touchpad-off - if m.touchPadController != nil { - if err := m.touchPadController.ExecCmd(cmd); err != nil { - logger.Warning(m.touchPadController.Name(), "Controller exec cmd err:", err) - } - } - } - } - } -} - -func (m *Manager) handleKeyEventByWayland(changKey string) { - action := shortcuts.GetAction(changKey) - var isWaylandGrabed bool = false - if _useWayland { - isWaylandGrabed = true - if action.Type == shortcuts.ActionTypeShowNumLockOSD || action.Type == shortcuts.ActionTypeShowCapsLockOSD { - sessionBus, err := dbus.SessionBus() - if err != nil { - return - } - sessionObj := sessionBus.Object("org.kde.KWin", "/KWin") - err = sessionObj.Call("org.kde.KWin.xwaylandGrabed", 0).Store(&isWaylandGrabed) - if err != nil { - logger.Warning(err) - return - } - logger.Debug("xwaylandGrabed: ", isWaylandGrabed) - } - } - // numlock/capslock - if action.Type == shortcuts.ActionTypeSystemShutdown { - var powerPressAction int32 - systemBus, _ := dbus.SystemBus() - systemPower := power.NewPower(systemBus) - onBattery, err := systemPower.OnBattery().Get(0) - if err != nil { - logger.Error(err) - } - if onBattery { - powerPressAction = m.gsPower.GetEnum("battery-press-power-button") - } else { - powerPressAction = m.gsPower.GetEnum("line-power-press-power-button") - } - logger.Debug("powerPressAction:", powerPressAction) - switch powerPressAction { - case powerActionShutdown: - m.systemShutdown() - case powerActionSuspend: - systemSuspend() - case powerActionHibernate: - m.systemHibernate() - case powerActionTurnOffScreen: - m.systemTurnOffScreen() - case powerActionShowUI: - cmd := "dde-shutdown" - go func() { - err := m.execCmd(cmd, false) - if err != nil { - logger.Warning("execCmd error:", err) - } - }() - } - } else if action.Type == shortcuts.ActionTypeShowControlCenter { - err := m.execCmd("dbus-send --session --dest=com.deepin.dde.ControlCenter --print-reply /com/deepin/dde/ControlCenter com.deepin.dde.ControlCenter.Show", - false) - if err != nil { - logger.Warning("failed to show control center:", err) - } - - } else if action.Type == shortcuts.ActionTypeToggleWireless { - // 如果已经开启了飞行模式,则不能通过快捷键去控制wifi的使能 - enabled, err := m.airplane.Enabled().Get(0) - if err != nil { - logger.Warningf("get airplane enabled failed, err: %v", err) - return - } - - if enabled { - logger.Debug("airplane mode enabled, can not enable wireless by key") - return - } - - // check if allow set wireless - // and check if Wifi shortcut effected by DDE software - if m.gsMediaKey.GetBoolean(gsKeyUpperLayerWLAN) && m.wifiControlEnable { - enabled, err := m.airplane.WifiEnabled().Get(0) - if err != nil { - logger.Warningf("get wireless enabled failed, err: %v", err) - return - } - // FIXME: 修复NM WiFi无法恢复bug, 使快捷键能够恢复WiFi问题 - if !enabled { - if devicesJson, err := m.network.Devices().Get(0); err == nil { - networkDevices := make(map[string][]*networkDevice) - json.Unmarshal([]byte(devicesJson), &networkDevices) - for _, wifiDevice := range networkDevices["wireless"] { - if wifiDevice.InterfaceFlags == 0 { - // wifi里有未up的网络接口时尝试重置下wifi网络 - logger.Info("rest wifi, because some link down") - if err := m.networkmanager.WirelessEnabled().Set(0, false); err != nil { - logger.Warning(err) - } - if err := m.networkmanager.WirelessEnabled().Set(0, true); err != nil { - logger.Warning(err) - } - break - } - } - } - } - err = m.airplane.EnableWifi(0, !enabled) - if err != nil { - logger.Warningf("set wireless enabled failed, err: %v", err) - return - } - } - } else if action.Type == shortcuts.ActionTypeShowNumLockOSD { - var state NumLockState - if !isWaylandGrabed { - if _useWayland { - sessionBus, err := dbus.SessionBus() - if err != nil { - return - } - time.Sleep(200 * time.Millisecond) // + 添加200ms延时,保证在dde-system-daemon中先获取状态; - sessionObj := sessionBus.Object("org.kde.KWin", "/Xkb") - var ret int32 - err = sessionObj.Call("org.kde.kwin.Xkb.getLeds", 0).Store(&ret) - if err != nil { - logger.Warning(err) - return - } - if 0 == (ret & 0x1) { - state = NumLockOff - } else { - state = NumLockOn - } - } else { - var err error - state, err = queryNumLockState(m.conn) - if err != nil { - logger.Warning(err) - return - } - } - - save := m.gsKeyboard.GetBoolean(gsKeySaveNumLockState) - - switch state { - case NumLockOn: - if save { - m.NumLockState.Set(int32(NumLockOn)) - } - showOSD("NumLockOn") - case NumLockOff: - if save { - m.NumLockState.Set(int32(NumLockOff)) - } - showOSD("NumLockOff") - } - } - } else if action.Type == shortcuts.ActionTypeShowCapsLockOSD { - if !m.shouldShowCapsLockOSD() { - return - } - - if !isWaylandGrabed { - var state CapsLockState - if _useWayland { - sessionBus, err := dbus.SessionBus() - if err != nil { - return - } - time.Sleep(200 * time.Millisecond) // + 添加200ms延时,保证在dde-system-daemon中先获取状态; - sessionObj := sessionBus.Object("org.kde.KWin", "/Xkb") - var ret int32 - err = sessionObj.Call("org.kde.kwin.Xkb.getLeds", 0).Store(&ret) - if err != nil { - logger.Warning(err) - return - } - if 0 == (ret & 0x2) { - state = CapsLockOff - } else { - state = CapsLockOn - } - } else { - state, err := queryCapsLockState(m.conn) - if err != nil { - logger.Warning(err) - return - } - logger.Debug("caps:", state) - } - - switch state { - case CapsLockOff: - showOSD("CapsLockOff") - case CapsLockOn: - showOSD("CapsLockOn") - } - } - } else if action.Type == shortcuts.ActionTypeSwitchKbdLayout { - switch m.switchKbdLayoutState { - case SKLStateNone: - m.switchKbdLayoutState = SKLStateWait - go m.sklWait() - - case SKLStateWait: - m.switchKbdLayoutState = SKLStateOSDShown - m.terminateSKLWait() - showOSD("SwitchLayout") - - case SKLStateOSDShown: - showOSD("SwitchLayout") - } - } else { - cmd, ok := action.Arg.(shortcuts.ActionCmd) - if !ok { - logger.Warning(errTypeAssertionFail) - } else { - if action.Type == shortcuts.ActionTypeAudioCtrl { - // audio-mute/audio-lower-volume/audio-raise-volume - if m.audioController != nil { - if err := m.audioController.ExecCmd(cmd); err != nil { - logger.Warning(m.audioController.Name(), "Controller exec cmd err:", err) - } - } - } else if action.Type == shortcuts.ActionTypeDisplayCtrl { - // mon-brightness-up/mon-brightness-down - if m.displayController != nil { - if err := m.displayController.ExecCmd(cmd); err != nil { - logger.Warning(m.displayController.Name(), "Controller exec cmd err:", err) - } - } - } else if action.Type == shortcuts.ActionTypeTouchpadCtrl { - // touchpad-toggle/touchpad-on/touchpad-off - if m.touchPadController != nil { - if err := m.touchPadController.ExecCmd(cmd); err != nil { - logger.Warning(m.touchPadController.Name(), "Controller exec cmd err:", err) - } - } - } else if action.Type == shortcuts.ActionTypeSystemShutdown { - - } else if action.Type == shortcuts.ActionTypeMediaPlayerCtrl { - // 增蓝牙耳机快捷键的处理 - if cmd == shortcuts.MediaPlayerPlay { - m.clickNum = m.clickNum + 1 - if m.clickNum == 1 { - time.AfterFunc(time.Millisecond*600, func() { - m.playMeadiaByHeadphone() - }) - } - } else { - if m.mediaPlayerController != nil { - err := m.mediaPlayerController.ExecCmd(cmd) - if err != nil { - logger.Warning(m.mediaPlayerController.Name(), "Controller exec cmd err:", err) - } - } - } - - } - } - } -} - -func getMediaPlayAction(num uint32) shortcuts.ActionCmd { - var cmd shortcuts.ActionCmd = shortcuts.MediaPlayerPlay - if num == 2 { - cmd = shortcuts.MediaPlayerNext - } else if num == 3 { - cmd = shortcuts.MediaPlayerPrevious - } else { - cmd = shortcuts.MediaPlayerPlay - } - return cmd -} - -func (m *Manager) playMeadiaByHeadphone() { - cmd := getMediaPlayAction(m.clickNum) - m.clickNum = 0 - if m.mediaPlayerController != nil { - err := m.mediaPlayerController.ExecCmd(cmd) - if err != nil { - logger.Warning(m.mediaPlayerController.Name(), "Controller exec cmd err:", err) - } - } -} - -func (m *Manager) handleKeyEventFromShutdownFront(changKey string) { - logger.Debugf("handleKeyEvent %s from ShutdownFront", changKey) - action := shortcuts.GetAction(changKey) - if action.Type == shortcuts.ActionTypeSystemShutdown { - if handler := m.handlers[int(action.Type)]; handler != nil { - handler(nil) - } else { - logger.Warning("handler [system shutdown] is nil") - } - } -} - -func (m *Manager) destroy() { - err := m.service.StopExport(m) - if err != nil { - logger.Warning("stop export failed:", err) - } - - if m.shortcutManager != nil { - m.shortcutManager.Destroy() - m.shortcutManager = nil - } - - // destroy settings - if m.gsSystem != nil { - m.gsSystem.Unref() - m.gsSystem = nil - } - - if m.gsMediaKey != nil { - m.gsMediaKey.Unref() - m.gsMediaKey = nil - } - - if m.gsGnomeWM != nil { - m.gsGnomeWM.Unref() - m.gsGnomeWM = nil - } - - if m.audioController != nil { - m.audioController.Destroy() - m.audioController = nil - } - - if m.mediaPlayerController != nil { - m.mediaPlayerController.Destroy() - m.mediaPlayerController = nil - } - - if m.keyboard != nil { - m.keyboard.RemoveHandler(proxy.RemoveAllHandlers) - m.keyboard = nil - } - - if m.keyEvent != nil { - m.keyEvent.RemoveHandler(proxy.RemoveAllHandlers) - m.keyEvent = nil - } - - if m.sessionSigLoop != nil { - m.sessionSigLoop.Stop() - m.sessionSigLoop = nil - } - - if m.systemSigLoop != nil { - m.systemSigLoop.Stop() - m.systemSigLoop = nil - } - - if m.conn != nil { - m.conn.Close() - m.conn = nil - } -} - -func (m *Manager) handleKeyEvent(ev *shortcuts.KeyEvent) { - if !m.checkKeyEventInterval() { - return - } - logger.Debugf("handleKeyEvent ev: %#v", ev) - action := ev.Shortcut.GetAction() - shortcutId := ev.Shortcut.GetId() - logger.Debugf("shortcut id: %s, type: %v, action: %#v", - shortcutId, ev.Shortcut.GetType(), action) - if action == nil { - logger.Warning("action is nil") - return - } - if len(m.handlers) == 0 { - logger.Warning("handlers is nil") - return - } - if handler := m.handlers[int(action.Type)]; handler != nil { - handler(ev) - } else { - logger.Warning("handler is nil") - } -} - -func (m *Manager) emitShortcutSignal(signalName string, shortcut shortcuts.Shortcut) { - logger.Debug("emit DBus signal", signalName, shortcut.GetId(), shortcut.GetType()) - err := m.service.Emit(m, signalName, shortcut.GetId(), shortcut.GetType()) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) enableListenGSettingsChanged(val bool) { - m.enableListenGSettings = val -} - -func (m *Manager) listenGSettingsChanged(schema string, settings *gio.Settings, type0 int32) { - gsettings.ConnectChanged(schema, "*", func(key string) { - if !m.enableListenGSettings { - return - } - - shortcut := m.shortcutManager.GetByIdType(key, type0) - if shortcut == nil { - return - } - - keystrokes := settings.GetStrv(key) - m.shortcutManager.ModifyShortcutKeystrokes(shortcut, shortcuts.ParseKeystrokes(keystrokes)) - m.emitShortcutSignal(shortcutSignalChanged, shortcut) - }) -} - -func (m *Manager) listenSystemEnableChanged() { - gsettings.ConnectChanged(gsSchemaSystemEnable, "*", func(key string) { - if !m.enableListenGSettings { - return - } - - if m.shortcutManager.CheckSystem(m.gsSystemPlatform, m.gsSystemEnable, key) { - m.shortcutManager.AddSystemById(m.gsSystem, m.wm, key) - } else { - m.shortcutManager.DelSystemById(key) - } - }) -} - -func (m *Manager) listenSystemPlatformChanged() { - gsettings.ConnectChanged(gsSchemaSystemPlatform, "*", func(key string) { - if !m.enableListenGSettings { - return - } - - if m.shortcutManager.CheckSystem(m.gsSystemPlatform, m.gsSystemEnable, key) { - m.shortcutManager.AddSystemById(m.gsSystem, m.wm, key) - } else { - m.shortcutManager.DelSystemById(key) - } - }) -} - -func runCommand(cmd string) (string, error) { - result, err := exec.Command("/bin/sh", "-c", cmd).Output() - if err != nil { - return "", err - } - return strings.TrimSpace(string(result)), err -} - -func checkProRunning(serverName string) bool { - cmd := `ps ux | awk '/` + serverName + `/ && !/awk/ {print $2}'` - pid, err := runCommand(cmd) - if err != nil { - logger.Warning(err) - return false - } - return pid != "" -} - -func (m *Manager) execCmd(cmd string, viaStartdde bool) error { - if cmd == "" { - logger.Debug("cmd is empty") - return nil - } - if strings.HasPrefix(cmd, "dbus-send ") || !viaStartdde { - logger.Debug("run cmd:", cmd) - // #nosec G204 - return exec.Command("/bin/sh", "-c", cmd).Run() - } - - logger.Debug("startdde run cmd:", cmd) - return m.startManager.RunCommand(0, "/bin/sh", []string{"-c", cmd}) -} - -func (m *Manager) handleCheckCamera() error { - cmd := "deepin-camera" - if checkProRunning(cmd) { - cmd = "killall deepin-camera" - } - return m.startManager.RunCommand(0, "/bin/sh", []string{"-c", cmd}) -} - -func (m *Manager) runDesktopFile(desktop string) error { - return m.startManager.LaunchApp(0, desktop, 0, []string{}) -} - -func (m *Manager) eliminateKeystrokeConflict() { - for _, ks := range m.shortcutManager.ConflictingKeystrokes { - shortcut := ks.Shortcut - logger.Infof("eliminate conflict shortcut: %s keystroke: %s", - ks.Shortcut.GetUid(), ks) - err := m.DeleteShortcutKeystroke(shortcut.GetId(), shortcut.GetType(), ks.String()) - if err != nil { - logger.Warning("delete shortcut keystroke failed:", err) - } - } - - m.shortcutManager.ConflictingKeystrokes = nil - m.shortcutManager.EliminateConflictDone = true -} diff --git a/keybinding/manager_ifc.go b/keybinding/manager_ifc.go deleted file mode 100644 index 48f0618f9..000000000 --- a/keybinding/manager_ifc.go +++ /dev/null @@ -1,517 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package keybinding - -import ( - "errors" - "fmt" - "strings" - "time" - - "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/keybinding/shortcuts" - "github.com/linuxdeepin/dde-daemon/keybinding/util" - wm "github.com/linuxdeepin/go-dbus-factory/com.deepin.wm" - "github.com/linuxdeepin/go-gir/gio-2.0" - "github.com/linuxdeepin/go-lib/dbusutil" -) - -const ( - dbusServiceName = "com.deepin.daemon.Keybinding" - dbusPath = "/com/deepin/daemon/Keybinding" - dbusInterface = "com.deepin.daemon.Keybinding" -) - -type ErrInvalidShortcutType struct { - Type int32 -} - -func (err ErrInvalidShortcutType) Error() string { - return fmt.Sprintf("shortcut type %v is invalid", err.Type) -} - -type ErrShortcutNotFound struct { - Id string - Type int32 -} - -func (err ErrShortcutNotFound) Error() string { - return fmt.Sprintf("shortcut id %q type %v is not found", err.Id, err.Type) -} - -var errTypeAssertionFail = errors.New("type assertion failed") -var errShortcutKeystrokesUnmodifiable = errors.New("keystrokes of this shortcut is unmodifiable") -var errKeystrokeUsed = errors.New("keystroke had been used") -var errNameUsed = errors.New("name had been used") - -func (*Manager) GetInterfaceName() string { - return dbusInterface -} - -//true : ignore -func (m *Manager) isIgnoreRepeat(name string) bool { - const minKeyEventInterval = 200 * time.Millisecond - now := time.Now() - duration := now.Sub(m.lastMethodCalledTime) - logger.Debug("duration:", duration) - if 0 < duration && duration < minKeyEventInterval { - logger.Debug(">>Ignore ", name) - return true - } - m.lastMethodCalledTime = now - return false -} - -func (m *Manager) setAccelForWayland(gsettings *gio.Settings, wmObj wm.Wm) { - for _, id := range gsettings.ListKeys() { - var accelJson string - var err error - if id == "screenshot-window" { - accelJson = `{"Id":"screenshot-window","Accels":["SysReq"]}` //+ Alt+print对应kwin识别的键SysReq - } else if id == "launcher" { - accelJson = `{"Id":"launcher","Accels":["Super_L"]}` // wayland左右super对应的都是Super_L - } else if id == "system_monitor" { - accelJson = `{"Id":"system_monitor","Accels":["Escape"]}` - } else { - accelJson, err = util.MarshalJSON(util.KWinAccel{ - Id: id, - Keystrokes: gsettings.GetStrv(id), - }) - if err != nil { - logger.Warning("failed to get json:", err) - continue - } - } - - ok, err := wmObj.SetAccel(0, accelJson) - if !ok { - logger.Warning("failed to set KWin accels:", id, gsettings.GetStrv(id), err) - } - } -} - -// Reset reset all shortcut -func (m *Manager) Reset() *dbus.Error { - if m.isIgnoreRepeat("Reset") { - return nil - } - - customShortcuts := m.customShortcutManager.List() - m.shortcutManager.UngrabAll() - - m.enableListenGSettingsChanged(false) - // reset all gsettings - resetGSettings(m.gsSystem) - resetGSettings(m.gsMediaKey) - if m.gsGnomeWM != nil { - resetGSettings(m.gsGnomeWM) - } - if _useWayland { - m.setAccelForWayland(m.gsSystem, m.wm) - m.setAccelForWayland(m.gsMediaKey, m.wm) - if m.gsGnomeWM != nil { - m.setAccelForWayland(m.gsGnomeWM, m.wm) - } - } - - // reset for KWin - if shouldUseDDEKwin() { - err := resetKWin(m.wm) - if err != nil { - logger.Warning("failed to reset for KWin:", err) - } - // 由于快捷键冲突原因,有必要重置两遍 - err = resetKWin(m.wm) - if err != nil { - logger.Warning("failed to reset for KWin:", err) - } - } - - changes := m.shortcutManager.ReloadAllShortcutsKeystrokes() - m.enableListenGSettingsChanged(true) - m.shortcutManager.GrabAll() - - for _, cs := range customShortcuts { - keystrokes := cs.GetKeystrokes() - var newKeystrokes []*shortcuts.Keystroke - modifyFlag := false - for _, keystroke := range keystrokes { - conflictKeystroke, err := m.shortcutManager.FindConflictingKeystroke(keystroke) - if err != nil { - logger.Warning(err) - modifyFlag = true - continue - } - if conflictKeystroke != nil { - logger.Debugf("keystroke %v has conflict", keystroke) - modifyFlag = true - } else { - newKeystrokes = append(newKeystrokes, keystroke) - } - } - - cs0 := m.shortcutManager.GetByUid(cs.GetUid()) - if cs0 == nil { - logger.Warning("cs0 is nil") - continue - } - - m.shortcutManager.ModifyShortcutKeystrokes(cs0, newKeystrokes) - if modifyFlag { - err := cs0.SaveKeystrokes() - if err != nil { - logger.Warning(err) - } - // 将修改的自定义快捷键补充到 changes 列表中 - changes = append(changes, cs0) - } - } - - for _, shortcut := range changes { - m.emitShortcutSignal(shortcutSignalChanged, shortcut) - } - return nil -} - -func (m *Manager) ListAllShortcuts() (shortcuts string, busErr *dbus.Error) { - list := m.shortcutManager.List() - ret, err := util.MarshalJSON(list) - if err != nil { - return "", dbusutil.ToError(err) - } - return ret, nil -} - -func (m *Manager) ListShortcutsByType(type0 int32) (shortcuts string, busErr *dbus.Error) { - list := m.shortcutManager.ListByType(type0) - ret, err := util.MarshalJSON(list) - if err != nil { - return "", dbusutil.ToError(err) - } - return ret, nil -} - -func (m *Manager) AddCustomShortcut(name, action, keystroke string) (id string, - type0 int32, busErr *dbus.Error) { - - logger.Debugf("Add custom key: %q %q %q", name, action, keystroke) - ks, err := shortcuts.ParseKeystroke(keystroke) - if err != nil { - logger.Warning(err) - busErr = dbusutil.ToError(err) - return - } - - exist := m.shortcutManager.GetByIdType(name, shortcuts.ShortcutTypeCustom) - if exist != nil { - err = errNameUsed - logger.Warning(err) - busErr = dbusutil.ToError(err) - return - } - - conflictKeystroke, err := m.shortcutManager.FindConflictingKeystroke(ks) - if err != nil { - logger.Warning(err) - busErr = dbusutil.ToError(err) - return - } - if conflictKeystroke != nil { - err = errKeystrokeUsed - logger.Warning(err) - busErr = dbusutil.ToError(err) - return - } - - shortcut, err := m.customShortcutManager.Add(name, action, []*shortcuts.Keystroke{ks}, m.wm) - if err != nil { - logger.Warning(err) - busErr = dbusutil.ToError(err) - return - } - if _useWayland { - err := m.processWaylandCustomShortcut(name, action, keystroke) - if err != nil { - logger.Warning(err) - busErr = dbusutil.ToError(err) - return - } - } - m.shortcutManager.Add(shortcut) - m.emitShortcutSignal(shortcutSignalAdded, shortcut) - id = shortcut.GetId() - type0 = shortcut.GetType() - return -} - -func (m *Manager) DeleteCustomShortcut(id string) *dbus.Error { - logger.Debug("DeleteCustomShortcut", id) - shortcut := m.shortcutManager.GetByIdType(id, shortcuts.ShortcutTypeCustom) - if err := m.customShortcutManager.Delete(shortcut.GetId()); err != nil { - return dbusutil.ToError(err) - } - m.shortcutManager.Delete(shortcut) - if _useWayland { - id += "-cs" - logger.Debug("RemoveAccel id: ", id) - err := m.wm.RemoveAccel(0, id) - if err != nil { - return dbusutil.ToError(errors.New("RemoveAccel failed, id: " + id)) - } - delete(m.shortcutManager.WaylandCustomShortCutMap, id) - } - m.emitShortcutSignal(shortcutSignalDeleted, shortcut) - return nil -} - -func (m *Manager) ClearShortcutKeystrokes(id string, type0 int32) *dbus.Error { - logger.Debug("ClearShortcutKeystrokes", id, type0) - shortcut := m.shortcutManager.GetByIdType(id, type0) - if shortcut == nil { - return dbusutil.ToError(ErrShortcutNotFound{id, type0}) - } - m.shortcutManager.ModifyShortcutKeystrokes(shortcut, nil) - err := shortcut.SaveKeystrokes() - if err != nil { - return dbusutil.ToError(err) - } - if shortcut.ShouldEmitSignalChanged() { - m.emitShortcutSignal(shortcutSignalChanged, shortcut) - } - return nil -} - -func (m *Manager) LookupConflictingShortcut(keystroke string) (shortcut string, busErr *dbus.Error) { - ks, err := shortcuts.ParseKeystroke(keystroke) - if err != nil { - // parse keystroke error - return "", dbusutil.ToError(err) - } - - conflictKeystroke, err := m.shortcutManager.FindConflictingKeystroke(ks) - if err != nil { - return "", dbusutil.ToError(err) - } - if conflictKeystroke != nil { - detail, err := util.MarshalJSON(conflictKeystroke.Shortcut) - if err != nil { - return "", dbusutil.ToError(err) - } - return detail, nil - } - return "", nil -} - -func (m *Manager) processWaylandCustomShortcut(id, cmd, keystroke string) *dbus.Error { - logger.Debugf("WaylandCustomShortcut id: %q, cmd: %q, keystroke: %q", id, cmd, keystroke) - wlname := id + "-cs" - keystrokeStrv := make([]string, 0) - keystrokeStrv = append(keystrokeStrv, keystroke) - accelJson, err := util.MarshalJSON(util.KWinAccel{ - Id: wlname, - Keystrokes: keystrokeStrv, - }) - if err != nil { - logger.Warning("accelJson failed: ", accelJson) - return dbusutil.ToError(err) - } - logger.Debug("SetAccel: ", wlname, keystrokeStrv) - ok, err := m.wm.SetAccel(0, accelJson) - if !ok { - logger.Warning("SetAccel failed, accelJson: ", accelJson) - return dbusutil.ToError(err) - } - sessionBus, err := dbus.SessionBus() - if err != nil { - logger.Warning("sessionBus create failed", err) - return dbusutil.ToError(err) - } - obj := sessionBus.Object("org.kde.kglobalaccel", "/kglobalaccel") - err = obj.Call("org.kde.KGlobalAccel.setActiveByUniqueName", 0, wlname, true).Err - logger.Debug("setActiveByUniqueName: ", wlname) - if err != nil { - logger.Warning("setActiveByUniqueName failed") - return dbusutil.ToError(err) - } - logger.Debug("WaylandCustomShortCutMap set", wlname) - m.shortcutManager.WaylandCustomShortCutMap[wlname] = cmd - return nil -} -// ModifyCustomShortcut modify custom shortcut -// -// id: shortcut id -// name: new name -// cmd: new commandline -// keystroke: new keystroke -func (m *Manager) ModifyCustomShortcut(id, name, cmd, keystroke string) *dbus.Error { - logger.Debugf("ModifyCustomShortcut id: %q, name: %q, cmd: %q, keystroke: %q", id, name, cmd, keystroke) - const ty = shortcuts.ShortcutTypeCustom - // get the shortcut - shortcut := m.shortcutManager.GetByIdType(id, ty) - if shortcut == nil { - return dbusutil.ToError(ErrShortcutNotFound{id, ty}) - } - customShortcut, ok := shortcut.(*shortcuts.CustomShortcut) - if !ok { - return dbusutil.ToError(errTypeAssertionFail) - } - - var keystrokes []*shortcuts.Keystroke - if keystroke != "" { - ks, err := shortcuts.ParseKeystroke(keystroke) - if err != nil { - return dbusutil.ToError(err) - } - // check conflicting - conflictKeystroke, err := m.shortcutManager.FindConflictingKeystroke(ks) - if err != nil { - return dbusutil.ToError(err) - } - if conflictKeystroke != nil && conflictKeystroke.Shortcut != shortcut { - return dbusutil.ToError(errKeystrokeUsed) - } - keystrokes = []*shortcuts.Keystroke{ks} - } - - if _useWayland { - err := m.processWaylandCustomShortcut(id, cmd, keystroke) - if err != nil { - return err - } - } - - // modify then save - customShortcut.SetName(name) - customShortcut.Cmd = cmd - m.shortcutManager.ModifyShortcutKeystrokes(shortcut, keystrokes) - err := customShortcut.Save() - if err != nil { - return dbusutil.ToError(err) - } - m.emitShortcutSignal(shortcutSignalChanged, shortcut) - return nil -} - -func (m *Manager) AddShortcutKeystroke(id string, type0 int32, keystroke string) *dbus.Error { - logger.Debug("AddShortcutKeystroke", id, type0, keystroke) - shortcut := m.shortcutManager.GetByIdType(id, type0) - if shortcut == nil { - return dbusutil.ToError(ErrShortcutNotFound{id, type0}) - } - if !shortcut.GetKeystrokesModifiable() { - return dbusutil.ToError(errShortcutKeystrokesUnmodifiable) - } - - ks, err := shortcuts.ParseKeystroke(keystroke) - if err != nil { - // parse keystroke error - return dbusutil.ToError(err) - } - logger.Debug("keystroke:", ks.DebugString()) - - if type0 == shortcuts.ShortcutTypeWM && ks.Mods == 0 { - keyLower := strings.ToLower(ks.Keystr) - if keyLower == "super_l" || keyLower == "super_r" { - return dbusutil.ToError(errors.New( - "keystroke of shortcut which type is wm can not be set to the Super key")) - } - } - - conflictKeystroke, err := m.shortcutManager.FindConflictingKeystroke(ks) - if err != nil { - return dbusutil.ToError(err) - } - if conflictKeystroke == nil { - m.shortcutManager.AddShortcutKeystroke(shortcut, ks) - err := shortcut.SaveKeystrokes() - if err != nil { - return dbusutil.ToError(err) - } - if shortcut.ShouldEmitSignalChanged() { - m.emitShortcutSignal(shortcutSignalChanged, shortcut) - } - } else if conflictKeystroke.Shortcut != shortcut { - return dbusutil.ToError(errKeystrokeUsed) - } - - return nil -} - -func (m *Manager) DeleteShortcutKeystroke(id string, type0 int32, keystroke string) *dbus.Error { - logger.Debug("DeleteShortcutKeystroke", id, type0, keystroke) - shortcut := m.shortcutManager.GetByIdType(id, type0) - if shortcut == nil { - return dbusutil.ToError(ErrShortcutNotFound{id, type0}) - } - if !shortcut.GetKeystrokesModifiable() { - return dbusutil.ToError(errShortcutKeystrokesUnmodifiable) - } - - ks, err := shortcuts.ParseKeystroke(keystroke) - if err != nil { - // parse keystroke error - return dbusutil.ToError(err) - } - logger.Debug("keystroke:", ks.DebugString()) - - m.shortcutManager.DeleteShortcutKeystroke(shortcut, ks) - err = shortcut.SaveKeystrokes() - if err != nil { - return dbusutil.ToError(err) - } - if shortcut.ShouldEmitSignalChanged() { - m.emitShortcutSignal(shortcutSignalChanged, shortcut) - } - return nil -} - -func (m *Manager) GetShortcut(id string, type0 int32) (shortcut string, busErr *dbus.Error) { - s := m.shortcutManager.GetByIdType(id, type0) - if s == nil { - return "", dbusutil.ToError(ErrShortcutNotFound{id, type0}) - } - detail, err := s.Marshal() - if err != nil { - return "", dbusutil.ToError(err) - } - return detail, nil -} - -func (m *Manager) SelectKeystroke() *dbus.Error { - logger.Debug("SelectKeystroke") - err := m.selectKeystroke() - return dbusutil.ToError(err) -} - -func (m *Manager) SetNumLockState(state int32) *dbus.Error { - logger.Debug("SetNumLockState", state) - if _useWayland { - err := setNumLockWl(m.waylandOutputMgr, m.conn, NumLockState(state)) - m.handleKeyEventByWayland("numlock") - return dbusutil.ToError(err) - } - - return dbusutil.ToError(setNumLockX11(m.conn, m.keySymbols, NumLockState(state))) -} - -func (m *Manager) SearchShortcuts(query string) (shortcuts string, busErr *dbus.Error) { - list := m.shortcutManager.Search(query) - ret, err := util.MarshalJSON(list) - if err != nil { - return "", dbusutil.ToError(err) - } - return ret, nil -} - -func (m *Manager) GetCapsLockState() (state int32, busErr *dbus.Error) { - lockState, err := queryCapsLockState(m.conn) - return int32(lockState), dbusutil.ToError(err) -} - -func (m *Manager) SetCapsLockState(state int32) *dbus.Error { - logger.Debug("SetCapsLockState", state) - err := setCapsLockState(m.conn, m.keySymbols, CapsLockState(state)) - return dbusutil.ToError(err) -} diff --git a/keybinding/shortcuts/id_name_map.go b/keybinding/shortcuts/id_name_map.go deleted file mode 100644 index 3cdf9d823..000000000 --- a/keybinding/shortcuts/id_name_map.go +++ /dev/null @@ -1,208 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package shortcuts - -import ( - "github.com/linuxdeepin/go-lib/gettext" -) - -func getSystemIdNameMap() map[string]string { - var idNameMap = map[string]string{ - "launcher": gettext.Tr("Launcher"), - "terminal": gettext.Tr("Terminal"), - "deepin-screen-recorder": gettext.Tr("Screen Recorder"), - "lock-screen": gettext.Tr("Lock screen"), - "show-dock": gettext.Tr("Show/Hide the dock"), - "logout": gettext.Tr("Shutdown interface"), - "terminal-quake": gettext.Tr("Terminal Quake Window"), - "screenshot": gettext.Tr("Screenshot"), - "screenshot-fullscreen": gettext.Tr("Full screenshot"), - "screenshot-window": gettext.Tr("Window screenshot"), - "screenshot-delayed": gettext.Tr("Delay screenshot"), - "screenshot-ocr": gettext.Tr("OCR (Image to Text)"), - "screenshot-scroll": gettext.Tr("Scrollshot"), - "file-manager": gettext.Tr("File manager"), - "disable-touchpad": gettext.Tr("Disable Touchpad"), - "wm-switcher": gettext.Tr("Switch window effects"), - "turn-off-screen": gettext.Tr("Fast Screen Off"), - "system-monitor": gettext.Tr("System Monitor"), - "color-picker": gettext.Tr("Deepin Picker"), - "ai-assistant": gettext.Tr("Desktop AI Assistant"), - "text-to-speech": gettext.Tr("Text to Speech"), - "speech-to-text": gettext.Tr("Speech to Text"), - "clipboard": gettext.Tr("Clipboard"), - "translation": gettext.Tr("Translation"), - "global-search": gettext.Tr("Grand Search"), - "notification-center": gettext.Tr("Notification Center"), - "switch-next-kbd-layout": gettext.Tr("Switch Layout"), - "switch-monitors": gettext.Tr("Toggle multiple displays"), - } - return idNameMap -} - -func getSpecialIdNameMap() map[string]string { - var idNameMap = map[string]string{ - "switch-kbd-layout": gettext.Tr("Switch Layout"), - } - return idNameMap -} - -func getWMIdNameMap() map[string]string { - var idNameMap = map[string]string{ - "switch-to-workspace-1": "Switch to workspace 1", - "switch-to-workspace-2": "Switch to workspace 2", - "switch-to-workspace-3": "Switch to workspace 3", - "switch-to-workspace-4": "Switch to workspace 4", - "switch-to-workspace-5": "Switch to workspace 5", - "switch-to-workspace-6": "Switch to workspace 6", - "switch-to-workspace-7": "Switch to workspace 7", - "switch-to-workspace-8": "Switch to workspace 8", - "switch-to-workspace-9": "Switch to workspace 9", - "switch-to-workspace-10": "Switch to workspace 10", - "switch-to-workspace-11": "Switch to workspace 11", - "switch-to-workspace-12": "Switch to workspace 12", - "switch-to-workspace-left": gettext.Tr("Switch to left workspace"), - "switch-to-workspace-right": gettext.Tr("Switch to right workspace"), - "switch-to-workspace-up": gettext.Tr("Switch to upper workspace"), - "switch-to-workspace-down": gettext.Tr("Switch to lower workspace"), - "switch-to-workspace-last": "Switch to last workspace", - "switch-group": gettext.Tr("Switch similar windows"), - "switch-group-backward": gettext.Tr("Switch similar windows in reverse"), - "switch-applications": gettext.Tr("Switch windows"), - "switch-applications-backward": gettext.Tr("Switch windows in reverse"), - "switch-windows": "Switch windows", - "switch-windows-backward": "Reverse switch windows", - "switch-panels": "Switch system controls", - "switch-panels-backward": "Reverse switch system controls", - "cycle-group": "Switch windows of an app directly", - "cycle-group-backward": "Reverse switch windows of an app directly", - "cycle-windows": "Switch windows directly", - "cycle-windows-backward": "Reverse switch windows directly", - "cycle-panels": "Switch system controls directly", - "cycle-panels-backward": "Reverse switch system controls directly", - "show-desktop": gettext.Tr("Show desktop"), - "panel-main-menu": "Show the activities overview", - "panel-run-dialog": "Show the run command prompt", - // Don't use - // "set-spew-mark": gettext.Tr(""), - "activate-window-menu": "Activate window menu", - "toggle-fullscreen": "toggle-fullscreen", - "toggle-maximized": "Toggle maximization state", - "toggle-above": "Toggle window always appearing on top", - "maximize": gettext.Tr("Maximize window"), - "unmaximize": gettext.Tr("Restore window"), - "toggle-shaded": "Switch furl state", - "minimize": gettext.Tr("Minimize window"), - "close": gettext.Tr("Close window"), - "begin-move": gettext.Tr("Move window"), - "begin-resize": gettext.Tr("Resize window"), - "toggle-on-all-workspaces": "Toggle window on all workspaces or one", - "move-to-workspace-1": "Move to workspace 1", - "move-to-workspace-2": "Move to workspace 2", - "move-to-workspace-3": "Move to workspace 3", - "move-to-workspace-4": "Move to workspace 4", - "move-to-workspace-5": "Move to workspace 5", - "move-to-workspace-6": "Move to workspace 6", - "move-to-workspace-7": "Move to workspace 7", - "move-to-workspace-8": "Move to workspace 8", - "move-to-workspace-9": "Move to workspace 9", - "move-to-workspace-10": "Move to workspace 10", - "move-to-workspace-11": "Move to workspace 11", - "move-to-workspace-12": "Move to workspace 12", - "move-to-workspace-last": "Move to last workspace", - "move-to-workspace-left": gettext.Tr("Move to left workspace"), - "move-to-workspace-right": gettext.Tr("Move to right workspace"), - "move-to-workspace-up": gettext.Tr("Move to upper workspace"), - "move-to-workspace-down": gettext.Tr("Move to lower workspace"), - "move-to-monitor-left": "Move to left monitor", - "move-to-monitor-right": "Move to right monitor", - "move-to-monitor-up": "Move to up monitor", - "move-to-monitor-down": "Move to down monitor", - "raise-or-lower": "Raise window if covered, otherwise lower it", - "raise": "Raise window above other windows", - "lower": "Lower window below other windows", - "maximize-vertically": "Maximize window vertically", - "maximize-horizontally": "Maximize window horizontally", - "move-to-corner-nw": "Move window to top left corner", - "move-to-corner-ne": "Move window to top right corner", - "move-to-corner-sw": "Move window to bottom left corner", - "move-to-corner-se": "Move window to bottom right corner", - "move-to-side-n": "Move window to top edge of screen", - "move-to-side-s": "Move window to bottom edge of screen", - "move-to-side-e": "Move window to right side of screen", - "move-to-side-w": "Move window to left side of screen", - "move-to-center": "Move window to center of screen", - "switch-input-source": "Binding to select the next input source", - "switch-input-source-backward": "Binding to select the previous input source", - "always-on-top": "Set or unset window to appear always on top", - "expose-all-windows": gettext.Tr("Display windows of all workspaces"), - "expose-windows": gettext.Tr("Display windows of current workspace"), - "preview-workspace": gettext.Tr("Display workspace"), - "view-zoom-in": gettext.Tr("Zoom In"), - "view-zoom-out": gettext.Tr("Zoom Out"), - "view-actual-size": gettext.Tr("Zoom to Actual Size"), - } - return idNameMap -} - -func getMediaIdNameMap() map[string]string { - var idNameMap = map[string]string{ - "messenger": "Messenger", // XF86Messenger - "save": "Save", // XF86Save - "new": "New", // XF86New - "wake-up": "WakeUp", // XF86WakeUp - "audio-rewind": "AudioRewind", // XF86AudioRewind - "audio-mute": "AudioMute", // XF86AudioMute - "mon-brightness-up": "MonBrightnessUp", // XF86MonBrightnessUp - "wlan": "WLAN", // XF86WLAN - "audio-media": "AudioMedia", // XF86AudioMedia - "reply": "Reply", // XF86Reply - "favorites": "Favorites", // XF86Favorites - "audio-play": "AudioPlay", // XF86AudioPlay - "audio-mic-mute": "AudioMicMute", // XF86AudioMicMute - "audio-pause": "AudioPause", // XF86AudioPause - "audio-stop": "AudioStop", // XF86AudioStop - "documents": "Documents", // XF86Documents - "game": "Game", // XF86Game - "search": "Search", // XF86Search - "audio-record": "AudioRecord", // XF86AudioRecord - "display": "Display", // XF86Display - "reload": "Reload", // XF86Reload - "explorer": "Explorer", // XF86Explorer - "calculator": "Calculator", // XF86Calculator - "calendar": "Calendar", // XF86Calendar - "forward": "Forward", // XF86Forward - "cut": "Cut", // XF86Cut - "mon-brightness-down": "MonBrightnessDown", // XF86MonBrightnessDown - "copy": "Copy", // XF86Copy - "tools": "Tools", // XF86Tools - "audio-raise-volume": "AudioRaiseVolume", // XF86AudioRaiseVolume - "media-close": "media-Close", // XF86Close - "www": "WWW", // XF86WWW - "home-page": "HomePage", // XF86HomePage - "sleep": "Sleep", // XF86Sleep - "audio-lower-volume": "AudioLowerVolume", // XF86AudioLowerVolume - "audio-prev": "AudioPrev", // XF86AudioPrev - "audio-next": "AudioNext", // XF86AudioNext - "paste": "Paste", // XF86Paste - "open": "Open", // XF86Open - "send": "Send", // XF86Send - "my-computer": "MyComputer", // XF86MyComputer - "mail": "Mail", // XF86Mail - "adjust-brightness": "BrightnessAdjust", // XF86BrightnessAdjust - "log-off": "LogOff", // XF86LogOff - "pictures": "Pictures", // XF86Pictures - "terminal": "Terminal", // XF86Terminal - "video": "Video", // XF86Video - "music": "Music", // XF86Music - "app-left": "ApplicationLeft", // XF86ApplicationLeft - "app-right": "ApplicationRight", // XF86ApplicationRight - "meeting": "Meeting", // XF86Meeting - "touchpad-toggle": "ToggleTouchpad", // XF86TouchpadToggle - "away": "Away", // XF86Away - "web-cam": "Camera", // XF86WebCam - } - return idNameMap -} diff --git a/keybinding/util/util.go b/keybinding/util/util.go deleted file mode 100644 index 081018feb..000000000 --- a/keybinding/util/util.go +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package util - -import ( - "bytes" - "encoding/json" - "strings" - "os" - - wm "github.com/linuxdeepin/go-dbus-factory/com.deepin.wm" -) - -func MarshalJSON(v interface{}) (string, error) { - var buf bytes.Buffer - enc := json.NewEncoder(&buf) - enc.SetEscapeHTML(false) - err := enc.Encode(v) - if err != nil { - return "", err - } - return buf.String(), nil -} - -type KWinAccel struct { - Id string - Keystrokes []string `json:"Accels"` - DefaultKeystrokes []string `json:"Default,omitempty"` -} - -func (kwa *KWinAccel) fix() { - var keystrokes []string - for _, ks := range kwa.Keystrokes { - if ks == "" { - continue - } - keystrokes = append(keystrokes, ks) - } - kwa.Keystrokes = keystrokes - - var defaultKeystrokes []string - for _, ks := range kwa.DefaultKeystrokes { - if ks == "" || strings.Contains(ks, " ") { - continue - } - defaultKeystrokes = append(defaultKeystrokes, ks) - } - - kwa.DefaultKeystrokes = defaultKeystrokes -} - -func GetAllKWinAccels(wm wm.Wm) ([]KWinAccel, error) { - allJson, err := wm.GetAllAccels(0) - if err != nil { - return nil, err - } - sessionType := os.Getenv("XDG_SESSION_TYPE") - if strings.Contains(sessionType, "wayland") && strings.Contains(allJson, "SysReq") { - allJson = strings.Replace(allJson, "SysReq", "Print", -1) - } - - var result []KWinAccel - err = json.Unmarshal([]byte(allJson), &result) - if err != nil { - return nil, err - } - - for idx := range result { - result[idx].fix() - } - - return result, nil -} diff --git a/keybinding/utils.go b/keybinding/utils.go deleted file mode 100644 index 07ea57da3..000000000 --- a/keybinding/utils.go +++ /dev/null @@ -1,421 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package keybinding - -import ( - "bytes" - "errors" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "strconv" - "strings" - "time" - - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/keybinding/util" - wm "github.com/linuxdeepin/go-dbus-factory/com.deepin.wm" - gio "github.com/linuxdeepin/go-gir/gio-2.0" - "github.com/linuxdeepin/go-lib/strv" - "github.com/linuxdeepin/go-x11-client/ext/dpms" -) - -// nolint -const ( - suspendStateUnknown = iota + 1 - suspendStateLidOpen - suspendStateFinish - suspendStateWakeup - suspendStatePrepare - suspendStateLidClose - suspendStateButtonClick -) - -type networkDevice struct { - Udi string - Path dbus.ObjectPath - State uint32 - Interface string - ClonedAddress string - HwAddress string - Driver string - Managed bool - Vendor string - UniqueUuid string - UsbDevice bool - ActiveAp dbus.ObjectPath - SupportHotspot bool - Mode uint32 - MobileNetworkType string - MobileSignalQuality uint32 - InterfaceFlags uint32 -} - -func resetGSettings(gs *gio.Settings) { - for _, key := range gs.ListKeys() { - userVal := gs.GetUserValue(key) - if userVal != nil { - // TODO unref userVal - logger.Debug("reset gsettings key", key) - gs.Reset(key) - } - } -} - -func resetKWin(wmObj wm.Wm) error { - accels, err := util.GetAllKWinAccels(wmObj) - if err != nil { - return err - } - for _, accel := range accels { - // logger.Debug("resetKwin each accel:", accel.Id, accel.Keystrokes, accel.DefaultKeystrokes) - if !strv.Strv(accel.Keystrokes).Equal(accel.DefaultKeystrokes) && - len(accel.DefaultKeystrokes) > 0 && accel.DefaultKeystrokes[0] != "" { - accelJson, err := util.MarshalJSON(&util.KWinAccel{ - Id: accel.Id, - Keystrokes: accel.DefaultKeystrokes, - }) - if err != nil { - logger.Warning(err) - continue - } - logger.Debug("resetKwin SetAccel", accelJson) - ok, err := wmObj.SetAccel(0, accelJson) - // 目前 wm 的实现,调用 SetAccel 如果遇到冲突情况,会导致目标快捷键被清空。 - if !ok { - logger.Warning("wm.SetAccel failed, id: ", accel.Id) - continue - } - if err != nil { - logger.Warning("failed to set accel:", err, accel.Id) - continue - } - } - } - return nil -} - -func showOSD(signal string) { - logger.Debug("show OSD", signal) - sessionDBus, _ := dbus.SessionBus() - go sessionDBus.Object("com.deepin.dde.osd", "/").Call("com.deepin.dde.osd.ShowOSD", 0, signal) -} - -const sessionManagerDest = "com.deepin.SessionManager" -const sessionManagerObjPath = "/com/deepin/SessionManager" - -func systemLock() { - sessionDBus, err := dbus.SessionBus() - if err != nil { - logger.Warning(err) - return - } - go sessionDBus.Object(sessionManagerDest, sessionManagerObjPath).Call(sessionManagerDest+".RequestLock", 0) -} - -func (m *Manager) canSuspend() bool { - can, err := m.sessionManager.CanSuspend(0) // 当前能否待机 - if err != nil { - logger.Warning(err) - return false - } - return can -} - -func (m *Manager) systemSuspend() { - if !m.canSuspend() { - logger.Info("can not suspend") - return - } - - logger.Debug("suspend") - err := m.sessionManager.RequestSuspend(0) - if err != nil { - logger.Warning("failed to suspend:", err) - } -} - -// 为了处理待机闪屏的问题,通过前端进行待机,前端会在待机前显示一个纯黑的界面 -func (m *Manager) systemSuspendByFront() { - if !m.canExcuteSuspendOrHiberate || m.prepareForSleep { - logger.Info("Avoid waking up and immediately going into suspend.") - return - } - - if !m.canSuspend() { - logger.Info("can not suspend") - return - } - - logger.Debug("suspend") - err := m.shutdownFront.Suspend(0) - if err != nil { - logger.Warning("failed to suspend:", err) - } -} - -func (m *Manager) canHibernate() bool { - can, err := m.sessionManager.CanHibernate(0) // 能否休眠 - if err != nil { - logger.Warning(err) - return false - } - return can -} - -func systemSuspend() { - sessionDBus, _ := dbus.SessionBus() - go sessionDBus.Object(sessionManagerDest, sessionManagerObjPath).Call(sessionManagerDest+".RequestSuspend", 0) -} - -func (m *Manager) systemHibernate() { - if !m.canHibernate() { - logger.Info("can not Hibernate") - return - } - - logger.Debug("Hibernate") - err := m.sessionManager.RequestHibernate(0) - if err != nil { - logger.Warning("failed to Hibernate:", err) - } -} - -func (m *Manager) systemHibernateByFront() { - if !m.canExcuteSuspendOrHiberate || m.prepareForSleep { - logger.Info("Avoid waking up and immediately going into suspend.") - return - } - - if !m.canHibernate() { - logger.Info("can not Hibernate") - return - } - - logger.Debug("Hibernate") - err := m.shutdownFront.Hibernate(0) - if err != nil { - logger.Warning("failed to Hibernate:", err) - } -} - -func (m *Manager) canShutdown() bool { - can, err := m.sessionManager.CanShutdown(0) // 当前能否关机 - if err != nil { - logger.Warning(err) - return false - } - return can -} - -func (m *Manager) hasShutdownInhibit() bool { - // 先检查是否有delay 或 block shutdown的inhibitor - inhibitors, err := m.login1Manager.ListInhibitors(0) - if err != nil { - logger.Warning("failed to call login ListInhibitors:", err) - } else { - for _, inhibit := range inhibitors { - logger.Infof("inhibit is: %+v", inhibit) - if strings.Contains(inhibit.What, "shutdown") { - return true - } - } - } - return false -} - -func (m *Manager) hasMultipleDisplaySession() bool { - // 检查是否有多个图形session,有多个图形session就需要显示阻塞界面 - sessions, err := m.displayManager.Sessions().Get(0) - if err != nil { - logger.Warning(err) - return false - } - return len(sessions) >= 2 -} - -func (m *Manager) systemShutdown() { - // 如果是锁定状态,那么不需要后端进行关机响应,前端会显示关机或者关机阻塞界面; - // 快捷键关机流程:判断是否存在多用户或任何shutdown阻塞项(block or delay),存在则跳转dde-shutdown界面,不存在进行sessionManager的注销 - if !m.canShutdown() { - logger.Info("can not Shutdown") - } - - locked, err := m.sessionManager.Locked().Get(0) - if err != nil { - logger.Warning("sessionManager get locked state error:", err) - return - } - if locked { - logger.Info("current session is locked") - return - } - - if m.hasShutdownInhibit() || m.hasMultipleDisplaySession() { - logger.Info("exist shutdown inhibit(delay or block) or multiple display session") - err := m.shutdownFront.Shutdown(0) - if err != nil { - logger.Warning(err) - } - } else { - logger.Debug("keybinding start request SessionManager shutdown") - err := m.sessionManager.RequestShutdown(0) - if err != nil { - logger.Warning("failed to Shutdown:", err) - } - } -} - -func (m *Manager) systemTurnOffScreen() { - const settingKeyScreenBlackLock = "screen-black-lock" - logger.Info("DPMS Off") - var err error - var useWayland bool - if len(os.Getenv("WAYLAND_DISPLAY")) != 0 { - useWayland = true - } else { - useWayland = false - } - - bScreenBlackLock := m.gsPower.GetBoolean(settingKeyScreenBlackLock) - if bScreenBlackLock { - m.doLock(true) - } - - doPrepareSuspend() - // bug-209669 : 部分厂商机器调用DPMS off后,调用锁屏show会被阻塞,只有当DPMS on了才show锁屏成功,这就导致唤醒闪桌面再进锁屏 - if bScreenBlackLock && !m.isWmBlackScreenActive() { - m.setWmBlackScreenActive(true) - time.Sleep(100 * time.Millisecond) - } - - if useWayland { - err = exec.Command("dde_wldpms", "-s", "Off").Run() - } else { - err = dpms.ForceLevelChecked(m.conn, dpms.DPMSModeOff).Check(m.conn) - } - if err != nil { - logger.Warning("Set DPMS off error:", err) - } - - if bScreenBlackLock && m.isWmBlackScreenActive() { - m.setWmBlackScreenActive(false) - } - undoPrepareSuspend() - ioutil.WriteFile("/tmp/dpms-state", []byte("1"), 0644) -} - -func (m *Manager) systemLogout() { - can, err := m.sessionManager.CanLogout(0) - if err != nil { - logger.Warning(err) - return - } - - if !can { - logger.Info("can not logout") - return - } - - logger.Debug("logout") - err = m.sessionManager.RequestLogout(0) - if err != nil { - logger.Warning("failed to logout:", err) - } -} - -func (m *Manager) systemAway() { - err := m.sessionManager.RequestLock(0) - if err != nil { - logger.Warning(err) - } -} - -func queryCommandByMime(mime string) string { - app := gio.AppInfoGetDefaultForType(mime, false) - if app == nil { - return "" - } - defer app.Unref() - - return app.GetExecutable() -} - -func getRfkillWlanState() (int, error) { - dir := "/sys/class/rfkill" - fileInfoList, err := ioutil.ReadDir(dir) - if err != nil { - return 0, err - } - - for _, fileInfo := range fileInfoList { - typeFile := filepath.Join(dir, fileInfo.Name(), "type") - typeBytes, err := readTinyFile(typeFile) - if err != nil { - continue - } - if bytes.Equal(bytes.TrimSpace(typeBytes), []byte("wlan")) { - stateFile := filepath.Join(dir, fileInfo.Name(), "state") - stateBytes, err := readTinyFile(stateFile) - if err != nil { - return 0, err - } - stateBytes = bytes.TrimSpace(stateBytes) - state, err := strconv.Atoi(string(stateBytes)) - if err != nil { - return 0, err - } - return state, nil - - } - } - return 0, errors.New("not found rfkill with type wlan") -} - -func readTinyFile(file string) ([]byte, error) { - f, err := os.Open(file) - if err != nil { - return nil, err - } - defer f.Close() - buf := make([]byte, 8) - n, err := f.Read(buf) - if err != nil { - return nil, err - } - return buf[:n], nil -} - -func shouldUseDDEKwin() bool { - _, err := os.Stat("/usr/bin/kwin_no_scale") - return err == nil -} - -func (m *Manager) doLock(autoStartAuth bool) { - logger.Info("Lock Screen") - err := m.lockFront.ShowAuth(0, autoStartAuth) - if err != nil { - logger.Warning("failed to call lockFront ShowAuth:", err) - } -} - -func doPrepareSuspend() { - sessionDBus, _ := dbus.SessionBus() - obj := sessionDBus.Object("com.deepin.daemon.Power", "/com/deepin/daemon/Power") - err := obj.Call("com.deepin.daemon.Power.SetPrepareSuspend", 0, suspendStateButtonClick).Err - if err != nil { - logger.Warning(err) - } -} - -func undoPrepareSuspend() { - sessionDBus, _ := dbus.SessionBus() - obj := sessionDBus.Object("com.deepin.daemon.Power", "/com/deepin/daemon/Power") - err := obj.Call("com.deepin.daemon.Power.SetPrepareSuspend", 0, suspendStateFinish).Err - if err != nil { - logger.Warning(err) - } -} diff --git a/keybinding/audio_controller.go b/keybinding1/audio_controller.go similarity index 95% rename from keybinding/audio_controller.go rename to keybinding1/audio_controller.go index 9f566269a..60bd24616 100644 --- a/keybinding/audio_controller.go +++ b/keybinding1/audio_controller.go @@ -8,10 +8,10 @@ import ( "errors" "strings" - "github.com/godbus/dbus" - . "github.com/linuxdeepin/dde-daemon/keybinding/shortcuts" - audio "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.audio" - backlight "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.helper.backlight" + "github.com/godbus/dbus/v5" + . "github.com/linuxdeepin/dde-daemon/keybinding1/shortcuts" + audio "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.audio1" + backlight "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.backlighthelper1" "github.com/linuxdeepin/go-gir/gio-2.0" ) diff --git a/keybinding/config.go b/keybinding1/config.go similarity index 100% rename from keybinding/config.go rename to keybinding1/config.go diff --git a/keybinding1/daemon.go b/keybinding1/daemon.go new file mode 100644 index 000000000..8fd331e66 --- /dev/null +++ b/keybinding1/daemon.go @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package keybinding + +import ( + "github.com/linuxdeepin/dde-daemon/keybinding1/shortcuts" + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" +) + +func init() { + loader.Register(NewDaemon(logger)) + shortcuts.SetLogger(logger) +} + +type Daemon struct { + *loader.ModuleBase + manager *Manager +} + +var ( + logger = log.NewLogger("daemon/keybinding") +) + +func NewDaemon(logger *log.Logger) *Daemon { + var d = new(Daemon) + d.ModuleBase = loader.NewModuleBase("keybinding", d, logger) + return d +} + +func (*Daemon) GetDependencies() []string { + return []string{} +} + +func (d *Daemon) Start() error { + if d.manager != nil { + return nil + } + var err error + + service := loader.GetService() + + loadConfig() + + d.manager, err = newManager(service) + if err != nil { + return err + } + + err = service.Export(dbusPath, d.manager) + if err != nil { + d.manager.destroy() + d.manager = nil + return err + } + + err = service.RequestName(dbusServiceName) + if err != nil { + d.manager.destroy() + d.manager = nil + return err + } + + go func() { + m := d.manager + m.initHandlers() + + // listen gsettings changed event + m.listenGSettingsChanged(gsSchemaSystem, d.manager.gsSystem, shortcuts.ShortcutTypeSystem) + m.listenGSettingsChanged(gsSchemaMediaKey, d.manager.gsMediaKey, shortcuts.ShortcutTypeMedia) + m.listenGSettingsChanged(gsSchemaGnomeWM, d.manager.gsGnomeWM, shortcuts.ShortcutTypeWM) + + m.listenSystemEnableChanged() + m.listenSystemPlatformChanged() + + m.eliminateKeystrokeConflict() + m.shortcutManager.EventLoop() + }() + + return nil +} + +func (d *Daemon) Stop() error { + if d.manager == nil { + return nil + } + + service := loader.GetService() + err := service.ReleaseName(dbusServiceName) + if err != nil { + logger.Warning(err) + } + + d.manager.destroy() + d.manager = nil + return nil +} diff --git a/keybinding/display_controller.go b/keybinding1/display_controller.go similarity index 91% rename from keybinding/display_controller.go rename to keybinding1/display_controller.go index 460bacd46..f50a47fee 100644 --- a/keybinding/display_controller.go +++ b/keybinding1/display_controller.go @@ -8,10 +8,10 @@ import ( "os/exec" "sync" - "github.com/godbus/dbus" - . "github.com/linuxdeepin/dde-daemon/keybinding/shortcuts" - display "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.display" - backlight "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.helper.backlight" + "github.com/godbus/dbus/v5" + . "github.com/linuxdeepin/dde-daemon/keybinding1/shortcuts" + display "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.display1" + backlight "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.backlighthelper1" "github.com/linuxdeepin/go-gir/gio-2.0" "github.com/linuxdeepin/go-lib/strv" ) @@ -73,7 +73,8 @@ func (c *DisplayController) ExecCmd(cmd ActionCmd) error { switch cmd { case DisplayModeSwitch: // TODO 联想xrandr -q需要修改成X的接口 - if strv.Strv(c.m.needXrandrQDevice).Contains(c.m.dmiInfo.ProductName) { + if c.m.dmiInfo.ProductName != "" && + strv.Strv(c.m.needXrandrQDevice).Contains(c.m.dmiInfo.ProductName) { logger.Info("win+p pressed,need run xrandr -q") err = exec.Command("xrandr", "-q").Run() if err != nil { diff --git a/keybinding1/exported_methods_auto.go b/keybinding1/exported_methods_auto.go new file mode 100644 index 000000000..ba76534bc --- /dev/null +++ b/keybinding1/exported_methods_auto.go @@ -0,0 +1,143 @@ +// Code generated by "dbusutil-gen em -type Manager"; DO NOT EDIT. + +package keybinding + +import ( + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (v *Manager) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "Add", + Fn: v.Add, + InArgs: []string{"name", "action", "keystroke"}, + OutArgs: []string{"ret0", "ret1"}, + }, + { + Name: "AddCustomShortcut", + Fn: v.AddCustomShortcut, + InArgs: []string{"name", "action", "keystroke"}, + OutArgs: []string{"id", "type0"}, + }, + { + Name: "AddShortcutKeystroke", + Fn: v.AddShortcutKeystroke, + InArgs: []string{"id", "type0", "keystroke"}, + }, + { + Name: "CheckAvaliable", + Fn: v.CheckAvaliable, + InArgs: []string{"keystroke"}, + OutArgs: []string{"available", "shortcut"}, + }, + { + Name: "ClearShortcutKeystrokes", + Fn: v.ClearShortcutKeystrokes, + InArgs: []string{"id", "type0"}, + }, + { + Name: "Delete", + Fn: v.Delete, + InArgs: []string{"id", "type0"}, + }, + { + Name: "DeleteCustomShortcut", + Fn: v.DeleteCustomShortcut, + InArgs: []string{"id"}, + }, + { + Name: "DeleteShortcutKeystroke", + Fn: v.DeleteShortcutKeystroke, + InArgs: []string{"id", "type0", "keystroke"}, + }, + { + Name: "Disable", + Fn: v.Disable, + InArgs: []string{"id", "type0"}, + }, + { + Name: "EnableSystemShortcut", + Fn: v.EnableSystemShortcut, + InArgs: []string{"shortcuts", "enabled", "isPersistent"}, + }, + { + Name: "GetCapsLockState", + Fn: v.GetCapsLockState, + OutArgs: []string{"state"}, + }, + { + Name: "GetShortcut", + Fn: v.GetShortcut, + InArgs: []string{"id", "type0"}, + OutArgs: []string{"shortcut"}, + }, + { + Name: "GrabScreen", + Fn: v.GrabScreen, + }, + { + Name: "List", + Fn: v.List, + OutArgs: []string{"shortcuts"}, + }, + { + Name: "ListAllShortcuts", + Fn: v.ListAllShortcuts, + OutArgs: []string{"shortcuts"}, + }, + { + Name: "ListShortcutsByType", + Fn: v.ListShortcutsByType, + InArgs: []string{"type0"}, + OutArgs: []string{"shortcuts"}, + }, + { + Name: "LookupConflictingShortcut", + Fn: v.LookupConflictingShortcut, + InArgs: []string{"keystroke"}, + OutArgs: []string{"shortcut"}, + }, + { + Name: "ModifiedAccel", + Fn: v.ModifiedAccel, + InArgs: []string{"id", "type0", "keystroke", "add"}, + OutArgs: []string{"ret0", "ret1"}, + }, + { + Name: "ModifyCustomShortcut", + Fn: v.ModifyCustomShortcut, + InArgs: []string{"id", "name", "cmd", "keystroke"}, + }, + { + Name: "Query", + Fn: v.Query, + InArgs: []string{"id", "type0"}, + OutArgs: []string{"shortcut"}, + }, + { + Name: "Reset", + Fn: v.Reset, + }, + { + Name: "SearchShortcuts", + Fn: v.SearchShortcuts, + InArgs: []string{"query"}, + OutArgs: []string{"shortcuts"}, + }, + { + Name: "SelectKeystroke", + Fn: v.SelectKeystroke, + }, + { + Name: "SetCapsLockState", + Fn: v.SetCapsLockState, + InArgs: []string{"state"}, + }, + { + Name: "SetNumLockState", + Fn: v.SetNumLockState, + InArgs: []string{"state"}, + }, + } +} diff --git a/keybinding/huawei_mic.go b/keybinding1/huawei_mic.go similarity index 97% rename from keybinding/huawei_mic.go rename to keybinding1/huawei_mic.go index 11a6c361a..e4e98b0be 100644 --- a/keybinding/huawei_mic.go +++ b/keybinding1/huawei_mic.go @@ -8,7 +8,7 @@ import ( "os" "path/filepath" - backlight "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.helper.backlight" + backlight "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.backlighthelper1" "github.com/linuxdeepin/go-lib/pulse" ) diff --git a/keybinding/kbd_light_controller.go b/keybinding1/kbd_light_controller.go similarity index 94% rename from keybinding/kbd_light_controller.go rename to keybinding1/kbd_light_controller.go index 6d2f335b0..1d3daac05 100644 --- a/keybinding/kbd_light_controller.go +++ b/keybinding1/kbd_light_controller.go @@ -7,10 +7,10 @@ package keybinding import ( "errors" - backlight "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.helper.backlight" + . "github.com/linuxdeepin/dde-daemon/keybinding1/shortcuts" + backlight "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.backlighthelper1" commonbl "github.com/linuxdeepin/go-lib/backlight/common" kbdbl "github.com/linuxdeepin/go-lib/backlight/keyboard" - . "github.com/linuxdeepin/dde-daemon/keybinding/shortcuts" ) const backlightTypeKeyboard = 2 diff --git a/keybinding/lock_state.go b/keybinding1/lock_state.go similarity index 96% rename from keybinding/lock_state.go rename to keybinding1/lock_state.go index 842d092a9..ec6a5d378 100644 --- a/keybinding/lock_state.go +++ b/keybinding1/lock_state.go @@ -10,10 +10,10 @@ import ( "os" "time" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" - "github.com/linuxdeepin/dde-daemon/keybinding/shortcuts" - kwayland "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.kwayland" + "github.com/linuxdeepin/dde-daemon/keybinding1/shortcuts" + kwayland "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.kwayland1" x "github.com/linuxdeepin/go-x11-client" "github.com/linuxdeepin/go-x11-client/ext/test" "github.com/linuxdeepin/go-x11-client/util/keysyms" diff --git a/keybinding1/manager.go b/keybinding1/manager.go new file mode 100644 index 000000000..22ed9777e --- /dev/null +++ b/keybinding1/manager.go @@ -0,0 +1,1358 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package keybinding + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "github.com/linuxdeepin/go-lib/appinfo/desktopappinfo" + "github.com/linuxdeepin/go-lib/strv" + + "os" + "os/exec" + "path/filepath" + "strings" + "time" + + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/keybinding1/shortcuts" + configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" + lockfront "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.dde.lockfront" + shutdownfront "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.dde.shutdownfront" + wm "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.wm" + appmanager "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.application1" + inputdevices "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.inputdevices1" + kwayland "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.kwayland1" + network "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.network1" + sessionmanager "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.sessionmanager1" + newAppmanager "github.com/linuxdeepin/go-dbus-factory/session/org.desktopspec.applicationmanager1" + airplanemode "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.airplanemode1" + backlight "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.backlighthelper1" + keyevent "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.keyevent1" + power "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.power1" + systeminfo "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.systeminfo1" + DisplayManager "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.DisplayManager" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" + networkmanager "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.networkmanager" + gio "github.com/linuxdeepin/go-gir/gio-2.0" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/dbusutil/gsprop" + "github.com/linuxdeepin/go-lib/dbusutil/proxy" + "github.com/linuxdeepin/go-lib/gsettings" + "github.com/linuxdeepin/go-lib/xdg/basedir" + x "github.com/linuxdeepin/go-x11-client" + "github.com/linuxdeepin/go-x11-client/util/keysyms" +) + +//go:generate dbusutil-gen em -type Manager + +const ( + // shortcut signals: + shortcutSignalChanged = "Changed" + shortcutSignalAdded = "Added" + shortcutSignalDeleted = "Deleted" + + gsSchemaKeyboard = "com.deepin.dde.keyboard" + gsKeyNumLockState = "numlock-state" + gsKeySaveNumLockState = "save-numlock-state" + gsKeyShortcutSwitchLayout = "shortcut-switch-layout" + gsKeyShowCapsLockOSD = "capslock-toggle" + gsKeyUpperLayerWLAN = "upper-layer-wlan" + + gsSchemaSystem = "com.deepin.dde.keybinding.system" + gsSchemaSystemPlatform = "com.deepin.dde.keybinding.system.platform" + gsSchemaSystemEnable = "com.deepin.dde.keybinding.system.enable" + gsSchemaMediaKey = "com.deepin.dde.keybinding.mediakey" + gsSchemaGnomeWM = "com.deepin.wrap.gnome.desktop.wm.keybindings" + gsSchemaSessionPower = "com.deepin.dde.power" + + customConfigFile = "deepin/dde-daemon/keybinding/custom.ini" + CapslockKey = 58 + NumlockKey = 69 + KeyPress = 1 +) + +const ( + DSettingsAppID = "org.deepin.dde.daemon" + DSettingsKeyBindingName = "org.deepin.dde.daemon.keybinding" + DSettingsKeyWirelessControlEnable = "wirelessControlEnable" + DSettingsKeyNeedXrandrQDevices = "need-xrandr-q-devices" + DSettingsKeyDeviceManagerControlEnable = "deviceManagerControlEnable" +) + +const ( // power按键事件的响应 + powerActionShutdown int32 = iota + powerActionSuspend + powerActionHibernate + powerActionTurnOffScreen + powerActionShowUI +) + +var _useWayland bool + +func setUseWayland(value bool) { + _useWayland = value +} + +const ( + appManagerDBusServiceName = "org.desktopspec.ApplicationManager1" + appManagerDBusPath = "/org/desktopspec/ApplicationManager1" +) + +const ( + KeyType = "Type" + KeyVersion = "Version" + KeyName = "Name" + KeyGenericName = "GenericName" + KeyNoDisplay = "NoDisplay" + KeyIcon = "Icon" + KeyExec = "Exec" + KeyPath = "Path" + KeyTerminal = "Terminal" + KeyMimeType = "MimeType" + KeyActions = "Actions" +) + +type Manager struct { + service *dbusutil.Service + // properties + NumLockState gsprop.Enum + ShortcutSwitchLayout gsprop.Uint `prop:"access:rw"` + + conn *x.Conn + keySymbols *keysyms.KeySymbols + + gsKeyboard *gio.Settings + gsSystem *gio.Settings + gsSystemPlatform *gio.Settings + gsSystemEnable *gio.Settings + gsMediaKey *gio.Settings + gsGnomeWM *gio.Settings + gsPower *gio.Settings + + enableListenGSettings bool + delayNetworkStateChange bool + canExcuteSuspendOrHiberate bool + prepareForSleep bool + clickNum uint32 + shortcutCmd string + shortcutKey string + shortcutKeyCmd string + customShortcutManager *shortcuts.CustomShortcutManager + + lockFront lockfront.LockFront + shutdownFront shutdownfront.ShutdownFront + + sessionSigLoop *dbusutil.SignalLoop + systemSigLoop *dbusutil.SignalLoop + //startManager sessionmanager.StartManager + appManager appmanager.Manager + sessionManager sessionmanager.SessionManager + airplane airplanemode.AirplaneMode + networkmanager networkmanager.Manager + backlightHelper backlight.Backlight + keyboard inputdevices.Keyboard + keyboardLayout string + wm wm.Wm + waylandOutputMgr kwayland.OutputManagement + login1Manager login1.Manager + keyEvent keyevent.KeyEvent + displayManager DisplayManager.DisplayManager + network network.Network + specialKeycodeBindingList map[SpecialKeycodeMapKey]func() + + // controllers + audioController *AudioController + mediaPlayerController *MediaPlayerController + displayController *DisplayController + kbdLightController *KbdLightController + touchPadController *TouchPadController + + shortcutManager *shortcuts.ShortcutManager + // shortcut action handlers + handlers []shortcuts.KeyEventFunc + lastKeyEventTime time.Time + lastMethodCalledTime time.Time + delayUpdateRfTimer *time.Timer + grabScreenKeystroke *shortcuts.Keystroke + + // for switch kbd layout + switchKbdLayoutState SKLState + sklWaitQuit chan int + + // dsg config + wifiControlEnable bool + needXrandrQDevice []string + useNewAppManager bool + deviceManagerControlEnable bool + + configManagerPath dbus.ObjectPath + DisabledSystemShortcutsList strv.Strv + + dmiInfo systeminfo.DMIInfo + rfkillState bool + repeatCount int + fnLockCount int + fnLocking bool + + // nolint + signals *struct { + Added, Deleted, Changed struct { + id string + typ int32 + } + + KeyEvent struct { + pressed bool + keystroke string + } + } +} + +// SKLState Switch keyboard Layout state +type SKLState uint + +const ( + SKLStateNone SKLState = iota + SKLStateWait + SKLStateOSDShown +) + +func newManager(service *dbusutil.Service) (*Manager, error) { + setUseWayland(strings.Contains(os.Getenv("XDG_SESSION_TYPE"), "wayland")) + conn, err := x.NewConn() + if err != nil { + return nil, err + } + + sessionBus := service.Conn() + sysBus, err := dbus.SystemBus() + if err != nil { + return nil, err + } + + var m = Manager{ + service: service, + enableListenGSettings: true, + conn: conn, + keySymbols: keysyms.NewKeySymbols(conn), + handlers: make([]shortcuts.KeyEventFunc, shortcuts.ActionTypeCount), + } + + m.sessionSigLoop = dbusutil.NewSignalLoop(sessionBus, 10) + m.systemSigLoop = dbusutil.NewSignalLoop(sysBus, 10) + + if _useWayland { + m.waylandOutputMgr = kwayland.NewOutputManagement(sessionBus) + } + m.login1Manager = login1.NewManager(sysBus) + m.login1Manager.InitSignalExt(m.systemSigLoop, true) + _, err = m.login1Manager.ConnectPrepareForSleep(func(isSleep bool) { + logger.Debugf("PreparingForSleep status changed, isSleep: %v", isSleep) + m.prepareForSleep = isSleep + // 待机或休眠时,唤醒后的1秒内不响应待机和休眠操作,避免按电源键唤醒时再次进入待机或休眠 + if !isSleep { + m.canExcuteSuspendOrHiberate = false + time.AfterFunc(1*time.Second, func() { + m.canExcuteSuspendOrHiberate = true + }) + } else { + m.canExcuteSuspendOrHiberate = false + } + }) + if err != nil { + logger.Warning("failed to connect signal PrepareForSleep:", err) + } + m.prepareForSleep, _ = m.login1Manager.PreparingForSleep().Get(0) + m.displayManager = DisplayManager.NewDisplayManager(sysBus) + m.shutdownFront = shutdownfront.NewShutdownFront(sessionBus) + m.gsKeyboard = gio.NewSettings(gsSchemaKeyboard) + m.NumLockState.Bind(m.gsKeyboard, gsKeyNumLockState) + m.ShortcutSwitchLayout.Bind(m.gsKeyboard, gsKeyShortcutSwitchLayout) + m.sessionSigLoop.Start() + m.systemSigLoop.Start() + + m.initNumLockState(sysBus) + m.initDSettings(sysBus) + + m.init() + + return &m, nil +} + +func (m *Manager) init() { + sessionBus := m.service.Conn() + sysBus, _ := dbus.SystemBus() + m.delayNetworkStateChange = true + m.canExcuteSuspendOrHiberate = true + + // init settings + m.gsSystem = gio.NewSettings(gsSchemaSystem) + m.gsSystemPlatform = gio.NewSettings(gsSchemaSystemPlatform) + m.gsSystemEnable = gio.NewSettings(gsSchemaSystemEnable) + m.gsMediaKey = gio.NewSettings(gsSchemaMediaKey) + m.gsPower = gio.NewSettings(gsSchemaSessionPower) + m.wm = wm.NewWm(sessionBus) + m.keyEvent = keyevent.NewKeyEvent(sysBus) + m.network = network.NewNetwork(sessionBus) + + m.shortcutManager = shortcuts.NewShortcutManager(m.conn, m.keySymbols, m.handleKeyEvent) + + // when session is locked, we need handle some keyboard function event + m.lockFront = lockfront.NewLockFront(sessionBus) + m.lockFront.InitSignalExt(m.sessionSigLoop, true) + m.lockFront.ConnectChangKey(func(changKey string) { + m.handleKeyEventFromLockFront(changKey) + }) + + m.shutdownFront = shutdownfront.NewShutdownFront(sessionBus) + m.shutdownFront.InitSignalExt(m.sessionSigLoop, true) + m.shutdownFront.ConnectChangKey(func(changKey string) { + m.handleKeyEventFromShutdownFront(changKey) + }) + + if _useWayland { + if shouldUseDDEKwin() { + m.shortcutManager.AddSpecialToKwin(m.wm) + m.shortcutManager.AddSystemToKwin(m.gsSystem, m.wm) + m.shortcutManager.AddMediaToKwin(m.gsMediaKey, m.wm) + m.shortcutManager.AddKWinForWayland(m.wm) + } else { + m.shortcutManager.AddSpecial() + m.shortcutManager.AddSystem(m.gsSystem, m.gsSystemPlatform, m.gsSystemEnable, m.wm) + m.shortcutManager.AddMedia(m.gsMediaKey, m.wm) + m.gsGnomeWM = gio.NewSettings(gsSchemaGnomeWM) + m.shortcutManager.AddWM(m.gsGnomeWM, m.wm) + } + } else { + m.shortcutManager.AddSystem(m.gsSystem, m.gsSystemPlatform, m.gsSystemEnable, m.wm) + m.shortcutManager.AddMedia(m.gsMediaKey, m.wm) + if shouldUseDDEKwin() { + logger.Debug("Use DDE KWin") + m.shortcutManager.AddKWin(m.wm) + } else { + logger.Debug("Use gnome WM") + m.gsGnomeWM = gio.NewSettings(gsSchemaGnomeWM) + m.shortcutManager.AddWM(m.gsGnomeWM, m.wm) + } + } + + // init custom shortcuts + customConfigFilePath := filepath.Join(basedir.GetUserConfigDir(), customConfigFile) + m.customShortcutManager = shortcuts.NewCustomShortcutManager(customConfigFilePath) + m.shortcutManager.AddCustom(m.customShortcutManager, m.wm) + + // init controllers + m.backlightHelper = backlight.NewBacklight(sysBus) + m.audioController = NewAudioController(sessionBus, m.backlightHelper) + m.mediaPlayerController = NewMediaPlayerController(m.systemSigLoop, sessionBus) + + //m.startManager = sessionmanager.NewStartManager(sessionBus) + m.airplane = airplanemode.NewAirplaneMode(sysBus) + m.networkmanager = networkmanager.NewManager(sysBus) + m.sessionManager = sessionmanager.NewSessionManager(sessionBus) + m.keyboard = inputdevices.NewKeyboard(sessionBus) + m.keyboard.InitSignalExt(m.sessionSigLoop, true) + err := m.keyboard.CurrentLayout().ConnectChanged(func(hasValue bool, layout string) { + if !hasValue { + return + } + if m.keyboardLayout != layout { + m.keyboardLayout = layout + logger.Debug("keyboard layout changed:", layout) + m.shortcutManager.NotifyLayoutChanged() + } + }) + + if err != nil { + logger.Warning("connect CurrentLayout property changed failed:", err) + } + + m.displayController = NewDisplayController(m.backlightHelper, sessionBus, m) + m.kbdLightController = NewKbdLightController(m.backlightHelper) + m.touchPadController = NewTouchPadController(sessionBus) + + m.initSpecialKeycodeMap() + m.keyEvent.InitSignalExt(m.systemSigLoop, true) + _, err = m.keyEvent.ConnectKeyEvent(m.handleSpecialKeycode) + if err != nil { + logger.Warning(err) + } + + sysInfo := systeminfo.NewSystemInfo(sysBus) + dmiInfo, err := sysInfo.DMIInfo().Get(0) + if err != nil { + logger.Warning(err) + } else { + m.dmiInfo = dmiInfo + } + + if _useWayland { + m.initHandlers() + m.clickNum = 0 + + go m.listenGlobalAccel(sessionBus) + go m.listenKeyboardEvent(sysBus) + } + + m.rfkillState, err = m.airplane.Enabled().Get(0) + if err != nil { + logger.Warning(err) + } else { + logger.Info("init rfkillState : ", m.rfkillState) + } + + hasOwner, err := m.service.NameHasOwner(appManagerDBusServiceName) + if err != nil { + logger.Warning("failed to call NameHasOwner:", err) + } + if hasOwner { + m.useNewAppManager = true + } +} + +func (m *Manager) initDSettings(bus *dbus.Conn) { + ds := configManager.NewConfigManager(bus) + dsPath, err := ds.AcquireManager(0, DSettingsAppID, DSettingsKeyBindingName, "") + if err != nil { + logger.Warning(err) + return + } + + keybindingDS, err := configManager.NewManager(bus, dsPath) + if err != nil { + logger.Warning(err) + return + } + + getWirelessControlEnableConfig := func() { + v, err := keybindingDS.Value(0, DSettingsKeyWirelessControlEnable) + if err != nil { + logger.Warning(err) + return + } + m.wifiControlEnable = v.Value().(bool) + } + getNeedXrandrQConfig := func() { + v, err := keybindingDS.Value(0, DSettingsKeyNeedXrandrQDevices) + if err != nil { + logger.Warning(err) + return + } + itemList := v.Value().([]dbus.Variant) + for _, i := range itemList { + m.needXrandrQDevice = append(m.needXrandrQDevice, i.Value().(string)) + } + } + + getDeviceManagerControlEnableConfig := func() { + v, err := keybindingDS.Value(0, DSettingsKeyDeviceManagerControlEnable) + if err != nil { + logger.Warning(err) + return + } + m.deviceManagerControlEnable = v.Value().(bool) + } + getWirelessControlEnableConfig() + getNeedXrandrQConfig() + getDeviceManagerControlEnableConfig() + + keybindingDS.InitSignalExt(m.systemSigLoop, true) + // 监听dsg配置变化 + _, err = keybindingDS.ConnectValueChanged(func(key string) { + switch key { + case DSettingsKeyWirelessControlEnable: + getWirelessControlEnableConfig() + case DSettingsKeyNeedXrandrQDevices: + getNeedXrandrQConfig() + case DSettingsKeyDeviceManagerControlEnable: + getDeviceManagerControlEnableConfig() + } + }) + if err != nil { + logger.Warning(err) + } +} + +var kwinSysActionCmdMap = map[string]string{ + "Launcher": "launcher", // Super_L Super_R + "Terminal": "terminal", // T + "Terminal Quake Window": "terminal-quake", // + "Lock screen": "lock-screen", // super+l + "Shutdown interface": "logout", // ctrl+alt+del + "File manager": "file-manager", // super+e + "Screenshot": "screenshot", // ctrl+alt+a + "Full screenshot": "screenshot-fullscreen", // print + "Window screenshot": "screenshot-window", // alt+print + "Delay screenshot": "screenshot-delayed", // ctrl+print + "Disable Touchpad": "disable-touchpad", // + "Switch window effects": "wm-switcher", // alt+tab + "turn-off-screen": "Fast Screen Off", // L + "Deepin Picker": "color-picker", // ctrl+alt+v + "System Monitor": "system-monitor", // ctrl+alt+escape + "Screen Recorder": "deepin-screen-recorder", // deepin-screen-recorder ctrl+alt+r + "Desktop AI Assistant": "ai-assistant", // ai-assistant [Q]q + "Text to Speech": "text-to-speech", + "Speech to Text": "speech-to-text", + "Clipboard": "clipboard", + "Translation": "translation", + "Show/Hide the dock": "show-dock", + + // cmd + "Calculator": "calculator", // XF86Calculator + "Search": "search", // XF86Search + "Notification Center": "notification-center", // Meta M + + "ScreenshotScroll": "screenshot-scroll", + "ScreenshotOcr": "screenshot-ocr", + "Global Search": "global-search", + "Switch monitors": "switch-monitors", +} + +var waylandMediaIdMap = map[string]string{ + "Messenger": "messenger", // XF86Messenger + "Save": "save", // XF86Save + "New": "new", // XF86New + "WakeUp": "wake-up", // XF86WakeUp + "audio-rewind": "AudioRewind", // XF86AudioRewind + "VolumeMute": "audio-mute", // XF86AudioMute "AudioMute": + "MonBrightnessUp": "mon-brightness-up", // XF86MonBrightnessUp + "WLAN": "wlan", // XF86WLAN + "AudioMedia": "audio-media", // XF86AudioMedia + "reply": "Reply", // XF86Reply + "favorites": "Favorites", // XF86Favorites + "AudioPlay": "audio-play", // XF86AudioPlay + "AudioMicMute": "audio-mic-mute", // XF86AudioMicMute + "AudioPause": "audio-pause", // XF86AudioPause + "AudioStop": "audio-stop", // XF86AudioStop + "documents": "Documents", // XF86Documents + "game": "Game", // XF86Game + "AudioRecord": "audio-record", // XF86AudioRecord + "Display": "display", // XF86Display + "reload": "Reload", // XF86Reload + "explorer": "Explorer", // XF86Explorer + "calendar": "Calendar", // XF86Calendar + "forward": "Forward", // XF86Forward + "cut": "Cut", // XF86Cut + "MonBrightnessDown": "mon-brightness-down", // XF86MonBrightnessDown + "Copy": "copy", // XF86Copy + "Tools": "tools", // XF86Tools + "VolumeUp": "audio-raise-volume", // XF86AudioRaiseVolume "AudioRaiseVolume": "audio-raise-volume", + "media-close": "media-Close", // XF86Close + "WWW": "www", // XF86WWW + "HomePage": "home-page", // XF86HomePage + "sleep": "Sleep", // XF86Sleep + "VolumeDown": "audio-lower-volume", // XF86AudioLowerVolume "AudioLowerVolume": "audio-lower-volume", + "AudioPrev": "audio-prev", // XF86AudioPrev + "AudioNext": "audio-next", // XF86AudioNext + "Paste": "paste", // XF86Paste + "open": "Open", // XF86Open + "send": "Send", // XF86Send + "my-computer": "MyComputer", // XF86MyComputer + "Mail": "mail", // XF86Mail + "adjust-brightness": "BrightnessAdjust", // XF86BrightnessAdjust + "LogOff": "log-off", // XF86LogOff + "pictures": "Pictures", // XF86Pictures + "Terminal": "terminal", // XF86Terminal + "video": "Video", // XF86Video + "Music": "music", // XF86Music + "app-left": "ApplicationLeft", // XF86ApplicationLeft + "app-right": "ApplicationRight", // XF86ApplicationRight + "meeting": "Meeting", // XF86Meeting + "Numlock": "numlock", + "Capslock": "capslock", + "Switch kbd layout": "switch-kbd-layout", +} + +func (m *Manager) listenGlobalAccel(sessionBus *dbus.Conn) error { + err := sessionBus.Object("org.kde.kglobalaccel", + "/component/kwin").AddMatchSignal("org.kde.kglobalaccel.Component", "globalShortcutPressed").Err + if err != nil { + logger.Warning(err) + return err + } + + m.sessionSigLoop.AddHandler(&dbusutil.SignalRule{ + Name: "org.kde.kglobalaccel.Component.globalShortcutPressed", + }, func(sig *dbus.Signal) { + if len(sig.Body) > 1 { + const minKeyEventInterval = 200 * time.Millisecond + now := time.Now() + duration := now.Sub(m.lastKeyEventTime) + if 0 < duration && duration < minKeyEventInterval { + logger.Debug("ignore key event duration:", duration) + return + } + m.lastKeyEventTime = now + + m.shortcutKey = sig.Body[0].(string) + m.shortcutKeyCmd = sig.Body[1].(string) + shortId := kwinSysActionCmdMap[m.shortcutKeyCmd] + if shortId != "" && m.DisabledSystemShortcutsList.Contains(shortId) { + logger.Warningf("shortcut id: %s is disabled", shortId) + return + } + ok := strings.Compare(string("kwin"), m.shortcutKey) + if ok == 0 { + logger.Debug("[global key] get accel sig.Body[1]", m.shortcutKeyCmd) + if m.shortcutKeyCmd == "" { + // + 把响应一次的逻辑放到协程外执行,防止协程响应延迟 + m.handleKeyEventByWayland(waylandMediaIdMap[m.shortcutKeyCmd]) + } else { + m.shortcutCmd = shortcuts.GetSystemActionCmd(kwinSysActionCmdMap[m.shortcutKeyCmd]) + if m.shortcutCmd == "" { + m.shortcutCmd = m.shortcutManager.WaylandCustomShortCutMap[m.shortcutKeyCmd] + } + logger.Debug("WaylandCustomShortCutMap", m.shortcutCmd) + if m.shortcutCmd == "" { + m.handleKeyEventByWayland(waylandMediaIdMap[m.shortcutKeyCmd]) + } else { + if strings.HasSuffix(m.shortcutCmd, ".desktop") { + err := m.runDesktopFile(m.shortcutCmd) + if err != nil { + logger.Warning(err) + } + } else { + go func() { + err := m.execCmd(m.shortcutCmd, true) + if err != nil { + logger.Warning(err) + } + }() + } + } + } + } + } + }) + + return nil +} + +func (m *Manager) listenKeyboardEvent(systemBus *dbus.Conn) { + err := systemBus.Object("org.deepin.dde.Gesture1", + "/org/deepin/dde/Gesture1").AddMatchSignal("org.deepin.dde.Gesture1", "KeyboardEvent").Err + if err != nil { + logger.Warning(err) + } + m.systemSigLoop.AddHandler(&dbusutil.SignalRule{ + Name: "org.deepin.dde.Gesture1.KeyboardEvent", + }, func(sig *dbus.Signal) { + if len(sig.Body) > 1 { + key := sig.Body[0].(uint32) + value := sig.Body[1].(uint32) + + if key == CapslockKey && value == KeyPress { + m.handleKeyEventByWayland("capslock") + } else if key == NumlockKey && value == KeyPress { + m.handleKeyEventByWayland("numlock") + } + } + }) +} + +// 初始化 NumLock 数字锁定键状态 +func (m *Manager) initNumLockState(sysBus *dbus.Conn) { + // 从 gsettings 读取相关设置 + nlState := NumLockState(m.NumLockState.Get()) + saveStateEnabled := m.gsKeyboard.GetBoolean(gsKeySaveNumLockState) + if nlState == NumLockUnknown { + // 判断是否是笔记本, 只根据电池状态,有电池则是笔记本。 + isLaptop := false + sysPower := power.NewPower(sysBus) + hasBattery, err := sysPower.HasBattery().Get(0) + if err != nil { + logger.Warning("failed to get sysPower HasBattery property:", err) + } else if hasBattery { + isLaptop = true + } + + state := NumLockUnknown + logger.Debug("isLaptop:", isLaptop) + if isLaptop { + // 笔记本,默认关闭。 + state = NumLockOff + } else { + // 台式机等,默认开启。 + state = NumLockOn + } + + if saveStateEnabled { + // 保存新状态到 gsettings + m.NumLockState.Set(int32(state)) + } + + err = setNumLockState(m.waylandOutputMgr, m.conn, m.keySymbols, state) + if err != nil { + logger.Warning("setNumLockState failed:", err) + } + } else { + if saveStateEnabled { + err := setNumLockState(m.waylandOutputMgr, m.conn, m.keySymbols, nlState) + if err != nil { + logger.Warning("setNumLockState failed:", err) + } + } + } + +} + +// 检查快捷键时间间隔,如果间隔太短返回false,不应该响应快捷键 +func (m *Manager) checkKeyEventInterval() bool { + const minKeyEventInterval = 200 * time.Millisecond + now := time.Now() + duration := now.Sub(m.lastKeyEventTime) + if 0 < duration && duration < minKeyEventInterval { + logger.Debug("handleKeyEvent ignore key event duration:", duration) + return false + } + m.lastKeyEventTime = now + return true +} + +func (m *Manager) handleKeyEventFromLockFront(changKey string) { + if !m.checkKeyEventInterval() { + return + } + logger.Debugf("Receive LockFront ChangKey Event %s", changKey) + action := shortcuts.GetAction(changKey) + + // numlock/capslock + if action.Type == shortcuts.ActionTypeShowNumLockOSD || + action.Type == shortcuts.ActionTypeShowCapsLockOSD || + action.Type == shortcuts.ActionTypeSystemShutdown { + if handler := m.handlers[int(action.Type)]; handler != nil { + handler(nil) + } else { + logger.Warning("handler is nil") + } + } else { + cmd, ok := action.Arg.(shortcuts.ActionCmd) + if !ok { + logger.Warning(errTypeAssertionFail) + } else { + if action.Type == shortcuts.ActionTypeAudioCtrl { + // audio-mute/audio-lower-volume/audio-raise-volume + if m.audioController != nil { + if err := m.audioController.ExecCmd(cmd); err != nil { + logger.Warning(m.audioController.Name(), "Controller exec cmd err:", err) + } + } + } else if action.Type == shortcuts.ActionTypeDisplayCtrl { + // mon-brightness-up/mon-brightness-down + if m.displayController != nil { + if err := m.displayController.ExecCmd(cmd); err != nil { + logger.Warning(m.displayController.Name(), "Controller exec cmd err:", err) + } + } + } else if action.Type == shortcuts.ActionTypeTouchpadCtrl { + // touchpad-toggle/touchpad-on/touchpad-off + if m.touchPadController != nil { + if err := m.touchPadController.ExecCmd(cmd); err != nil { + logger.Warning(m.touchPadController.Name(), "Controller exec cmd err:", err) + } + } + } + } + } +} + +func (m *Manager) handleKeyEventByWayland(changKey string) { + action := shortcuts.GetAction(changKey) + var isWaylandGrabed bool = false + if _useWayland { + isWaylandGrabed = true + if action.Type == shortcuts.ActionTypeShowNumLockOSD || action.Type == shortcuts.ActionTypeShowCapsLockOSD { + sessionBus, err := dbus.SessionBus() + if err != nil { + return + } + sessionObj := sessionBus.Object("org.kde.KWin", "/KWin") + err = sessionObj.Call("org.kde.KWin.xwaylandGrabed", 0).Store(&isWaylandGrabed) + if err != nil { + logger.Warning(err) + return + } + logger.Debug("xwaylandGrabed: ", isWaylandGrabed) + } + } + // numlock/capslock + if action.Type == shortcuts.ActionTypeSystemShutdown { + var powerPressAction int32 + systemBus, _ := dbus.SystemBus() + systemPower := power.NewPower(systemBus) + onBattery, err := systemPower.OnBattery().Get(0) + if err != nil { + logger.Error(err) + } + if onBattery { + powerPressAction = m.gsPower.GetEnum("battery-press-power-button") + } else { + powerPressAction = m.gsPower.GetEnum("line-power-press-power-button") + } + logger.Debug("powerPressAction:", powerPressAction) + switch powerPressAction { + case powerActionShutdown: + m.systemShutdown() + case powerActionSuspend: + systemSuspend() + case powerActionHibernate: + m.systemHibernate() + case powerActionTurnOffScreen: + m.systemTurnOffScreen() + case powerActionShowUI: + cmd := "dde-shutdown" + go func() { + err := m.execCmd(cmd, false) + if err != nil { + logger.Warning("execCmd error:", err) + } + }() + } + } else if action.Type == shortcuts.ActionTypeShowControlCenter { + err := m.execCmd("dbus-send --session --dest=com.deepin.dde.ControlCenter --print-reply /com/deepin/dde/ControlCenter com.deepin.dde.ControlCenter.Show", + false) + if err != nil { + logger.Warning("failed to show control center:", err) + } + + } else if action.Type == shortcuts.ActionTypeToggleWireless { + // 如果已经开启了飞行模式,则不能通过快捷键去控制wifi的使能 + enabled, err := m.airplane.Enabled().Get(0) + if err != nil { + logger.Warningf("get airplane enabled failed, err: %v", err) + return + } + + if enabled { + logger.Debug("airplane mode enabled, can not enable wireless by key") + return + } + + // check if allow set wireless + // and check if Wifi shortcut effected by DDE software + if m.gsMediaKey.GetBoolean(gsKeyUpperLayerWLAN) && m.wifiControlEnable { + enabled, err := m.airplane.WifiEnabled().Get(0) + if err != nil { + logger.Warningf("get wireless enabled failed, err: %v", err) + return + } + // FIXME: 修复NM WiFi无法恢复bug, 使快捷键能够恢复WiFi问题 + if !enabled { + if devicesJson, err := m.network.Devices().Get(0); err == nil { + networkDevices := make(map[string][]*networkDevice) + json.Unmarshal([]byte(devicesJson), &networkDevices) + for _, wifiDevice := range networkDevices["wireless"] { + if wifiDevice.InterfaceFlags == 0 { + // wifi里有未up的网络接口时尝试重置下wifi网络 + logger.Info("rest wifi, because some link down") + if err := m.networkmanager.WirelessEnabled().Set(0, false); err != nil { + logger.Warning(err) + } + if err := m.networkmanager.WirelessEnabled().Set(0, true); err != nil { + logger.Warning(err) + } + break + } + } + } + } + err = m.airplane.EnableWifi(0, !enabled) + if err != nil { + logger.Warningf("set wireless enabled failed, err: %v", err) + return + } + } + } else if action.Type == shortcuts.ActionTypeShowNumLockOSD { + var state NumLockState + if !isWaylandGrabed { + if _useWayland { + sessionBus, err := dbus.SessionBus() + if err != nil { + return + } + time.Sleep(200 * time.Millisecond) // + 添加200ms延时,保证在dde-system-daemon中先获取状态; + sessionObj := sessionBus.Object("org.kde.KWin", "/Xkb") + var ret int32 + err = sessionObj.Call("org.kde.kwin.Xkb.getLeds", 0).Store(&ret) + if err != nil { + logger.Warning(err) + return + } + if 0 == (ret & 0x1) { + state = NumLockOff + } else { + state = NumLockOn + } + } else { + var err error + state, err = queryNumLockState(m.conn) + if err != nil { + logger.Warning(err) + return + } + } + + save := m.gsKeyboard.GetBoolean(gsKeySaveNumLockState) + + switch state { + case NumLockOn: + if save { + m.NumLockState.Set(int32(NumLockOn)) + } + showOSD("NumLockOn") + case NumLockOff: + if save { + m.NumLockState.Set(int32(NumLockOff)) + } + showOSD("NumLockOff") + } + } + } else if action.Type == shortcuts.ActionTypeShowCapsLockOSD { + if !m.shouldShowCapsLockOSD() { + return + } + + if !isWaylandGrabed { + var state CapsLockState + if _useWayland { + sessionBus, err := dbus.SessionBus() + if err != nil { + return + } + time.Sleep(200 * time.Millisecond) // + 添加200ms延时,保证在dde-system-daemon中先获取状态; + sessionObj := sessionBus.Object("org.kde.KWin", "/Xkb") + var ret int32 + err = sessionObj.Call("org.kde.kwin.Xkb.getLeds", 0).Store(&ret) + if err != nil { + logger.Warning(err) + return + } + if 0 == (ret & 0x2) { + state = CapsLockOff + } else { + state = CapsLockOn + } + } else { + state, err := queryCapsLockState(m.conn) + if err != nil { + logger.Warning(err) + return + } + logger.Debug("caps:", state) + } + + switch state { + case CapsLockOff: + showOSD("CapsLockOff") + case CapsLockOn: + showOSD("CapsLockOn") + } + } + } else if action.Type == shortcuts.ActionTypeSwitchKbdLayout { + switch m.switchKbdLayoutState { + case SKLStateNone: + m.switchKbdLayoutState = SKLStateWait + go m.sklWait() + + case SKLStateWait: + m.switchKbdLayoutState = SKLStateOSDShown + m.terminateSKLWait() + showOSD("SwitchLayout") + + case SKLStateOSDShown: + showOSD("SwitchLayout") + } + } else { + cmd, ok := action.Arg.(shortcuts.ActionCmd) + if !ok { + logger.Warning(errTypeAssertionFail) + } else { + if action.Type == shortcuts.ActionTypeAudioCtrl { + // audio-mute/audio-lower-volume/audio-raise-volume + if m.audioController != nil { + if err := m.audioController.ExecCmd(cmd); err != nil { + logger.Warning(m.audioController.Name(), "Controller exec cmd err:", err) + } + } + } else if action.Type == shortcuts.ActionTypeDisplayCtrl { + // mon-brightness-up/mon-brightness-down + if m.displayController != nil { + if err := m.displayController.ExecCmd(cmd); err != nil { + logger.Warning(m.displayController.Name(), "Controller exec cmd err:", err) + } + } + } else if action.Type == shortcuts.ActionTypeTouchpadCtrl { + // touchpad-toggle/touchpad-on/touchpad-off + if m.touchPadController != nil { + if err := m.touchPadController.ExecCmd(cmd); err != nil { + logger.Warning(m.touchPadController.Name(), "Controller exec cmd err:", err) + } + } + } else if action.Type == shortcuts.ActionTypeSystemShutdown { + + } else if action.Type == shortcuts.ActionTypeMediaPlayerCtrl { + // 增蓝牙耳机快捷键的处理 + if cmd == shortcuts.MediaPlayerPlay { + m.clickNum = m.clickNum + 1 + if m.clickNum == 1 { + time.AfterFunc(time.Millisecond*600, func() { + m.playMeadiaByHeadphone() + }) + } + } else { + if m.mediaPlayerController != nil { + err := m.mediaPlayerController.ExecCmd(cmd) + if err != nil { + logger.Warning(m.mediaPlayerController.Name(), "Controller exec cmd err:", err) + } + } + } + + } + } + } +} + +func getMediaPlayAction(num uint32) shortcuts.ActionCmd { + var cmd shortcuts.ActionCmd = shortcuts.MediaPlayerPlay + if num == 2 { + cmd = shortcuts.MediaPlayerNext + } else if num == 3 { + cmd = shortcuts.MediaPlayerPrevious + } else { + cmd = shortcuts.MediaPlayerPlay + } + return cmd +} + +func (m *Manager) playMeadiaByHeadphone() { + cmd := getMediaPlayAction(m.clickNum) + m.clickNum = 0 + if m.mediaPlayerController != nil { + err := m.mediaPlayerController.ExecCmd(cmd) + if err != nil { + logger.Warning(m.mediaPlayerController.Name(), "Controller exec cmd err:", err) + } + } +} + +func (m *Manager) handleKeyEventFromShutdownFront(changKey string) { + logger.Debugf("handleKeyEvent %s from ShutdownFront", changKey) + action := shortcuts.GetAction(changKey) + if action.Type == shortcuts.ActionTypeSystemShutdown { + if handler := m.handlers[int(action.Type)]; handler != nil { + handler(nil) + } else { + logger.Warning("handler [system shutdown] is nil") + } + } +} + +func (m *Manager) destroy() { + err := m.service.StopExport(m) + if err != nil { + logger.Warning("stop export failed:", err) + } + + if m.shortcutManager != nil { + m.shortcutManager.Destroy() + m.shortcutManager = nil + } + + // destroy settings + if m.gsSystem != nil { + m.gsSystem.Unref() + m.gsSystem = nil + } + + if m.gsMediaKey != nil { + m.gsMediaKey.Unref() + m.gsMediaKey = nil + } + + if m.gsGnomeWM != nil { + m.gsGnomeWM.Unref() + m.gsGnomeWM = nil + } + + if m.audioController != nil { + m.audioController.Destroy() + m.audioController = nil + } + + if m.mediaPlayerController != nil { + m.mediaPlayerController.Destroy() + m.mediaPlayerController = nil + } + + if m.keyboard != nil { + m.keyboard.RemoveHandler(proxy.RemoveAllHandlers) + m.keyboard = nil + } + + if m.keyEvent != nil { + m.keyEvent.RemoveHandler(proxy.RemoveAllHandlers) + m.keyEvent = nil + } + + if m.sessionSigLoop != nil { + m.sessionSigLoop.Stop() + m.sessionSigLoop = nil + } + + if m.systemSigLoop != nil { + m.systemSigLoop.Stop() + m.systemSigLoop = nil + } + + if m.conn != nil { + m.conn.Close() + m.conn = nil + } +} + +func (m *Manager) handleKeyEvent(ev *shortcuts.KeyEvent) { + if !m.checkKeyEventInterval() { + return + } + logger.Debugf("handleKeyEvent ev: %#v", ev) + action := ev.Shortcut.GetAction() + shortcutId := ev.Shortcut.GetId() + logger.Debugf("shortcut id: %s, type: %v, action: %#v", + shortcutId, ev.Shortcut.GetType(), action) + if ev.Shortcut.GetType() == shortcuts.ShortcutTypeSystem && m.DisabledSystemShortcutsList.Contains(shortcutId) { + logger.Warningf("shortcut id: %s is disabled", shortcutId) + return + } + if action == nil { + logger.Warning("action is nil") + return + } + if len(m.handlers) == 0 { + logger.Warning("handlers is nil") + return + } + if handler := m.handlers[int(action.Type)]; handler != nil { + handler(ev) + } else { + logger.Warning("handler is nil") + } +} + +func (m *Manager) emitShortcutSignal(signalName string, shortcut shortcuts.Shortcut) { + logger.Debug("emit DBus signal", signalName, shortcut.GetId(), shortcut.GetType()) + err := m.service.Emit(m, signalName, shortcut.GetId(), shortcut.GetType()) + if err != nil { + logger.Warning(err) + } +} + +func (m *Manager) enableListenGSettingsChanged(val bool) { + m.enableListenGSettings = val +} + +func (m *Manager) listenGSettingsChanged(schema string, settings *gio.Settings, type0 int32) { + gsettings.ConnectChanged(schema, "*", func(key string) { + if !m.enableListenGSettings { + return + } + + shortcut := m.shortcutManager.GetByIdType(key, type0) + if shortcut == nil { + return + } + + keystrokes := settings.GetStrv(key) + m.shortcutManager.ModifyShortcutKeystrokes(shortcut, shortcuts.ParseKeystrokes(keystrokes)) + m.emitShortcutSignal(shortcutSignalChanged, shortcut) + }) +} + +func (m *Manager) listenSystemEnableChanged() { + gsettings.ConnectChanged(gsSchemaSystemEnable, "*", func(key string) { + if !m.enableListenGSettings { + return + } + + if m.shortcutManager.CheckSystem(m.gsSystemPlatform, m.gsSystemEnable, key) { + m.shortcutManager.AddSystemById(m.gsSystem, m.wm, key) + } else { + m.shortcutManager.DelSystemById(key) + } + }) +} + +func (m *Manager) listenSystemPlatformChanged() { + gsettings.ConnectChanged(gsSchemaSystemPlatform, "*", func(key string) { + if !m.enableListenGSettings { + return + } + + if m.shortcutManager.CheckSystem(m.gsSystemPlatform, m.gsSystemEnable, key) { + m.shortcutManager.AddSystemById(m.gsSystem, m.wm, key) + } else { + m.shortcutManager.DelSystemById(key) + } + }) +} + +func runCommand(cmd string) (string, error) { + result, err := exec.Command("/bin/sh", "-c", cmd).Output() + if err != nil { + return "", err + } + return strings.TrimSpace(string(result)), err +} + +func checkProRunning(serverName string) bool { + cmd := `ps ux | awk '/` + serverName + `/ && !/awk/ {print $2}'` + pid, err := runCommand(cmd) + if err != nil { + logger.Warning(err) + return false + } + return pid != "" +} + +func (m *Manager) execCmd(cmd string, viaStartdde bool) error { + if cmd == "" { + logger.Debug("cmd is empty") + return nil + } + if strings.HasPrefix(cmd, "dbus-send ") || !viaStartdde { + logger.Debug("run cmd:", cmd) + // #nosec G204 + return exec.Command("/bin/sh", "-c", cmd).Run() + } + + logger.Debug("exec run cmd:", cmd) + + if m.useNewAppManager { + desktopExt := ".desktop" + sha256Hasher := sha256.New() + _, err := sha256Hasher.Write([]byte(cmd)) + if err != nil { + logger.Warning("generate sha256 hash failed with error: ", err) + return err + } + desktopPre := sha256Hasher.Sum(nil) + name := hex.EncodeToString(desktopPre) + desktopFileName := "daemon-keybinding-" + name + desktopExt + + _, err = os.Stat(basedir.GetUserDataDir() + "/applications/" + desktopFileName) + // 如果对应命令的desktop文件不存在,需要新建desktop文件 + if os.IsNotExist(err) { + desktopInfoMap := map[string]dbus.Variant{ + KeyExec: dbus.MakeVariant(map[string]string{ + "default": cmd, + }), + KeyIcon: dbus.MakeVariant(map[string]string{ + "default-icon": "", + }), + KeyMimeType: dbus.MakeVariant([]string{""}), + KeyName: dbus.MakeVariant(map[string]string{ + "default": name, + }), + KeyTerminal: dbus.MakeVariant(false), + KeyType: dbus.MakeVariant("Application"), + KeyVersion: dbus.MakeVariant(1), + KeyNoDisplay: dbus.MakeVariant(true), + } + + appManager := newAppmanager.NewManager(m.sessionSigLoop.Conn()) + err := appManager.ReloadApplications(0) + if err != nil { + logger.Warning("reload applications error: ", err) + } + + desktopFileName, err = appManager.AddUserApplication(0, desktopInfoMap, desktopFileName) + if err != nil { + logger.Warning("adding user application error: ", err) + return err + } + } + + obj, err := desktopappinfo.GetDBusObjectFromAppDesktop(desktopFileName, appManagerDBusServiceName, appManagerDBusPath) + if err != nil { + logger.Warning("get dbus object error:", err) + return err + } + + appManagerAppObj, err := newAppmanager.NewApplication(m.sessionSigLoop.Conn(), obj) + if err != nil { + return err + } + + _, err = appManagerAppObj.Launch(0, "", []string{}, make(map[string]dbus.Variant)) + + if err != nil { + logger.Warningf("launch keybinding cmd %s error: %v", cmd, err) + return err + } + } else { + err := m.appManager.RunCommand(0, "/bin/sh", []string{"-c", cmd}) + if err != nil { + logger.Warningf("launch keybinding cmd %s error: %v", cmd, err) + return err + } + } + + return nil +} + +func (m *Manager) handleCheckCamera() error { + cmd := "deepin-camera" + viaStartdde := true + if checkProRunning(cmd) { + cmd = "killall deepin-camera" + viaStartdde = false + } + return m.execCmd(cmd, viaStartdde) +} + +func (m *Manager) runDesktopFile(desktop string) error { + if m.useNewAppManager { + obj, err := desktopappinfo.GetDBusObjectFromAppDesktop(desktop, appManagerDBusServiceName, appManagerDBusPath) + if err != nil { + logger.Warning("get dbus object error: ", err) + return err + } + + appManagerAppObj, err := newAppmanager.NewApplication(m.sessionSigLoop.Conn(), obj) + if err != nil { + return err + } + + _, err = appManagerAppObj.Launch(0, "", []string{}, make(map[string]dbus.Variant)) + if err != nil { + logger.Warning("failed to launch application", desktop) + return err + } + } else { + err := m.appManager.LaunchApp(0, desktop, 0, []string{}) + if err != nil { + logger.Warning("failed to launch application", desktop) + } + } + + return nil +} + +func (m *Manager) eliminateKeystrokeConflict() { + for _, ks := range m.shortcutManager.ConflictingKeystrokes { + shortcut := ks.Shortcut + logger.Infof("eliminate conflict shortcut: %s keystroke: %s", + ks.Shortcut.GetUid(), ks) + err := m.DeleteShortcutKeystroke(shortcut.GetId(), shortcut.GetType(), ks.String()) + if err != nil { + logger.Warning("delete shortcut keystroke failed:", err) + } + } + + m.shortcutManager.ConflictingKeystrokes = nil + m.shortcutManager.EliminateConflictDone = true +} diff --git a/keybinding/manager_handlers.go b/keybinding1/manager_handlers.go similarity index 98% rename from keybinding/manager_handlers.go rename to keybinding1/manager_handlers.go index e646d52fc..3b2212b50 100644 --- a/keybinding/manager_handlers.go +++ b/keybinding1/manager_handlers.go @@ -8,7 +8,7 @@ import ( "fmt" "time" - . "github.com/linuxdeepin/dde-daemon/keybinding/shortcuts" + . "github.com/linuxdeepin/dde-daemon/keybinding1/shortcuts" ) func (m *Manager) shouldShowCapsLockOSD() bool { diff --git a/keybinding1/manager_ifc.go b/keybinding1/manager_ifc.go new file mode 100644 index 000000000..3c1d828d5 --- /dev/null +++ b/keybinding1/manager_ifc.go @@ -0,0 +1,530 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package keybinding + +import ( + "errors" + "fmt" + "strings" + "time" + + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/keybinding1/shortcuts" + "github.com/linuxdeepin/dde-daemon/keybinding1/util" + wm "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.wm" + "github.com/linuxdeepin/go-gir/gio-2.0" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +const ( + dbusServiceName = "org.deepin.dde.Keybinding1" + dbusPath = "/org/deepin/dde/Keybinding1" + dbusInterface = "org.deepin.dde.Keybinding1" +) + +type ErrInvalidShortcutType struct { + Type int32 +} + +func (err ErrInvalidShortcutType) Error() string { + return fmt.Sprintf("shortcut type %v is invalid", err.Type) +} + +type ErrShortcutNotFound struct { + Id string + Type int32 +} + +func (err ErrShortcutNotFound) Error() string { + return fmt.Sprintf("shortcut id %q type %v is not found", err.Id, err.Type) +} + +var errTypeAssertionFail = errors.New("type assertion failed") +var errShortcutKeystrokesUnmodifiable = errors.New("keystrokes of this shortcut is unmodifiable") +var errKeystrokeUsed = errors.New("keystroke had been used") +var errNameUsed = errors.New("name had been used") + +func (*Manager) GetInterfaceName() string { + return dbusInterface +} + +// true : ignore +func (m *Manager) isIgnoreRepeat(name string) bool { + const minKeyEventInterval = 200 * time.Millisecond + now := time.Now() + duration := now.Sub(m.lastMethodCalledTime) + logger.Debug("duration:", duration) + if 0 < duration && duration < minKeyEventInterval { + logger.Debug(">>Ignore ", name) + return true + } + m.lastMethodCalledTime = now + return false +} + +func (m *Manager) setAccelForWayland(gsettings *gio.Settings, wmObj wm.Wm) { + for _, id := range gsettings.ListKeys() { + var accelJson string + var err error + if id == "screenshot-window" { + accelJson = `{"Id":"screenshot-window","Accels":["SysReq"]}` //+ Alt+print对应kwin识别的键SysReq + } else if id == "launcher" { + accelJson = `{"Id":"launcher","Accels":["Super_L"]}` // wayland左右super对应的都是Super_L + } else if id == "system_monitor" { + accelJson = `{"Id":"system_monitor","Accels":["Escape"]}` + } else { + accelJson, err = util.MarshalJSON(util.KWinAccel{ + Id: id, + Keystrokes: gsettings.GetStrv(id), + }) + if err != nil { + logger.Warning("failed to get json:", err) + continue + } + } + + ok, err := wmObj.SetAccel(0, accelJson) + if !ok { + logger.Warning("failed to set KWin accels:", id, gsettings.GetStrv(id), err) + } + } +} + +// Reset reset all shortcut +func (m *Manager) Reset() *dbus.Error { + if m.isIgnoreRepeat("Reset") { + return nil + } + + customShortcuts := m.customShortcutManager.List() + m.shortcutManager.UngrabAll() + + m.enableListenGSettingsChanged(false) + // reset all gsettings + resetGSettings(m.gsSystem) + resetGSettings(m.gsMediaKey) + if m.gsGnomeWM != nil { + resetGSettings(m.gsGnomeWM) + } + if _useWayland { + m.setAccelForWayland(m.gsSystem, m.wm) + m.setAccelForWayland(m.gsMediaKey, m.wm) + if m.gsGnomeWM != nil { + m.setAccelForWayland(m.gsGnomeWM, m.wm) + } + } + + // reset for KWin + if shouldUseDDEKwin() { + err := resetKWin(m.wm) + if err != nil { + logger.Warning("failed to reset for KWin:", err) + } + // 由于快捷键冲突原因,有必要重置两遍 + err = resetKWin(m.wm) + if err != nil { + logger.Warning("failed to reset for KWin:", err) + } + } + + changes := m.shortcutManager.ReloadAllShortcutsKeystrokes() + m.enableListenGSettingsChanged(true) + m.shortcutManager.GrabAll() + + for _, cs := range customShortcuts { + keystrokes := cs.GetKeystrokes() + var newKeystrokes []*shortcuts.Keystroke + modifyFlag := false + for _, keystroke := range keystrokes { + conflictKeystroke, err := m.shortcutManager.FindConflictingKeystroke(keystroke) + if err != nil { + logger.Warning(err) + modifyFlag = true + continue + } + if conflictKeystroke != nil { + logger.Debugf("keystroke %v has conflict", keystroke) + modifyFlag = true + } else { + newKeystrokes = append(newKeystrokes, keystroke) + } + } + + cs0 := m.shortcutManager.GetByUid(cs.GetUid()) + if cs0 == nil { + logger.Warning("cs0 is nil") + continue + } + + m.shortcutManager.ModifyShortcutKeystrokes(cs0, newKeystrokes) + if modifyFlag { + err := cs0.SaveKeystrokes() + if err != nil { + logger.Warning(err) + } + // 将修改的自定义快捷键补充到 changes 列表中 + changes = append(changes, cs0) + } + } + + for _, shortcut := range changes { + m.emitShortcutSignal(shortcutSignalChanged, shortcut) + } + return nil +} + +func (m *Manager) ListAllShortcuts() (shortcuts string, busErr *dbus.Error) { + list := m.shortcutManager.List() + ret, err := util.MarshalJSON(list) + if err != nil { + return "", dbusutil.ToError(err) + } + return ret, nil +} + +func (m *Manager) EnableSystemShortcut(shortcuts []string, enabled bool, isPersistent bool) *dbus.Error { + for _, shortcut := range shortcuts { + if enabled { + m.DisabledSystemShortcutsList, _ = m.DisabledSystemShortcutsList.Delete(shortcut) + } else { + m.DisabledSystemShortcutsList, _ = m.DisabledSystemShortcutsList.Add(shortcut) + } + } + logger.Debug("DisabledSystemShortcutsList:", m.DisabledSystemShortcutsList) + return nil +} + +func (m *Manager) ListShortcutsByType(type0 int32) (shortcuts string, busErr *dbus.Error) { + list := m.shortcutManager.ListByType(type0) + ret, err := util.MarshalJSON(list) + if err != nil { + return "", dbusutil.ToError(err) + } + return ret, nil +} + +func (m *Manager) AddCustomShortcut(name, action, keystroke string) (id string, + type0 int32, busErr *dbus.Error) { + + logger.Debugf("Add custom key: %q %q %q", name, action, keystroke) + ks, err := shortcuts.ParseKeystroke(keystroke) + if err != nil { + logger.Warning(err) + busErr = dbusutil.ToError(err) + return + } + + exist := m.shortcutManager.GetByIdType(name, shortcuts.ShortcutTypeCustom) + if exist != nil { + err = errNameUsed + logger.Warning(err) + busErr = dbusutil.ToError(err) + return + } + + conflictKeystroke, err := m.shortcutManager.FindConflictingKeystroke(ks) + if err != nil { + logger.Warning(err) + busErr = dbusutil.ToError(err) + return + } + if conflictKeystroke != nil { + err = errKeystrokeUsed + logger.Warning(err) + busErr = dbusutil.ToError(err) + return + } + + shortcut, err := m.customShortcutManager.Add(name, action, []*shortcuts.Keystroke{ks}, m.wm) + if err != nil { + logger.Warning(err) + busErr = dbusutil.ToError(err) + return + } + if _useWayland { + err := m.processWaylandCustomShortcut(name, action, keystroke) + if err != nil { + logger.Warning(err) + busErr = dbusutil.ToError(err) + return + } + } + m.shortcutManager.Add(shortcut) + m.emitShortcutSignal(shortcutSignalAdded, shortcut) + id = shortcut.GetId() + type0 = shortcut.GetType() + return +} + +func (m *Manager) DeleteCustomShortcut(id string) *dbus.Error { + logger.Debug("DeleteCustomShortcut", id) + shortcut := m.shortcutManager.GetByIdType(id, shortcuts.ShortcutTypeCustom) + if err := m.customShortcutManager.Delete(shortcut.GetId()); err != nil { + return dbusutil.ToError(err) + } + m.shortcutManager.Delete(shortcut) + if _useWayland { + id += "-cs" + logger.Debug("RemoveAccel id: ", id) + err := m.wm.RemoveAccel(0, id) + if err != nil { + return dbusutil.ToError(errors.New("RemoveAccel failed, id: " + id)) + } + delete(m.shortcutManager.WaylandCustomShortCutMap, id) + } + m.emitShortcutSignal(shortcutSignalDeleted, shortcut) + return nil +} + +func (m *Manager) ClearShortcutKeystrokes(id string, type0 int32) *dbus.Error { + logger.Debug("ClearShortcutKeystrokes", id, type0) + shortcut := m.shortcutManager.GetByIdType(id, type0) + if shortcut == nil { + return dbusutil.ToError(ErrShortcutNotFound{id, type0}) + } + m.shortcutManager.ModifyShortcutKeystrokes(shortcut, nil) + err := shortcut.SaveKeystrokes() + if err != nil { + return dbusutil.ToError(err) + } + if shortcut.ShouldEmitSignalChanged() { + m.emitShortcutSignal(shortcutSignalChanged, shortcut) + } + return nil +} + +func (m *Manager) LookupConflictingShortcut(keystroke string) (shortcut string, busErr *dbus.Error) { + ks, err := shortcuts.ParseKeystroke(keystroke) + if err != nil { + // parse keystroke error + return "", dbusutil.ToError(err) + } + + conflictKeystroke, err := m.shortcutManager.FindConflictingKeystroke(ks) + if err != nil { + return "", dbusutil.ToError(err) + } + if conflictKeystroke != nil { + detail, err := util.MarshalJSON(conflictKeystroke.Shortcut) + if err != nil { + return "", dbusutil.ToError(err) + } + return detail, nil + } + return "", nil +} + +func (m *Manager) processWaylandCustomShortcut(id, cmd, keystroke string) *dbus.Error { + logger.Debugf("WaylandCustomShortcut id: %q, cmd: %q, keystroke: %q", id, cmd, keystroke) + wlname := id + "-cs" + keystrokeStrv := make([]string, 0) + keystrokeStrv = append(keystrokeStrv, keystroke) + accelJson, err := util.MarshalJSON(util.KWinAccel{ + Id: wlname, + Keystrokes: keystrokeStrv, + }) + if err != nil { + logger.Warning("accelJson failed: ", accelJson) + return dbusutil.ToError(err) + } + logger.Debug("SetAccel: ", wlname, keystrokeStrv) + ok, err := m.wm.SetAccel(0, accelJson) + if !ok { + logger.Warning("SetAccel failed, accelJson: ", accelJson) + return dbusutil.ToError(err) + } + sessionBus, err := dbus.SessionBus() + if err != nil { + logger.Warning("sessionBus create failed", err) + return dbusutil.ToError(err) + } + obj := sessionBus.Object("org.kde.kglobalaccel", "/kglobalaccel") + err = obj.Call("org.kde.KGlobalAccel.setActiveByUniqueName", 0, wlname, true).Err + logger.Debug("setActiveByUniqueName: ", wlname) + if err != nil { + logger.Warning("setActiveByUniqueName failed") + return dbusutil.ToError(err) + } + logger.Debug("WaylandCustomShortCutMap set", wlname) + m.shortcutManager.WaylandCustomShortCutMap[wlname] = cmd + return nil +} + +// ModifyCustomShortcut modify custom shortcut +// +// id: shortcut id +// name: new name +// cmd: new commandline +// keystroke: new keystroke +func (m *Manager) ModifyCustomShortcut(id, name, cmd, keystroke string) *dbus.Error { + logger.Debugf("ModifyCustomShortcut id: %q, name: %q, cmd: %q, keystroke: %q", id, name, cmd, keystroke) + const ty = shortcuts.ShortcutTypeCustom + // get the shortcut + shortcut := m.shortcutManager.GetByIdType(id, ty) + if shortcut == nil { + return dbusutil.ToError(ErrShortcutNotFound{id, ty}) + } + customShortcut, ok := shortcut.(*shortcuts.CustomShortcut) + if !ok { + return dbusutil.ToError(errTypeAssertionFail) + } + + var keystrokes []*shortcuts.Keystroke + if keystroke != "" { + ks, err := shortcuts.ParseKeystroke(keystroke) + if err != nil { + return dbusutil.ToError(err) + } + // check conflicting + conflictKeystroke, err := m.shortcutManager.FindConflictingKeystroke(ks) + if err != nil { + return dbusutil.ToError(err) + } + if conflictKeystroke != nil && conflictKeystroke.Shortcut != shortcut { + return dbusutil.ToError(errKeystrokeUsed) + } + keystrokes = []*shortcuts.Keystroke{ks} + } + + if _useWayland { + err := m.processWaylandCustomShortcut(id, cmd, keystroke) + if err != nil { + return err + } + } + + // modify then save + customShortcut.SetName(name) + customShortcut.Cmd = cmd + m.shortcutManager.ModifyShortcutKeystrokes(shortcut, keystrokes) + err := customShortcut.Save() + if err != nil { + return dbusutil.ToError(err) + } + m.emitShortcutSignal(shortcutSignalChanged, shortcut) + return nil +} + +func (m *Manager) AddShortcutKeystroke(id string, type0 int32, keystroke string) *dbus.Error { + logger.Debug("AddShortcutKeystroke", id, type0, keystroke) + shortcut := m.shortcutManager.GetByIdType(id, type0) + if shortcut == nil { + return dbusutil.ToError(ErrShortcutNotFound{id, type0}) + } + if !shortcut.GetKeystrokesModifiable() { + return dbusutil.ToError(errShortcutKeystrokesUnmodifiable) + } + + ks, err := shortcuts.ParseKeystroke(keystroke) + if err != nil { + // parse keystroke error + return dbusutil.ToError(err) + } + logger.Debug("keystroke:", ks.DebugString()) + + if type0 == shortcuts.ShortcutTypeWM && ks.Mods == 0 { + keyLower := strings.ToLower(ks.Keystr) + if keyLower == "super_l" || keyLower == "super_r" { + return dbusutil.ToError(errors.New( + "keystroke of shortcut which type is wm can not be set to the Super key")) + } + } + + conflictKeystroke, err := m.shortcutManager.FindConflictingKeystroke(ks) + if err != nil { + return dbusutil.ToError(err) + } + if conflictKeystroke == nil { + m.shortcutManager.AddShortcutKeystroke(shortcut, ks) + err := shortcut.SaveKeystrokes() + if err != nil { + return dbusutil.ToError(err) + } + if shortcut.ShouldEmitSignalChanged() { + m.emitShortcutSignal(shortcutSignalChanged, shortcut) + } + } else if conflictKeystroke.Shortcut != shortcut { + return dbusutil.ToError(errKeystrokeUsed) + } + + return nil +} + +func (m *Manager) DeleteShortcutKeystroke(id string, type0 int32, keystroke string) *dbus.Error { + logger.Debug("DeleteShortcutKeystroke", id, type0, keystroke) + shortcut := m.shortcutManager.GetByIdType(id, type0) + if shortcut == nil { + return dbusutil.ToError(ErrShortcutNotFound{id, type0}) + } + if !shortcut.GetKeystrokesModifiable() { + return dbusutil.ToError(errShortcutKeystrokesUnmodifiable) + } + + ks, err := shortcuts.ParseKeystroke(keystroke) + if err != nil { + // parse keystroke error + return dbusutil.ToError(err) + } + logger.Debug("keystroke:", ks.DebugString()) + + m.shortcutManager.DeleteShortcutKeystroke(shortcut, ks) + err = shortcut.SaveKeystrokes() + if err != nil { + return dbusutil.ToError(err) + } + if shortcut.ShouldEmitSignalChanged() { + m.emitShortcutSignal(shortcutSignalChanged, shortcut) + } + return nil +} + +func (m *Manager) GetShortcut(id string, type0 int32) (shortcut string, busErr *dbus.Error) { + s := m.shortcutManager.GetByIdType(id, type0) + if s == nil { + return "", dbusutil.ToError(ErrShortcutNotFound{id, type0}) + } + detail, err := s.Marshal() + if err != nil { + return "", dbusutil.ToError(err) + } + return detail, nil +} + +func (m *Manager) SelectKeystroke() *dbus.Error { + logger.Debug("SelectKeystroke") + err := m.selectKeystroke() + return dbusutil.ToError(err) +} + +func (m *Manager) SetNumLockState(state int32) *dbus.Error { + logger.Debug("SetNumLockState", state) + if _useWayland { + err := setNumLockWl(m.waylandOutputMgr, m.conn, NumLockState(state)) + m.handleKeyEventByWayland("numlock") + return dbusutil.ToError(err) + } + + return dbusutil.ToError(setNumLockX11(m.conn, m.keySymbols, NumLockState(state))) +} + +func (m *Manager) SearchShortcuts(query string) (shortcuts string, busErr *dbus.Error) { + list := m.shortcutManager.Search(query) + ret, err := util.MarshalJSON(list) + if err != nil { + return "", dbusutil.ToError(err) + } + return ret, nil +} + +func (m *Manager) GetCapsLockState() (state int32, busErr *dbus.Error) { + lockState, err := queryCapsLockState(m.conn) + return int32(lockState), dbusutil.ToError(err) +} + +func (m *Manager) SetCapsLockState(state int32) *dbus.Error { + logger.Debug("SetCapsLockState", state) + err := setCapsLockState(m.conn, m.keySymbols, CapsLockState(state)) + return dbusutil.ToError(err) +} diff --git a/keybinding/manager_ifc_deprecated.go b/keybinding1/manager_ifc_deprecated.go similarity index 96% rename from keybinding/manager_ifc_deprecated.go rename to keybinding1/manager_ifc_deprecated.go index b15847fba..92c732434 100644 --- a/keybinding/manager_ifc_deprecated.go +++ b/keybinding1/manager_ifc_deprecated.go @@ -5,9 +5,9 @@ package keybinding import ( - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/keybinding1/shortcuts" "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/dde-daemon/keybinding/shortcuts" ) // List list all shortcut diff --git a/keybinding/media_player_controller.go b/keybinding1/media_player_controller.go similarity index 91% rename from keybinding/media_player_controller.go rename to keybinding1/media_player_controller.go index 1f5431ba2..84793f48a 100644 --- a/keybinding/media_player_controller.go +++ b/keybinding1/media_player_controller.go @@ -8,13 +8,13 @@ import ( "errors" "strings" - dbus "github.com/godbus/dbus" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" - mpris2 "github.com/linuxdeepin/go-dbus-factory/org.mpris.mediaplayer2" + dbus "github.com/godbus/dbus/v5" + . "github.com/linuxdeepin/dde-daemon/keybinding1/shortcuts" + ofdbus "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.dbus" + mpris2 "github.com/linuxdeepin/go-dbus-factory/session/org.mpris.mediaplayer2" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/dbusutil/proxy" - . "github.com/linuxdeepin/dde-daemon/keybinding/shortcuts" ) const ( diff --git a/keybinding/select_keystroke.go b/keybinding1/select_keystroke.go similarity index 97% rename from keybinding/select_keystroke.go rename to keybinding1/select_keystroke.go index b4c202f49..bc41d7d48 100644 --- a/keybinding/select_keystroke.go +++ b/keybinding1/select_keystroke.go @@ -5,10 +5,10 @@ package keybinding import ( + "github.com/linuxdeepin/dde-daemon/keybinding1/shortcuts" x "github.com/linuxdeepin/go-x11-client" "github.com/linuxdeepin/go-x11-client/util/keybind" "github.com/linuxdeepin/go-x11-client/util/mousebind" - "github.com/linuxdeepin/dde-daemon/keybinding/shortcuts" ) func (m *Manager) selectKeystroke() error { diff --git a/keybinding/shortcuts/action.go b/keybinding1/shortcuts/action.go similarity index 100% rename from keybinding/shortcuts/action.go rename to keybinding1/shortcuts/action.go diff --git a/keybinding/shortcuts/custom_shortcut.go b/keybinding1/shortcuts/custom_shortcut.go similarity index 96% rename from keybinding/shortcuts/custom_shortcut.go rename to keybinding1/shortcuts/custom_shortcut.go index 53ef0d33a..ab91e77b4 100644 --- a/keybinding/shortcuts/custom_shortcut.go +++ b/keybinding1/shortcuts/custom_shortcut.go @@ -9,8 +9,8 @@ import ( "path/filepath" "strings" - "github.com/linuxdeepin/dde-daemon/keybinding/util" - wm "github.com/linuxdeepin/go-dbus-factory/com.deepin.wm" + "github.com/linuxdeepin/dde-daemon/keybinding1/util" + wm "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.wm" "github.com/linuxdeepin/go-lib/keyfile" ) @@ -109,8 +109,8 @@ func newCustomShort(id, name, cmd string, keystrokes []string, wm wm.Wm, csm *Cu Keystrokes: ParseKeystrokes(keystrokes), }, manager: csm, - wm: wm, - Cmd: cmd, + wm: wm, + Cmd: cmd, } } diff --git a/keybinding/shortcuts/gsettings_shortcut.go b/keybinding1/shortcuts/gsettings_shortcut.go similarity index 96% rename from keybinding/shortcuts/gsettings_shortcut.go rename to keybinding1/shortcuts/gsettings_shortcut.go index fe5672454..3d8f9f4ac 100644 --- a/keybinding/shortcuts/gsettings_shortcut.go +++ b/keybinding1/shortcuts/gsettings_shortcut.go @@ -5,7 +5,7 @@ package shortcuts import ( - wm "github.com/linuxdeepin/go-dbus-factory/com.deepin.wm" + wm "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.wm" "github.com/linuxdeepin/go-gir/gio-2.0" ) diff --git a/keybinding1/shortcuts/id_name_map.go b/keybinding1/shortcuts/id_name_map.go new file mode 100644 index 000000000..86829f73e --- /dev/null +++ b/keybinding1/shortcuts/id_name_map.go @@ -0,0 +1,208 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package shortcuts + +import ( + "github.com/linuxdeepin/go-lib/gettext" +) + +func getSystemIdNameMap() map[string]string { + var idNameMap = map[string]string{ + "launcher": gettext.Tr("Launcher"), + "terminal": gettext.Tr("Terminal"), + "deepin-screen-recorder": gettext.Tr("Screen Recorder"), + "lock-screen": gettext.Tr("Lock screen"), + "show-dock": gettext.Tr("Show/Hide the dock"), + "logout": gettext.Tr("Shutdown interface"), + "terminal-quake": gettext.Tr("Terminal Quake Window"), + "screenshot": gettext.Tr("Screenshot"), + "screenshot-fullscreen": gettext.Tr("Full screenshot"), + "screenshot-window": gettext.Tr("Window screenshot"), + "screenshot-delayed": gettext.Tr("Delay screenshot"), + "screenshot-ocr": gettext.Tr("OCR (Image to Text)"), + "screenshot-scroll": gettext.Tr("Scrollshot"), + "file-manager": gettext.Tr("File manager"), + "disable-touchpad": gettext.Tr("Disable Touchpad"), + "wm-switcher": gettext.Tr("Switch window effects"), + "turn-off-screen": gettext.Tr("Fast Screen Off"), + "system-monitor": gettext.Tr("System Monitor"), + "color-picker": gettext.Tr("Deepin Picker"), + "ai-assistant": gettext.Tr("Desktop AI Assistant"), + "text-to-speech": gettext.Tr("Text to Speech"), + "speech-to-text": gettext.Tr("Speech to Text"), + "clipboard": gettext.Tr("Clipboard"), + "translation": gettext.Tr("Translation"), + "global-search": gettext.Tr("Grand Search"), + "notification-center": gettext.Tr("Notification Center"), + "switch-next-kbd-layout": gettext.Tr("Switch Layout"), + "switch-monitors": gettext.Tr("Toggle multiple displays"), + } + return idNameMap +} + +func getSpecialIdNameMap() map[string]string { + var idNameMap = map[string]string{ + "switch-kbd-layout": gettext.Tr("Switch Layout"), + } + return idNameMap +} + +func getWMIdNameMap() map[string]string { + var idNameMap = map[string]string{ + "switch-to-workspace-1": "Switch to workspace 1", + "switch-to-workspace-2": "Switch to workspace 2", + "switch-to-workspace-3": "Switch to workspace 3", + "switch-to-workspace-4": "Switch to workspace 4", + "switch-to-workspace-5": "Switch to workspace 5", + "switch-to-workspace-6": "Switch to workspace 6", + "switch-to-workspace-7": "Switch to workspace 7", + "switch-to-workspace-8": "Switch to workspace 8", + "switch-to-workspace-9": "Switch to workspace 9", + "switch-to-workspace-10": "Switch to workspace 10", + "switch-to-workspace-11": "Switch to workspace 11", + "switch-to-workspace-12": "Switch to workspace 12", + "switch-to-workspace-left": gettext.Tr("Switch to left workspace"), + "switch-to-workspace-right": gettext.Tr("Switch to right workspace"), + "switch-to-workspace-up": gettext.Tr("Switch to upper workspace"), + "switch-to-workspace-down": gettext.Tr("Switch to lower workspace"), + "switch-to-workspace-last": "Switch to last workspace", + "switch-group": gettext.Tr("Switch similar windows"), + "switch-group-backward": gettext.Tr("Switch similar windows in reverse"), + "switch-applications": gettext.Tr("Switch windows"), + "switch-applications-backward": gettext.Tr("Switch windows in reverse"), + "switch-windows": "Switch windows", + "switch-windows-backward": "Reverse switch windows", + "switch-panels": "Switch system controls", + "switch-panels-backward": "Reverse switch system controls", + "cycle-group": "Switch windows of an app directly", + "cycle-group-backward": "Reverse switch windows of an app directly", + "cycle-windows": "Switch windows directly", + "cycle-windows-backward": "Reverse switch windows directly", + "cycle-panels": "Switch system controls directly", + "cycle-panels-backward": "Reverse switch system controls directly", + "show-desktop": gettext.Tr("Show desktop"), + "panel-main-menu": "Show the activities overview", + "panel-run-dialog": "Show the run command prompt", + // Don't use + // "set-spew-mark": gettext.Tr(""), + "activate-window-menu": "Activate window menu", + "toggle-fullscreen": "toggle-fullscreen", + "toggle-maximized": "Toggle maximization state", + "toggle-above": "Toggle window always appearing on top", + "maximize": gettext.Tr("Maximize window"), + "unmaximize": gettext.Tr("Restore window"), + "toggle-shaded": "Switch furl state", + "minimize": gettext.Tr("Minimize window"), + "close": gettext.Tr("Close window"), + "begin-move": gettext.Tr("Move window"), + "begin-resize": gettext.Tr("Resize window"), + "toggle-on-all-workspaces": "Toggle window on all workspaces or one", + "move-to-workspace-1": "Move to workspace 1", + "move-to-workspace-2": "Move to workspace 2", + "move-to-workspace-3": "Move to workspace 3", + "move-to-workspace-4": "Move to workspace 4", + "move-to-workspace-5": "Move to workspace 5", + "move-to-workspace-6": "Move to workspace 6", + "move-to-workspace-7": "Move to workspace 7", + "move-to-workspace-8": "Move to workspace 8", + "move-to-workspace-9": "Move to workspace 9", + "move-to-workspace-10": "Move to workspace 10", + "move-to-workspace-11": "Move to workspace 11", + "move-to-workspace-12": "Move to workspace 12", + "move-to-workspace-last": "Move to last workspace", + "move-to-workspace-left": gettext.Tr("Move to left workspace"), + "move-to-workspace-right": gettext.Tr("Move to right workspace"), + "move-to-workspace-up": gettext.Tr("Move to upper workspace"), + "move-to-workspace-down": gettext.Tr("Move to lower workspace"), + "move-to-monitor-left": "Move to left monitor", + "move-to-monitor-right": "Move to right monitor", + "move-to-monitor-up": "Move to up monitor", + "move-to-monitor-down": "Move to down monitor", + "raise-or-lower": "Raise window if covered, otherwise lower it", + "raise": "Raise window above other windows", + "lower": "Lower window below other windows", + "maximize-vertically": "Maximize window vertically", + "maximize-horizontally": "Maximize window horizontally", + "move-to-corner-nw": "Move window to top left corner", + "move-to-corner-ne": "Move window to top right corner", + "move-to-corner-sw": "Move window to bottom left corner", + "move-to-corner-se": "Move window to bottom right corner", + "move-to-side-n": "Move window to top edge of screen", + "move-to-side-s": "Move window to bottom edge of screen", + "move-to-side-e": "Move window to right side of screen", + "move-to-side-w": "Move window to left side of screen", + "move-to-center": "Move window to center of screen", + "switch-input-source": "Binding to select the next input source", + "switch-input-source-backward": "Binding to select the previous input source", + "always-on-top": "Set or unset window to appear always on top", + "expose-all-windows": gettext.Tr("Display windows of all workspaces"), + "expose-windows": gettext.Tr("Display windows of current workspace"), + "preview-workspace": gettext.Tr("Display workspace"), + "view-zoom-in": gettext.Tr("Zoom In"), + "view-zoom-out": gettext.Tr("Zoom Out"), + "view-actual-size": gettext.Tr("Zoom to Actual Size"), + } + return idNameMap +} + +func getMediaIdNameMap() map[string]string { + var idNameMap = map[string]string{ + "messenger": "Messenger", // XF86Messenger + "save": "Save", // XF86Save + "new": "New", // XF86New + "wake-up": "WakeUp", // XF86WakeUp + "audio-rewind": "AudioRewind", // XF86AudioRewind + "audio-mute": "AudioMute", // XF86AudioMute + "mon-brightness-up": "MonBrightnessUp", // XF86MonBrightnessUp + "wlan": "WLAN", // XF86WLAN + "audio-media": "AudioMedia", // XF86AudioMedia + "reply": "Reply", // XF86Reply + "favorites": "Favorites", // XF86Favorites + "audio-play": "AudioPlay", // XF86AudioPlay + "audio-mic-mute": "AudioMicMute", // XF86AudioMicMute + "audio-pause": "AudioPause", // XF86AudioPause + "audio-stop": "AudioStop", // XF86AudioStop + "documents": "Documents", // XF86Documents + "game": "Game", // XF86Game + "search": "Search", // XF86Search + "audio-record": "AudioRecord", // XF86AudioRecord + "display": "Display", // XF86Display + "reload": "Reload", // XF86Reload + "explorer": "Explorer", // XF86Explorer + "calculator": "Calculator", // XF86Calculator + "calendar": "Calendar", // XF86Calendar + "forward": "Forward", // XF86Forward + "cut": "Cut", // XF86Cut + "mon-brightness-down": "MonBrightnessDown", // XF86MonBrightnessDown + "copy": "Copy", // XF86Copy + "tools": "Tools", // XF86Tools + "audio-raise-volume": "AudioRaiseVolume", // XF86AudioRaiseVolume + "media-close": "media-Close", // XF86Close + "www": "WWW", // XF86WWW + "home-page": "HomePage", // XF86HomePage + "sleep": "Sleep", // XF86Sleep + "audio-lower-volume": "AudioLowerVolume", // XF86AudioLowerVolume + "audio-prev": "AudioPrev", // XF86AudioPrev + "audio-next": "AudioNext", // XF86AudioNext + "paste": "Paste", // XF86Paste + "open": "Open", // XF86Open + "send": "Send", // XF86Send + "my-computer": "MyComputer", // XF86MyComputer + "mail": "Mail", // XF86Mail + "adjust-brightness": "BrightnessAdjust", // XF86BrightnessAdjust + "log-off": "LogOff", // XF86LogOff + "pictures": "Pictures", // XF86Pictures + "terminal": "Terminal", // XF86Terminal + "video": "Video", // XF86Video + "music": "Music", // XF86Music + "app-left": "ApplicationLeft", // XF86ApplicationLeft + "app-right": "ApplicationRight", // XF86ApplicationRight + "meeting": "Meeting", // XF86Meeting + "touchpad-toggle": "ToggleTouchpad", // XF86TouchpadToggle + "away": "Away", // XF86Away + "web-cam": "Camera", // XF86WebCam + } + return idNameMap +} diff --git a/keybinding/shortcuts/key.go b/keybinding1/shortcuts/key.go similarity index 100% rename from keybinding/shortcuts/key.go rename to keybinding1/shortcuts/key.go diff --git a/keybinding/shortcuts/keystroke.go b/keybinding1/shortcuts/keystroke.go similarity index 100% rename from keybinding/shortcuts/keystroke.go rename to keybinding1/shortcuts/keystroke.go diff --git a/keybinding/shortcuts/keystroke_test.go b/keybinding1/shortcuts/keystroke_test.go similarity index 100% rename from keybinding/shortcuts/keystroke_test.go rename to keybinding1/shortcuts/keystroke_test.go diff --git a/keybinding/shortcuts/kwin_shortcut.go b/keybinding1/shortcuts/kwin_shortcut.go similarity index 93% rename from keybinding/shortcuts/kwin_shortcut.go rename to keybinding1/shortcuts/kwin_shortcut.go index c1ed9ffd6..4fa1d61c1 100644 --- a/keybinding/shortcuts/kwin_shortcut.go +++ b/keybinding1/shortcuts/kwin_shortcut.go @@ -9,8 +9,8 @@ import ( "os" "strings" - wm "github.com/linuxdeepin/go-dbus-factory/com.deepin.wm" - "github.com/linuxdeepin/dde-daemon/keybinding/util" + "github.com/linuxdeepin/dde-daemon/keybinding1/util" + wm "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.wm" ) type kWinShortcut struct { diff --git a/keybinding/shortcuts/media_shortcut.go b/keybinding1/shortcuts/media_shortcut.go similarity index 96% rename from keybinding/shortcuts/media_shortcut.go rename to keybinding1/shortcuts/media_shortcut.go index 5d611df8c..56e28d18a 100644 --- a/keybinding/shortcuts/media_shortcut.go +++ b/keybinding1/shortcuts/media_shortcut.go @@ -5,7 +5,7 @@ package shortcuts import ( - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" ) type MediaShortcut struct { @@ -30,7 +30,7 @@ const ( cmdMeeting = "deepin-contacts" cmdTerminal = "/usr/lib/deepin-daemon/default-terminal" cmdMessenger = "dbus-send --print-reply --dest=com.deepin.dde.osd /com/deepin/dde/Notification com.deepin.dde.Notification.Toggle" - cmdLauncher = "dbus-send --print-reply --dest=com.deepin.dde.Launcher /com/deepin/dde/Launcher com.deepin.dde.Launcher.Toggle" + cmdLauncher = "dbus-send --print-reply --dest=org.deepin.dde.Launcher1 /org/deepin/dde/Launcher1 org.deepin.dde.Launcher1.Toggle" cmdCamera = "/usr/share/dde-daemon/keybinding/cameraSwitch.sh" ) diff --git a/keybinding/shortcuts/shortcut.go b/keybinding1/shortcuts/shortcut.go similarity index 98% rename from keybinding/shortcuts/shortcut.go rename to keybinding1/shortcuts/shortcut.go index 23fedd1e5..972982cdf 100644 --- a/keybinding/shortcuts/shortcut.go +++ b/keybinding1/shortcuts/shortcut.go @@ -10,7 +10,7 @@ import ( "strconv" "sync" - "github.com/linuxdeepin/dde-daemon/keybinding/util" + "github.com/linuxdeepin/dde-daemon/keybinding1/util" "github.com/linuxdeepin/go-lib/pinyin_search" ) diff --git a/keybinding/shortcuts/shortcut_manager.go b/keybinding1/shortcuts/shortcut_manager.go similarity index 98% rename from keybinding/shortcuts/shortcut_manager.go rename to keybinding1/shortcuts/shortcut_manager.go index 0978dd14a..fe1f8e70b 100644 --- a/keybinding/shortcuts/shortcut_manager.go +++ b/keybinding1/shortcuts/shortcut_manager.go @@ -14,10 +14,10 @@ import ( "time" "unicode" - "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/keybinding/util" - daemon "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.daemon" - wm "github.com/linuxdeepin/go-dbus-factory/com.deepin.wm" + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/keybinding1/util" + wm "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.wm" + daemon "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.daemon1" gio "github.com/linuxdeepin/go-gir/gio-2.0" "github.com/linuxdeepin/go-lib/gettext" "github.com/linuxdeepin/go-lib/keyfile" @@ -702,8 +702,8 @@ func (sm *ShortcutManager) SetAllModKeysReleasedCallback(cb func()) { sm.xRecordEventHandler.allModKeysReleasedCb = cb } -//get Active Window pid -//注意: 从D-BUS启动dde-system-daemon的时候x会取不到环境变量,只能把获取pid放到dde-session-daemon +// get Active Window pid +// 注意: 从D-BUS启动dde-system-daemon的时候x会取不到环境变量,只能把获取pid放到dde-session-daemon func (sm *ShortcutManager) getActiveWindowPid() (uint32, error) { activeWin, err := ewmh.GetActiveWindow(sm.conn).Reply(sm.conn) if err != nil { @@ -730,7 +730,7 @@ func (sm *ShortcutManager) isPidVirtualMachine(pid uint32) (bool, error) { return ret, nil } -//初始化go-dbus-factory system DBUS : com.deepin.daemon.Daemon +// 初始化go-dbus-factory system DBUS : org.deepin.dde.Daemon1 func (sm *ShortcutManager) initSysDaemon() error { sysBus, err := dbus.SystemBus() if err != nil { @@ -786,7 +786,7 @@ func (sm *ShortcutManager) handleXRecordKeyEvent(pressed bool, code uint8, state // 显示桌面快捷键是窗管控制,此处需要隐藏启动器 if shortcut != nil && shortcut.GetType() == ShortcutTypeWM && shortcut.GetId() == "show-desktop" { go func() { - cmd := "dbus-send --print-reply --dest=com.deepin.dde.Launcher /com/deepin/dde/Launcher com.deepin.dde.Launcher.Hide" + cmd := "dbus-send --print-reply --dest=org.deepin.dde.Launcher1 /org/deepin/dde/Launcher1 org.deepin.dde.Launcher1.Hide" err := exec.Command("/bin/sh", "-c", cmd).Run() if err != nil { logger.Warning(err) diff --git a/keybinding/shortcuts/shortcut_manager_test.go b/keybinding1/shortcuts/shortcut_manager_test.go similarity index 100% rename from keybinding/shortcuts/shortcut_manager_test.go rename to keybinding1/shortcuts/shortcut_manager_test.go diff --git a/keybinding/shortcuts/system_shortcut.go b/keybinding1/shortcuts/system_shortcut.go similarity index 87% rename from keybinding/shortcuts/system_shortcut.go rename to keybinding1/shortcuts/system_shortcut.go index d80ace4a1..87f807861 100644 --- a/keybinding/shortcuts/system_shortcut.go +++ b/keybinding1/shortcuts/system_shortcut.go @@ -82,12 +82,12 @@ func getSystemActionCmd(id string) string { // key is id, value is commandline. var defaultSysActionCmdMap = map[string]string{ - "launcher": "dbus-send --print-reply --dest=com.deepin.dde.Launcher /com/deepin/dde/Launcher com.deepin.dde.Launcher.Toggle", + "launcher": "dbus-send --print-reply --dest=org.deepin.dde.Launcher1 /org/deepin/dde/Launcher1 org.deepin.dde.Launcher1.Toggle", "terminal": "/usr/lib/deepin-daemon/default-terminal", "terminal-quake": "deepin-terminal --quake-mode", - "lock-screen": "originmap=$(setxkbmap -query | grep option | awk -F ' ' '{print $2}');/usr/bin/setxkbmap -option grab:break_actions&&/usr/bin/xdotool key XF86Ungrab&&dbus-send --print-reply --dest=com.deepin.dde.lockFront /com/deepin/dde/lockFront com.deepin.dde.lockFront.Show&&/usr/bin/setxkbmap -option $originmap", + "lock-screen": "originmap=$(setxkbmap -query | grep option | awk -F ' ' '{print $2}');/usr/bin/setxkbmap -option grab:break_actions&&/usr/bin/xdotool key XF86Ungrab&&dbus-send --print-reply --dest=org.deepin.dde.LockFront1 /org/deepin/dde/LockFront1 org.deepin.dde.LockFront1.Show&&/usr/bin/setxkbmap -option $originmap", //wayland不能设置XF86Ungrab,否则会导致Bug-224309 - "lock-screen-wayland": "originmap=$(setxkbmap -query | grep option | awk -F ' ' '{print $2}');/usr/bin/setxkbmap -option grab:break_actions&&dbus-send --print-reply --dest=com.deepin.dde.lockFront /com/deepin/dde/lockFront com.deepin.dde.lockFront.Show&&/usr/bin/setxkbmap -option $originmap", + "lock-screen-wayland": "originmap=$(setxkbmap -query | grep option | awk -F ' ' '{print $2}');/usr/bin/setxkbmap -option grab:break_actions&&dbus-send --print-reply --dest=org.deepin.dde.LockFront1 /org/deepin/dde/LockFront1 org.deepin.dde.LockFront1.Show&&/usr/bin/setxkbmap -option $originmap", "logout": "dbus-send --print-reply --dest=com.deepin.dde.shutdownFront /com/deepin/dde/shutdownFront com.deepin.dde.shutdownFront.Show", "deepin-screen-recorder": "dbus-send --print-reply --dest=com.deepin.ScreenRecorder /com/deepin/ScreenRecorder com.deepin.ScreenRecorder.stopRecord", "system-monitor": "/usr/bin/deepin-system-monitor", @@ -104,9 +104,9 @@ var defaultSysActionCmdMap = map[string]string{ "wm-switcher": "dbus-send --type=method_call --dest=com.deepin.WMSwitcher /com/deepin/WMSwitcher com.deepin.WMSwitcher.RequestSwitchWM", "turn-off-screen": "sleep 0.5; xset dpms force off", "notification-center": "dbus-send --print-reply --dest=com.deepin.dde.osd /org/freedesktop/Notifications com.deepin.dde.Notification.Toggle", - "clipboard": "dbus-send --print-reply --dest=com.deepin.dde.Clipboard /com/deepin/dde/Clipboard com.deepin.dde.Clipboard.Toggle; dbus-send --print-reply --dest=com.deepin.dde.Launcher /com/deepin/dde/Launcher com.deepin.dde.Launcher.Hide", + "clipboard": "dbus-send --print-reply --dest=com.deepin.dde.Clipboard /com/deepin/dde/Clipboard com.deepin.dde.Clipboard.Toggle; dbus-send --print-reply --dest=org.deepin.dde.Launcher1 /org/deepin/dde/Launcher1 org.deepin.dde.Launcher1.Hide", "global-search": "/usr/libexec/dde-daemon/keybinding/shortcut-dde-grand-search.sh", - "switch-next-kbd-layout": "dbus-send --print-reply --dest=com.deepin.daemon.Keybinding /com/deepin/daemon/InputDevice/Keyboard com.deepin.daemon.InputDevice.Keyboard.ToggleNextLayout", + "switch-next-kbd-layout": "dbus-send --print-reply --dest=org.deepin.dde.Keybinding1 /org/deepin/dde/InputDevice1/Keyboard org.deepin.dde.InputDevice1.Keyboard.ToggleNextLayout", "switch-monitors": "dbus-send --print-reply --dest=com.deepin.dde.osd / com.deepin.dde.osd.ShowOSD string:SwitchMonitors", // cmd "calculator": "/usr/bin/deepin-calculator", diff --git a/keybinding/shortcuts/xrecord_event_handler.go b/keybinding1/shortcuts/xrecord_event_handler.go similarity index 100% rename from keybinding/shortcuts/xrecord_event_handler.go rename to keybinding1/shortcuts/xrecord_event_handler.go diff --git a/keybinding/shortcuts/xrecord_event_handler_test.go b/keybinding1/shortcuts/xrecord_event_handler_test.go similarity index 100% rename from keybinding/shortcuts/xrecord_event_handler_test.go rename to keybinding1/shortcuts/xrecord_event_handler_test.go diff --git a/keybinding/special_keycode.go b/keybinding1/special_keycode.go similarity index 91% rename from keybinding/special_keycode.go rename to keybinding1/special_keycode.go index 7af89d0b8..cb1768f5a 100644 --- a/keybinding/special_keycode.go +++ b/keybinding1/special_keycode.go @@ -10,10 +10,8 @@ import ( "strings" "time" - "github.com/godbus/dbus" - launcher "github.com/linuxdeepin/go-dbus-factory/com.deepin.dde.daemon.launcher" - sessionmanager "github.com/linuxdeepin/go-dbus-factory/com.deepin.sessionmanager" - power "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.power" + "github.com/godbus/dbus/v5" + power "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.power1" ) // 按键码 @@ -123,8 +121,10 @@ func (m *Manager) initSpecialKeycodeMap() { m.specialKeycodeBindingList[key] = m.handleScreenshot // 打开设备管理器 - key = createSpecialKeycodeIndex(KEY_UNKNOWN, false, MODIFY_NONE) - m.specialKeycodeBindingList[key] = m.handleOpenDeviceManager + if m.deviceManagerControlEnable { + key = createSpecialKeycodeIndex(KEY_UNKNOWN, false, MODIFY_NONE) + m.specialKeycodeBindingList[key] = m.handleOpenDeviceManager + } } // 处理函数的总入口 @@ -360,9 +360,9 @@ func (m *Manager) handlePower() { } m.systemTurnOffScreen() case powerActionShowUI: - cmd := "originmap=$(setxkbmap -query | grep option | awk -F ' ' '{print $2}');/usr/bin/setxkbmap -option grab:break_actions&&/usr/bin/xdotool key XF86Ungrab&&dbus-send --print-reply --dest=com.deepin.dde.lockFront /com/deepin/dde/shutdownFront com.deepin.dde.shutdownFront.Show&&/usr/bin/setxkbmap -option $originmap" + cmd := "originmap=$(setxkbmap -query | grep option | awk -F ' ' '{print $2}');/usr/bin/setxkbmap -option grab:break_actions&&/usr/bin/xdotool key XF86Ungrab&&dbus-send --print-reply --dest=org.deepin.dde.LockFront1 /com/deepin/dde/shutdownFront com.deepin.dde.shutdownFront.Show&&/usr/bin/setxkbmap -option $originmap" if _useWayland { - cmd = "originmap=$(setxkbmap -query | grep option | awk -F ' ' '{print $2}');/usr/bin/setxkbmap -option grab:break_actions&&dbus-send --print-reply --dest=com.deepin.dde.lockFront /com/deepin/dde/shutdownFront com.deepin.dde.shutdownFront.Show&&/usr/bin/setxkbmap -option $originmap" + cmd = "originmap=$(setxkbmap -query | grep option | awk -F ' ' '{print $2}');/usr/bin/setxkbmap -option grab:break_actions&&dbus-send --print-reply --dest=org.deepin.dde.LockFront1 /com/deepin/dde/shutdownFront com.deepin.dde.shutdownFront.Show&&/usr/bin/setxkbmap -option $originmap" } go func() { locked, err := m.sessionManager.Locked().Get(0) @@ -472,14 +472,7 @@ func (m *Manager) handleOpenDeviceManager() { return } - launcher := launcher.NewLauncher(m.service.Conn()) - info, err := launcher.GetItemInfo(0, "deepin-devicemanager") - if err != nil { - logger.Warning(err) - return - } - sessionmanager := sessionmanager.NewStartManager(m.service.Conn()) - _, err = sessionmanager.Launch(0, info.Path) + err := m.execCmd("deepin-devicemanager", true) if err != nil { logger.Warning(err) } diff --git a/keybinding/testdata/hotkey b/keybinding1/testdata/hotkey similarity index 100% rename from keybinding/testdata/hotkey rename to keybinding1/testdata/hotkey diff --git a/keybinding/testdata/hotkey_disable b/keybinding1/testdata/hotkey_disable similarity index 100% rename from keybinding/testdata/hotkey_disable rename to keybinding1/testdata/hotkey_disable diff --git a/keybinding/touchpad_controller.go b/keybinding1/touchpad_controller.go similarity index 89% rename from keybinding/touchpad_controller.go rename to keybinding1/touchpad_controller.go index c899b087a..e9df68ac5 100644 --- a/keybinding/touchpad_controller.go +++ b/keybinding1/touchpad_controller.go @@ -5,9 +5,9 @@ package keybinding import ( - "github.com/godbus/dbus" - inputdevices "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.inputdevices" - . "github.com/linuxdeepin/dde-daemon/keybinding/shortcuts" + "github.com/godbus/dbus/v5" + . "github.com/linuxdeepin/dde-daemon/keybinding1/shortcuts" + inputdevices "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.inputdevices1" ) type TouchPadController struct { diff --git a/keybinding1/util/util.go b/keybinding1/util/util.go new file mode 100644 index 000000000..714fb1b05 --- /dev/null +++ b/keybinding1/util/util.go @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package util + +import ( + "bytes" + "encoding/json" + "os" + "strings" + + wm "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.wm" +) + +func MarshalJSON(v interface{}) (string, error) { + var buf bytes.Buffer + enc := json.NewEncoder(&buf) + enc.SetEscapeHTML(false) + err := enc.Encode(v) + if err != nil { + return "", err + } + return buf.String(), nil +} + +type KWinAccel struct { + Id string + Keystrokes []string `json:"Accels"` + DefaultKeystrokes []string `json:"Default,omitempty"` +} + +func (kwa *KWinAccel) fix() { + var keystrokes []string + for _, ks := range kwa.Keystrokes { + if ks == "" { + continue + } + keystrokes = append(keystrokes, ks) + } + kwa.Keystrokes = keystrokes + + var defaultKeystrokes []string + for _, ks := range kwa.DefaultKeystrokes { + if ks == "" || strings.Contains(ks, " ") { + continue + } + defaultKeystrokes = append(defaultKeystrokes, ks) + } + + kwa.DefaultKeystrokes = defaultKeystrokes +} + +func GetAllKWinAccels(wm wm.Wm) ([]KWinAccel, error) { + allJson, err := wm.GetAllAccels(0) + if err != nil { + return nil, err + } + sessionType := os.Getenv("XDG_SESSION_TYPE") + if strings.Contains(sessionType, "wayland") && strings.Contains(allJson, "SysReq") { + allJson = strings.Replace(allJson, "SysReq", "Print", -1) + } + + var result []KWinAccel + err = json.Unmarshal([]byte(allJson), &result) + if err != nil { + return nil, err + } + + for idx := range result { + result[idx].fix() + } + + return result, nil +} diff --git a/keybinding1/utils.go b/keybinding1/utils.go new file mode 100644 index 000000000..8d7f8af53 --- /dev/null +++ b/keybinding1/utils.go @@ -0,0 +1,421 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package keybinding + +import ( + "bytes" + "errors" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strconv" + "strings" + "time" + + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/keybinding1/util" + wm "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.wm" + gio "github.com/linuxdeepin/go-gir/gio-2.0" + "github.com/linuxdeepin/go-lib/strv" + "github.com/linuxdeepin/go-x11-client/ext/dpms" +) + +// nolint +const ( + suspendStateUnknown = iota + 1 + suspendStateLidOpen + suspendStateFinish + suspendStateWakeup + suspendStatePrepare + suspendStateLidClose + suspendStateButtonClick +) + +type networkDevice struct { + Udi string + Path dbus.ObjectPath + State uint32 + Interface string + ClonedAddress string + HwAddress string + Driver string + Managed bool + Vendor string + UniqueUuid string + UsbDevice bool + ActiveAp dbus.ObjectPath + SupportHotspot bool + Mode uint32 + MobileNetworkType string + MobileSignalQuality uint32 + InterfaceFlags uint32 +} + +func resetGSettings(gs *gio.Settings) { + for _, key := range gs.ListKeys() { + userVal := gs.GetUserValue(key) + if userVal != nil { + // TODO unref userVal + logger.Debug("reset gsettings key", key) + gs.Reset(key) + } + } +} + +func resetKWin(wmObj wm.Wm) error { + accels, err := util.GetAllKWinAccels(wmObj) + if err != nil { + return err + } + for _, accel := range accels { + // logger.Debug("resetKwin each accel:", accel.Id, accel.Keystrokes, accel.DefaultKeystrokes) + if !strv.Strv(accel.Keystrokes).Equal(accel.DefaultKeystrokes) && + len(accel.DefaultKeystrokes) > 0 && accel.DefaultKeystrokes[0] != "" { + accelJson, err := util.MarshalJSON(&util.KWinAccel{ + Id: accel.Id, + Keystrokes: accel.DefaultKeystrokes, + }) + if err != nil { + logger.Warning(err) + continue + } + logger.Debug("resetKwin SetAccel", accelJson) + ok, err := wmObj.SetAccel(0, accelJson) + // 目前 wm 的实现,调用 SetAccel 如果遇到冲突情况,会导致目标快捷键被清空。 + if !ok { + logger.Warning("wm.SetAccel failed, id: ", accel.Id) + continue + } + if err != nil { + logger.Warning("failed to set accel:", err, accel.Id) + continue + } + } + } + return nil +} + +func showOSD(signal string) { + logger.Debug("show OSD", signal) + sessionDBus, _ := dbus.SessionBus() + go sessionDBus.Object("com.deepin.dde.osd", "/").Call("com.deepin.dde.osd.ShowOSD", 0, signal) +} + +const sessionManagerDest = "com.deepin.SessionManager" +const sessionManagerObjPath = "/com/deepin/SessionManager" + +func systemLock() { + sessionDBus, err := dbus.SessionBus() + if err != nil { + logger.Warning(err) + return + } + go sessionDBus.Object(sessionManagerDest, sessionManagerObjPath).Call(sessionManagerDest+".RequestLock", 0) +} + +func (m *Manager) canSuspend() bool { + can, err := m.sessionManager.CanSuspend(0) // 当前能否待机 + if err != nil { + logger.Warning(err) + return false + } + return can +} + +func (m *Manager) systemSuspend() { + if !m.canSuspend() { + logger.Info("can not suspend") + return + } + + logger.Debug("suspend") + err := m.sessionManager.RequestSuspend(0) + if err != nil { + logger.Warning("failed to suspend:", err) + } +} + +// 为了处理待机闪屏的问题,通过前端进行待机,前端会在待机前显示一个纯黑的界面 +func (m *Manager) systemSuspendByFront() { + if !m.canExcuteSuspendOrHiberate || m.prepareForSleep { + logger.Info("Avoid waking up and immediately going into suspend.") + return + } + + if !m.canSuspend() { + logger.Info("can not suspend") + return + } + + logger.Debug("suspend") + err := m.shutdownFront.Suspend(0) + if err != nil { + logger.Warning("failed to suspend:", err) + } +} + +func (m *Manager) canHibernate() bool { + can, err := m.sessionManager.CanHibernate(0) // 能否休眠 + if err != nil { + logger.Warning(err) + return false + } + return can +} + +func systemSuspend() { + sessionDBus, _ := dbus.SessionBus() + go sessionDBus.Object(sessionManagerDest, sessionManagerObjPath).Call(sessionManagerDest+".RequestSuspend", 0) +} + +func (m *Manager) systemHibernate() { + if !m.canHibernate() { + logger.Info("can not Hibernate") + return + } + + logger.Debug("Hibernate") + err := m.sessionManager.RequestHibernate(0) + if err != nil { + logger.Warning("failed to Hibernate:", err) + } +} + +func (m *Manager) systemHibernateByFront() { + if !m.canExcuteSuspendOrHiberate || m.prepareForSleep { + logger.Info("Avoid waking up and immediately going into suspend.") + return + } + + if !m.canHibernate() { + logger.Info("can not Hibernate") + return + } + + logger.Debug("Hibernate") + err := m.shutdownFront.Hibernate(0) + if err != nil { + logger.Warning("failed to Hibernate:", err) + } +} + +func (m *Manager) canShutdown() bool { + can, err := m.sessionManager.CanShutdown(0) // 当前能否关机 + if err != nil { + logger.Warning(err) + return false + } + return can +} + +func (m *Manager) hasShutdownInhibit() bool { + // 先检查是否有delay 或 block shutdown的inhibitor + inhibitors, err := m.login1Manager.ListInhibitors(0) + if err != nil { + logger.Warning("failed to call login ListInhibitors:", err) + } else { + for _, inhibit := range inhibitors { + logger.Infof("inhibit is: %+v", inhibit) + if strings.Contains(inhibit.What, "shutdown") { + return true + } + } + } + return false +} + +func (m *Manager) hasMultipleDisplaySession() bool { + // 检查是否有多个图形session,有多个图形session就需要显示阻塞界面 + sessions, err := m.displayManager.Sessions().Get(0) + if err != nil { + logger.Warning(err) + return false + } + return len(sessions) >= 2 +} + +func (m *Manager) systemShutdown() { + // 如果是锁定状态,那么不需要后端进行关机响应,前端会显示关机或者关机阻塞界面; + // 快捷键关机流程:判断是否存在多用户或任何shutdown阻塞项(block or delay),存在则跳转dde-shutdown界面,不存在进行sessionManager的注销 + if !m.canShutdown() { + logger.Info("can not Shutdown") + } + + locked, err := m.sessionManager.Locked().Get(0) + if err != nil { + logger.Warning("sessionManager get locked state error:", err) + return + } + if locked { + logger.Info("current session is locked") + return + } + + if m.hasShutdownInhibit() || m.hasMultipleDisplaySession() { + logger.Info("exist shutdown inhibit(delay or block) or multiple display session") + err := m.shutdownFront.Shutdown(0) + if err != nil { + logger.Warning(err) + } + } else { + logger.Debug("keybinding start request SessionManager shutdown") + err := m.sessionManager.RequestShutdown(0) + if err != nil { + logger.Warning("failed to Shutdown:", err) + } + } +} + +func (m *Manager) systemTurnOffScreen() { + const settingKeyScreenBlackLock = "screen-black-lock" + logger.Info("DPMS Off") + var err error + var useWayland bool + if len(os.Getenv("WAYLAND_DISPLAY")) != 0 { + useWayland = true + } else { + useWayland = false + } + + bScreenBlackLock := m.gsPower.GetBoolean(settingKeyScreenBlackLock) + if bScreenBlackLock { + m.doLock(true) + } + + doPrepareSuspend() + // bug-209669 : 部分厂商机器调用DPMS off后,调用锁屏show会被阻塞,只有当DPMS on了才show锁屏成功,这就导致唤醒闪桌面再进锁屏 + if bScreenBlackLock && !m.isWmBlackScreenActive() { + m.setWmBlackScreenActive(true) + time.Sleep(100 * time.Millisecond) + } + + if useWayland { + err = exec.Command("dde_wldpms", "-s", "Off").Run() + } else { + err = dpms.ForceLevelChecked(m.conn, dpms.DPMSModeOff).Check(m.conn) + } + if err != nil { + logger.Warning("Set DPMS off error:", err) + } + + if bScreenBlackLock && m.isWmBlackScreenActive() { + m.setWmBlackScreenActive(false) + } + undoPrepareSuspend() + ioutil.WriteFile("/tmp/dpms-state", []byte("1"), 0644) +} + +func (m *Manager) systemLogout() { + can, err := m.sessionManager.CanLogout(0) + if err != nil { + logger.Warning(err) + return + } + + if !can { + logger.Info("can not logout") + return + } + + logger.Debug("logout") + err = m.sessionManager.RequestLogout(0) + if err != nil { + logger.Warning("failed to logout:", err) + } +} + +func (m *Manager) systemAway() { + err := m.sessionManager.RequestLock(0) + if err != nil { + logger.Warning(err) + } +} + +func queryCommandByMime(mime string) string { + app := gio.AppInfoGetDefaultForType(mime, false) + if app == nil { + return "" + } + defer app.Unref() + + return app.GetExecutable() +} + +func getRfkillWlanState() (int, error) { + dir := "/sys/class/rfkill" + fileInfoList, err := ioutil.ReadDir(dir) + if err != nil { + return 0, err + } + + for _, fileInfo := range fileInfoList { + typeFile := filepath.Join(dir, fileInfo.Name(), "type") + typeBytes, err := readTinyFile(typeFile) + if err != nil { + continue + } + if bytes.Equal(bytes.TrimSpace(typeBytes), []byte("wlan")) { + stateFile := filepath.Join(dir, fileInfo.Name(), "state") + stateBytes, err := readTinyFile(stateFile) + if err != nil { + return 0, err + } + stateBytes = bytes.TrimSpace(stateBytes) + state, err := strconv.Atoi(string(stateBytes)) + if err != nil { + return 0, err + } + return state, nil + + } + } + return 0, errors.New("not found rfkill with type wlan") +} + +func readTinyFile(file string) ([]byte, error) { + f, err := os.Open(file) + if err != nil { + return nil, err + } + defer f.Close() + buf := make([]byte, 8) + n, err := f.Read(buf) + if err != nil { + return nil, err + } + return buf[:n], nil +} + +func shouldUseDDEKwin() bool { + _, err := os.Stat("/usr/bin/kwin_no_scale") + return err == nil +} + +func (m *Manager) doLock(autoStartAuth bool) { + logger.Info("Lock Screen") + err := m.lockFront.ShowAuth(0, autoStartAuth) + if err != nil { + logger.Warning("failed to call lockFront ShowAuth:", err) + } +} + +func doPrepareSuspend() { + sessionDBus, _ := dbus.SessionBus() + obj := sessionDBus.Object("org.deepin.dde.Power1", "/org/deepin/dde/Power1") + err := obj.Call("org.deepin.dde.Power1.SetPrepareSuspend", 0, suspendStateButtonClick).Err + if err != nil { + logger.Warning(err) + } +} + +func undoPrepareSuspend() { + sessionDBus, _ := dbus.SessionBus() + obj := sessionDBus.Object("org.deepin.dde.Power1", "/org/deepin/dde/Power1") + err := obj.Call("org.deepin.dde.Power.SetPrepareSuspend", 0, suspendStateFinish).Err + if err != nil { + logger.Warning(err) + } +} diff --git a/keybinding/utils_test.go b/keybinding1/utils_test.go similarity index 100% rename from keybinding/utils_test.go rename to keybinding1/utils_test.go diff --git a/langselector/main.go b/langselector/main.go deleted file mode 100644 index 7554b084f..000000000 --- a/langselector/main.go +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package langselector - -import ( - "time" - - "github.com/linuxdeepin/go-gir/gio-2.0" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/gsettings" - "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/go-lib/strv" -) - -const ( - dbusServiceName = "com.deepin.daemon.LangSelector" -) - -var ( - logger = log.NewLogger("daemon/langselector") -) - -func Run() { - service, err := dbusutil.NewSessionService() - if err != nil { - logger.Fatal("failed to new session service:", err) - } - - lang, err := newLangSelector(service) - if err != nil { - logger.Fatal("failed to new langSelector:", err) - } - err = service.Export(dbusPath, lang) - if err != nil { - logger.Fatal("failed to export:", err) - } - - err = service.RequestName(dbusServiceName) - if err != nil { - logger.Fatal("failed to request name:", err) - } - - initNotifyTxt() - lang.connectSettingsChanged() - err = gsettings.StartMonitor() - if err != nil { - logger.Warning("failed to start monitor settings:", err) - } - service.SetAutoQuitHandler(time.Minute*5, func() bool { - lang.PropsMu.RLock() - canQuit := lang.LocaleState != LocaleStateChanging - lang.PropsMu.RUnlock() - return canQuit - }) - service.Wait() -} - -func GetLocales() []string { - currentLocale := getCurrentUserLocale() - settings := gio.NewSettings(gsSchemaLocale) - locales := settings.GetStrv(gsKeyLocales) - if !strv.Strv(locales).Contains(currentLocale) { - locales = append(locales, currentLocale) - } - settings.Unref() - return locales -} diff --git a/langselector/exported_methods_auto.go b/langselector1/exported_methods_auto.go similarity index 100% rename from langselector/exported_methods_auto.go rename to langselector1/exported_methods_auto.go diff --git a/langselector/langselector_dbusutil.go b/langselector1/langselector_dbusutil.go similarity index 100% rename from langselector/langselector_dbusutil.go rename to langselector1/langselector_dbusutil.go diff --git a/langselector/locale.go b/langselector1/locale.go similarity index 97% rename from langselector/locale.go rename to langselector1/locale.go index 8b8a96831..7d37e1602 100644 --- a/langselector/locale.go +++ b/langselector1/locale.go @@ -16,22 +16,22 @@ import ( "sync" "time" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" // dbus services: - localehelper "github.com/linuxdeepin/go-dbus-factory/com.deepin.api.localehelper" - libnetwork "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.network" - lastore "github.com/linuxdeepin/go-dbus-factory/com.deepin.lastore" - notifications "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.notifications" + "github.com/linuxdeepin/dde-api/lang_info" + "github.com/linuxdeepin/dde-api/language_support" + "github.com/linuxdeepin/dde-api/userenv" + ddbus "github.com/linuxdeepin/dde-daemon/dbus" + libnetwork "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.network1" + notifications "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.notifications" + localehelper "github.com/linuxdeepin/go-dbus-factory/system/com.deepin.api.localehelper" + lastore "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.lastore1" "github.com/linuxdeepin/go-gir/gio-2.0" "github.com/linuxdeepin/go-lib/dbusutil" . "github.com/linuxdeepin/go-lib/gettext" "github.com/linuxdeepin/go-lib/gsettings" "github.com/linuxdeepin/go-lib/strv" "github.com/linuxdeepin/go-lib/xdg/basedir" - "github.com/linuxdeepin/dde-api/lang_info" - "github.com/linuxdeepin/dde-api/language_support" - "github.com/linuxdeepin/dde-api/userenv" - ddbus "github.com/linuxdeepin/dde-daemon/dbus" ) const ( diff --git a/langselector/locale_ifc.go b/langselector1/locale_ifc.go similarity index 95% rename from langselector/locale_ifc.go rename to langselector1/locale_ifc.go index e575e5c1e..e8cb15d19 100644 --- a/langselector/locale_ifc.go +++ b/langselector1/locale_ifc.go @@ -8,14 +8,14 @@ import ( "errors" "fmt" - "github.com/godbus/dbus" - "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-api/language_support" + "github.com/linuxdeepin/go-lib/dbusutil" ) const ( - dbusPath = "/com/deepin/daemon/LangSelector" - dbusInterface = "com.deepin.daemon.LangSelector" + dbusPath = "/org/deepin/dde/LangSelector1" + dbusInterface = "org.deepin.dde.LangSelector1" localeIconStart = "notification-change-language-start" localeIconFailed = "notification-change-language-failed" diff --git a/langselector/locale_test.go b/langselector1/locale_test.go similarity index 100% rename from langselector/locale_test.go rename to langselector1/locale_test.go diff --git a/langselector1/main.go b/langselector1/main.go new file mode 100644 index 000000000..032df5b17 --- /dev/null +++ b/langselector1/main.go @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package langselector + +import ( + "time" + + "github.com/linuxdeepin/go-gir/gio-2.0" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/gsettings" + "github.com/linuxdeepin/go-lib/log" + "github.com/linuxdeepin/go-lib/strv" +) + +const ( + dbusServiceName = dbusInterface +) + +var ( + logger = log.NewLogger("daemon/langselector") +) + +func Run() { + service, err := dbusutil.NewSessionService() + if err != nil { + logger.Fatal("failed to new session service:", err) + } + + lang, err := newLangSelector(service) + if err != nil { + logger.Fatal("failed to new langSelector:", err) + } + err = service.Export(dbusPath, lang) + if err != nil { + logger.Fatal("failed to export:", err) + } + + err = service.RequestName(dbusServiceName) + if err != nil { + logger.Fatal("failed to request name:", err) + } + + initNotifyTxt() + lang.connectSettingsChanged() + err = gsettings.StartMonitor() + if err != nil { + logger.Warning("failed to start monitor settings:", err) + } + service.SetAutoQuitHandler(time.Minute*5, func() bool { + lang.PropsMu.RLock() + canQuit := lang.LocaleState != LocaleStateChanging + lang.PropsMu.RUnlock() + return canQuit + }) + service.Wait() +} + +func GetLocales() []string { + currentLocale := getCurrentUserLocale() + settings := gio.NewSettings(gsSchemaLocale) + locales := settings.GetStrv(gsKeyLocales) + if !strv.Strv(locales).Contains(currentLocale) { + locales = append(locales, currentLocale) + } + settings.Unref() + return locales +} diff --git a/langselector/testdata/pam_environment b/langselector1/testdata/pam_environment similarity index 100% rename from langselector/testdata/pam_environment rename to langselector1/testdata/pam_environment diff --git a/langselector/testdata/support_languages.json b/langselector1/testdata/support_languages.json similarity index 100% rename from langselector/testdata/support_languages.json rename to langselector1/testdata/support_languages.json diff --git a/lastore/agent.go b/lastore/agent.go deleted file mode 100644 index 1c9af9504..000000000 --- a/lastore/agent.go +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package lastore - -import ( - "os" - "strings" - "sync" - - "github.com/godbus/dbus" - kwayland "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.kwayland" - ControlCenter "github.com/linuxdeepin/go-dbus-factory/com.deepin.dde.ControlCenter" - lastore "github.com/linuxdeepin/go-dbus-factory/com.deepin.lastore" - "github.com/linuxdeepin/go-lib/dbusutil" -) - -const ( - // lastore agent的interface name - sessionAgentInterface = "com.deepin.lastore.Agent" - sessionAgentPath = "/com/deepin/lastore/agent" -) - -// 对应com.deepin.daemon.Network.GetProxy方法的key值 -const ( - proxyTypeHttp = "http" - proxyTypeHttps = "https" - proxyTypeFtp = "ftp" - proxyTypeSocks = "socks" -) - -// 对应系统代理环境变量 -const ( - envHttpProxy = "http_proxy" - envHttpsProxy = "https_proxy" - envFtpProxy = "ftp_proxy" - envAllProxy = "all_proxy" -) - -// Agent 需要实现GetManualProxy、SendNotify、CloseNotification、ReportLog四个接口 -type Agent struct { - sysService *dbusutil.Service - sessionService *dbusutil.Service - lastoreObj *Lastore - sysLastore lastore.Lastore - waylandWM kwayland.WindowManager - controlCenter ControlCenter.ControlCenter - mu sync.Mutex - isWaylandSession bool -} - -func newAgent(l *Lastore) (*Agent, error) { - sysBus, err := dbusutil.NewSystemService() - if err != nil { - logger.Warning(err) - return nil, err - } - sessionBus, err := dbusutil.NewSessionService() - if err != nil { - logger.Warning(err) - return nil, err - } - a := &Agent{ - sysService: sysBus, - sessionService: sessionBus, - } - a.lastoreObj = l - a.sysLastore = lastore.NewLastore(a.sysService.Conn()) - if strings.Contains(os.Getenv("XDG_SESSION_TYPE"), "wayland") { - a.isWaylandSession = true - a.waylandWM = kwayland.NewWindowManager(a.sessionService.Conn()) - } - a.controlCenter = ControlCenter.NewControlCenter(a.sessionService.Conn()) - return a, nil -} - -func (a *Agent) init() error { - err := a.sysService.Export(sessionAgentPath, a) - if err != nil { - logger.Warning(err) - return err - } - err = a.sysLastore.Manager().RegisterAgent(0, sessionAgentPath) - if err != nil { - logger.Warning(err) - return err - } - return nil -} - -func (a *Agent) destroy() { - err := a.sysLastore.Manager().UnRegisterAgent(0, sessionAgentPath) - if err != nil { - logger.Warning(err) - } -} - -func (a *Agent) checkCallerAuth(sender dbus.Sender) bool { - const rootUid = 0 - uid, err := a.sysService.GetConnUID(string(sender)) - if err != nil { - return false - } - if uid != rootUid { - logger.Warningf("not allow %v call this method", sender) - return false - } - return true -} diff --git a/lastore/daemon.go b/lastore/daemon.go deleted file mode 100644 index df43fe462..000000000 --- a/lastore/daemon.go +++ /dev/null @@ -1,296 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package lastore - -import ( - "encoding/json" - "sync" - "time" - - "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/loader" - abrecovery "github.com/linuxdeepin/go-dbus-factory/com.deepin.abrecovery" - notifications "github.com/linuxdeepin/go-dbus-factory/com.deepin.dde.notification" - lastore "github.com/linuxdeepin/go-dbus-factory/com.deepin.lastore" - ConfigManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/gettext" - "github.com/linuxdeepin/go-lib/log" -) - -const ( - dbusPath = "/com/deepin/LastoreSessionHelper" - dbusServiceName = "com.deepin.LastoreSessionHelper" -) - -const ( - dSettingsAppID = "org.deepin.lastore" - dSettingsLastoreName = "org.deepin.lastore" - dSettingsKeyUpgradeStatus = "upgrade-status" - dSettingsKeyLastoreDaemonStatus = "lastore-daemon-status" -) - -const ( - UpgradeReady = "ready" - UpgradeRunning = "running" - UpgradeFailed = "failed" - - runningUpgradeBackend = 1 << 2 // 是否处于更新状态 - -) - -type UpgradeReasonType string - -const ( - NoError UpgradeReasonType = "NoError" - ErrorUnknown UpgradeReasonType = "ErrorUnknown" - ErrorFetchFailed UpgradeReasonType = "fetchFailed" - ErrorDpkgError UpgradeReasonType = "dpkgError" - ErrorPkgNotFound UpgradeReasonType = "pkgNotFound" - ErrorUnmetDependencies UpgradeReasonType = "unmetDependencies" - ErrorNoInstallationCandidate UpgradeReasonType = "noInstallationCandidate" - ErrorInsufficientSpace UpgradeReasonType = "insufficientSpace" - ErrorUnauthenticatedPackages UpgradeReasonType = "unauthenticatedPackages" - ErrorOperationNotPermitted UpgradeReasonType = "operationNotPermitted" - ErrorIndexDownloadFailed UpgradeReasonType = "IndexDownloadFailed" - ErrorIO UpgradeReasonType = "ioError" - ErrorDamagePackage UpgradeReasonType = "damagePackage" // 包损坏,需要删除后重新下载或者安装 -) - -const ( - NotifyExpireTimeoutDefault = -1 - NotifyExpireTimeoutNoHide = 0 -) - -const distUpgradeJobPath = "/com/deepin/lastore/Jobdist_upgrade" - -var logger = log.NewLogger("daemon/lastore") - -func init() { - loader.Register(newDaemon()) -} - -type Daemon struct { - lastore *Lastore - agent *Agent - *loader.ModuleBase -} - -func newDaemon() *Daemon { - daemon := new(Daemon) - daemon.ModuleBase = loader.NewModuleBase("lastore", daemon, logger) - return daemon -} - -func (*Daemon) GetDependencies() []string { - return []string{} -} - -func (d *Daemon) Start() error { - var lastoreOnce sync.Once - service := loader.GetService() - sysBus, err := dbus.SystemBus() - if err != nil { - logger.Warning(err) - return err - } - sysDBusDaemon := ofdbus.NewDBus(sysBus) - systemSigLoop := dbusutil.NewSignalLoop(sysBus, 10) - systemSigLoop.Start() - initLastore := func() error { - lastoreObj, err := newLastore(service) - if err != nil { - logger.Warning(err) - return err - } - d.lastore = lastoreObj - err = service.Export(dbusPath, lastoreObj, lastoreObj.syncConfig) - if err != nil { - logger.Warning(err) - return err - } - - err = service.RequestName(dbusServiceName) - if err != nil { - logger.Warning(err) - return err - } - err = lastoreObj.syncConfig.Register() - if err != nil { - logger.Warning("Failed to register sync service:", err) - } - defer func() { - sysDBusDaemon.RemoveAllHandlers() - systemSigLoop.Stop() - }() - agent, err := newAgent(lastoreObj) - if err != nil { - logger.Warning(err) - return err - } - d.agent = agent - return agent.init() - - } - core := lastore.NewLastore(sysBus) - // 处理更新失败/中断的记录 - go func() { - // 获取lastore-daemon记录的更新状态 - ds := ConfigManager.NewConfigManager(sysBus) - dsPath, err := ds.AcquireManager(0, dSettingsAppID, dSettingsLastoreName, "") - if err != nil { - logger.Warning(err) - return - } - dsLastoreManager, err := ConfigManager.NewManager(sysBus, dsPath) - if err != nil { - logger.Warning(err) - return - } - v, err := dsLastoreManager.Value(0, dSettingsKeyUpgradeStatus) - if err != nil { - logger.Warning(err) - return - } else { - jobList, _ := core.Manager().JobList().Get(0) - // 如果正常系统更新,那么不需要处理(更新中切换用户场景) - for _, path := range jobList { - if path == distUpgradeJobPath { - logger.Info("running dist-upgrade,don't need handle status") - return - } - } - upgradeStatus := struct { - Status string - ReasonCode UpgradeReasonType - }{} - statusContent := v.Value().(string) - err = json.Unmarshal([]byte(statusContent), &upgradeStatus) - if err != nil { - logger.Warning(err) - return - } - logger.Infof("lastore status:%+v", upgradeStatus) - // 记录处理异常更新的通知 - osd := notifications.NewNotification(service.Conn()) - abObj := abrecovery.NewABRecovery(sysBus) - valid, err := abObj.ConfigValid().Get(0) // config失效时,无法回滚,提示重新更新 - var msg string - switch upgradeStatus.Status { - // running状态,更新被中断 - case UpgradeRunning: - if err != nil || !valid { - msg = gettext.Tr("Updates failed: it was interrupted.") - } else { - msg = gettext.Tr("Updates failed: it was interrupted. Please roll back to the old version and try again.") - } - case UpgradeFailed: - switch upgradeStatus.ReasonCode { - case ErrorDpkgError: - if err != nil || !valid { - msg = gettext.Tr("Updates failed: DPKG error.") - } else { - msg = gettext.Tr("Updates failed: DPKG error. Please roll back to the old version and try again.") - } - case ErrorInsufficientSpace: - if err != nil || !valid { - msg = gettext.Tr("Updates failed: insufficient disk space.") - } else { - msg = gettext.Tr("Updates failed: insufficient disk space. Please roll back to the old version and try again.") - } - case ErrorUnknown, ErrorPkgNotFound, ErrorNoInstallationCandidate, ErrorIO, ErrorDamagePackage: - if err != nil || !valid { - msg = gettext.Tr("Updates failed") - } else { - msg = gettext.Tr("Updates failed. Please roll back to the old version and try again.") - } - } - } - logger.Infof("notify msg is:%v", msg) - if len(msg) != 0 { - _, err = osd.Notify(0, "dde-control-center", 0, "preferences-system", "", msg, nil, nil, NotifyExpireTimeoutNoHide) - if err != nil { - logger.Warning(err) - } - } - // 通知发完之后,恢复配置文件的内容 - upgradeStatus.Status = UpgradeReady - upgradeStatus.ReasonCode = NoError - v, err := json.Marshal(upgradeStatus) - if err != nil { - logger.Warning(err) - } else { - err = dsLastoreManager.SetValue(0, dSettingsKeyUpgradeStatus, dbus.MakeVariant(v)) - if err != nil { - logger.Warning(err) - } - } - } - }() - time.AfterFunc(10*time.Minute, func() { - lastoreOnce.Do(func() { - err := initLastore() - if err != nil { - logger.Warning(err) - } - }) - }) - - sysDBusDaemon.InitSignalExt(systemSigLoop, true) - _, err = sysDBusDaemon.ConnectNameOwnerChanged(func(name, oldOwner, newOwner string) { - if name == core.ServiceName_() && newOwner != "" { - lastoreOnce.Do(func() { - err := initLastore() - if err != nil { - logger.Warning(err) - } - }) - } - }) - if err != nil { - logger.Warning(err) - } - hasOwner, err := sysDBusDaemon.NameHasOwner(0, core.ServiceName_()) - if err != nil { - logger.Warning(err) - } else if hasOwner { - lastoreOnce.Do(func() { - err := initLastore() - if err != nil { - logger.Warning(err) - } - }) - } - return nil -} - -func (d *Daemon) Stop() error { - if d.lastore != nil { - service := loader.GetService() - err := service.ReleaseName(dbusServiceName) - if err != nil { - logger.Warning(err) - } - d.lastore.destroy() - err = service.StopExport(d.lastore) - if err != nil { - logger.Warning(err) - } - - d.lastore = nil - } - - if d.agent != nil { - service := loader.GetService() - d.agent.destroy() - err := service.StopExport(d.agent) - if err != nil { - logger.Warning(err) - } - d.agent = nil - } - return nil -} diff --git a/lastore/sync_config.go b/lastore/sync_config.go deleted file mode 100644 index f67e801c0..000000000 --- a/lastore/sync_config.go +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package lastore - -import ( - "encoding/json" - "errors" - - "github.com/godbus/dbus" -) - -type syncConfig struct { - l *Lastore -} - -type syncData struct { - Version string `json:"version"` - AutoCheckUpdates bool `json:"auto_check_updates"` - AutoClean bool `json:"auto_clean"` - AutoDownloadUpdates bool `json:"auto_download_updates"` - SmartMirrorEnabled bool `json:"smart_mirror_enabled"` -} - -const ( - syncVersion = "1.0" - - smartMirrorService = "com.deepin.lastore.Smartmirror" - smartMirrorPath = "/com/deepin/lastore/Smartmirror" - smartMirrorIFC = smartMirrorService -) - -func (sc *syncConfig) Get() (interface{}, error) { - var info syncData - info.Version = syncVersion - info.AutoCheckUpdates, _ = sc.l.core.Updater().AutoCheckUpdates().Get(0) - info.AutoClean, _ = sc.l.core.Manager().AutoClean().Get(0) - info.AutoDownloadUpdates, _ = sc.l.core.Updater().AutoDownloadUpdates().Get(0) - info.SmartMirrorEnabled, _ = smartMirrorEnabledGet() - return &info, nil -} - -func (sc *syncConfig) Set(data []byte) error { - var info syncData - err := json.Unmarshal(data, &info) - if err != nil { - return err - } - err = sc.l.core.Updater().SetAutoCheckUpdates(0, info.AutoCheckUpdates) - if err != nil { - logger.Warning("Failed to set lastore auto check updates:", err) - } - err = sc.l.core.Manager().SetAutoClean(0, info.AutoClean) - if err != nil { - logger.Warning("Failed to set lastore auto clean:", err) - } - err = sc.l.core.Updater().SetAutoDownloadUpdates(0, info.AutoDownloadUpdates) - if err != nil { - logger.Warning("Failed to set lastore auto download updates:", err) - } - err = smartMirrorEnabledSet(info.SmartMirrorEnabled) - if err != nil { - logger.Warning("Failed to set lastore smart mirror:", err) - } - return nil -} - -func smartMirrorEnabledSet(enabled bool) error { - conn, err := dbus.SystemBus() - if err != nil { - return err - } - return conn.Object(smartMirrorService, smartMirrorPath).Call( - smartMirrorIFC+".SetEnable", 0, enabled).Store() -} - -func smartMirrorEnabledGet() (bool, error) { - conn, err := dbus.SystemBus() - if err != nil { - return false, err - } - var variant dbus.Variant - err = conn.Object(smartMirrorService, smartMirrorPath).Call( - "org.freedesktop.DBus.Properties.Get", 0, smartMirrorIFC, "Enable").Store(&variant) - if err != nil { - return false, err - } - - if variant.Signature().String() != "b" { - return false, errors.New("not excepted value type") - } - return variant.Value().(bool), nil -} diff --git a/lastore1/agent.go b/lastore1/agent.go new file mode 100644 index 000000000..678c9c8a0 --- /dev/null +++ b/lastore1/agent.go @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package lastore + +import ( + "os" + "strings" + "sync" + + "github.com/godbus/dbus/v5" + ControlCenter "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.dde.ControlCenter" + kwayland "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.kwayland1" + lastore "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.lastore1" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +const ( + // lastore agent的interface name + sessionAgentInterface = "com.deepin.lastore.Agent" + sessionAgentPath = "/com/deepin/lastore/agent" +) + +// 对应org.deepin.dde.Network1.GetProxy方法的key值 +const ( + proxyTypeHttp = "http" + proxyTypeHttps = "https" + proxyTypeFtp = "ftp" + proxyTypeSocks = "socks" +) + +// 对应系统代理环境变量 +const ( + envHttpProxy = "http_proxy" + envHttpsProxy = "https_proxy" + envFtpProxy = "ftp_proxy" + envAllProxy = "all_proxy" +) + +// Agent 需要实现GetManualProxy、SendNotify、CloseNotification、ReportLog四个接口 +type Agent struct { + sysService *dbusutil.Service + sessionService *dbusutil.Service + lastoreObj *Lastore + sysLastore lastore.Lastore + waylandWM kwayland.WindowManager + controlCenter ControlCenter.ControlCenter + mu sync.Mutex + isWaylandSession bool +} + +func newAgent(l *Lastore) (*Agent, error) { + sysBus, err := dbusutil.NewSystemService() + if err != nil { + logger.Warning(err) + return nil, err + } + sessionBus, err := dbusutil.NewSessionService() + if err != nil { + logger.Warning(err) + return nil, err + } + a := &Agent{ + sysService: sysBus, + sessionService: sessionBus, + } + a.lastoreObj = l + a.sysLastore = lastore.NewLastore(a.sysService.Conn()) + if strings.Contains(os.Getenv("XDG_SESSION_TYPE"), "wayland") { + a.isWaylandSession = true + a.waylandWM = kwayland.NewWindowManager(a.sessionService.Conn()) + } + a.controlCenter = ControlCenter.NewControlCenter(a.sessionService.Conn()) + return a, nil +} + +func (a *Agent) init() error { + err := a.sysService.Export(sessionAgentPath, a) + if err != nil { + logger.Warning(err) + return err + } + err = a.sysLastore.Manager().RegisterAgent(0, sessionAgentPath) + if err != nil { + logger.Warning(err) + return err + } + return nil +} + +func (a *Agent) destroy() { + err := a.sysLastore.Manager().UnRegisterAgent(0, sessionAgentPath) + if err != nil { + logger.Warning(err) + } +} + +func (a *Agent) checkCallerAuth(sender dbus.Sender) bool { + const rootUid = 0 + uid, err := a.sysService.GetConnUID(string(sender)) + if err != nil { + return false + } + if uid != rootUid { + logger.Warningf("not allow %v call this method", sender) + return false + } + return true +} diff --git a/lastore/agent_ifc.go b/lastore1/agent_ifc.go similarity index 96% rename from lastore/agent_ifc.go rename to lastore1/agent_ifc.go index 185ac50da..7adcb7e4c 100644 --- a/lastore/agent_ifc.go +++ b/lastore1/agent_ifc.go @@ -10,8 +10,8 @@ import ( "os/exec" "strings" - "github.com/godbus/dbus" - kwayland "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.kwayland" + "github.com/godbus/dbus/v5" + kwayland "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.kwayland1" "github.com/linuxdeepin/go-lib/dbusutil" ) @@ -92,7 +92,7 @@ func (a *Agent) SendNotify(sender dbus.Sender, appName string, replacesId uint32 if err != nil { logger.Warning(err) } else { - wInfo, err := kwayland.NewWindow(a.sessionService.Conn(), dbus.ObjectPath(fmt.Sprintf("/com/deepin/daemon/KWayland/PlasmaWindow_%v", winId))) + wInfo, err := kwayland.NewWindow(a.sessionService.Conn(), dbus.ObjectPath(fmt.Sprintf("/org/deepin/dde/KWayland1/PlasmaWindow_%v", winId))) if err != nil { logger.Warning(err) } else { diff --git a/lastore1/daemon.go b/lastore1/daemon.go new file mode 100644 index 000000000..e8dab3ab3 --- /dev/null +++ b/lastore1/daemon.go @@ -0,0 +1,296 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package lastore + +import ( + "encoding/json" + "sync" + "time" + + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/loader" + ConfigManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" + notifications "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.dde.notification" + abrecovery "github.com/linuxdeepin/go-dbus-factory/system/com.deepin.abrecovery" + lastore "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.lastore1" + ofdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.dbus" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/gettext" + "github.com/linuxdeepin/go-lib/log" +) + +const ( + dbusPath = "/org/deepin/dde/LastoreSessionHelper1" + dbusServiceName = "org.deepin.dde.LastoreSessionHelper1" +) + +const ( + dSettingsAppID = "org.deepin.lastore" + dSettingsLastoreName = "org.deepin.lastore" + dSettingsKeyUpgradeStatus = "upgrade-status" + dSettingsKeyLastoreDaemonStatus = "lastore-daemon-status" +) + +const ( + UpgradeReady = "ready" + UpgradeRunning = "running" + UpgradeFailed = "failed" + + runningUpgradeBackend = 1 << 2 // 是否处于更新状态 + +) + +type UpgradeReasonType string + +const ( + NoError UpgradeReasonType = "NoError" + ErrorUnknown UpgradeReasonType = "ErrorUnknown" + ErrorFetchFailed UpgradeReasonType = "fetchFailed" + ErrorDpkgError UpgradeReasonType = "dpkgError" + ErrorPkgNotFound UpgradeReasonType = "pkgNotFound" + ErrorUnmetDependencies UpgradeReasonType = "unmetDependencies" + ErrorNoInstallationCandidate UpgradeReasonType = "noInstallationCandidate" + ErrorInsufficientSpace UpgradeReasonType = "insufficientSpace" + ErrorUnauthenticatedPackages UpgradeReasonType = "unauthenticatedPackages" + ErrorOperationNotPermitted UpgradeReasonType = "operationNotPermitted" + ErrorIndexDownloadFailed UpgradeReasonType = "IndexDownloadFailed" + ErrorIO UpgradeReasonType = "ioError" + ErrorDamagePackage UpgradeReasonType = "damagePackage" // 包损坏,需要删除后重新下载或者安装 +) + +const ( + NotifyExpireTimeoutDefault = -1 + NotifyExpireTimeoutNoHide = 0 +) + +const distUpgradeJobPath = "/com/deepin/lastore/Jobdist_upgrade" + +var logger = log.NewLogger("daemon/lastore") + +func init() { + loader.Register(newDaemon()) +} + +type Daemon struct { + lastore *Lastore + agent *Agent + *loader.ModuleBase +} + +func newDaemon() *Daemon { + daemon := new(Daemon) + daemon.ModuleBase = loader.NewModuleBase("lastore", daemon, logger) + return daemon +} + +func (*Daemon) GetDependencies() []string { + return []string{} +} + +func (d *Daemon) Start() error { + var lastoreOnce sync.Once + service := loader.GetService() + sysBus, err := dbus.SystemBus() + if err != nil { + logger.Warning(err) + return err + } + sysDBusDaemon := ofdbus.NewDBus(sysBus) + systemSigLoop := dbusutil.NewSignalLoop(sysBus, 10) + systemSigLoop.Start() + initLastore := func() error { + lastoreObj, err := newLastore(service) + if err != nil { + logger.Warning(err) + return err + } + d.lastore = lastoreObj + err = service.Export(dbusPath, lastoreObj, lastoreObj.syncConfig) + if err != nil { + logger.Warning(err) + return err + } + + err = service.RequestName(dbusServiceName) + if err != nil { + logger.Warning(err) + return err + } + err = lastoreObj.syncConfig.Register() + if err != nil { + logger.Warning("Failed to register sync service:", err) + } + defer func() { + sysDBusDaemon.RemoveAllHandlers() + systemSigLoop.Stop() + }() + agent, err := newAgent(lastoreObj) + if err != nil { + logger.Warning(err) + return err + } + d.agent = agent + return agent.init() + + } + core := lastore.NewLastore(sysBus) + // 处理更新失败/中断的记录 + go func() { + // 获取lastore-daemon记录的更新状态 + ds := ConfigManager.NewConfigManager(sysBus) + dsPath, err := ds.AcquireManager(0, dSettingsAppID, dSettingsLastoreName, "") + if err != nil { + logger.Warning(err) + return + } + dsLastoreManager, err := ConfigManager.NewManager(sysBus, dsPath) + if err != nil { + logger.Warning(err) + return + } + v, err := dsLastoreManager.Value(0, dSettingsKeyUpgradeStatus) + if err != nil { + logger.Warning(err) + return + } else { + jobList, _ := core.Manager().JobList().Get(0) + // 如果正常系统更新,那么不需要处理(更新中切换用户场景) + for _, path := range jobList { + if path == distUpgradeJobPath { + logger.Info("running dist-upgrade,don't need handle status") + return + } + } + upgradeStatus := struct { + Status string + ReasonCode UpgradeReasonType + }{} + statusContent := v.Value().(string) + err = json.Unmarshal([]byte(statusContent), &upgradeStatus) + if err != nil { + logger.Warning(err) + return + } + logger.Infof("lastore status:%+v", upgradeStatus) + // 记录处理异常更新的通知 + osd := notifications.NewNotification(service.Conn()) + abObj := abrecovery.NewABRecovery(sysBus) + valid, err := abObj.ConfigValid().Get(0) // config失效时,无法回滚,提示重新更新 + var msg string + switch upgradeStatus.Status { + // running状态,更新被中断 + case UpgradeRunning: + if err != nil || !valid { + msg = gettext.Tr("Updates failed: it was interrupted.") + } else { + msg = gettext.Tr("Updates failed: it was interrupted. Please roll back to the old version and try again.") + } + case UpgradeFailed: + switch upgradeStatus.ReasonCode { + case ErrorDpkgError: + if err != nil || !valid { + msg = gettext.Tr("Updates failed: DPKG error.") + } else { + msg = gettext.Tr("Updates failed: DPKG error. Please roll back to the old version and try again.") + } + case ErrorInsufficientSpace: + if err != nil || !valid { + msg = gettext.Tr("Updates failed: insufficient disk space.") + } else { + msg = gettext.Tr("Updates failed: insufficient disk space. Please roll back to the old version and try again.") + } + case ErrorUnknown, ErrorPkgNotFound, ErrorNoInstallationCandidate, ErrorIO, ErrorDamagePackage: + if err != nil || !valid { + msg = gettext.Tr("Updates failed") + } else { + msg = gettext.Tr("Updates failed. Please roll back to the old version and try again.") + } + } + } + logger.Infof("notify msg is:%v", msg) + if len(msg) != 0 { + _, err = osd.Notify(0, "dde-control-center", 0, "preferences-system", "", msg, nil, nil, NotifyExpireTimeoutNoHide) + if err != nil { + logger.Warning(err) + } + } + // 通知发完之后,恢复配置文件的内容 + upgradeStatus.Status = UpgradeReady + upgradeStatus.ReasonCode = NoError + v, err := json.Marshal(upgradeStatus) + if err != nil { + logger.Warning(err) + } else { + err = dsLastoreManager.SetValue(0, dSettingsKeyUpgradeStatus, dbus.MakeVariant(v)) + if err != nil { + logger.Warning(err) + } + } + } + }() + time.AfterFunc(10*time.Minute, func() { + lastoreOnce.Do(func() { + err := initLastore() + if err != nil { + logger.Warning(err) + } + }) + }) + + sysDBusDaemon.InitSignalExt(systemSigLoop, true) + _, err = sysDBusDaemon.ConnectNameOwnerChanged(func(name, oldOwner, newOwner string) { + if name == core.ServiceName_() && newOwner != "" { + lastoreOnce.Do(func() { + err := initLastore() + if err != nil { + logger.Warning(err) + } + }) + } + }) + if err != nil { + logger.Warning(err) + } + hasOwner, err := sysDBusDaemon.NameHasOwner(0, core.ServiceName_()) + if err != nil { + logger.Warning(err) + } else if hasOwner { + lastoreOnce.Do(func() { + err := initLastore() + if err != nil { + logger.Warning(err) + } + }) + } + return nil +} + +func (d *Daemon) Stop() error { + if d.lastore != nil { + service := loader.GetService() + err := service.ReleaseName(dbusServiceName) + if err != nil { + logger.Warning(err) + } + d.lastore.destroy() + err = service.StopExport(d.lastore) + if err != nil { + logger.Warning(err) + } + + d.lastore = nil + } + + if d.agent != nil { + service := loader.GetService() + d.agent.destroy() + err := service.StopExport(d.agent) + if err != nil { + logger.Warning(err) + } + d.agent = nil + } + return nil +} diff --git a/lastore/exported_methods_auto.go b/lastore1/exported_methods_auto.go similarity index 100% rename from lastore/exported_methods_auto.go rename to lastore1/exported_methods_auto.go diff --git a/lastore/lastore.go b/lastore1/lastore.go similarity index 84% rename from lastore/lastore.go rename to lastore1/lastore.go index ca0877389..69e4432e4 100644 --- a/lastore/lastore.go +++ b/lastore1/lastore.go @@ -7,12 +7,12 @@ package lastore import ( "sync" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-daemon/common/dsync" - eventLog "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.EventLog" - network "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.network" - lastore "github.com/linuxdeepin/go-dbus-factory/com.deepin.lastore" - notifications "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.notifications" + eventLog "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.EventLog1" + network "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.network1" + notifications "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.notifications" + lastore "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.lastore1" "github.com/linuxdeepin/go-lib/dbusutil" ) diff --git a/lastore1/sync_config.go b/lastore1/sync_config.go new file mode 100644 index 000000000..5e17e83a3 --- /dev/null +++ b/lastore1/sync_config.go @@ -0,0 +1,94 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package lastore + +import ( + "encoding/json" + "errors" + + "github.com/godbus/dbus/v5" +) + +type syncConfig struct { + l *Lastore +} + +type syncData struct { + Version string `json:"version"` + AutoCheckUpdates bool `json:"auto_check_updates"` + AutoClean bool `json:"auto_clean"` + AutoDownloadUpdates bool `json:"auto_download_updates"` + SmartMirrorEnabled bool `json:"smart_mirror_enabled"` +} + +const ( + syncVersion = "1.0" + + smartMirrorService = "com.deepin.lastore.Smartmirror" + smartMirrorPath = "/com/deepin/lastore/Smartmirror" + smartMirrorIFC = smartMirrorService +) + +func (sc *syncConfig) Get() (interface{}, error) { + var info syncData + info.Version = syncVersion + info.AutoCheckUpdates, _ = sc.l.core.Updater().AutoCheckUpdates().Get(0) + info.AutoClean, _ = sc.l.core.Manager().AutoClean().Get(0) + info.AutoDownloadUpdates, _ = sc.l.core.Updater().AutoDownloadUpdates().Get(0) + info.SmartMirrorEnabled, _ = smartMirrorEnabledGet() + return &info, nil +} + +func (sc *syncConfig) Set(data []byte) error { + var info syncData + err := json.Unmarshal(data, &info) + if err != nil { + return err + } + err = sc.l.core.Updater().SetAutoCheckUpdates(0, info.AutoCheckUpdates) + if err != nil { + logger.Warning("Failed to set lastore auto check updates:", err) + } + err = sc.l.core.Manager().SetAutoClean(0, info.AutoClean) + if err != nil { + logger.Warning("Failed to set lastore auto clean:", err) + } + err = sc.l.core.Updater().SetAutoDownloadUpdates(0, info.AutoDownloadUpdates) + if err != nil { + logger.Warning("Failed to set lastore auto download updates:", err) + } + err = smartMirrorEnabledSet(info.SmartMirrorEnabled) + if err != nil { + logger.Warning("Failed to set lastore smart mirror:", err) + } + return nil +} + +func smartMirrorEnabledSet(enabled bool) error { + conn, err := dbus.SystemBus() + if err != nil { + return err + } + return conn.Object(smartMirrorService, smartMirrorPath).Call( + smartMirrorIFC+".SetEnable", 0, enabled).Store() +} + +func smartMirrorEnabledGet() (bool, error) { + conn, err := dbus.SystemBus() + if err != nil { + return false, err + } + var variant dbus.Variant + err = conn.Object(smartMirrorService, smartMirrorPath).Call( + "org.freedesktop.DBus.Properties.Get", 0, smartMirrorIFC, "Enable").Store(&variant) + if err != nil { + return false, err + } + + if variant.Signature().String() != "b" { + return false, errors.New("not excepted value type") + } + return variant.Value().(bool), nil +} diff --git a/lastore/tools.go b/lastore1/tools.go similarity index 100% rename from lastore/tools.go rename to lastore1/tools.go diff --git a/lastore/tools_test.go b/lastore1/tools_test.go similarity index 100% rename from lastore/tools_test.go rename to lastore1/tools_test.go diff --git a/launcher/manager.go b/launcher/manager.go index a0e3cce1f..8d964c1a2 100644 --- a/launcher/manager.go +++ b/launcher/manager.go @@ -17,17 +17,17 @@ import ( "time" "github.com/fsnotify/fsnotify" - "github.com/godbus/dbus" - libApps "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.apps" - libLastore "github.com/linuxdeepin/go-dbus-factory/com.deepin.lastore" - notifications "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.notifications" + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/common/dsync" + "github.com/linuxdeepin/dde-daemon/session/common" + notifications "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.notifications" + libApps "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.apps1" + libLastore "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.lastore1" gio "github.com/linuxdeepin/go-gir/gio-2.0" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/dbusutil/gsprop" "github.com/linuxdeepin/go-lib/gettext" "github.com/linuxdeepin/go-lib/strv" - "github.com/linuxdeepin/dde-daemon/common/dsync" - "github.com/linuxdeepin/dde-daemon/session/common" ) //go:generate dbusutil-gen em -type Manager diff --git a/launcher/manager_ifc.go b/launcher/manager_ifc.go index 440aa8e56..15028cea3 100644 --- a/launcher/manager_ifc.go +++ b/launcher/manager_ifc.go @@ -12,11 +12,11 @@ import ( "strings" "sync/atomic" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-api/soundutils" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/keyfile" "github.com/linuxdeepin/go-lib/procfs" - "github.com/linuxdeepin/dde-api/soundutils" ) const ( diff --git a/launcher/manager_uninstall.go b/launcher/manager_uninstall.go index a23c6eb9f..2f4380c82 100644 --- a/launcher/manager_uninstall.go +++ b/launcher/manager_uninstall.go @@ -15,7 +15,7 @@ import ( "regexp" "strings" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/appinfo/desktopappinfo" "github.com/linuxdeepin/go-lib/dbusutil" . "github.com/linuxdeepin/go-lib/gettext" diff --git a/loader/module.go b/loader/module.go index b444562b6..95d2e5d5a 100644 --- a/loader/module.go +++ b/loader/module.go @@ -8,7 +8,7 @@ import ( "fmt" "sync" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" ConfigManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/log" diff --git a/mime/manager.go b/mime/manager.go index 7b6949301..c302fa021 100644 --- a/mime/manager.go +++ b/mime/manager.go @@ -13,7 +13,7 @@ import ( "time" "github.com/fsnotify/fsnotify" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/appinfo/desktopappinfo" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/gsettings" diff --git a/misc/conf/com.deepin.daemon.Accounts.conf b/misc/conf/com.deepin.daemon.Accounts.conf deleted file mode 100644 index b055fe81a..000000000 --- a/misc/conf/com.deepin.daemon.Accounts.conf +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.daemon.AirplaneMode.conf b/misc/conf/com.deepin.daemon.AirplaneMode.conf deleted file mode 100644 index 2c0a095d5..000000000 --- a/misc/conf/com.deepin.daemon.AirplaneMode.conf +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.daemon.Apps.conf b/misc/conf/com.deepin.daemon.Apps.conf deleted file mode 100644 index 4cba02796..000000000 --- a/misc/conf/com.deepin.daemon.Apps.conf +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.daemon.Authority.conf b/misc/conf/com.deepin.daemon.Authority.conf deleted file mode 100644 index 8e67fd2bc..000000000 --- a/misc/conf/com.deepin.daemon.Authority.conf +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.daemon.Daemon.conf b/misc/conf/com.deepin.daemon.Daemon.conf deleted file mode 100644 index 904facc1a..000000000 --- a/misc/conf/com.deepin.daemon.Daemon.conf +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.daemon.Fprintd.conf b/misc/conf/com.deepin.daemon.Fprintd.conf deleted file mode 100644 index a7614b176..000000000 --- a/misc/conf/com.deepin.daemon.Fprintd.conf +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.daemon.Gesture.conf b/misc/conf/com.deepin.daemon.Gesture.conf deleted file mode 100644 index 5d1c7ee4d..000000000 --- a/misc/conf/com.deepin.daemon.Gesture.conf +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.daemon.Greeter.conf b/misc/conf/com.deepin.daemon.Greeter.conf deleted file mode 100644 index f64244dee..000000000 --- a/misc/conf/com.deepin.daemon.Greeter.conf +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.daemon.Grub2.conf b/misc/conf/com.deepin.daemon.Grub2.conf deleted file mode 100644 index 7caae477e..000000000 --- a/misc/conf/com.deepin.daemon.Grub2.conf +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.daemon.ImageEffect.conf b/misc/conf/com.deepin.daemon.ImageEffect.conf deleted file mode 100644 index 628fedfc2..000000000 --- a/misc/conf/com.deepin.daemon.ImageEffect.conf +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.daemon.KeyEvent.conf b/misc/conf/com.deepin.daemon.KeyEvent.conf deleted file mode 100644 index c789e9682..000000000 --- a/misc/conf/com.deepin.daemon.KeyEvent.conf +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.daemon.PowerManager.conf b/misc/conf/com.deepin.daemon.PowerManager.conf deleted file mode 100644 index 071f54fc8..000000000 --- a/misc/conf/com.deepin.daemon.PowerManager.conf +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.daemon.SwapSchedHelper.conf b/misc/conf/com.deepin.daemon.SwapSchedHelper.conf deleted file mode 100644 index f574862ad..000000000 --- a/misc/conf/com.deepin.daemon.SwapSchedHelper.conf +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.daemon.Timedated.conf b/misc/conf/com.deepin.daemon.Timedated.conf deleted file mode 100644 index 89fa9f3d8..000000000 --- a/misc/conf/com.deepin.daemon.Timedated.conf +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.daemon.Uadp.conf b/misc/conf/com.deepin.daemon.Uadp.conf deleted file mode 100644 index 1f97d2ea3..000000000 --- a/misc/conf/com.deepin.daemon.Uadp.conf +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.daemon.helper.Backlight.conf b/misc/conf/com.deepin.daemon.helper.Backlight.conf deleted file mode 100644 index 18d500e79..000000000 --- a/misc/conf/com.deepin.daemon.helper.Backlight.conf +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.dde.LockService.conf b/misc/conf/com.deepin.dde.LockService.conf deleted file mode 100644 index 407c9a0c1..000000000 --- a/misc/conf/com.deepin.dde.LockService.conf +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.system.Bluetooth.conf b/misc/conf/com.deepin.system.Bluetooth.conf deleted file mode 100644 index 22b55fb3d..000000000 --- a/misc/conf/com.deepin.system.Bluetooth.conf +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.system.Display.conf b/misc/conf/com.deepin.system.Display.conf deleted file mode 100644 index d442bd979..000000000 --- a/misc/conf/com.deepin.system.Display.conf +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.system.InputDevices.conf b/misc/conf/com.deepin.system.InputDevices.conf deleted file mode 100644 index 0a669f63c..000000000 --- a/misc/conf/com.deepin.system.InputDevices.conf +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.system.Network.conf b/misc/conf/com.deepin.system.Network.conf deleted file mode 100644 index 4734f8fb2..000000000 --- a/misc/conf/com.deepin.system.Network.conf +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.system.Power.conf b/misc/conf/com.deepin.system.Power.conf deleted file mode 100644 index 8129ffa6b..000000000 --- a/misc/conf/com.deepin.system.Power.conf +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/misc/conf/com.deepin.system.SystemInfo.conf b/misc/conf/com.deepin.system.SystemInfo.conf deleted file mode 100644 index 0e228a356..000000000 --- a/misc/conf/com.deepin.system.SystemInfo.conf +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/misc/conf/org.deepin.dde.Accounts1.conf b/misc/conf/org.deepin.dde.Accounts1.conf new file mode 100644 index 000000000..bd11fe50c --- /dev/null +++ b/misc/conf/org.deepin.dde.Accounts1.conf @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.AirplaneMode1.conf b/misc/conf/org.deepin.dde.AirplaneMode1.conf new file mode 100644 index 000000000..c0825f458 --- /dev/null +++ b/misc/conf/org.deepin.dde.AirplaneMode1.conf @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.Apps1.conf b/misc/conf/org.deepin.dde.Apps1.conf new file mode 100644 index 000000000..53eb1ccc8 --- /dev/null +++ b/misc/conf/org.deepin.dde.Apps1.conf @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.Authority1.conf b/misc/conf/org.deepin.dde.Authority1.conf new file mode 100644 index 000000000..f712c7dc1 --- /dev/null +++ b/misc/conf/org.deepin.dde.Authority1.conf @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.BacklightHelper1.conf b/misc/conf/org.deepin.dde.BacklightHelper1.conf new file mode 100644 index 000000000..ae0178780 --- /dev/null +++ b/misc/conf/org.deepin.dde.BacklightHelper1.conf @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.Bluetooth1.conf b/misc/conf/org.deepin.dde.Bluetooth1.conf new file mode 100644 index 000000000..51ba7c7e3 --- /dev/null +++ b/misc/conf/org.deepin.dde.Bluetooth1.conf @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.Daemon1.conf b/misc/conf/org.deepin.dde.Daemon1.conf new file mode 100644 index 000000000..cd1bb871a --- /dev/null +++ b/misc/conf/org.deepin.dde.Daemon1.conf @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.Display1.conf b/misc/conf/org.deepin.dde.Display1.conf new file mode 100644 index 000000000..990800e80 --- /dev/null +++ b/misc/conf/org.deepin.dde.Display1.conf @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.Fprintd1.conf b/misc/conf/org.deepin.dde.Fprintd1.conf new file mode 100644 index 000000000..3bc7200bd --- /dev/null +++ b/misc/conf/org.deepin.dde.Fprintd1.conf @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.Gesture1.conf b/misc/conf/org.deepin.dde.Gesture1.conf new file mode 100644 index 000000000..f0c75fac9 --- /dev/null +++ b/misc/conf/org.deepin.dde.Gesture1.conf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.Greeter1.conf b/misc/conf/org.deepin.dde.Greeter1.conf new file mode 100644 index 000000000..5cccda8a6 --- /dev/null +++ b/misc/conf/org.deepin.dde.Greeter1.conf @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.Grub2.conf b/misc/conf/org.deepin.dde.Grub2.conf new file mode 100644 index 000000000..5c1b44499 --- /dev/null +++ b/misc/conf/org.deepin.dde.Grub2.conf @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.ImageBlur1.conf b/misc/conf/org.deepin.dde.ImageBlur1.conf new file mode 100644 index 000000000..2e2cec820 --- /dev/null +++ b/misc/conf/org.deepin.dde.ImageBlur1.conf @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.ImageEffect1.conf b/misc/conf/org.deepin.dde.ImageEffect1.conf new file mode 100644 index 000000000..d46bae18b --- /dev/null +++ b/misc/conf/org.deepin.dde.ImageEffect1.conf @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.InputDevices1.conf b/misc/conf/org.deepin.dde.InputDevices1.conf new file mode 100644 index 000000000..2566c06fe --- /dev/null +++ b/misc/conf/org.deepin.dde.InputDevices1.conf @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.KeyEvent1.conf b/misc/conf/org.deepin.dde.KeyEvent1.conf new file mode 100644 index 000000000..b0f95603f --- /dev/null +++ b/misc/conf/org.deepin.dde.KeyEvent1.conf @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.LockService1.conf b/misc/conf/org.deepin.dde.LockService1.conf new file mode 100644 index 000000000..9b25218dc --- /dev/null +++ b/misc/conf/org.deepin.dde.LockService1.conf @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.Network1.conf b/misc/conf/org.deepin.dde.Network1.conf new file mode 100644 index 000000000..956e4d8ae --- /dev/null +++ b/misc/conf/org.deepin.dde.Network1.conf @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.Power1.conf b/misc/conf/org.deepin.dde.Power1.conf new file mode 100644 index 000000000..181ba374d --- /dev/null +++ b/misc/conf/org.deepin.dde.Power1.conf @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.PowerManager1.conf b/misc/conf/org.deepin.dde.PowerManager1.conf new file mode 100644 index 000000000..5fbd238fc --- /dev/null +++ b/misc/conf/org.deepin.dde.PowerManager1.conf @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.SwapSchedHelper1.conf b/misc/conf/org.deepin.dde.SwapSchedHelper1.conf new file mode 100644 index 000000000..001f798cb --- /dev/null +++ b/misc/conf/org.deepin.dde.SwapSchedHelper1.conf @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.SystemInfo1.conf b/misc/conf/org.deepin.dde.SystemInfo1.conf new file mode 100644 index 000000000..0734824e4 --- /dev/null +++ b/misc/conf/org.deepin.dde.SystemInfo1.conf @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.Timedate1.conf b/misc/conf/org.deepin.dde.Timedate1.conf new file mode 100644 index 000000000..e4f9cd02d --- /dev/null +++ b/misc/conf/org.deepin.dde.Timedate1.conf @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/conf/org.deepin.dde.Uadp1.conf b/misc/conf/org.deepin.dde.Uadp1.conf new file mode 100644 index 000000000..38b0117f5 --- /dev/null +++ b/misc/conf/org.deepin.dde.Uadp1.conf @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/misc/dde-daemon/gesture.json b/misc/dde-daemon/gesture.json index a790fa1a2..14db6803e 100644 --- a/misc/dde-daemon/gesture.json +++ b/misc/dde-daemon/gesture.json @@ -106,7 +106,7 @@ }, "Action": { "Type": "commandline", - "Action": "dbus-send --type=method_call --dest=com.deepin.dde.Launcher /com/deepin/dde/Launcher com.deepin.dde.Launcher.Toggle" + "Action": "dbus-send --type=method_call --dest=org.deepin.dde.Launcher1 /org/deepin/dde/Launcher1 org.deepin.dde.Launcher1.Toggle" } }, { @@ -161,7 +161,7 @@ }, "Action": { "Type": "commandline", - "Action": "dbus-send --type=method_call --dest=com.deepin.dde.Launcher /com/deepin/dde/Launcher com.deepin.dde.Launcher.Toggle" + "Action": "dbus-send --type=method_call --dest=org.deepin.dde.Launcher1 /org/deepin/dde/Launcher1 org.deepin.dde.Launcher1.Toggle" } } ] diff --git a/misc/dde-daemon/keybinding/system_actions.json b/misc/dde-daemon/keybinding/system_actions.json index 57991a70d..a30f0966e 100644 --- a/misc/dde-daemon/keybinding/system_actions.json +++ b/misc/dde-daemon/keybinding/system_actions.json @@ -1,7 +1,7 @@ { "Actions": [ { - "Action": "dbus-send --print-reply --dest=com.deepin.dde.Launcher /com/deepin/dde/Launcher com.deepin.dde.Launcher.Toggle", + "Action": "dbus-send --print-reply --dest=org.deepin.dde.Launcher1 /org/deepin/dde/Launcher1 org.deepin.dde.Launcher1.Toggle", "Key": "launcher" }, { @@ -13,23 +13,19 @@ "Action": "dbus-send --print-reply --dest=com.deepin.ScreenRecorder /com/deepin/ScreenRecorder com.deepin.ScreenRecorder.stopRecord" }, { - "Action": "/usr/bin/deepin-system-monitor", - "Key": "system-monitor" + "Key": "system-monitor", + "Action": "dde-am deepin-system-monitor" }, { "Key": "deepin-picker", "Action": "dbus-send --print-reply --dest=com.deepin.Picker /com/deepin/Picker com.deepin.Picker.Show" }, { - "Action": "originmap=$(setxkbmap -query | grep option | awk -F ' ' '{print $2}');/usr/bin/setxkbmap -option grab:break_actions&&/usr/bin/xdotool key XF86Ungrab&&dbus-send --print-reply --dest=com.deepin.dde.lockFront /com/deepin/dde/lockFront com.deepin.dde.lockFront.Show&&/usr/bin/setxkbmap -option $originmap", + "Action": "/usr/lib/deepin-daemon/dde-lock.sh", "Key": "lock-screen" }, { - "Action": "originmap=$(setxkbmap -query | grep option | awk -F ' ' '{print $2}');/usr/bin/setxkbmap -option grab:break_actions&&dbus-send --print-reply --dest=com.deepin.dde.lockFront /com/deepin/dde/lockFront com.deepin.dde.lockFront.Show&&/usr/bin/setxkbmap -option $originmap", - "Key": "lock-screen-wayland" - }, - { - "Action": "dbus-send --print-reply --dest=com.deepin.dde.shutdownFront /com/deepin/dde/shutdownFront com.deepin.dde.shutdownFront.Show", + "Action": "dbus-send --print-reply --dest=org.deepin.dde.ShutdownFront1 /org/deepin/dde/ShutdownFront1 org.deepin.dde.ShutdownFront1.Show", "Key": "logout" }, { @@ -61,7 +57,7 @@ "Key": "disable-touchpad" }, { - "Action": "dbus-send --type=method_call --dest=com.deepin.WMSwitcher /com/deepin/WMSwitcher com.deepin.WMSwitcher.RequestSwitchWM", + "Action": "dbus-send --type=method_call --dest=org.deepin.dde.WMSwitcher1 /org/deepin/dde/WMSwitcher1 org.deepin.dde.WMSwitcher1.RequestSwitchWM", "Key": "wm-switcher" }, { @@ -82,7 +78,7 @@ }, { "Key": "clipboard", - "Action": "dbus-send --print-reply --dest=com.deepin.dde.Clipboard /com/deepin/dde/Clipboard com.deepin.dde.Clipboard.Toggle; dbus-send --print-reply --dest=com.deepin.dde.Launcher /com/deepin/dde/Launcher com.deepin.dde.Launcher.Hide" + "Action": "dbus-send --print-reply --dest=org.deepin.dde.Clipboard1 /org/deepin/dde/Clipboard1 org.deepin.dde.Clipboard1.Toggle" }, { "Key": "translation", @@ -90,7 +86,7 @@ }, { "key":"notification-center", - "Action":"dbus-send --print-reply --dest=com.deepin.dde.osd /org/freedesktop/Notifications com.deepin.dde.Notification.Toggle" + "Action":"dbus-send --print-reply --dest=org.deepin.dde.Widgets1 /org/deepin/dde/Widgets1 org.deepin.dde.Widgets1.Toggle" }, { "Key": "screenshot-ocr", diff --git a/misc/dsg-configs/org.deepin.dde.daemon.audio.json b/misc/dsg-configs/org.deepin.dde.daemon.audio.json index 85ef04e8a..870de8152 100644 --- a/misc/dsg-configs/org.deepin.dde.daemon.audio.json +++ b/misc/dsg-configs/org.deepin.dde.daemon.audio.json @@ -77,6 +77,17 @@ "description[zh_CN]": "通过端口类型设置输出优先级,0:蓝牙音频 1:3.5mm, 耳麦 2:USB, 3:内置扬声器和话筒, 4:HDMI, 5:线缆输入输出, 6:多声道, 7:其他类型", "permissions": "read", "visibility": "private" + }, + "bluezModeDefault": { + "value": "a2dp", + "serial": 0, + "flags": [], + "global": true, + "name": "BluezModeDefault", + "name[zh_CN]": "蓝牙默认模式", + "description": "bluetooth audio default mode", + "permissions": "readwrite", + "visibility": "private" } } } diff --git a/misc/dsg-configs/org.deepin.dde.daemon.keybinding.json b/misc/dsg-configs/org.deepin.dde.daemon.keybinding.json index f7783dff2..be6c5d45e 100644 --- a/misc/dsg-configs/org.deepin.dde.daemon.keybinding.json +++ b/misc/dsg-configs/org.deepin.dde.daemon.keybinding.json @@ -24,6 +24,16 @@ "description": "system-product-names need xrandr+q to resolve hot plug", "permissions": "readwrite", "visibility": "private" + }, + "deviceManagerControlEnable": { + "value": false, + "serial": 0, + "flags": [], + "name": "deviceManagerControlEnable", + "name[zh_CN]": "通过DDE控制实现设备管理器热键功能", + "description": "DeviceManager shortcut effected by DDE software", + "permissions": "readonly", + "visibility": "private" } } } \ No newline at end of file diff --git a/misc/polkit-action/com.deepin.daemon.Fprintd.policy.in b/misc/polkit-action/com.deepin.daemon.Fprintd.policy.in deleted file mode 100644 index 02e21e366..000000000 --- a/misc/polkit-action/com.deepin.daemon.Fprintd.policy.in +++ /dev/null @@ -1,43 +0,0 @@ - - - - LinuxDeepin - https://www.deepin.com/ - - Add fingerprint password - Authentication is required to add fingerprint password - - no - no - auth_admin_keep - - - - Clear fingerprint passwords - Authentication is required to clear fingerprint passwords - - no - no - auth_admin_keep - - - - Rename fingerprint password - Authentication is required to rename fingerprint password - - no - no - auth_admin_keep - - - - Manage fingerprint passwords - Password is required to perform this action - - no - no - auth_admin_keep - - - diff --git a/misc/polkit-action/com.deepin.daemon.Grub2.policy.in b/misc/polkit-action/com.deepin.daemon.Grub2.policy.in deleted file mode 100644 index 2f3f8af1a..000000000 --- a/misc/polkit-action/com.deepin.daemon.Grub2.policy.in +++ /dev/null @@ -1,29 +0,0 @@ - - - - LinuxDeepin - https://www.deepin.com/ - - - Change the grub configuration - Authentication is required to change the grub configuration - - no - no - auth_admin_keep - - - - - Prepare grub display resolution detection - Authentication is required to prepare grub display resolution detection - - no - no - auth_admin_keep - - - - diff --git a/misc/polkit-action/com.deepin.daemon.accounts.policy.in b/misc/polkit-action/com.deepin.daemon.accounts.policy.in deleted file mode 100644 index 7f73fae77..000000000 --- a/misc/polkit-action/com.deepin.daemon.accounts.policy.in +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - Change your own user data - Authentication is required to change your own user data - - no - no - auth_self_keep - - - - - Manage user accounts - Authentication is required to change user data - - no - no - auth_admin_keep - - - - - Enable Auto Login - Authentication is required to enable auto login - - no - no - auth_self - - - - - Disable Auto Login - Authentication is required to disable auto login - - no - no - auth_self - - - - - Enable Quick Login - Authentication is required to enable quick login - - no - no - auth_self - - - - - Disable Quick Login - Authentication is required to disable quick login - - no - no - auth_self - - - - - Enable Login without password - Authentication is required to enable login without password - - no - no - auth_self - - - - - Disable Login without password - Authentication is required to disable login without password - - no - no - auth_self - - - - - Set keyboard layout - Authentication is required to set keyboard layout - - no - no - auth_self - - - - diff --git a/misc/polkit-action/com.deepin.daemon.airplane-mode.policy b/misc/polkit-action/com.deepin.daemon.airplane-mode.policy deleted file mode 100644 index bccf29e73..000000000 --- a/misc/polkit-action/com.deepin.daemon.airplane-mode.policy +++ /dev/null @@ -1,19 +0,0 @@ - - - - LinuxDeepin - https://www.deepin.com/ - - - Enable or disable any switch in airplane mode - Authentication is required to enable or disable any switch in airplane mode - - no - no - yes - - - - diff --git a/misc/polkit-action/org.deepin.dde.Fprintd1.policy.in b/misc/polkit-action/org.deepin.dde.Fprintd1.policy.in new file mode 100644 index 000000000..9003e6faf --- /dev/null +++ b/misc/polkit-action/org.deepin.dde.Fprintd1.policy.in @@ -0,0 +1,43 @@ + + + + LinuxDeepin + https://www.deepin.com/ + + Add fingerprint password + Authentication is required to add fingerprint password + + no + no + auth_admin_keep + + + + Clear fingerprint passwords + Authentication is required to clear fingerprint passwords + + no + no + auth_admin_keep + + + + Rename fingerprint password + Authentication is required to rename fingerprint password + + no + no + auth_admin_keep + + + + Manage fingerprint passwords + Password is required to perform this action + + no + no + auth_admin_keep + + + diff --git a/misc/polkit-action/org.deepin.dde.Grub2.policy.in b/misc/polkit-action/org.deepin.dde.Grub2.policy.in new file mode 100644 index 000000000..127576822 --- /dev/null +++ b/misc/polkit-action/org.deepin.dde.Grub2.policy.in @@ -0,0 +1,29 @@ + + + + LinuxDeepin + https://www.deepin.com/ + + + Change the grub configuration + Authentication is required to change the grub configuration + + no + no + auth_admin_keep + + + + + Prepare grub display resolution detection + Authentication is required to prepare grub display resolution detection + + no + no + auth_admin_keep + + + + diff --git a/misc/polkit-action/org.deepin.dde.accounts1.policy.in b/misc/polkit-action/org.deepin.dde.accounts1.policy.in new file mode 100644 index 000000000..54eaca85d --- /dev/null +++ b/misc/polkit-action/org.deepin.dde.accounts1.policy.in @@ -0,0 +1,119 @@ + + + + + + + + Change your own user data + Authentication is required to change your own user data + + no + no + auth_self_keep + + + + + Manage user accounts + Authentication is required to change user data + + no + no + auth_admin_keep + + + + + Enable Auto Login + Authentication is required to enable auto login + + no + no + auth_self + + + + + Disable Auto Login + Authentication is required to disable auto login + + no + no + auth_self + + + + + Enable Quick Login + Authentication is required to enable quick login + + no + no + auth_self + + + + + Disable Quick Login + Authentication is required to disable quick login + + no + no + auth_self + + + + + Enable WeChat Code Login + Authentication is required to enable WeChat code login + + no + no + auth_self + + + + + Disable WeChat Code Login + Authentication is required to disable WeChat code login + + no + no + auth_self + + + + + Enable Login without password + Authentication is required to enable login without password + + no + no + auth_self + + + + + Disable Login without password + Authentication is required to disable login without password + + no + no + auth_self + + + + + Set keyboard layout + Authentication is required to set keyboard layout + + no + no + auth_self + + + + diff --git a/misc/polkit-localauthority/com.deepin.daemon.Accounts.pkla b/misc/polkit-localauthority/com.deepin.daemon.Accounts.pkla deleted file mode 100644 index 431edfe1d..000000000 --- a/misc/polkit-localauthority/com.deepin.daemon.Accounts.pkla +++ /dev/null @@ -1,6 +0,0 @@ -[Greeter Set Keyboard Layout] -Identity=unix-user:lightdm -Action=com.deepin.daemon.accounts.set-keyboard-layout -ResultAny=no -ResultInactive=no -ResultActive=yes diff --git a/misc/polkit-localauthority/com.deepin.daemon.Grub2.pkla b/misc/polkit-localauthority/com.deepin.daemon.Grub2.pkla deleted file mode 100644 index 814cb32f7..000000000 --- a/misc/polkit-localauthority/com.deepin.daemon.Grub2.pkla +++ /dev/null @@ -1,6 +0,0 @@ -[Prepare grub2 gfxmode deletection] -Identity=unix-group:sudo -Action=com.deepin.daemon.grub2.prepare-gfxmode-detect -ResultAny=no -ResultInactive=no -ResultActive=yes diff --git a/misc/polkit-localauthority/org.deepin.dde.accounts.pkla b/misc/polkit-localauthority/org.deepin.dde.accounts.pkla new file mode 100644 index 000000000..8580c1d42 --- /dev/null +++ b/misc/polkit-localauthority/org.deepin.dde.accounts.pkla @@ -0,0 +1,6 @@ +[Greeter Set Keyboard Layout] +Identity=unix-user:lightdm +Action=org.deepin.dde.accounts.set-keyboard-layout +ResultAny=no +ResultInactive=no +ResultActive=yes diff --git a/misc/polkit-localauthority/com.deepin.daemon.Fprintd.pkla b/misc/polkit-localauthority/org.deepin.dde.fprintd.pkla similarity index 100% rename from misc/polkit-localauthority/com.deepin.daemon.Fprintd.pkla rename to misc/polkit-localauthority/org.deepin.dde.fprintd.pkla diff --git a/misc/polkit-localauthority/org.deepin.dde.grub2.pkla b/misc/polkit-localauthority/org.deepin.dde.grub2.pkla new file mode 100644 index 000000000..03b6a5763 --- /dev/null +++ b/misc/polkit-localauthority/org.deepin.dde.grub2.pkla @@ -0,0 +1,6 @@ +[Prepare grub2 gfxmode deletection] +Identity=unix-group:sudo +Action=org.deepin.dde.grub2.prepare-gfxmode-detect +ResultAny=no +ResultInactive=no +ResultActive=yes diff --git a/misc/scripts/dde-lock.sh b/misc/scripts/dde-lock.sh new file mode 100644 index 000000000..e98e52503 --- /dev/null +++ b/misc/scripts/dde-lock.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +originmap=$(setxkbmap -query | grep option | awk -F ' ' '{print $2}');setxkbmap -option grab:break_actions&&xdotool key XF86Ungrab&&dbus-send --print-reply --dest=org.deepin.dde.LockFront1 /org/deepin/dde/LockFront1 org.deepin.dde.LockFront1.Show; setxkbmap -option $originmap \ No newline at end of file diff --git a/misc/scripts/dde-system-daemon-power-refresh.sh b/misc/scripts/dde-system-daemon-power-refresh.sh index 470d9831e..2038c9c5c 100755 --- a/misc/scripts/dde-system-daemon-power-refresh.sh +++ b/misc/scripts/dde-system-daemon-power-refresh.sh @@ -3,6 +3,6 @@ case $1/$2 in pre/*) ;; post/*) - gdbus call -y -d com.deepin.system.Power -o /com/deepin/system/Power -m com.deepin.system.Power.Refresh --timeout 2 + gdbus call -y -d org.deepin.dde.Power1 -o /org/deepin/dde/Power1 -m org.deepin.dde.Power1.Refresh --timeout 2 ;; esac diff --git a/misc/services/com.deepin.LastoreSessionHelper.service b/misc/services/com.deepin.LastoreSessionHelper.service deleted file mode 100644 index 7a0c0a90e..000000000 --- a/misc/services/com.deepin.LastoreSessionHelper.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.LastoreSessionHelper -Exec=/usr/lib/deepin-daemon/dde-session-daemon - diff --git a/misc/services/com.deepin.api.XEventMonitor.service b/misc/services/com.deepin.api.XEventMonitor.service deleted file mode 100644 index 699664844..000000000 --- a/misc/services/com.deepin.api.XEventMonitor.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.api.XEventMonitor -Exec=/usr/lib/deepin-daemon/dde-session-daemon diff --git a/misc/services/com.deepin.daemon.Appearance.service b/misc/services/com.deepin.daemon.Appearance.service deleted file mode 100644 index e72c8f0c9..000000000 --- a/misc/services/com.deepin.daemon.Appearance.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Appearance -Exec=/usr/lib/deepin-daemon/dde-session-daemon diff --git a/misc/services/com.deepin.daemon.Audio.service b/misc/services/com.deepin.daemon.Audio.service deleted file mode 100644 index 37fd1808e..000000000 --- a/misc/services/com.deepin.daemon.Audio.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Audio -Exec=/usr/lib/deepin-daemon/dde-session-daemon diff --git a/misc/services/com.deepin.daemon.Bluetooth.service b/misc/services/com.deepin.daemon.Bluetooth.service deleted file mode 100644 index 8db042f83..000000000 --- a/misc/services/com.deepin.daemon.Bluetooth.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Bluetooth -Exec=/usr/lib/deepin-daemon/dde-session-daemon diff --git a/misc/services/com.deepin.daemon.EventLog.service b/misc/services/com.deepin.daemon.EventLog.service deleted file mode 100644 index 89bef9547..000000000 --- a/misc/services/com.deepin.daemon.EventLog.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.EventLog -Exec=/usr/lib/deepin-daemon/dde-session-daemon \ No newline at end of file diff --git a/misc/services/com.deepin.daemon.InputDevices.service b/misc/services/com.deepin.daemon.InputDevices.service deleted file mode 100644 index 9d3cf38b0..000000000 --- a/misc/services/com.deepin.daemon.InputDevices.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.InputDevices -Exec=/usr/lib/deepin-daemon/dde-session-daemon diff --git a/misc/services/com.deepin.daemon.Keybinding.service b/misc/services/com.deepin.daemon.Keybinding.service deleted file mode 100644 index 3c4f4e3a5..000000000 --- a/misc/services/com.deepin.daemon.Keybinding.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Keybinding -Exec=/usr/lib/deepin-daemon/dde-session-daemon diff --git a/misc/services/com.deepin.daemon.LangSelector.service b/misc/services/com.deepin.daemon.LangSelector.service deleted file mode 100644 index d1b349d09..000000000 --- a/misc/services/com.deepin.daemon.LangSelector.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.LangSelector -Exec=/usr/lib/deepin-daemon/langselector diff --git a/misc/services/com.deepin.daemon.Mime.service b/misc/services/com.deepin.daemon.Mime.service deleted file mode 100644 index b50715da4..000000000 --- a/misc/services/com.deepin.daemon.Mime.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Mime -Exec=/usr/lib/deepin-daemon/dde-session-daemon diff --git a/misc/services/com.deepin.daemon.Network.service b/misc/services/com.deepin.daemon.Network.service deleted file mode 100644 index e5c637a80..000000000 --- a/misc/services/com.deepin.daemon.Network.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Network -Exec=/usr/lib/deepin-daemon/dde-session-daemon diff --git a/misc/services/com.deepin.daemon.Power.service b/misc/services/com.deepin.daemon.Power.service deleted file mode 100644 index d029d2004..000000000 --- a/misc/services/com.deepin.daemon.Power.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Power -Exec=/usr/lib/deepin-daemon/dde-session-daemon diff --git a/misc/services/com.deepin.daemon.Search.service b/misc/services/com.deepin.daemon.Search.service deleted file mode 100644 index 20bb0eea1..000000000 --- a/misc/services/com.deepin.daemon.Search.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Search -Exec=/usr/lib/deepin-daemon/search diff --git a/misc/services/com.deepin.daemon.SessionWatcher.service b/misc/services/com.deepin.daemon.SessionWatcher.service deleted file mode 100644 index 901556344..000000000 --- a/misc/services/com.deepin.daemon.SessionWatcher.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.SessionWatcher -Exec=/usr/lib/deepin-daemon/dde-session-daemon diff --git a/misc/services/com.deepin.daemon.SoundEffect.service b/misc/services/com.deepin.daemon.SoundEffect.service deleted file mode 100644 index 9e404ab4f..000000000 --- a/misc/services/com.deepin.daemon.SoundEffect.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.SoundEffect -Exec=/usr/lib/deepin-daemon/soundeffect diff --git a/misc/services/com.deepin.daemon.SystemInfo.service b/misc/services/com.deepin.daemon.SystemInfo.service deleted file mode 100644 index 5b5b09892..000000000 --- a/misc/services/com.deepin.daemon.SystemInfo.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.SystemInfo -Exec=/usr/lib/deepin-daemon/dde-session-daemon diff --git a/misc/services/com.deepin.daemon.Timedate.service b/misc/services/com.deepin.daemon.Timedate.service deleted file mode 100644 index d18672968..000000000 --- a/misc/services/com.deepin.daemon.Timedate.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Timedate -Exec=/usr/lib/deepin-daemon/dde-session-daemon diff --git a/misc/services/com.deepin.daemon.Zone.service b/misc/services/com.deepin.daemon.Zone.service deleted file mode 100644 index e183801e8..000000000 --- a/misc/services/com.deepin.daemon.Zone.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Zone -Exec=/usr/lib/deepin-daemon/dde-session-daemon diff --git a/misc/services/com.deepin.dde.daemon.Dock.service b/misc/services/com.deepin.dde.daemon.Dock.service deleted file mode 100644 index 1696a9105..000000000 --- a/misc/services/com.deepin.dde.daemon.Dock.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.dde.daemon.Dock -Exec=/usr/lib/deepin-daemon/dde-session-daemon diff --git a/misc/services/com.deepin.dde.daemon.Launcher.service b/misc/services/com.deepin.dde.daemon.Launcher.service deleted file mode 100644 index df329366f..000000000 --- a/misc/services/com.deepin.dde.daemon.Launcher.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=com.deepin.dde.daemon.Launcher -Exec=/usr/lib/deepin-daemon/dde-session-daemon diff --git a/misc/services/org.deepin.dde.Audio1.service b/misc/services/org.deepin.dde.Audio1.service new file mode 100644 index 000000000..86963cf3f --- /dev/null +++ b/misc/services/org.deepin.dde.Audio1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Audio1 +Exec=/usr/lib/deepin-daemon/dde-session-daemon +SystemdService=org.dde.session.Daemon1.service diff --git a/misc/services/org.deepin.dde.Bluetooth1.service b/misc/services/org.deepin.dde.Bluetooth1.service new file mode 100644 index 000000000..b0def8523 --- /dev/null +++ b/misc/services/org.deepin.dde.Bluetooth1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Bluetooth1 +Exec=/usr/lib/deepin-daemon/dde-session-daemon +SystemdService=org.dde.session.Daemon1.service diff --git a/misc/services/org.deepin.dde.InputDevices1.service b/misc/services/org.deepin.dde.InputDevices1.service new file mode 100644 index 000000000..20b7904f1 --- /dev/null +++ b/misc/services/org.deepin.dde.InputDevices1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.InputDevices1 +Exec=/usr/lib/deepin-daemon/dde-session-daemon +SystemdService=org.dde.session.Daemon1.service diff --git a/misc/services/org.deepin.dde.Keybinding1.service b/misc/services/org.deepin.dde.Keybinding1.service new file mode 100644 index 000000000..450a59052 --- /dev/null +++ b/misc/services/org.deepin.dde.Keybinding1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Keybinding1 +Exec=/usr/lib/deepin-daemon/dde-session-daemon +SystemdService=org.dde.session.Daemon1.service diff --git a/misc/services/org.deepin.dde.LangSelector1.service b/misc/services/org.deepin.dde.LangSelector1.service new file mode 100644 index 000000000..84357675b --- /dev/null +++ b/misc/services/org.deepin.dde.LangSelector1.service @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.deepin.dde.LangSelector1 +Exec=/usr/lib/deepin-daemon/langselector diff --git a/misc/services/org.deepin.dde.LastoreSessionHelper1.service b/misc/services/org.deepin.dde.LastoreSessionHelper1.service new file mode 100644 index 000000000..97de6e8e7 --- /dev/null +++ b/misc/services/org.deepin.dde.LastoreSessionHelper1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.LastoreSessionHelper1 +Exec=/usr/lib/deepin-daemon/dde-session-daemon +SystemdService=org.dde.session.Daemon1.service diff --git a/misc/services/org.deepin.dde.Network1.service b/misc/services/org.deepin.dde.Network1.service new file mode 100644 index 000000000..79d6e9d13 --- /dev/null +++ b/misc/services/org.deepin.dde.Network1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Network1 +Exec=/usr/lib/deepin-daemon/dde-session-daemon +SystemdService=org.dde.session.Daemon1.service diff --git a/misc/services/org.deepin.dde.Power1.service b/misc/services/org.deepin.dde.Power1.service new file mode 100644 index 000000000..7b8350d01 --- /dev/null +++ b/misc/services/org.deepin.dde.Power1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Power1 +Exec=/usr/lib/deepin-daemon/dde-session-daemon +SystemdService=org.dde.session.Daemon1.service diff --git a/misc/services/org.deepin.dde.Search1.service b/misc/services/org.deepin.dde.Search1.service new file mode 100644 index 000000000..4e7aa9db9 --- /dev/null +++ b/misc/services/org.deepin.dde.Search1.service @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.deepin.dde.Search1 +Exec=/usr/lib/deepin-daemon/search diff --git a/misc/services/org.deepin.dde.SessionWatcher1.service b/misc/services/org.deepin.dde.SessionWatcher1.service new file mode 100644 index 000000000..b24841615 --- /dev/null +++ b/misc/services/org.deepin.dde.SessionWatcher1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.SessionWatcher1 +Exec=/usr/lib/deepin-daemon/dde-session-daemon +SystemdService=org.dde.session.Daemon1.service diff --git a/misc/services/org.deepin.dde.SoundEffect1.service b/misc/services/org.deepin.dde.SoundEffect1.service new file mode 100644 index 000000000..a135253af --- /dev/null +++ b/misc/services/org.deepin.dde.SoundEffect1.service @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.deepin.dde.SoundEffect1 +Exec=/usr/lib/deepin-daemon/soundeffect diff --git a/misc/services/org.deepin.dde.SystemInfo1.service b/misc/services/org.deepin.dde.SystemInfo1.service new file mode 100644 index 000000000..17113be6d --- /dev/null +++ b/misc/services/org.deepin.dde.SystemInfo1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.SystemInfo1 +Exec=/usr/lib/deepin-daemon/dde-session-daemon +SystemdService=org.dde.session.Daemon1.service diff --git a/misc/services/org.deepin.dde.Timedate1.service b/misc/services/org.deepin.dde.Timedate1.service new file mode 100644 index 000000000..17fd901e7 --- /dev/null +++ b/misc/services/org.deepin.dde.Timedate1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Timedate1 +Exec=/usr/lib/deepin-daemon/dde-session-daemon +SystemdService=org.dde.session.Daemon1.service diff --git a/misc/services/org.deepin.dde.XEventMonitor1.service b/misc/services/org.deepin.dde.XEventMonitor1.service new file mode 100644 index 000000000..126719d95 --- /dev/null +++ b/misc/services/org.deepin.dde.XEventMonitor1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.XEventMonitor1 +Exec=/usr/lib/deepin-daemon/dde-session-daemon -l info +SystemdService=org.dde.session.Daemon1.service diff --git a/misc/services/org.deepin.dde.Zone1.service b/misc/services/org.deepin.dde.Zone1.service new file mode 100644 index 000000000..ed150fc20 --- /dev/null +++ b/misc/services/org.deepin.dde.Zone1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Zone1 +Exec=/usr/lib/deepin-daemon/dde-session-daemon +SystemdService=org.dde.session.Daemon1.service diff --git a/misc/system-services/com.deepin.daemon.Accounts.service b/misc/system-services/com.deepin.daemon.Accounts.service deleted file mode 100644 index 25260d2dd..000000000 --- a/misc/system-services/com.deepin.daemon.Accounts.service +++ /dev/null @@ -1,5 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Accounts -Exec=/usr/lib/deepin-daemon/dde-system-daemon -User=root -SystemdService=deepin-accounts-daemon.service diff --git a/misc/system-services/com.deepin.daemon.AirplaneMode.service b/misc/system-services/com.deepin.daemon.AirplaneMode.service deleted file mode 100644 index 3bbf94524..000000000 --- a/misc/system-services/com.deepin.daemon.AirplaneMode.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.AirplaneMode -Exec=/usr/lib/deepin-daemon/dde-system-daemon -User=root diff --git a/misc/system-services/com.deepin.daemon.Apps.service b/misc/system-services/com.deepin.daemon.Apps.service deleted file mode 100644 index 0d315119b..000000000 --- a/misc/system-services/com.deepin.daemon.Apps.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Apps -Exec=/usr/lib/deepin-daemon/dde-system-daemon -User=root diff --git a/misc/system-services/com.deepin.daemon.Authority.service b/misc/system-services/com.deepin.daemon.Authority.service deleted file mode 100644 index 689928cac..000000000 --- a/misc/system-services/com.deepin.daemon.Authority.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Authority -Exec=/usr/lib/deepin-daemon/dde-authority -User=root diff --git a/misc/system-services/com.deepin.daemon.Daemon.service b/misc/system-services/com.deepin.daemon.Daemon.service deleted file mode 100644 index 064ddb9e9..000000000 --- a/misc/system-services/com.deepin.daemon.Daemon.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Daemon -Exec=/usr/lib/deepin-daemon/dde-system-daemon -User=root diff --git a/misc/system-services/com.deepin.daemon.Fprintd.service b/misc/system-services/com.deepin.daemon.Fprintd.service deleted file mode 100644 index a8a373794..000000000 --- a/misc/system-services/com.deepin.daemon.Fprintd.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Fprintd -Exec=/usr/lib/deepin-daemon/dde-system-daemon -User=root diff --git a/misc/system-services/com.deepin.daemon.Gesture.service b/misc/system-services/com.deepin.daemon.Gesture.service deleted file mode 100644 index 575ba5871..000000000 --- a/misc/system-services/com.deepin.daemon.Gesture.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Gesture -Exec=/usr/lib/deepin-daemon/dde-system-daemon -User=root diff --git a/misc/system-services/com.deepin.daemon.Greeter.service b/misc/system-services/com.deepin.daemon.Greeter.service deleted file mode 100644 index e8e026595..000000000 --- a/misc/system-services/com.deepin.daemon.Greeter.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Greeter -Exec=/usr/lib/deepin-daemon/dde-greeter-setter -User=root diff --git a/misc/system-services/com.deepin.daemon.Grub2.service b/misc/system-services/com.deepin.daemon.Grub2.service deleted file mode 100644 index 031ff9878..000000000 --- a/misc/system-services/com.deepin.daemon.Grub2.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Grub2 -Exec=/usr/lib/deepin-daemon/grub2 -User=root diff --git a/misc/system-services/com.deepin.daemon.ImageEffect.service b/misc/system-services/com.deepin.daemon.ImageEffect.service deleted file mode 100644 index c06bf49d7..000000000 --- a/misc/system-services/com.deepin.daemon.ImageEffect.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.ImageEffect -Exec=/usr/lib/deepin-daemon/dde-system-daemon -User=root diff --git a/misc/system-services/com.deepin.daemon.SwapSchedHelper.service b/misc/system-services/com.deepin.daemon.SwapSchedHelper.service deleted file mode 100644 index 28e5dd5be..000000000 --- a/misc/system-services/com.deepin.daemon.SwapSchedHelper.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.SwapSchedHelper -Exec=/usr/lib/deepin-daemon/dde-system-daemon -User=root diff --git a/misc/system-services/com.deepin.daemon.Timedated.service b/misc/system-services/com.deepin.daemon.Timedated.service deleted file mode 100644 index 691b4f7bc..000000000 --- a/misc/system-services/com.deepin.daemon.Timedated.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Timedated -Exec=/usr/lib/deepin-daemon/dde-system-daemon -User=root diff --git a/misc/system-services/com.deepin.daemon.Uadp.service b/misc/system-services/com.deepin.daemon.Uadp.service deleted file mode 100644 index 509462c5f..000000000 --- a/misc/system-services/com.deepin.daemon.Uadp.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.Uadp -Exec=/usr/lib/deepin-daemon/dde-system-daemon -User=root \ No newline at end of file diff --git a/misc/system-services/com.deepin.daemon.helper.Backlight.service b/misc/system-services/com.deepin.daemon.helper.Backlight.service deleted file mode 100644 index 958e9ec71..000000000 --- a/misc/system-services/com.deepin.daemon.helper.Backlight.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.daemon.helper.Backlight -Exec=/usr/lib/deepin-daemon/backlight_helper -User=root diff --git a/misc/system-services/com.deepin.dde.LockService.service b/misc/system-services/com.deepin.dde.LockService.service deleted file mode 100644 index 9de324c77..000000000 --- a/misc/system-services/com.deepin.dde.LockService.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.dde.LockService -Exec=/usr/lib/deepin-daemon/dde-lockservice -User=root diff --git a/misc/system-services/com.deepin.system.Bluetooth.service b/misc/system-services/com.deepin.system.Bluetooth.service deleted file mode 100644 index f1405796f..000000000 --- a/misc/system-services/com.deepin.system.Bluetooth.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.system.Bluetooth -Exec=/usr/lib/deepin-daemon/dde-system-daemon -User=root diff --git a/misc/system-services/com.deepin.system.Display.service b/misc/system-services/com.deepin.system.Display.service deleted file mode 100644 index 3f71eff2f..000000000 --- a/misc/system-services/com.deepin.system.Display.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.system.Display -Exec=/usr/lib/deepin-daemon/dde-system-daemon -User=root diff --git a/misc/system-services/com.deepin.system.Network.service b/misc/system-services/com.deepin.system.Network.service deleted file mode 100644 index 5fd04a4c4..000000000 --- a/misc/system-services/com.deepin.system.Network.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.system.Network -Exec=/usr/lib/deepin-daemon/dde-system-daemon -User=root diff --git a/misc/system-services/com.deepin.system.Power.service b/misc/system-services/com.deepin.system.Power.service deleted file mode 100644 index c32b47fad..000000000 --- a/misc/system-services/com.deepin.system.Power.service +++ /dev/null @@ -1,4 +0,0 @@ -[D-BUS Service] -Name=com.deepin.system.Power -Exec=/usr/lib/deepin-daemon/dde-system-daemon -User=root diff --git a/misc/system-services/org.deepin.dde.Accounts1.service b/misc/system-services/org.deepin.dde.Accounts1.service new file mode 100644 index 000000000..5ca7e331b --- /dev/null +++ b/misc/system-services/org.deepin.dde.Accounts1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Accounts1 +Exec=/bin/false +SystemdService=deepin-accounts1-daemon.service diff --git a/misc/system-services/org.deepin.dde.AirplaneMode1.service b/misc/system-services/org.deepin.dde.AirplaneMode1.service new file mode 100644 index 000000000..e87b44e30 --- /dev/null +++ b/misc/system-services/org.deepin.dde.AirplaneMode1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.AirplaneMode1 +Exec=/bin/false +SystemdService=deepin-accounts1-daemon.service diff --git a/misc/system-services/org.deepin.dde.Apps1.service b/misc/system-services/org.deepin.dde.Apps1.service new file mode 100644 index 000000000..2727600a9 --- /dev/null +++ b/misc/system-services/org.deepin.dde.Apps1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Apps1 +Exec=/bin/false +SystemdService=deepin-accounts1-daemon.service \ No newline at end of file diff --git a/misc/system-services/org.deepin.dde.Authority1.service b/misc/system-services/org.deepin.dde.Authority1.service new file mode 100644 index 000000000..b2ed5d592 --- /dev/null +++ b/misc/system-services/org.deepin.dde.Authority1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Authority1 +Exec=/bin/false +SystemdService=deepin-authority.service diff --git a/misc/system-services/org.deepin.dde.BacklightHelper1.service b/misc/system-services/org.deepin.dde.BacklightHelper1.service new file mode 100644 index 000000000..d007e6b73 --- /dev/null +++ b/misc/system-services/org.deepin.dde.BacklightHelper1.service @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.deepin.dde.BacklightHelper1 +Exec=/bin/false +User=root +SystemdService=deepin-helper-backlight.service diff --git a/misc/system-services/org.deepin.dde.Bluetooth1.service b/misc/system-services/org.deepin.dde.Bluetooth1.service new file mode 100644 index 000000000..5e5ddef25 --- /dev/null +++ b/misc/system-services/org.deepin.dde.Bluetooth1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Bluetooth1 +Exec=/bin/false +SystemdService=deepin-accounts1-daemon.service \ No newline at end of file diff --git a/misc/system-services/org.deepin.dde.Daemon1.service b/misc/system-services/org.deepin.dde.Daemon1.service new file mode 100644 index 000000000..6c0b6e986 --- /dev/null +++ b/misc/system-services/org.deepin.dde.Daemon1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Daemon1 +Exec=/bin/false +SystemdService=deepin-accounts1-daemon.service diff --git a/misc/system-services/org.deepin.dde.Display1.service b/misc/system-services/org.deepin.dde.Display1.service new file mode 100644 index 000000000..1e97450df --- /dev/null +++ b/misc/system-services/org.deepin.dde.Display1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Display1 +Exec=/bin/false +SystemdService=deepin-accounts1-daemon.service \ No newline at end of file diff --git a/misc/system-services/org.deepin.dde.Fprintd1.service b/misc/system-services/org.deepin.dde.Fprintd1.service new file mode 100644 index 000000000..f5b164f05 --- /dev/null +++ b/misc/system-services/org.deepin.dde.Fprintd1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Fprintd1 +Exec=/bin/false +SystemdService=deepin-accounts1-daemon.service diff --git a/misc/system-services/org.deepin.dde.Gesture1.service b/misc/system-services/org.deepin.dde.Gesture1.service new file mode 100644 index 000000000..a5157d360 --- /dev/null +++ b/misc/system-services/org.deepin.dde.Gesture1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Gesture1 +Exec=/bin/false +SystemdService=deepin-accounts1-daemon.service diff --git a/misc/system-services/org.deepin.dde.Greeter1.service b/misc/system-services/org.deepin.dde.Greeter1.service new file mode 100644 index 000000000..238358c63 --- /dev/null +++ b/misc/system-services/org.deepin.dde.Greeter1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Greeter1 +Exec=/bin/false +SystemdService=deepin-greeter-setter.service diff --git a/misc/system-services/org.deepin.dde.Grub2.service b/misc/system-services/org.deepin.dde.Grub2.service new file mode 100644 index 000000000..5191c653d --- /dev/null +++ b/misc/system-services/org.deepin.dde.Grub2.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Grub2 +Exec=/bin/false +SystemdService=deepin-grub2.service diff --git a/misc/system-services/org.deepin.dde.ImageEffect1.service b/misc/system-services/org.deepin.dde.ImageEffect1.service new file mode 100644 index 000000000..638f7f436 --- /dev/null +++ b/misc/system-services/org.deepin.dde.ImageEffect1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.ImageEffect1 +Exec=/bin/false +SystemdService=deepin-accounts1-daemon.service diff --git a/misc/system-services/org.deepin.dde.LockService1.service b/misc/system-services/org.deepin.dde.LockService1.service new file mode 100644 index 000000000..321b336eb --- /dev/null +++ b/misc/system-services/org.deepin.dde.LockService1.service @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.deepin.dde.LockService1 +Exec=/bin/false +User=deepin-daemon +SystemdService=deepin-user-lock.service diff --git a/misc/system-services/org.deepin.dde.Network1.service b/misc/system-services/org.deepin.dde.Network1.service new file mode 100644 index 000000000..4a9111a6d --- /dev/null +++ b/misc/system-services/org.deepin.dde.Network1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Network1 +Exec=/bin/false +SystemdService=deepin-accounts1-daemon.service diff --git a/misc/system-services/org.deepin.dde.Power1.service b/misc/system-services/org.deepin.dde.Power1.service new file mode 100644 index 000000000..d01c22e6a --- /dev/null +++ b/misc/system-services/org.deepin.dde.Power1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Power1 +Exec=/bin/false +SystemdService=deepin-accounts1-daemon.service diff --git a/misc/system-services/org.deepin.dde.SwapSchedHelper1.service b/misc/system-services/org.deepin.dde.SwapSchedHelper1.service new file mode 100644 index 000000000..779110c71 --- /dev/null +++ b/misc/system-services/org.deepin.dde.SwapSchedHelper1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.SwapSchedHelper1 +Exec=/bin/false +SystemdService=deepin-accounts1-daemon.service diff --git a/misc/system-services/org.deepin.dde.Timedate1.service b/misc/system-services/org.deepin.dde.Timedate1.service new file mode 100644 index 000000000..16c7fc1a0 --- /dev/null +++ b/misc/system-services/org.deepin.dde.Timedate1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Timedate1 +Exec=/bin/false +SystemdService=deepin-accounts1-daemon.service diff --git a/misc/system-services/org.deepin.dde.Uadp1.service b/misc/system-services/org.deepin.dde.Uadp1.service new file mode 100644 index 000000000..384fe950c --- /dev/null +++ b/misc/system-services/org.deepin.dde.Uadp1.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.deepin.dde.Uadp1 +Exec=/bin/false +SystemdService=deepin-accounts1-daemon.service \ No newline at end of file diff --git a/misc/systemd/services/deepin-accounts-daemon.service b/misc/systemd/services/deepin-accounts-daemon.service deleted file mode 100644 index c2d33a554..000000000 --- a/misc/systemd/services/deepin-accounts-daemon.service +++ /dev/null @@ -1,24 +0,0 @@ -[Unit] -Description=Accounts Service - -# In order to avoid races with identity-providing services like SSSD or -# winbind, we need to ensure that Accounts Service starts after -# nss-user-lookup.target -After=nss-user-lookup.target lightdm.service -Wants=nss-user-lookup.target fprintd.service - -[Service] -Type=dbus -BusName=com.deepin.daemon.Accounts -ExecStart=/usr/lib/deepin-daemon/dde-system-daemon -StandardOutput=syslog -Environment=GVFS_DISABLE_FUSE=1 -Environment=GIO_USE_VFS=local -Environment=GVFS_REMOTE_VOLUME_MONITOR_IGNORE=1 - -[Install] -# We pull this in by graphical.target instead of waiting for the bus -# activation, to speed things up a little: gdm uses this anyway so it is nice -# if it is already around when gdm wants to use it and doesn't have to wait for -# it. -WantedBy=graphical.target diff --git a/misc/systemd/services/system/deepin-accounts1-daemon.service b/misc/systemd/services/system/deepin-accounts1-daemon.service new file mode 100644 index 000000000..b82fbcdc5 --- /dev/null +++ b/misc/systemd/services/system/deepin-accounts1-daemon.service @@ -0,0 +1,27 @@ +[Unit] +Description=Accounts Service + +# In order to avoid races with identity-providing services like SSSD or +# winbind, we need to ensure that Accounts Service starts after +# nss-user-lookup.target +After=nss-user-lookup.target lightdm.service +Wants=nss-user-lookup.target fprintd.service + +[Service] +Type=dbus +BusName=org.deepin.dde.Accounts1 +ExecStart=/usr/lib/deepin-daemon/dde-system-daemon +StandardOutput=null +StandardError=journal +Environment=GVFS_DISABLE_FUSE=1 +Environment=GIO_USE_VFS=local +Environment=GVFS_REMOTE_VOLUME_MONITOR_IGNORE=1 +CapabilityBoundingSet=~CAP_AUDIT_CONTROL +NoNewPrivileges=true + +[Install] +# We pull this in by graphical.target instead of waiting for the bus +# activation, to speed things up a little: gdm uses this anyway so it is nice +# if it is already around when gdm wants to use it and doesn't have to wait for +# it. +WantedBy=graphical.target diff --git a/misc/systemd/services/system/deepin-authority.service b/misc/systemd/services/system/deepin-authority.service new file mode 100644 index 000000000..a94305014 --- /dev/null +++ b/misc/systemd/services/system/deepin-authority.service @@ -0,0 +1,36 @@ +[Unit] +Description=Authority + +[Service] +Type=dbus +User=deepin-daemon +BusName=org.deepin.dde.Authority1 +ExecStart=/usr/lib/deepin-daemon/dde-authority +StandardOutput=null +StandardError=journal + +ProtectSystem=strict +# pam 校验密码需要访问 +#InaccessiblePaths=/etc/shadow +InaccessiblePaths=-/etc/NetworkManager/system-connections +# pam认证需要该配置 +#InaccessiblePaths=-/etc/pam.d +InaccessiblePaths=-/usr/share/uadp/ + +NoNewPrivileges=yes +ProtectHome=yes +ProtectKernelTunables=yes +ProtectKernelModules=yes +ProtectControlGroups=yes +PrivateMounts=yes +PrivateTmp=yes +PrivateDevices=yes +PrivateNetwork=yes +# 需要读取/proc的exe字段数据 +#PrivateUsers=yes +RestrictNamespaces=yes +LockPersonality=yes +RestrictRealtime=yes +RemoveIPC=yes +# 和golang -pie参数冲突,导致进程无法启动 +#MemoryDenyWriteExecute=yes diff --git a/misc/systemd/services/system/deepin-greeter-setter.service b/misc/systemd/services/system/deepin-greeter-setter.service new file mode 100644 index 000000000..e5cd22545 --- /dev/null +++ b/misc/systemd/services/system/deepin-greeter-setter.service @@ -0,0 +1,36 @@ +[Unit] +Description=deepin greeter setter service + +[Service] +Type=dbus +User=root +BusName=org.deepin.dde.Greeter1 +ExecStart=/usr/lib/deepin-daemon/dde-greeter-setter +StandardOutput=null +StandardError=journal + +ProtectSystem=strict +InaccessiblePaths=-/etc/shadow +InaccessiblePaths=-/etc/NetworkManager/system-connections +InaccessiblePaths=-/etc/pam.d +InaccessiblePaths=-/usr/share/uadp/ +# /etc/lightdm/deepin/qt-theme.ini文件为dde-session-shell安装 +ReadWritePaths=-/etc/lightdm/ + +NoNewPrivileges=yes +ProtectHome=yes +ProtectKernelTunables=yes +ProtectKernelModules=yes +ProtectControlGroups=yes +PrivateMounts=yes +PrivateTmp=yes +PrivateDevices=yes +PrivateNetwork=yes +# 需要读取/proc的exe字段数据 +#PrivateUsers=yes +RestrictNamespaces=yes +LockPersonality=yes +RestrictRealtime=yes +RemoveIPC=yes +# 和golang -pie参数冲突,导致进程无法启动 +#MemoryDenyWriteExecute=yes diff --git a/misc/systemd/services/system/deepin-grub2.service b/misc/systemd/services/system/deepin-grub2.service new file mode 100644 index 000000000..4aaa991ef --- /dev/null +++ b/misc/systemd/services/system/deepin-grub2.service @@ -0,0 +1,44 @@ +[Unit] +Description=deepin grub2 config service + +[Service] +Type=dbus +User=root +BusName=org.deepin.dde.Grub2 +ExecStart=/usr/lib/deepin-daemon/grub2 +StandardOutput=null +StandardError=journal + +ProtectSystem=strict +InaccessiblePaths=/etc/shadow +InaccessiblePaths=-/etc/NetworkManager/system-connections +InaccessiblePaths=-/etc/pam.d +InaccessiblePaths=-/usr/share/uadp/ +# 创建/etc/default/grub.d/11_dde.cfg +ReadWritePaths=-/etc/default/grub.d +# 创建/tmp/deepin-gfxmode-detect-ready // TODO分析该文件是否有被其他进程使用,该文件存放需要修改 +ReadWritePaths=-/tmp/ +# /var/cache/deepin/grub2.log +ReadWritePaths=-/var/cache/deepin +# /etc/grub.d/42_uos_menu_crypto +ReadWritePaths=-/etc/grub.d +ReadWritePaths=-/boot + +NoNewPrivileges=yes +ProtectHome=yes +ProtectKernelTunables=yes +ProtectKernelModules=yes +ProtectControlGroups=yes +PrivateMounts=yes +#PrivateTmp=yes +# /usr/sbin/grub-probe需要使用 +#PrivateDevices=yes +PrivateNetwork=yes +# 需要读取/proc的exe字段数据 +#PrivateUsers=yes +RestrictNamespaces=yes +LockPersonality=yes +RestrictRealtime=yes +RemoveIPC=yes +# 和golang -pie参数冲突,导致进程无法启动 +#MemoryDenyWriteExecute=yes diff --git a/misc/systemd/services/system/deepin-helper-backlight.service b/misc/systemd/services/system/deepin-helper-backlight.service new file mode 100644 index 000000000..3ebab4ebf --- /dev/null +++ b/misc/systemd/services/system/deepin-helper-backlight.service @@ -0,0 +1,37 @@ +[Unit] +Description=deepin backlight helper service + +[Service] +Type=dbus +BusName=org.deepin.dde.BacklightHelper1 +User=root +ExecStart=/usr/lib/deepin-daemon/backlight_helper +StandardOutput=null +StandardError=journal + +ProtectSystem=strict + +InaccessiblePaths=/etc/shadow +InaccessiblePaths=-/etc/NetworkManager/system-connections +InaccessiblePaths=-/etc/pam.d +InaccessiblePaths=-/usr/share/uadp/ +#ReadOnlyPaths=/lib +#ReadWritePaths=/sys/class + +NoNewPrivileges=yes +ProtectHome=yes +# 设置背光需要 +#ProtectKeirnelTunables=yes +ProtectKernelModules=yes +ProtectControlGroups=yes +PrivateMounts=yes +PrivateTmp=yes +# 背光设置需要 +#PrivateDevices=yes +PrivateNetwork=yes +PrivateUsers=yes +RestrictNamespaces=yes +LockPersonality=yes +RestrictRealtime=yes +RemoveIPC=yes +#MemoryDenyWriteExecute=yes diff --git a/misc/systemd/services/system/deepin-user-lock.service b/misc/systemd/services/system/deepin-user-lock.service new file mode 100644 index 000000000..cdca4c32b --- /dev/null +++ b/misc/systemd/services/system/deepin-user-lock.service @@ -0,0 +1,39 @@ +[Unit] +Description=deepin user lock service + +[Service] +Type=dbus +BusName=org.deepin.dde.LockService1 +ExecStart=/usr/lib/deepin-daemon/dde-lockservice +# display和lockservice都会读写/var/lib/lightdm/lightdm-deepin-greeter/state_user文件,因此无法将lockservice单独改为非root +#User=deepin-daemon +User=root +StandardOutput=journal +StandardError=journal + +ProtectSystem=strict +InaccessiblePaths=-/etc/shadow +InaccessiblePaths=-/etc/NetworkManager/system-connections +InaccessiblePaths=-/etc/pam.d +InaccessiblePaths=-/usr/share/uadp/ + +ReadWritePaths=-/var/lib/lightdm + +NoNewPrivileges=true +PrivateMounts=yes +ProtectHome=yes +ProtectKernelTunables=yes +ProtectKernelModules=yes +ProtectControlGroups=yes +PrivateMounts=yes +PrivateTmp=yes +PrivateDevices=yes +PrivateNetwork=yes +# 需要读取/proc的exe字段数据 +#PrivateUsers=yes +RestrictNamespaces=yes +LockPersonality=yes +RestrictRealtime=yes +RemoveIPC=yes +# 和golang -pie参数冲突,导致进程无法启动 +#MemoryDenyWriteExecute=yes diff --git a/misc/systemd/services/user/org.dde.session.Daemon1.service b/misc/systemd/services/user/org.dde.session.Daemon1.service new file mode 100644 index 000000000..bfc769dbe --- /dev/null +++ b/misc/systemd/services/user/org.dde.session.Daemon1.service @@ -0,0 +1,20 @@ +[Unit] +Description=dde-session-daemon service +RefuseManualStart=no +RefuseManualStop=no +CollectMode=inactive-or-failed + +Requisite=dde-session-pre.target +After=dde-session-pre.target + +Requisite=dde-session-initialized.target +PartOf=dde-session-initialized.target +Before=dde-session-initialized.target + +[Service] +Type=dbus +BusName=org.deepin.dde.XEventMonitor1 +ExecStart=/usr/lib/deepin-daemon/dde-session-daemon +Slice=app.slice +Restart=on-failure +NotifyAccess=main diff --git a/misc/systemd/system-services/deepin-accounts1-daemon.service b/misc/systemd/system-services/deepin-accounts1-daemon.service new file mode 100644 index 000000000..c3fe2b1a4 --- /dev/null +++ b/misc/systemd/system-services/deepin-accounts1-daemon.service @@ -0,0 +1,25 @@ +[Unit] +Description=Accounts1 Service + +# In order to avoid races with identity-providing services like SSSD or +# winbind, we need to ensure that Accounts Service starts after +# nss-user-lookup.target +After=nss-user-lookup.target lightdm.service +Wants=nss-user-lookup.target fprintd.service + +[Service] +Type=dbus +BusName=org.deepin.dde.Accounts1 +ExecStart=/usr/lib/deepin-daemon/dde-system-daemon +StandardOutput=null +StandardError=journal +Environment=GVFS_DISABLE_FUSE=1 +Environment=GIO_USE_VFS=local +Environment=GVFS_REMOTE_VOLUME_MONITOR_IGNORE=1 + +[Install] +# We pull this in by graphical.target instead of waiting for the bus +# activation, to speed things up a little: gdm uses this anyway so it is nice +# if it is already around when gdm wants to use it and doesn't have to wait for +# it. +WantedBy=graphical.target diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy.ts deleted file mode 100644 index c0738cbf8..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Authentication is required to add fingerprint password - - - - Add fingerprint password - Add fingerprint password - - - - Authentication is required to clear fingerprint passwords - Authentication is required to clear fingerprint passwords - - - - Clear fingerprint passwords - Clear fingerprint passwords - - - - Authentication is required to rename fingerprint password - Authentication is required to rename fingerprint password - - - - Rename fingerprint password - Rename fingerprint password - - - - Password is required to perform this action - Password is required to perform this action - - - - Manage fingerprint passwords - Manage fingerprint passwords - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ady.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ady.ts deleted file mode 100644 index ce3649775..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ady.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_af.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_af.ts deleted file mode 100644 index 665ca0158..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_af.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_af_ZA.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_af_ZA.ts deleted file mode 100644 index 013275491..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_af_ZA.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ak.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ak.ts deleted file mode 100644 index f32ed6e1f..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ak.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_am.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_am.ts deleted file mode 100644 index 2b294ae11..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_am.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_am_ET.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_am_ET.ts deleted file mode 100644 index 7002c0983..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_am_ET.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ar.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ar.ts deleted file mode 100644 index b71e2c5de..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ar.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - المصادقة ضرورية لإضافة كلمة مرور بالبصمة - - - - Add fingerprint password - إضافة كلمة مرور ببصمة الأصبع - - - - Authentication is required to clear fingerprint passwords - المصادقة ضرورية لحذف كلمات المرور بالبصمة - - - - Clear fingerprint passwords - حذف كلمات المرور بالبصمة - - - - Authentication is required to rename fingerprint password - المصادقة ضرورية لإعادة تسمية كلمة المرور بالبصمة - - - - Rename fingerprint password - إعادة تسمية كلمة المرور بالبصمة - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ar_EG.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ar_EG.ts deleted file mode 100644 index 42e34dc9e..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ar_EG.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ast.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ast.ts deleted file mode 100644 index 2605b424f..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ast.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_az.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_az.ts deleted file mode 100644 index 603f4c86d..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_az.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Barmaq izi şifrəsini əlavə etmək üçün doğrulama tələb edilir - - - - Add fingerprint password - Barmaq izi şifrəsi əlavə etmək - - - - Authentication is required to clear fingerprint passwords - Barmaq izi şifrəsini silmək üçün doğrulama tələb edilir - - - - Clear fingerprint passwords - Barmaq izi şifrəsini silmək - - - - Authentication is required to rename fingerprint password - Barmaq izi şifrəsinin adını dəyişmək üçün doğrulama tələb edilir - - - - Rename fingerprint password - Barmaq izi şifrəsinin adını dəyişmək - - - - Password is required to perform this action - Bu əməlin icra edilməsi üçün şifrə tələb olunur - - - - Manage fingerprint passwords - Barmaq izi şifrələrinin idarə edilməsi - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_bg.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_bg.ts deleted file mode 100644 index e78d823cf..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_bg.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_bn.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_bn.ts deleted file mode 100644 index 1eaf76c06..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_bn.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_bo.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_bo.ts deleted file mode 100644 index 2f4ded676..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_bo.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - མཛུབ་རིས་སྣོན་པར་ར་སྤྲོད་བྱེད་དགོས། - - - - Add fingerprint password - མཛུབ་རིས་གསང་ཨང་སྣོན་པ། - - - - Authentication is required to clear fingerprint passwords - མཛུབ་རིས་མེད་པ་བཟོ་ཚེ་ར་སྤྲོད་བྱེད་དགོས། - - - - Clear fingerprint passwords - མཛུབ་རིས་གསང་ཨང་མེད་པར་བཟོ་བ། - - - - Authentication is required to rename fingerprint password - མཛུབ་རིས་བསྐྱར་དུ་འདོགས་ཚེ་ར་སྤྲོད་བྱེད་དགོས། - - - - Rename fingerprint password - མཛུབ་རིས་མིང་བསྐྱར་དུ་འདོགས་པ། - - - - Password is required to perform this action - གསང་ཨང་བཅུག་རྗེས་བཀོལ་སྤྱོད་འདི་ལག་བསྟར་བྱེད་པ། - - - - Manage fingerprint passwords - མཛུབ་རིས་གསང་ཨང་དོ་དམ། - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_bqi.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_bqi.ts deleted file mode 100644 index 06b281768..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_bqi.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_br.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_br.ts deleted file mode 100644 index ec65d571f..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_br.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ca.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ca.ts deleted file mode 100644 index 8bcc7aad5..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ca.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Cal autenticació per afegir una contrasenya d'empremta. - - - - Add fingerprint password - Afegiu una contrasenya d'empremta - - - - Authentication is required to clear fingerprint passwords - Cal autenticació per netejar contrasenyes d'empremta. - - - - Clear fingerprint passwords - Neteja les contrasenyes d'empremta - - - - Authentication is required to rename fingerprint password - Cal autenticació per canviar de nom una contrasenya d'empremta. - - - - Rename fingerprint password - Canvia de nom la contrasenya d'empremta - - - - Password is required to perform this action - Cal la contrasenya per realitzar aquesta acció - - - - Manage fingerprint passwords - Gestiona les contrasenyes d'empremta - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_cgg.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_cgg.ts deleted file mode 100644 index 11ac3fcfe..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_cgg.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_cs.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_cs.ts deleted file mode 100644 index 641fcc79b..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_cs.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Pro přidání hesla zastupovaného otiskem prstu je požadováno ověření se - - - - Add fingerprint password - Přidat heslo zastupované otiskem prstu - - - - Authentication is required to clear fingerprint passwords - Pro smazání hesel zastupovaných otiskem prstu je požadováno ověření se - - - - Clear fingerprint passwords - Smazat hesla zastupovaná otiskem prstu - - - - Authentication is required to rename fingerprint password - Pro přejmenování hesla, zastupovaného otiskem prstu, je požadováno ověření se - - - - Rename fingerprint password - Přejmenovat heslo zastupované otiskem prstu - - - - Password is required to perform this action - Pro provedení této akce je zapotřebí zadat heslo - - - - Manage fingerprint passwords - Spravovat hesla zastupovaná otiskem prstu - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_da.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_da.ts deleted file mode 100644 index cd364cbf5..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_da.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Der kræves autentifikation for at tilføje fingeraftryksadgangskode - - - - Add fingerprint password - Tilføj fingeraftryksadgangskode - - - - Authentication is required to clear fingerprint passwords - Der kræves autentifikation for at rydde fingeraftryksadgangskoder - - - - Clear fingerprint passwords - Ryd fingeraftryksadgangskoder - - - - Authentication is required to rename fingerprint password - Der kræves autentifikation for at omdøbe fingeraftryksadgangskode - - - - Rename fingerprint password - Omdøb fingeraftryksadgangskode - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_de.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_de.ts deleted file mode 100644 index 420791545..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_de.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Zum Hinzufügen des Fingerabdruckpassworts ist eine Authentifizierung erforderlich - - - - Add fingerprint password - Fingerabdruckpasswort hinzufügen - - - - Authentication is required to clear fingerprint passwords - Zum Löschen von Fingerabdruckpasswörtern ist eine Authentifizierung erforderlich - - - - Clear fingerprint passwords - Fingerabdruckpasswörter löschen - - - - Authentication is required to rename fingerprint password - Zum Umbenennen des Fingerabdruckpassworts ist eine Authentifizierung erforderlich - - - - Rename fingerprint password - Fingerabdruckpasswort umbenennen - - - - Password is required to perform this action - Zur Durchführung dieser Aktion ist ein Passwort erforderlich - - - - Manage fingerprint passwords - Fingerabdruckpasswörter verwalten - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_de_CH.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_de_CH.ts deleted file mode 100644 index ab08f08da..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_de_CH.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_de_DE.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_de_DE.ts deleted file mode 100644 index 1bb90c194..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_de_DE.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Sie müssen sich authentifizieren, um das Anmelden per Fingerabdruck hinzuzufügen - - - - Add fingerprint password - Fingerabdruck-Daten hinzufügen - - - - Authentication is required to clear fingerprint passwords - Sie müssen sich authentifizieren, um die Fingerabdruck-Daten zu löschen - - - - Clear fingerprint passwords - Fingerabdruck-Daten löschen - - - - Authentication is required to rename fingerprint password - Sie müssen sich authentifizieren, um Fingerabdruck-Daten neu zu benennen - - - - Rename fingerprint password - Fingerabdruck-Daten neu benennen - - - - Password is required to perform this action - Sie müssen das Passwort eingeben, um diese Aktion auszuführen - - - - Manage fingerprint passwords - Fingerabdruck-Daten verwalten - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_el.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_el.ts deleted file mode 100644 index dd623f477..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_el.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Απαιτείται πιστοποίηση για προσθήκη κωδικού αποτυπώματος - - - - Add fingerprint password - Προσθήκη κωδικού αποτυπώματος - - - - Authentication is required to clear fingerprint passwords - Απαιτείται πιστοποίηση για διαγραφή κωδικών αποτυπώματος - - - - Clear fingerprint passwords - Διαγραφή κωδικών αποτυπωμάτων - - - - Authentication is required to rename fingerprint password - Απαιτείται πιστοποίηση για μετονομασία κωδικού αποτυπώματος - - - - Rename fingerprint password - Μετονομασία κωδικού αποτυπώματος - - - - Password is required to perform this action - Απαιτείται κωδικός για εκτέλεση αυτής της ενέργειας - - - - Manage fingerprint passwords - Διαχείρηση κωδικών αποτυπωμάτων - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_el_GR.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_el_GR.ts deleted file mode 100644 index ab9b99743..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_el_GR.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_en_AU.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_en_AU.ts deleted file mode 100644 index d8d54a4b2..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_en_AU.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Authentication is required to add fingerprint password - - - - Add fingerprint password - Add fingerprint password - - - - Authentication is required to clear fingerprint passwords - Authentication is required to clear fingerprint passwords - - - - Clear fingerprint passwords - Clear fingerprint passwords - - - - Authentication is required to rename fingerprint password - Authentication is required to rename fingerprint password - - - - Rename fingerprint password - Rename fingerprint password - - - - Password is required to perform this action - Password is required to perform this action - - - - Manage fingerprint passwords - Manage fingerprint passwords - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_en_GB.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_en_GB.ts deleted file mode 100644 index ea703f575..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_en_GB.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_en_NO.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_en_NO.ts deleted file mode 100644 index c70fb702d..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_en_NO.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_en_US.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_en_US.ts deleted file mode 100644 index b0595cf62..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_en_US.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Authentication is required to add fingerprint password - - - - Add fingerprint password - Add fingerprint password - - - - Authentication is required to clear fingerprint passwords - Authentication is required to clear fingerprint passwords - - - - Clear fingerprint passwords - Clear fingerprint passwords - - - - Authentication is required to rename fingerprint password - Authentication is required to rename fingerprint password - - - - Rename fingerprint password - Rename fingerprint password - - - - Password is required to perform this action - Password is required to perform this action - - - - Manage fingerprint passwords - Manage fingerprint passwords - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_eo.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_eo.ts deleted file mode 100644 index 7b3736f62..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_eo.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_es.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_es.ts deleted file mode 100644 index 557405d51..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_es.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Se requiere autenticación para añadir contraseña de huella dactilar - - - - Add fingerprint password - Añadir contraseña de huella dactilar - - - - Authentication is required to clear fingerprint passwords - Se requiere autenticación para borrar contraseñas de huellas dactilares. - - - - Clear fingerprint passwords - Borrar contraseñas de huellas dactilares - - - - Authentication is required to rename fingerprint password - Se requiere autenticación para renombrar la contraseña huella dactilar - - - - Rename fingerprint password - Renombrar contraseña de huella dactilar - - - - Password is required to perform this action - Se requiere contraseña para realizar esta acción - - - - Manage fingerprint passwords - Administrar contraseñas de huellas digitales - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_es_MX.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_es_MX.ts deleted file mode 100644 index 8933253d9..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_es_MX.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_et.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_et.ts deleted file mode 100644 index da46fbb62..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_et.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_eu.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_eu.ts deleted file mode 100644 index 69b09357e..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_eu.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_fa.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_fa.ts deleted file mode 100644 index bf53a1b7c..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_fa.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - برای اضافه کردن رمزعبور اثر انگشت ، احراز هویت لازم است - - - - Add fingerprint password - اضافه کردن رمزعبور اثر انگشت - - - - Authentication is required to clear fingerprint passwords - برای پاک کردن رمزهای عبور اثر انگشت ، احراز هویت لازم است - - - - Clear fingerprint passwords - رمزهای عبور اثر انگشت را پاک کن - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_fi.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_fi.ts deleted file mode 100644 index 50d9ce184..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_fi.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Sormenjälkitunnuksen lisääminen edellyttää todennusta - - - - Add fingerprint password - Lisää sormenjälki salasanaksi - - - - Authentication is required to clear fingerprint passwords - Sormenjälkien tyhjentäminen edellyttää todennusta - - - - Clear fingerprint passwords - Tyhjennä sormenjäljet - - - - Authentication is required to rename fingerprint password - Nimeä sormenjälki uudelleen, tämä vaatii tunnistautumisen - - - - Rename fingerprint password - Nimeä sormenjäljen salasana uudelleen - - - - Password is required to perform this action - Tämän suorittamiseen tarvitaan salasana - - - - Manage fingerprint passwords - Hallitse sormenjälkien tunnuksia - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_fil.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_fil.ts deleted file mode 100644 index aed2473d3..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_fil.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_fr.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_fr.ts deleted file mode 100644 index dac5a03db..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_fr.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Une authentification est requise pour ajouter une empreinte digitale comme mot de passe - - - - Add fingerprint password - Ajouter une empreinte digitale comme mot de passe - - - - Authentication is required to clear fingerprint passwords - Une authentification est requise pour effacer les empreintes digitales enregistrées - - - - Clear fingerprint passwords - Effacer les empreintes digitales enregistrées - - - - Authentication is required to rename fingerprint password - Une authentification est requise pour changer le mot de passe d'une empreinte digitale - - - - Rename fingerprint password - Changer le mot de passe d'une empreinte digitale - - - - Password is required to perform this action - Mot de passe requis pour effectuer cette action - - - - Manage fingerprint passwords - Gérer les empreintes digitales - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_gl.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_gl.ts deleted file mode 100644 index 913f05304..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_gl.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_gl_ES.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_gl_ES.ts deleted file mode 100644 index 376c5308e..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_gl_ES.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Requírese autenticación para engadir un contrasinal para a pegada dixital - - - - Add fingerprint password - Engadir un contrasinal para a pegada dixital - - - - Authentication is required to clear fingerprint passwords - Requírese autenticación para eliminar os contrasinais das pegadas dixitais - - - - Clear fingerprint passwords - Eliminar os contrasinais das pegadas dixitais - - - - Authentication is required to rename fingerprint password - Requírese autenticación para mudar o contrasinal da pegada dixital - - - - Rename fingerprint password - Mudar o contrasinal da pegada dixital - - - - Password is required to perform this action - Requírese un contrasinal para realizar esta acción - - - - Manage fingerprint passwords - Xestionar contrasinais de pegadas dixitais - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_he.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_he.ts deleted file mode 100644 index fc0054359..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_he.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_hi_IN.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_hi_IN.ts deleted file mode 100644 index d4b1c3bfe..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_hi_IN.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_hr.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_hr.ts deleted file mode 100644 index 98e797667..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_hr.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Potrebna je ovjera za dodavanje lozinke otiska prsta - - - - Add fingerprint password - Dodaj lozinku otiska prsta - - - - Authentication is required to clear fingerprint passwords - Potrebna je ovjera za čišćenje lozinki otiska prsta - - - - Clear fingerprint passwords - Očisti lozinke otiska prsta - - - - Authentication is required to rename fingerprint password - Potrebna je ovjera za preimenovanje lozinke otiska prsta - - - - Rename fingerprint password - Preimenuj lozinku otiska prsta - - - - Password is required to perform this action - Potrebna je lozinka da bi ste izveli ovu radnju - - - - Manage fingerprint passwords - Upravljajte lozinkama otiska prsta - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_hu.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_hu.ts deleted file mode 100644 index 6cfb510f6..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_hu.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Hitelesítés szükséges az ujjlenyomat azonosítók hozzáadásához - - - - Add fingerprint password - Ujjlenyomat azonosító hozzáadása - - - - Authentication is required to clear fingerprint passwords - Hitelesítés szükséges az ujjlenyomat azonosítók törléséhez - - - - Clear fingerprint passwords - Ujjlenyomatok törlése - - - - Authentication is required to rename fingerprint password - Hitelesítés szükséges az ujjlenyomat azonosító átnevezéséhez - - - - Rename fingerprint password - Ujjlenyomat azonosító átnevezése - - - - Password is required to perform this action - A művelet végrehajtásához jelszó szükséges - - - - Manage fingerprint passwords - Ujjlenyomat azonosítók kezelése - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_hy.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_hy.ts deleted file mode 100644 index 6e77b3b22..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_hy.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_id.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_id.ts deleted file mode 100644 index de41779f3..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_id.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Otentikasi diperlukan untuk menambahkan password sidik jari - - - - Add fingerprint password - Tambah password sidik jari - - - - Authentication is required to clear fingerprint passwords - Otentikasi diperlukan untuk membersihkan password sidik jari - - - - Clear fingerprint passwords - Bersihkan password sidik jari - - - - Authentication is required to rename fingerprint password - Otentikasi diperlukan untuk mengganti nama password sidik jari - - - - Rename fingerprint password - Ubah nama password sidik jari - - - - Password is required to perform this action - Kata sandi diperlukan untuk melakukan tindakan ini - - - - Manage fingerprint passwords - Kelola password sidik jari - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_id_ID.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_id_ID.ts deleted file mode 100644 index f2525da28..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_id_ID.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_it.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_it.ts deleted file mode 100644 index de863d62d..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_it.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Autenticazione richiesta per aggiungere l'impronta digitale come password - - - - Add fingerprint password - Aggiungi impronta digitale come password - - - - Authentication is required to clear fingerprint passwords - Autenticazione richiesta per eliminare l'impronta digitale come password - - - - Clear fingerprint passwords - Cancella impronte digitali utilizzare come password - - - - Authentication is required to rename fingerprint password - Autenticazione richiesta per rinominare l'impronta digitale - - - - Rename fingerprint password - Rinomina l'impronta digitale - - - - Password is required to perform this action - Password richiesta per questa operazione - - - - Manage fingerprint passwords - Gestisci le impronte digitali - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ja.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ja.ts deleted file mode 100644 index c849a4a04..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ja.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - 指紋パスワードを追加するには認証が必要です - - - - Add fingerprint password - 指紋パスワードを追加 - - - - Authentication is required to clear fingerprint passwords - 指紋パスワードを削除するには認証が必要です - - - - Clear fingerprint passwords - 指紋パスワードを削除 - - - - Authentication is required to rename fingerprint password - 指紋パスワードの名前を変更するには認証が必要です - - - - Rename fingerprint password - 指紋パスワードの名前を変更 - - - - Password is required to perform this action - この操作にはパスワードが必要です - - - - Manage fingerprint passwords - 指紋パスワードを管理 - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ka.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ka.ts deleted file mode 100644 index 4c9ec0982..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ka.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_kab.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_kab.ts deleted file mode 100644 index 841436618..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_kab.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Asesteb yettusra i tmerna n wawal uffir n udsil umḍin - - - - Add fingerprint password - Rnu awal uffir n udsil umḍin - - - - Authentication is required to clear fingerprint passwords - Asesteb yettusra i usfaḍ n wawalen uffiren n udsil umḍin - - - - Clear fingerprint passwords - Sfeḍ wawalen uffiren n udsil umḍin - - - - Authentication is required to rename fingerprint password - Asesteb yettusra i ubeddel n yisem - - - - Rename fingerprint password - Beddl isem i wawal uffir n udsil umḍin - - - - Password is required to perform this action - Yettusra wawal uffir i uselken n tigawt-a - - - - Manage fingerprint passwords - Sefrek awalen uffiren n udsil umḍin - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_kk.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_kk.ts deleted file mode 100644 index d2ce512de..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_kk.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_km_KH.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_km_KH.ts deleted file mode 100644 index d6f2c0425..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_km_KH.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_kn_IN.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_kn_IN.ts deleted file mode 100644 index 7546c5c38..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_kn_IN.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ko.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ko.ts deleted file mode 100644 index ec7f61d50..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ko.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - 지문 암호를 추가하려면 인증이 필요합니다 - - - - Add fingerprint password - 지문 암호 추가 - - - - Authentication is required to clear fingerprint passwords - 지문 암호를 지우려면 인증이 필요합니다 - - - - Clear fingerprint passwords - 지문 암호 지우기 - - - - Authentication is required to rename fingerprint password - 지문 암호의 이름을 변경하려면 인증이 필요함 - - - - Rename fingerprint password - 지문 암호 이름 변경 - - - - Password is required to perform this action - 이 작업을 수행하려면 암호가 필요함 - - - - Manage fingerprint passwords - 지문 암호 관리 - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ku.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ku.ts deleted file mode 100644 index 76eedb64e..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ku.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ku_IQ.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ku_IQ.ts deleted file mode 100644 index 1c687b0a2..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ku_IQ.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ky.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ky.ts deleted file mode 100644 index 54cf19cf6..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ky.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ky@Arab.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ky@Arab.ts deleted file mode 100644 index 7d72458e9..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ky@Arab.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_la.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_la.ts deleted file mode 100644 index 390e9c88c..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_la.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_lo.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_lo.ts deleted file mode 100644 index 796318289..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_lo.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_lt.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_lt.ts deleted file mode 100644 index ccbcca9d9..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_lt.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Norint pridėti piršto atspaudo slaptažodį, reikalingas tapatybės nustatymas - - - - Add fingerprint password - Pridėti piršto atspaudo slaptažodį - - - - Authentication is required to clear fingerprint passwords - Norint išvalyti piršto atspaudo slaptažodžius, reikalingas tapatybės nustatymas - - - - Clear fingerprint passwords - Išvalyti piršto atspaudo slaptažodžius - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_lv.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_lv.ts deleted file mode 100644 index 97748ced0..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_lv.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ml.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ml.ts deleted file mode 100644 index d63bb8a75..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ml.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_mn.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_mn.ts deleted file mode 100644 index 9b1bddd38..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_mn.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_mr.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_mr.ts deleted file mode 100644 index 34bedfc7e..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_mr.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ms.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ms.ts deleted file mode 100644 index 625cec59f..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ms.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Pengesahihan diperlukan untuk menambah kata laluan cap jari - - - - Add fingerprint password - Tambah kata laluan cap jari - - - - Authentication is required to clear fingerprint passwords - Pengesahihan diperlukan untuk mengosongkan kata laluan cap jari - - - - Clear fingerprint passwords - Kosongkan kata laluan cap jari - - - - Authentication is required to rename fingerprint password - Pengesahihan diperlukan untuk menamakan semula kata laluan cap jari - - - - Rename fingerprint password - Namakan semula kata laluan cap jari - - - - Password is required to perform this action - Kata laluan diperlukan untuk membuat tindakan ini - - - - Manage fingerprint passwords - Urus kata laluan cap jari - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_nb.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_nb.ts deleted file mode 100644 index b78dd034b..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_nb.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ne.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ne.ts deleted file mode 100644 index ebb914065..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ne.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_nl.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_nl.ts deleted file mode 100644 index 706a5a59c..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_nl.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Authenticatie vereist om vingerafdrukken toe te voegen - - - - Add fingerprint password - Wachtwoord voor vingerafdrukken toevoegen - - - - Authentication is required to clear fingerprint passwords - Authenticatie vereist om vingerafdrukken te wissen - - - - Clear fingerprint passwords - Vingerafdrukken wissen - - - - Authentication is required to rename fingerprint password - Authenticatie is vereist om vingerafdruknamen te wijzigen - - - - Rename fingerprint password - Vingerafdruknamen wijzigen - - - - Password is required to perform this action - Voer je wachtwoord in om deze actie uit te voeren - - - - Manage fingerprint passwords - Vingerafdrukwachtwoorden beheren - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_pa.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_pa.ts deleted file mode 100644 index 5131c6702..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_pa.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_pam.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_pam.ts deleted file mode 100644 index cb2d6365b..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_pam.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_pl.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_pl.ts deleted file mode 100644 index d40ab33db..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_pl.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Wymagane jest uwierzytelnienie do dodania hasła odcisku palca - - - - Add fingerprint password - Dodaj hasło odcisku palca - - - - Authentication is required to clear fingerprint passwords - Wymagane jest uwierzytelnienie do wyczyszczenia haseł odcisków palców - - - - Clear fingerprint passwords - Wyczyść hasła odcisków palców - - - - Authentication is required to rename fingerprint password - Wymagane jest uwierzytelnienie do zmiany nazwy hasła odcisku palca - - - - Rename fingerprint password - Zmień nazwę hasła odcisku palca - - - - Password is required to perform this action - Do wykonania tej czynności wymagane jest hasło - - - - Manage fingerprint passwords - Zarządzaj hasłami odcisków palców - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ps.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ps.ts deleted file mode 100644 index d8ec15bca..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ps.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_pt.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_pt.ts deleted file mode 100644 index 1a0f144f1..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_pt.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - É necessária a autenticação para adicionar palavra-passe de impressão digital - - - - Add fingerprint password - Adicionar palavra-passe de impressão digital - - - - Authentication is required to clear fingerprint passwords - É necessária a autenticação para limpar palavras-passe de impressões digitais - - - - Clear fingerprint passwords - Limpar palavras-passe de impressão digital - - - - Authentication is required to rename fingerprint password - É necessária a autenticação para renomear a palavra-passe de impressão digital - - - - Rename fingerprint password - Renomear a palavra-passe de impressão digital - - - - Password is required to perform this action - Para realizar esta ação é necessária uma palavra-passe - - - - Manage fingerprint passwords - Gerir as palavras-passe das impressões digitais - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_pt_BR.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_pt_BR.ts deleted file mode 100644 index 378a230d8..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_pt_BR.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - A autenticação é necessária para adicionar a impressão digital - - - - Add fingerprint password - Adicionar impressão digital - - - - Authentication is required to clear fingerprint passwords - A autenticação é necessária para remover as impressões digitais - - - - Clear fingerprint passwords - Remover as impressões digitais - - - - Authentication is required to rename fingerprint password - A autenticação é necessária para renomear a impressão digital - - - - Rename fingerprint password - Renomear impressão digital - - - - Password is required to perform this action - A senha é necessária para executar esta ação - - - - Manage fingerprint passwords - Gerenciar senhas por impressão digital - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ro.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ro.ts deleted file mode 100644 index 36a2bbad4..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ro.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Autentificare necesară pentru adăugare parolă amprentă - - - - Add fingerprint password - Adaugă parolă amprentă - - - - Authentication is required to clear fingerprint passwords - Autentificare necesară pentru ştergere parolă amprentă - - - - Clear fingerprint passwords - Ștergere parolă amprentă - - - - Authentication is required to rename fingerprint password - Autentificare necesară pentru redenumire parolă amprentă - - - - Rename fingerprint password - Redenumește parolă cu amprentă - - - - Password is required to perform this action - Parolă necesară să efectuați această acțiune - - - - Manage fingerprint passwords - Administrează parole cu amprentă - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ru.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ru.ts deleted file mode 100644 index 6f9d5f04e..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ru.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Требуется аутентификация для добавления пароля по отпечатку пальца - - - - Add fingerprint password - Добавить пароль по отпечатку пальца - - - - Authentication is required to clear fingerprint passwords - Требуется аутентификация для очистки паролей по отпечатку пальца - - - - Clear fingerprint passwords - Очистка паролей по отпечатку пальца - - - - Authentication is required to rename fingerprint password - Требуется аутентификация для переименования пароля отпечатка пальца - - - - Rename fingerprint password - Переименовать пароль отпечатка пальца - - - - Password is required to perform this action - Необходим пароль для выполнения этого действия - - - - Manage fingerprint passwords - Управление паролями отпечатков пальцев - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ru_UA.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ru_UA.ts deleted file mode 100644 index fa2f30bb2..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ru_UA.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sc.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sc.ts deleted file mode 100644 index b67fdf774..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sc.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_si.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_si.ts deleted file mode 100644 index 2e93c5960..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_si.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - ඇඟිලි සලකුණු මුරපදය එක් කිරීමට සත්‍යාපනය අවශ්‍ය වේ - - - - Add fingerprint password - ඇඟිලි සලකුණු මුරපදය එක් කරන්න - - - - Authentication is required to clear fingerprint passwords - ඇඟිලි සලකුණු මුරපදය ඉවත් කිරීමට සත්‍යාපනය අවශ්‍ය වේ - - - - Clear fingerprint passwords - ඇඟිලි සලකුණු මුරපදය ඉවත් කරන්න - - - - Authentication is required to rename fingerprint password - ඇඟිලි සලකුණු මුරපදය නැවත නම් කිරීම සඳහා සත්‍යාපනය අවශ්‍ය වේ - - - - Rename fingerprint password - ඇඟිලි සලකුණු මුරපදය නැවත නම් කරන්න - - - - Password is required to perform this action - මෙම ක්‍රියාව සිදු කිරීම සඳහා මුරපදය අවශ්‍ය වේ - - - - Manage fingerprint passwords - ඇඟිලි සලකුණු මුරපද කළමනාකරණය කරන්න - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sk.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sk.ts deleted file mode 100644 index 2f52b7a57..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sk.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Na pridanie hesla pomocou odtlačku prsta je potrebné overenie - - - - Add fingerprint password - Pridať heslo pomocou odtlačku prsta - - - - Authentication is required to clear fingerprint passwords - Na vymazanie hesiel odtlačkov prstov je potrebné overenie - - - - Clear fingerprint passwords - Vymazať heslá odtlačkov prstov - - - - Authentication is required to rename fingerprint password - Na premenovanie hesla odtlačkov prstov sa vyžaduje overenie - - - - Rename fingerprint password - Premenovať heslo odtlačku prstov - - - - Password is required to perform this action - Na vykonanie tejto akcie je potrebné heslo - - - - Manage fingerprint passwords - Spravovať heslá odtlačkov prstov - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sl.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sl.ts deleted file mode 100644 index f3778a631..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sl.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Dodajanje prstnega odtisa zahteva overitev - - - - Add fingerprint password - Dodaj prstni odtis - - - - Authentication is required to clear fingerprint passwords - Odstranjevanje prstnega odtsia zahteva overitev - - - - Clear fingerprint passwords - Odstrani prstni odtis - - - - Authentication is required to rename fingerprint password - Preimenovanje prstnega odtisa zahteva overitev - - - - Rename fingerprint password - Preimenuj prstni odtis - - - - Password is required to perform this action - To dejanje zahteva overitev - - - - Manage fingerprint passwords - Upravljanje prstnih odtisov - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sq.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sq.ts deleted file mode 100644 index 3ead1a692..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sq.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Që të shtoni fjalëkalim shenjash gishti, lypset mirëfilltësim - - - - Add fingerprint password - Shtoni fjalëkalim shenjash gishti - - - - Authentication is required to clear fingerprint passwords - Që të spastrohen fjalëkalime shenjash gishti, lypset mirëfilltësim - - - - Clear fingerprint passwords - Spastro fjalëkalime shenjash gishti - - - - Authentication is required to rename fingerprint password - Që të riemërtoni fjalëkalim shenjash gishti, lypset mirëfilltësim - - - - Rename fingerprint password - Riemërtoni fjalëkalim shenjash gishti - - - - Password is required to perform this action - Që të kryeni këtë veprim, lypset fjalëkalim - - - - Manage fingerprint passwords - Administroni fjalëkalime shenjash gishtash - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sr.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sr.ts deleted file mode 100644 index f085638bc..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sr.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Идентификација је неопходна да додате отисак лозинку - - - - Add fingerprint password - Додај отисак лозинку - - - - Authentication is required to clear fingerprint passwords - Идентификација је неопходна да обришете отисак лозинку - - - - Clear fingerprint passwords - Обриши отисак лозинку - - - - Authentication is required to rename fingerprint password - Идентификација је неопходна да преименујете отисак лозинку - - - - Rename fingerprint password - Преименуј отисак лозинку - - - - Password is required to perform this action - Лозинка је потребна за овај поступак - - - - Manage fingerprint passwords - Управљај отисак лозинкама - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sv.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sv.ts deleted file mode 100644 index 807057de2..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sv.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Autentisering krävs för att lägga till fingeravtryck - - - - Add fingerprint password - Lägg till fingeravtryck - - - - Authentication is required to clear fingerprint passwords - Autentisiering krävs för att radera fingeravtryck - - - - Clear fingerprint passwords - Radera fingeravtryck - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sv_SE.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sv_SE.ts deleted file mode 100644 index faef7481a..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sv_SE.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sw.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sw.ts deleted file mode 100644 index 647d07e5a..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_sw.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ta.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ta.ts deleted file mode 100644 index 64b1a718e..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ta.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_te.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_te.ts deleted file mode 100644 index 5217d5aca..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_te.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_th.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_th.ts deleted file mode 100644 index 874eae44c..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_th.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_tr.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_tr.ts deleted file mode 100644 index 6b46e71b9..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_tr.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Parmak izi parolası eklemek için kimlik doğrulaması gerekli - - - - Add fingerprint password - Parmak izi parolası ekle - - - - Authentication is required to clear fingerprint passwords - Parmak izi parolalarını silmek için kimlik doğrulaması gerekli - - - - Clear fingerprint passwords - Parmak izi parolalarını temizle - - - - Authentication is required to rename fingerprint password - Parmak izi parolasını yeniden adlandırmak için kimlik doğrulaması gerekli - - - - Rename fingerprint password - Parmak izi parolasını yeniden adlandır - - - - Password is required to perform this action - Bu işlemi gerçekleştirmek için parola gerekli - - - - Manage fingerprint passwords - Parmak izi parolalarını yönet - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_tzm.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_tzm.ts deleted file mode 100644 index e86e6cb4b..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_tzm.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ug.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ug.ts deleted file mode 100644 index be7dce86e..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ug.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - بارماق ئىزىنى قوشۇش دەلىللەشنى تەلەپ قىلىدۇ - - - - Add fingerprint password - بارماق ئىزى پارولى قوشۇڭ - - - - Authentication is required to clear fingerprint passwords - بارماق ئىزىنى ئېلىۋېتىش دەلىللەشنى تەلەپ قىلىدۇ - - - - Clear fingerprint passwords - بارماق ئىزى پارولىنى ئېلىۋېتىش - - - - Authentication is required to rename fingerprint password - بارماق ئىزىنىنىڭ نامىنى ئۆزگەرتىش دەلىللەشنى تەلەپ قىلىدۇ - - - - Rename fingerprint password - بارماق ئىزى پارولىنىڭ نامىنى ئۆزگەرتىش - - - - Password is required to perform this action - بۇ مەشغۇلاتنى قىلىش ئۈچۈن پارول كىرگۈزۈڭ - - - - Manage fingerprint passwords - بارماق ئىزى پارولىنى باشقۇرۇش - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_uk.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_uk.ts deleted file mode 100644 index bb5be74c4..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_uk.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Для додавання пароля до відбитка слід пройти розпізнавання - - - - Add fingerprint password - Додавання пароля до відбитка - - - - Authentication is required to clear fingerprint passwords - Для вилучення паролів до відбитків слід пройти розпізнавання - - - - Clear fingerprint passwords - Вилучення паролів до відбитків - - - - Authentication is required to rename fingerprint password - Для зміни пароля до відбитка слід пройти розпізнавання - - - - Rename fingerprint password - Зміна пароля до відбитка - - - - Password is required to perform this action - Для виконання цієї дії слід вказати пароль - - - - Manage fingerprint passwords - Керування паролями до відбитків - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ur.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ur.ts deleted file mode 100644 index 4eee9ff1d..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_ur.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_uz.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_uz.ts deleted file mode 100644 index 75b732c6c..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_uz.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - - - - - Add fingerprint password - - - - - Authentication is required to clear fingerprint passwords - - - - - Clear fingerprint passwords - - - - - Authentication is required to rename fingerprint password - - - - - Rename fingerprint password - - - - - Password is required to perform this action - - - - - Manage fingerprint passwords - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_vi.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_vi.ts deleted file mode 100644 index 6d8250462..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_vi.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - Yêu cầu xác thực để thêm vân tay - - - - Add fingerprint password - Thêm dấu vân tay - - - - Authentication is required to clear fingerprint passwords - Yêu cầu xác thực để xoá dấu vân tay - - - - Clear fingerprint passwords - Xoá dấu vân tay - - - - Authentication is required to rename fingerprint password - Yêu cầu xác thực để đổi tên mật khẩu vân tay - - - - Rename fingerprint password - Đổi tên mật khẩu vân tay - - - - Password is required to perform this action - Mật khẩu là cần thiết để thực hiện hành động này - - - - Manage fingerprint passwords - Quản lý mật khẩu vân tay - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_zh_CN.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_zh_CN.ts deleted file mode 100644 index a102e6b75..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_zh_CN.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - 添加指纹需要认证 - - - - Add fingerprint password - 添加指纹密码 - - - - Authentication is required to clear fingerprint passwords - 清除指纹需要认证 - - - - Clear fingerprint passwords - 清除指纹密码 - - - - Authentication is required to rename fingerprint password - 重命名指纹需要认证 - - - - Rename fingerprint password - 重命名指纹密码 - - - - Password is required to perform this action - 请输入密码以执行该操作 - - - - Manage fingerprint passwords - 管理指纹密码 - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_zh_HK.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_zh_HK.ts deleted file mode 100644 index c33e650f3..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_zh_HK.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - 添加指紋需要認證 - - - - Add fingerprint password - 添加指紋密碼 - - - - Authentication is required to clear fingerprint passwords - 清除指紋需要認證 - - - - Clear fingerprint passwords - 清除指紋密碼 - - - - Authentication is required to rename fingerprint password - 重命名指紋需要認證 - - - - Rename fingerprint password - 重命名指紋密碼 - - - - Password is required to perform this action - 請輸入密碼以執行該操作 - - - - Manage fingerprint passwords - 管理指紋密碼 - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_zh_TW.ts b/misc/ts/com.deepin.daemon.Fprintd.policy/policy_zh_TW.ts deleted file mode 100644 index 043a19edb..000000000 --- a/misc/ts/com.deepin.daemon.Fprintd.policy/policy_zh_TW.ts +++ /dev/null @@ -1,45 +0,0 @@ - - - policy - - - Authentication is required to add fingerprint password - 需要身份驗證才可新增指紋密碼 - - - - Add fingerprint password - 新增指紋密碼 - - - - Authentication is required to clear fingerprint passwords - 需要身份驗證才可清除指紋密碼 - - - - Clear fingerprint passwords - 清除指紋密碼 - - - - Authentication is required to rename fingerprint password - 重命名指紋需要認證 - - - - Rename fingerprint password - 重命名指紋密碼 - - - - Password is required to perform this action - 請輸入密碼以執行該操作 - - - - Manage fingerprint passwords - 管理指紋密碼 - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy.ts deleted file mode 100644 index 81851a3bb..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy.ts +++ /dev/null @@ -1,27 +0,0 @@ - - - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ady.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ady.ts deleted file mode 100644 index fce9d66a5..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ady.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_af.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_af.ts deleted file mode 100644 index 24395702b..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_af.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_af_ZA.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_af_ZA.ts deleted file mode 100644 index da5a802ad..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_af_ZA.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ak.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ak.ts deleted file mode 100644 index 95b5aca1c..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ak.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_am.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_am.ts deleted file mode 100644 index 9cc17bd7f..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_am.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_am_ET.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_am_ET.ts deleted file mode 100644 index c29e8645d..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_am_ET.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ar.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ar.ts deleted file mode 100644 index 20756dbc3..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ar.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ar_EG.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ar_EG.ts deleted file mode 100644 index 62803cbc2..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ar_EG.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ast.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ast.ts deleted file mode 100644 index 1ce90c4a0..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ast.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_az.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_az.ts deleted file mode 100644 index 0387bf4ea..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_az.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_bg.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_bg.ts deleted file mode 100644 index 6380f3069..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_bg.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_bn.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_bn.ts deleted file mode 100644 index cfc7b3207..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_bn.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_bo.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_bo.ts deleted file mode 100644 index 09912044b..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_bo.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - འགོ་སློང་འདེམས་བྱང་གི་སྒྲིག་འགོད་བཟོ་བཅོས་བྱེད་དགོས་ན་བདེན་དཔང་ར་སྤྲོད་བྱེད་དགོས། - - - - Change the grub configuration - འགོ་སློང་འདེམས་བྱང་གི་སྒྲིག་འགོད་བཟོ་བཅོས། - - - - Authentication is required to prepare grub display resolution detection - གྲ་སྒྲིག་འགོ་སློང་འདེམས་བྱང་གི་མངོན་སྟོན་འབྱེད་ཕྱོད་དཔྱད་འཇལ་བྱེད་ཚེ་ར་སྤྲོད་བྱེད་དགོས། - - - - Prepare grub display resolution detection - གྲ་སྒྲིག་འགོ་སློང་འདེམས་བྱང་གི་མངོན་སྟོན་འབྱེད་ཕྱོད་དཔྱད་འཇལ། - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_bqi.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_bqi.ts deleted file mode 100644 index 74cf574cf..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_bqi.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_br.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_br.ts deleted file mode 100644 index 395b95e67..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_br.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ca.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ca.ts deleted file mode 100644 index ecf27cfab..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ca.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_cgg.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_cgg.ts deleted file mode 100644 index 0ec50df9a..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_cgg.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_cs.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_cs.ts deleted file mode 100644 index 3a7906812..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_cs.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_da.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_da.ts deleted file mode 100644 index ad643cbf8..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_da.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_de.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_de.ts deleted file mode 100644 index ed3e54782..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_de.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_de_CH.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_de_CH.ts deleted file mode 100644 index d453618d0..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_de_CH.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_de_DE.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_de_DE.ts deleted file mode 100644 index d41e612d6..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_de_DE.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_el.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_el.ts deleted file mode 100644 index 9a712937e..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_el.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_el_GR.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_el_GR.ts deleted file mode 100644 index bf26a48fc..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_el_GR.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_en_AU.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_en_AU.ts deleted file mode 100644 index 8217c4a4a..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_en_AU.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_en_GB.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_en_GB.ts deleted file mode 100644 index 8b23918ed..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_en_GB.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_en_NO.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_en_NO.ts deleted file mode 100644 index 62c6600c8..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_en_NO.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_en_US.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_en_US.ts deleted file mode 100644 index c9350c145..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_en_US.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_eo.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_eo.ts deleted file mode 100644 index 4438932db..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_eo.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_es.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_es.ts deleted file mode 100644 index e47f748a4..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_es.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_es_419.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_es_419.ts deleted file mode 100644 index 4e2a38791..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_es_419.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub2 configuration - Se requiere autenticación para cambiar la configuración de grub2 - - - - Change the grub2 configuration - Cambiar la configuración del grub2 - - - - Authentication is required to prepare grub2 display resolution detection - - - - - Prepare grub2 display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_es_MX.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_es_MX.ts deleted file mode 100644 index b06b19f02..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_es_MX.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub2 configuration - - - - - Change the grub2 configuration - - - - - Authentication is required to prepare grub2 display resolution detection - - - - - Prepare grub2 display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_et.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_et.ts deleted file mode 100644 index 664a62abc..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_et.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_eu.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_eu.ts deleted file mode 100644 index 07e7f4f7f..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_eu.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_fa.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_fa.ts deleted file mode 100644 index d7120d004..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_fa.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_fi.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_fi.ts deleted file mode 100644 index 571f0211e..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_fi.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_fil.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_fil.ts deleted file mode 100644 index f09e86571..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_fil.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_fr.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_fr.ts deleted file mode 100644 index dad9d1599..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_fr.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_gl.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_gl.ts deleted file mode 100644 index 417487ecd..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_gl.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_gl_ES.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_gl_ES.ts deleted file mode 100644 index 65cce4e5a..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_gl_ES.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_he.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_he.ts deleted file mode 100644 index 68b435ce8..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_he.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_hi_IN.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_hi_IN.ts deleted file mode 100644 index 6e76d936b..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_hi_IN.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_hr.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_hr.ts deleted file mode 100644 index e5e6cf6bb..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_hr.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_hu.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_hu.ts deleted file mode 100644 index e038ec25a..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_hu.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - Hitelesítés szükséges a grub konfiguráció módosításához - - - - Change the grub configuration - Módosítsa a grub konfigurációt - - - - Authentication is required to prepare grub display resolution detection - Hitelesítés szükséges a grub képernyőfelbontás érzékeléshez - - - - Prepare grub display resolution detection - Grub képernyőfelbontás érzékelése - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_hy.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_hy.ts deleted file mode 100644 index bde48e927..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_hy.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_id.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_id.ts deleted file mode 100644 index 98d48b1bb..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_id.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_id_ID.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_id_ID.ts deleted file mode 100644 index 181f4277e..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_id_ID.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_it.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_it.ts deleted file mode 100644 index 9f69d8ada..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_it.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ja.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ja.ts deleted file mode 100644 index bd9707dd6..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ja.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ka.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ka.ts deleted file mode 100644 index 71e4dba7b..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ka.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_kab.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_kab.ts deleted file mode 100644 index 4a3ad53c0..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_kab.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_kk.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_kk.ts deleted file mode 100644 index 7b9bc29e8..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_kk.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_km_KH.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_km_KH.ts deleted file mode 100644 index 5460d550e..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_km_KH.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_kn_IN.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_kn_IN.ts deleted file mode 100644 index 7e84d8902..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_kn_IN.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ko.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ko.ts deleted file mode 100644 index df0d47a9b..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ko.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ku.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ku.ts deleted file mode 100644 index f4f1e3f0b..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ku.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ku_IQ.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ku_IQ.ts deleted file mode 100644 index 9f0184ca0..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ku_IQ.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ky.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ky.ts deleted file mode 100644 index 36ecc0ff5..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ky.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ky@Arab.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ky@Arab.ts deleted file mode 100644 index 971ea86aa..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ky@Arab.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_la.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_la.ts deleted file mode 100644 index ae7cb685e..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_la.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_lo.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_lo.ts deleted file mode 100644 index e4571e3a4..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_lo.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_lt.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_lt.ts deleted file mode 100644 index 010a08118..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_lt.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_lv.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_lv.ts deleted file mode 100644 index e74fbf0f3..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_lv.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ml.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ml.ts deleted file mode 100644 index fc5e45c94..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ml.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_mn.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_mn.ts deleted file mode 100644 index c59b834d8..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_mn.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_mr.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_mr.ts deleted file mode 100644 index 58da32e8f..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_mr.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ms.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ms.ts deleted file mode 100644 index d44e21adf..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ms.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_nb.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_nb.ts deleted file mode 100644 index 7e58dd276..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_nb.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ne.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ne.ts deleted file mode 100644 index e116becbe..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ne.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_nl.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_nl.ts deleted file mode 100644 index b4658d0f3..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_nl.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - Verificatie vereist om de grub-instellingen aan te passen - - - - Change the grub configuration - Grub-instellingen aanpassen - - - - Authentication is required to prepare grub display resolution detection - Verificatie vereist om de grub-schermresolutiedetectie voor te bereiden - - - - Prepare grub display resolution detection - Grub-schermresolutiedetectie voorbereiden - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_pa.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_pa.ts deleted file mode 100644 index 8391b8904..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_pa.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_pam.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_pam.ts deleted file mode 100644 index c499c6a04..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_pam.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_pl.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_pl.ts deleted file mode 100644 index cd606a909..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_pl.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - Wymagane jest uwierzytelnienie, aby zmienić konfigurację grub - - - - Change the grub configuration - Zmień konfigurację grub - - - - Authentication is required to prepare grub display resolution detection - Wymagane jest uwierzytelnienie do wykrywania rozdzielczości grub - - - - Prepare grub display resolution detection - Wykrywanie rozdzielczości wyświetlacza grub2 - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ps.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ps.ts deleted file mode 100644 index bea483b26..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ps.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_pt.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_pt.ts deleted file mode 100644 index 0adb33c4d..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_pt.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_pt_BR.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_pt_BR.ts deleted file mode 100644 index 2ed80967d..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_pt_BR.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ro.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ro.ts deleted file mode 100644 index 3a2c0e49a..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ro.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ru.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ru.ts deleted file mode 100644 index e4d6b8238..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ru.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ru_UA.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ru_UA.ts deleted file mode 100644 index e7997dd30..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ru_UA.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_sc.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_sc.ts deleted file mode 100644 index 4e06ef5ff..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_sc.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_si.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_si.ts deleted file mode 100644 index 5737c5d80..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_si.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_sk.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_sk.ts deleted file mode 100644 index 0ddf52935..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_sk.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_sl.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_sl.ts deleted file mode 100644 index 7a12c79af..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_sl.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_sq.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_sq.ts deleted file mode 100644 index 405e92a24..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_sq.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - Që të ndryshoni formësim për grub, duhet bërë mirëfilltësimi - - - - Change the grub configuration - Ndryshoni formësimin për grub - - - - Authentication is required to prepare grub display resolution detection - Që të përgatitet pikasje qartësie ekrani nga grub, duhet bërë mirëfilltësimi - - - - Prepare grub display resolution detection - Përgatit pikasje qartësie ekrani nga grub - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_sr.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_sr.ts deleted file mode 100644 index 1d4f30d78..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_sr.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_sv.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_sv.ts deleted file mode 100644 index 54ed3fe36..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_sv.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_sv_SE.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_sv_SE.ts deleted file mode 100644 index 04a0c4613..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_sv_SE.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_sw.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_sw.ts deleted file mode 100644 index 2554b7e1f..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_sw.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ta.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ta.ts deleted file mode 100644 index 32538f928..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ta.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_te.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_te.ts deleted file mode 100644 index 19ae7efb7..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_te.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_th.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_th.ts deleted file mode 100644 index 194e3931f..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_th.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_tr.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_tr.ts deleted file mode 100644 index 1c218ff78..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_tr.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_tzm.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_tzm.ts deleted file mode 100644 index 592a483c1..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_tzm.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ug.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ug.ts deleted file mode 100644 index f19c73822..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ug.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_uk.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_uk.ts deleted file mode 100644 index 5c5bd1cc7..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_uk.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ur.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_ur.ts deleted file mode 100644 index 744b48173..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_ur.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_uz.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_uz.ts deleted file mode 100644 index f348c5b4f..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_uz.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_vi.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_vi.ts deleted file mode 100644 index 1e6f33023..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_vi.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - - - - - Change the grub configuration - - - - - Authentication is required to prepare grub display resolution detection - - - - - Prepare grub display resolution detection - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_zh_CN.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_zh_CN.ts deleted file mode 100644 index 8776ae3f9..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_zh_CN.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - 修改启动菜单配置需要认证 - - - - Change the grub configuration - 修改启动菜单配置 - - - - Authentication is required to prepare grub display resolution detection - 预备启动菜单显示分辨率探测需要认证 - - - - Prepare grub display resolution detection - 预备启动菜单显示分辨率探测 - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_zh_HK.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_zh_HK.ts deleted file mode 100644 index 6cd76a87b..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_zh_HK.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - 修改啟動菜單配置需要認證 - - - - Change the grub configuration - 修改啟動菜單配置 - - - - Authentication is required to prepare grub display resolution detection - 預備啟動菜單顯示解像度探測需要認證 - - - - Prepare grub display resolution detection - 預備啟動菜單顯示解像度探測 - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.Grub2.policy/policy_zh_TW.ts b/misc/ts/com.deepin.daemon.Grub2.policy/policy_zh_TW.ts deleted file mode 100644 index a46ad0dde..000000000 --- a/misc/ts/com.deepin.daemon.Grub2.policy/policy_zh_TW.ts +++ /dev/null @@ -1,25 +0,0 @@ - - - policy - - - Authentication is required to change the grub configuration - 修改啟動選單配置需要認證 - - - - Change the grub configuration - 修改啟動選單配置 - - - - Authentication is required to prepare grub display resolution detection - 預備啟動選單顯示解析度探測需要認證 - - - - Prepare grub display resolution detection - 預備啟動選單顯示解析度探測 - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy.ts deleted file mode 100644 index dcc880669..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Authentication is required to change your own user data - - - - Change your own user data - Change your own user data - - - - Authentication is required to change user data - Authentication is required to change user data - - - - Manage user accounts - Manage user accounts - - - - Authentication is required to enable auto login - Authentication is required to enable auto login - - - - Enable Auto Login - Enable Auto Login - - - - Authentication is required to disable auto login - Authentication is required to disable auto login - - - - Disable Auto Login - Disable Auto Login - - - - Authentication is required to enable quick login - Authentication is required to enable quick login - - - - Enable Quick Login - Enable Quick Login - - - - Authentication is required to disable quick login - Authentication is required to disable quick login - - - - Disable Quick Login - Disable Quick Login - - - - Authentication is required to enable login without password - Authentication is required to enable login without password - - - - Enable Login without password - Enable Login without password - - - - Authentication is required to disable login without password - Authentication is required to disable login without password - - - - Disable Login without password - Disable Login without password - - - - Authentication is required to set keyboard layout - Authentication is required to set keyboard layout - - - - Set keyboard layout - Set keyboard layout - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ady.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ady.ts deleted file mode 100644 index 01f1bef49..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ady.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_af.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_af.ts deleted file mode 100644 index a6c3af95c..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_af.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_af_ZA.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_af_ZA.ts deleted file mode 100644 index dcccef382..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_af_ZA.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ak.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ak.ts deleted file mode 100644 index c8b01e4b4..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ak.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_am.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_am.ts deleted file mode 100644 index 39e30488c..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_am.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_am_ET.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_am_ET.ts deleted file mode 100644 index 5defc85aa..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_am_ET.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - ማረጋገጫ ያስፈልጋል የ እርስዎን ተጠቃሚ ዳታ ማሰናጃ ለ መቀየር - - - - Change your own user data - የ እርስዎን ተጠቃሚ ዳታ ማሰናጃ መቀየሪያ - - - - Authentication is required to change user data - ማረጋገጫ ያስፈልጋል የ ተጠቃሚ ዳታ ማሰናጃ ለ መቀየር - - - - Manage user accounts - የተጠቃሚ መግለጫዎች አስተዳዳሪ - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ar.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ar.ts deleted file mode 100644 index 38fb95eea..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ar.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - المصادقة مطلوبة لتغيير ملكية بيانات المستخدم الخاصة بك - - - - Change your own user data - تغيير ملكية بيانات المستخدم الخاصة بك - - - - Authentication is required to change user data - المصادقة مطلوبة لتغيير بيانات المستخدم - - - - Manage user accounts - إدارة حسابات المستخدمين - - - - Authentication is required to enable auto login - المصادقة مطلوبة لتمكين تسجيل الدخول التلقائي - - - - Enable Auto Login - تمكين تسجيل الدخول التلقائي - - - - Authentication is required to disable auto login - المصادقة مطلوبة لتعطيل تسجيل الدخول التلقائي - - - - Disable Auto Login - تعطيل تسجيل الدخول التلقائي - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - المصادقة مطلوبة لتمكين تسجيل الدخول بدون كلمة المرور - - - - Enable Login without password - تمكين تسجيل الدخول بدون كلمة المرور - - - - Authentication is required to disable login without password - المصادقة مطلوبة لتعطيل تسجيل الدخول بدون كلمة المرور - - - - Disable Login without password - تعطيل تسجيل الدخول بدون كلمة المرور - - - - Authentication is required to set keyboard layout - المصادقة مطلوبة لإعداد تخطيط لوحة المفاتيح - - - - Set keyboard layout - إعداد لوحة المفاتيح - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ar_EG.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ar_EG.ts deleted file mode 100644 index 1990b2fa9..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ar_EG.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ast.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ast.ts deleted file mode 100644 index 110e0ed24..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ast.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Ríquese l'autenticación pa camudar los tos datos d'usuariu - - - - Change your own user data - Camudar los tos datos d'usuariu - - - - Authentication is required to change user data - Ríquese l'autenticación pa camudar los datos d'usuariu - - - - Manage user accounts - Xestionar cuentes d'usuariu - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_az.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_az.ts deleted file mode 100644 index 856d63543..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_az.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Sizə aid istifadəçi məlumatlarınızı dəyişmək üçün doğrulama tələb edilir - - - - Change your own user data - Öz istifadəçi məlumatlarınızı dəyişin - - - - Authentication is required to change user data - İstifadəçi məlumatlarını dəyişmək üçün doğrulama tələb edilir - - - - Manage user accounts - İstifadəçi hesablarının idarə edilməsi - - - - Authentication is required to enable auto login - Avtomatik giriş üçün doğrulama tələb edilir - - - - Enable Auto Login - Avtomatik girişi aktiv etmək - - - - Authentication is required to disable auto login - Avtomatik girişi söndürmək üçün doğrulama tələb edilir - - - - Disable Auto Login - Avtomatik girişi söndürmək - - - - Authentication is required to enable quick login - Kimlik doğrulaması avtomatik girişi aktiv etmək üçün tələb olunur - - - - Enable Quick Login - Sürətli girişi aktiv edin - - - - Authentication is required to disable quick login - Kimlik doğrulaması avtomatik girişi söndürmək üçün tələb olunur - - - - Disable Quick Login - Sürətli girişi söndürün - - - - Authentication is required to enable login without password - Şifrəsiz girişi aktiv etmək üçün doğrulama tələb edilir - - - - Enable Login without password - Şifrəsiz girişi aktiv etmək - - - - Authentication is required to disable login without password - Şifrəsiz girişi söndürmək üçün doğrulama tələb edilir - - - - Disable Login without password - Şifrəsiz girişi söndürmək - - - - Authentication is required to set keyboard layout - Klaviatura qatını təyin etmək üçün doğrulama tələb edilir - - - - Set keyboard layout - Klaviatura qatını təyin etmək - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_bg.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_bg.ts deleted file mode 100644 index 5ff703ac8..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_bg.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Удостоверяването изисква да смените вашите потребителски данни - - - - Change your own user data - Променете вашите потребителски данни - - - - Authentication is required to change user data - Удостоверяването изисква промяна на потребителските данни - - - - Manage user accounts - Управление на потребителските акаунти - - - - Authentication is required to enable auto login - Необходима е идентификация за включване на автоматичното влизане - - - - Enable Auto Login - Включи автоматично влизане - - - - Authentication is required to disable auto login - Необходима е идентификация за изключване на автоматичното влизане - - - - Disable Auto Login - Изключи автоматичното влизане - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Необходима е идентификация за разрешаване на влизане без парола - - - - Enable Login without password - Разрешаване на влизане без парола - - - - Authentication is required to disable login without password - Необходима е идентификация за изключване на влизането без парола - - - - Disable Login without password - Изключване на влизането без парола - - - - Authentication is required to set keyboard layout - Изисква се идентификация за да зададете клавиатурна подредба - - - - Set keyboard layout - Задаване на клавиатурна подредба - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_bn.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_bn.ts deleted file mode 100644 index 61da55d4e..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_bn.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - আপনার নিজস্ব ব্যবহারকারী তথ্যাবলী পরিবর্তন করার জন্য প্রমাণীকরণের প্রয়োজন - - - - Change your own user data - আপনার নিজস্ব ব্যবহারকারী তথ্যাবলী পরিবর্তন করুন - - - - Authentication is required to change user data - ব্যবহারকারী তথ্যাবলী পরিবর্তন করার জন্য প্রমাণীকরণের প্রয়োজন - - - - Manage user accounts - ব্যবহারকারী অ্যাকাউন্টগুলি ব্যবস্থাপনা করুন - - - - Authentication is required to enable auto login - স্বয়ংক্রিয় লগইন চালু করার জন্য প্রমাণীকরণের প্রয়োজন - - - - Enable Auto Login - স্বয়ংক্রিয় লগইন চালু করুন - - - - Authentication is required to disable auto login - স্বয়ংক্রিয় লগইন বন্ধ করতে প্রমাণীকরণ প্রয়োজন - - - - Disable Auto Login - স্বয়ংক্রিয় লগইন বন্ধ করুন - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - পাসওয়ার্ড ছাড়া লগইন চালু করার জন্য প্রমাণীকরণ প্রয়োজন - - - - Enable Login without password - পাসওয়ার্ড ছাড়া লগইন চালু করুন - - - - Authentication is required to disable login without password - পাসওয়ার্ড ছাড়া লগইন বন্ধ করার জন্য প্রমাণীকরণ প্রয়োজন - - - - Disable Login without password - পাসওয়ার্ড ছাড়া লগইন বন্ধ করুন - - - - Authentication is required to set keyboard layout - কীবোর্ড লেআউট সেট করতে প্রমাণীকরণের প্রয়োজন - - - - Set keyboard layout - কীবোর্ড লেআউট সেট করুন - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_bo.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_bo.ts deleted file mode 100644 index c1c3e2276..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_bo.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - ཁྱོད་ཀྱི་སྤྱོད་མཁན་གཞི་གྲངས་བཟོ་བཅོས་བྱེད་ཚེ་ར་སྤྲོད་བྱེད་དགོས། - - - - Change your own user data - ཁྱོད་ཀྱི་སྤྱོད་མཁན་གཞི་གྲངས་བཟོ་བཅོས་བྱེད་པ། - - - - Authentication is required to change user data - སྤྱོད་མཁན་གཞི་གྲངས་བཟོ་བཅོས་བྱེད་ཚེ་ར་སྤྲོད་བྱེད་དགོས། - - - - Manage user accounts - སྤྱོད་མཁན་གྱི་རྩིས་ཁྲ་དོ་དམ། - - - - Authentication is required to enable auto login - ཐོ་རང་འཇུག་བྱེད་པར་ར་སྤྲོད་བྱེད་དགོས། - - - - Enable Auto Login - ཐོ་རང་འཇུག་བྱེད་པ། - - - - Authentication is required to disable auto login - ཐོ་རང་འཇུག་སྒོ་རྒྱག་ཚེ་ར་སྤྲོད་བྱེད་དགོས། - - - - Disable Auto Login - ཐོ་རང་འཇུག་སྒོ་རྒྱག་པ། - - - - Authentication is required to enable quick login - འཕྲལ་དུ་ཐོ་འཇུག་པར་ར་སྤྲོད་བྱེད་དགོས། - - - - Enable Quick Login - འཕྲུལ་དུ་ཐོ་འཇུག - - - - Authentication is required to disable quick login - འཕྲལ་དུ་ཐོ་འཇུག་པར་ར་སྤྲོད་བྱེད་མི་དགོས། - - - - Disable Quick Login - འཕྲུལ་དུ་ཐོ་འཇུག་ཅེས་པ་སྒོ་རྒྱག་པ། - - - - Authentication is required to enable login without password - གསང་ཨང་མེད་པར་ཐོ་འཇུག་བྱེད་ཚེ་ར་སྤྲོད་བྱེད་དགོས། - - - - Enable Login without password - གསང་ཨང་མེད་པར་ཐོ་འཇུག་བྱེད་པ། - - - - Authentication is required to disable login without password - གསང་ཨང་མེད་པར་ཐོ་འཇུག་བྱེད་པ་སྒོ་རྒྱག་ཚེ་ར་སྤྲོད་བྱེད་དགོས། - - - - Disable Login without password - གསང་ཨང་མེད་པར་ཐོ་འཇུག་བྱེད་པ་སྒོ་རྒྱག་པ། - - - - Authentication is required to set keyboard layout - མཐེབ་གཞོང་བཀོད་པ་སྒྲིག་འགོད་བྱེད་ཚེ་ར་སྤྲོད་བྱེད་དགོས། - - - - Set keyboard layout - མཐེབ་གཞོང་བཀོད་པ་སྒྲིག་འགོད་བྱེད་པ། - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_bqi.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_bqi.ts deleted file mode 100644 index 866eef0e4..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_bqi.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_br.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_br.ts deleted file mode 100644 index a7466a865..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_br.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ca.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ca.ts deleted file mode 100644 index 20c16c9e6..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ca.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Cal autenticació per canviar les dades d'usuari pròpies. - - - - Change your own user data - Canvieu les dades d'usuari pròpies - - - - Authentication is required to change user data - Cal autenticació per canviar les dades d'usuari. - - - - Manage user accounts - Gestioneu els comptes d'usuari - - - - Authentication is required to enable auto login - Cal autenticació per habilitar l'entrada automàtica. - - - - Enable Auto Login - Habilita l'entrada automàtica. - - - - Authentication is required to disable auto login - Cal autenticació per inhabilitar l'entrada automàtica. - - - - Disable Auto Login - Inhabilita l'entrada automàtica. - - - - Authentication is required to enable quick login - Cal autenticació per habilitar l'inici de sessió ràpid. - - - - Enable Quick Login - Activa l'inici de sessió ràpid - - - - Authentication is required to disable quick login - Cal autenticació per desactivar l'inici de sessió ràpid. - - - - Disable Quick Login - Desactiva l'inici de sessió ràpid - - - - Authentication is required to enable login without password - Cal autenticació per habilitar l'entrada sense contrasenya. - - - - Enable Login without password - Habilita l'entrada sense contrasenya. - - - - Authentication is required to disable login without password - Cal autenticació per inhabilitar l'entrada sense contrasenya. - - - - Disable Login without password - Inhabilita l'entrada sense contrasenya. - - - - Authentication is required to set keyboard layout - Cal autenticació per establir la disposició del teclat. - - - - Set keyboard layout - Establiu la disposició del teclat. - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_cgg.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_cgg.ts deleted file mode 100644 index 52395713f..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_cgg.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_cs.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_cs.ts deleted file mode 100644 index 45a1da45c..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_cs.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Pro změnu svých vlastních údajů je vyžadováno ověření se - - - - Change your own user data - Změnit si své vlastní údaje - - - - Authentication is required to change user data - Pro změnu údajů o uživateli je vyžadováno ověření se - - - - Manage user accounts - Spravovat uživatelské účty - - - - Authentication is required to enable auto login - Pro povolení automatického přihlašování je požadováno ověření se - - - - Enable Auto Login - Povolit automatické přihlašování - - - - Authentication is required to disable auto login - Pro zakázání automatického přihlašování je požadováno ověření se - - - - Disable Auto Login - Zakázat automatické přihlašování - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Pro povolení přihlašování bez hesla je požadováno ověření se - - - - Enable Login without password - Povolit přihlašování bez hesla - - - - Authentication is required to disable login without password - Pro zakázání přihlašování bez hesla je požadováno ověření se - - - - Disable Login without password - Zakázat přihlašování bez hesla - - - - Authentication is required to set keyboard layout - Pro nastavení rozložení klávesnice je vyžadováno ověření se - - - - Set keyboard layout - Nastavit rozložení klávesnice - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_da.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_da.ts deleted file mode 100644 index 889c9bd68..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_da.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Der kræves autentifikation for at ændre dine egne brugerdata - - - - Change your own user data - Ændr dine egne brugerdata - - - - Authentication is required to change user data - Der kræves autentifikation for at ændre brugerdata - - - - Manage user accounts - Håndter brugerkonti - - - - Authentication is required to enable auto login - Der kræves autentifikation for at aktivere automatisk login - - - - Enable Auto Login - Aktivér automatisk login - - - - Authentication is required to disable auto login - Der kræves autentifikation for at deaktivere automatisk login - - - - Disable Auto Login - Deaktivér automatisk login - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Der kræves autentifikation for at aktivere login uden adgangskode - - - - Enable Login without password - Aktivér login uden adgangskode - - - - Authentication is required to disable login without password - Der kræves autentifikation for at deaktivere login uden adgangskode - - - - Disable Login without password - Deaktivér login uden adgangskode - - - - Authentication is required to set keyboard layout - Der kræves autentifikation for at sætte tastaturlayout - - - - Set keyboard layout - Sæt tastaturlayout - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_de.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_de.ts deleted file mode 100644 index 421109cbe..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_de.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Zum Ändern Ihrer eigenen Benutzerdaten ist eine Authentifizierung erforderlich - - - - Change your own user data - Ändern Ihrer eigenen Benutzerdaten - - - - Authentication is required to change user data - Zum Ändern von Benutzerdaten ist eine Authentifizierung erforderlich - - - - Manage user accounts - Benutzerkonten verwalten - - - - Authentication is required to enable auto login - Zum Aktivieren der automatischen Anmeldung ist eine Authentifizierung erforderlich - - - - Enable Auto Login - Automatische Anmeldung aktivieren - - - - Authentication is required to disable auto login - Zum Deaktivieren der automatischen Anmeldung ist eine Authentifizierung erforderlich - - - - Disable Auto Login - Automatische Anmeldung deaktivieren - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Zum Aktivieren der Anmeldung ohne Passwort ist eine Authentifizierung erforderlich - - - - Enable Login without password - Anmeldung ohne Passwort aktivieren - - - - Authentication is required to disable login without password - Zum Deaktivieren der Anmeldung ohne Passwort ist eine Authentifizierung erforderlich - - - - Disable Login without password - Anmeldung ohne Passwort deaktivieren - - - - Authentication is required to set keyboard layout - Zum Festlegen der Tastaturbelegung ist eine Authentifizierung erforderlich - - - - Set keyboard layout - Tastaturbelegung festlegen - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_de_CH.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_de_CH.ts deleted file mode 100644 index 58ac0d972..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_de_CH.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_de_DE.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_de_DE.ts deleted file mode 100644 index 97c1a2df8..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_de_DE.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Sie müssen sich authentifizieren, um ihre Benutzerdaten zu ändern - - - - Change your own user data - Ändern Sie ihre Benutzerdaten - - - - Authentication is required to change user data - Sie müssen sich authentifizieren, um Benutzerdaten zu ändern - - - - Manage user accounts - Benutzerkonten verwalten - - - - Authentication is required to enable auto login - Sie müssen sich authentifizieren, um Auto-LogIn einzurichten - - - - Enable Auto Login - Auto-LogIn Einrichten - - - - Authentication is required to disable auto login - Sie müssen sich authentifizieren, um Auto-LogIn abzuschalten - - - - Disable Auto Login - Auto-LogIn abschalten - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Sie müssen sich authentifizieren, um LogIn ohne Passwort einzurichten - - - - Enable Login without password - LogIn ohne Passwort einrichten - - - - Authentication is required to disable login without password - Sie müssen sich authentifizieren, um LogIn ohne Passwort abzuschalten - - - - Disable Login without password - LogIn ohne Passwort abschalten - - - - Authentication is required to set keyboard layout - Sie müssen sich authentifizieren, um das Tastatur-Layout einzustellen - - - - Set keyboard layout - Tastatur-Layout einstellen - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_el.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_el.ts deleted file mode 100644 index ae863c074..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_el.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Απαιτείται πιστοποίηση για αλλαγή των δικών σας δεδομένων χρήστη - - - - Change your own user data - Αλλάξτε τα δεδομένα χρήστη σας - - - - Authentication is required to change user data - Απαιτείται πιστοποίηση για αλλαγή των δεδομένων χρήστη - - - - Manage user accounts - Διαχείριση λογαριασμών χρηστών - - - - Authentication is required to enable auto login - Απαιτείται πιστοποίηση για ενεργοποίηση αυτόματης εισόδου - - - - Enable Auto Login - Ενεργοποίηση Αυτόματης Εισόδου - - - - Authentication is required to disable auto login - Απαιτείται πιστοποίηση για απενεργοποίηση αυτόματης εισόδου - - - - Disable Auto Login - Απενεργοποίηση Αυτόματης Εισόδου - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Απαιτείται πιστοποίηση για ενεργοποίηση εισόδου χωρίς κωδικό - - - - Enable Login without password - Ενεργοποίηση Εισόδου χωρίς κωδικό - - - - Authentication is required to disable login without password - Απαιτείται πιστοποίηση για απενεργοποίηση εισόδου χωρίς κωδικό - - - - Disable Login without password - Απενεργοποίηση Εισόδου χωρίς κωδικό - - - - Authentication is required to set keyboard layout - Απαιτείται πιστοποίηση για να θέσετε τη διάταξη του πληκτρολογίου - - - - Set keyboard layout - Θέστε διάταξης πληκτρολογίου - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_el_GR.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_el_GR.ts deleted file mode 100644 index 6a99783b0..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_el_GR.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_en_AU.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_en_AU.ts deleted file mode 100644 index a3aa11f77..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_en_AU.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Authentication is required to change your own user data - - - - Change your own user data - Change your own user data - - - - Authentication is required to change user data - Authentication is required to change user data - - - - Manage user accounts - Manage user accounts - - - - Authentication is required to enable auto login - Authentication is required to enable auto-login - - - - Enable Auto Login - Enable Auto Login - - - - Authentication is required to disable auto login - Authentication is required to disable auto-login - - - - Disable Auto Login - Disable Auto Login - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Authentication is required to enable login without password - - - - Enable Login without password - Enable Login without password - - - - Authentication is required to disable login without password - Authentication is required to disable login without password - - - - Disable Login without password - Disable Login without password - - - - Authentication is required to set keyboard layout - Authentication is required to set keyboard layout - - - - Set keyboard layout - Set keyboard layout - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_en_GB.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_en_GB.ts deleted file mode 100644 index 607514a56..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_en_GB.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Authentication is required to change your own user data - - - - Change your own user data - Change your own user data - - - - Authentication is required to change user data - Authentication is required to change user data - - - - Manage user accounts - Manage user accounts - - - - Authentication is required to enable auto login - Authentication is required to enable auto login - - - - Enable Auto Login - Enable auto login - - - - Authentication is required to disable auto login - Authentication is required to disable auto login - - - - Disable Auto Login - Disable auto login - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Authentication is required to enable logging in without a password - - - - Enable Login without password - Enable logging in without a password - - - - Authentication is required to disable login without password - Authentication is required to disable logging in without a password - - - - Disable Login without password - Disable logging in without a password - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_en_NO.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_en_NO.ts deleted file mode 100644 index bbacfc954..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_en_NO.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_en_US.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_en_US.ts deleted file mode 100644 index 5c8ed3972..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_en_US.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Authentication is required to change your own user data - - - - Change your own user data - Change your own user data - - - - Authentication is required to change user data - Authentication is required to change user data - - - - Manage user accounts - Manage user accounts - - - - Authentication is required to enable auto login - Authentication is required to enable auto login - - - - Enable Auto Login - Enable Auto Login - - - - Authentication is required to disable auto login - Authentication is required to disable auto login - - - - Disable Auto Login - Disable Auto Login - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Authentication is required to enable login without password - - - - Enable Login without password - Enable Login without password - - - - Authentication is required to disable login without password - Authentication is required to disable login without password - - - - Disable Login without password - Disable Login without password - - - - Authentication is required to set keyboard layout - Authentication is required to set keyboard layout - - - - Set keyboard layout - Set keyboard layout - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_eo.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_eo.ts deleted file mode 100644 index ebbbbab19..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_eo.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Aŭtentigo bezonatas por ŝanĝi viajn proprajn uzantodatumojn - - - - Change your own user data - Ŝanĝi viajn proprajn uzantodatumojn - - - - Authentication is required to change user data - Aŭtentigo bezonatas por ŝanĝi uzantodatumojn - - - - Manage user accounts - Administri uzantokontojn - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_es.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_es.ts deleted file mode 100644 index 3b995a0a7..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_es.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Se requiere autenticación para cambiar sus datos de usuario - - - - Change your own user data - Cambiar sus datos de usuario - - - - Authentication is required to change user data - Se requiere autenticación para cambiar datos de usuario - - - - Manage user accounts - Gestionar cuentas de usuario - - - - Authentication is required to enable auto login - Se requiere autenticación para habilitar el inicio de sesión automático - - - - Enable Auto Login - Habilitar inicio de sesión automático - - - - Authentication is required to disable auto login - Se requiere autenticación para desactivar el inicio de sesión automático - - - - Disable Auto Login - Desactivar inicio de sesión automático - - - - Authentication is required to enable quick login - Se requiere autenticación para permitir el inicio de sesión rápido - - - - Enable Quick Login - Habilitar inicio de sesión rápido - - - - Authentication is required to disable quick login - Se requiere autenticación para deshabilitar el inicio de sesión rápido - - - - Disable Quick Login - Deshabilitar el inicio de sesión rápido - - - - Authentication is required to enable login without password - Se requiere autenticación para habilitar el inicio de sesión sin contraseña - - - - Enable Login without password - Habilitar inicio de sesión sin contraseña - - - - Authentication is required to disable login without password - Se requiere autenticación para desactivar el inicio de sesión sin contraseña - - - - Disable Login without password - Desactivar inicio de sesión sin contraseña - - - - Authentication is required to set keyboard layout - Se requiere autenticación para establecer la distribución del teclado - - - - Set keyboard layout - Establecer distribución del teclado - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_es_419.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_es_419.ts deleted file mode 100644 index f33847915..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_es_419.ts +++ /dev/null @@ -1,75 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Se requiere autenticación para modificar su propia data de usuario - - - - Change your own user data - Modifique su propia data de usuario - - - - Authentication is required to change user data - Se requiere autenticación para modificar la data de usuario - - - - Manage user accounts - Administrar las cuentas de usuario - - - - Authentication is required to enable auto login - Se requiere autenticación para habilitar inicio de sesión automático - - - - Enable Auto Login - Habilitar inicio de sesión automático - - - - Authentication is required to disable auto login - Se requiere autenticación para deshabilitar inicio de sesión automático - - - - Disable Auto Login - Deshabilitar inicio de sesión automático - - - - Authentication is required to enable login without password - Se requiere autenticación para habilitar inicio de sesión sin contraseña - - - - Enable Login without password - Habilitar inicio de sesión sin contraseña - - - - Authentication is required to disable login without password - Se requiere autenticación para deshabilitar inicio de sesión sin contraseña - - - - Disable Login without password - Deshabilitar inicio de sesión sin contraseña - - - - Authentication is required to set keyboard layout - Se requiere autenticación para establecer distribución del teclado - - - - Set keyboard layout - Establecer distribución del teclado - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_es_MX.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_es_MX.ts deleted file mode 100644 index 4e962ea17..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_es_MX.ts +++ /dev/null @@ -1,75 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_et.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_et.ts deleted file mode 100644 index 85cd8de8e..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_et.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_eu.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_eu.ts deleted file mode 100644 index ed66fa4a3..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_eu.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_fa.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_fa.ts deleted file mode 100644 index 82843dc51..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_fa.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - احراز هویت برای تغییر اطلاعات کاربری شما لازم است - - - - Change your own user data - تغییر اطلاعات کاربری شما - - - - Authentication is required to change user data - احراز هویت برای تغییر اطلاعات کاربر لازم است - - - - Manage user accounts - مدیریت حساب کاربران - - - - Authentication is required to enable auto login - احراز هویت برای فعالسازی ورود خودکار لازم است - - - - Enable Auto Login - فعالسازی ورود خودکار - - - - Authentication is required to disable auto login - احراز هویت برای غیرفعالسازی ورود خودکار لازم است - - - - Disable Auto Login - غیرفعالسازی ورود خودکار - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - احراز هویت برای فعالسازی ورود بدون رمزعبور لازم است - - - - Enable Login without password - فعالسازی ورود بدون رمزعبور - - - - Authentication is required to disable login without password - احراز هویت برای غیرفعالسازی ورود بدون رمزعبور لازم است - - - - Disable Login without password - غیرفعالسازی ورود بدون رمز - - - - Authentication is required to set keyboard layout - احراز هویت برای انتخاب طرح بندی صفحه کلید لازم است - - - - Set keyboard layout - انتخاب طرح بندی صفحه کلید - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_fi.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_fi.ts deleted file mode 100644 index c7888e299..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_fi.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Omien käyttäjätietojen muuttaminen vaatii tunnistautumisen - - - - Change your own user data - Muuta omia käyttäjätietojasi - - - - Authentication is required to change user data - Käyttäjätietojen muuttaminen vaatii tunnistautumisen - - - - Manage user accounts - Hallitse käyttäjätilejä - - - - Authentication is required to enable auto login - Automaattisen kirjautumisen käyttöönotto vaatii tunnistautumisen - - - - Enable Auto Login - Käytä automaattista kirjautumista - - - - Authentication is required to disable auto login - Automaattisen kirjautumisen poisto vaatii tunnistautumisen - - - - Disable Auto Login - Poista automaattinen kirjautuminen - - - - Authentication is required to enable quick login - Tunnistautuminen vaaditaan nopeaan kirjautumiseen - - - - Enable Quick Login - Käytä nopeaa kirjautumista - - - - Authentication is required to disable quick login - Tunnistautuminen vaaditaan nopean kirjautumisen poistamiseksi - - - - Disable Quick Login - Poista nopea kirjautuminen - - - - Authentication is required to enable login without password - Kirjautumisen käyttöönotto ilman salasanaa vaatii tunnistautumisen - - - - Enable Login without password - Salli kirjautuminen ilman salasanaa - - - - Authentication is required to disable login without password - Kirjautumisen käytöstäpoisto ilman salasanaa vaatii tunnistautumisen - - - - Disable Login without password - Poista kirjautuminen ilman salasanaa - - - - Authentication is required to set keyboard layout - Näppäimistön asetukset vaatii tunnistautumisen - - - - Set keyboard layout - Aseta näppäimistöasettelu - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_fil.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_fil.ts deleted file mode 100644 index d8d24acfc..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_fil.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_fr.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_fr.ts deleted file mode 100644 index b0853098d..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_fr.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Vous devez vous authentifier pour modifier vos données utilisateur - - - - Change your own user data - Modifier vos données utilisateur - - - - Authentication is required to change user data - Il est nécessaire de s'authentifier pour modifier des données utilisateur - - - - Manage user accounts - Gérer les comptes des utilisateurs - - - - Authentication is required to enable auto login - Il est nécessaire de s'authentifier pour activer la connexion automatique - - - - Enable Auto Login - Activer la connexion automatique - - - - Authentication is required to disable auto login - Il est nécessaire de s'authentifier pour désactiver la connexion automatique - - - - Disable Auto Login - Désactiver la connexion automatique - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Il est nécessaire de s'authentifier pour activer la connexion sans mot de passe - - - - Enable Login without password - Activer la connexion sans mot de passe - - - - Authentication is required to disable login without password - Il est nécessaire de s'authentifier pour désactiver la connexion sans mot de passe - - - - Disable Login without password - Désactiver la connexion sans mot de passe - - - - Authentication is required to set keyboard layout - L'authentification est nécessaire pour définir la disposition du clavier - - - - Set keyboard layout - Définir la disposition du clavier - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_gl.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_gl.ts deleted file mode 100644 index 8e6b78eec..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_gl.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_gl_ES.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_gl_ES.ts deleted file mode 100644 index bfef63667..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_gl_ES.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Requírese autenticación para cambiar os seus datos de usuario - - - - Change your own user data - Cambiar os seus datos de usuario - - - - Authentication is required to change user data - Requírese autenticación para cambiar os datos de usuario - - - - Manage user accounts - Xestionar as contas de usuario - - - - Authentication is required to enable auto login - Requírese autenticación para habilitar o inicio automático - - - - Enable Auto Login - Habilitar o inicio automático - - - - Authentication is required to disable auto login - Requírese autenticación para inhabilitar o inicio automático - - - - Disable Auto Login - Inhabilitar o inicio automático - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Requírese autenticación para habilitar o inicio sen contrasinal - - - - Enable Login without password - Habilitar o inicio sen contrasinal - - - - Authentication is required to disable login without password - Requírese autenticación para inhabilitar o inicio sen contrasinal - - - - Disable Login without password - Inhabilitar o incio sen contrasinal - - - - Authentication is required to set keyboard layout - Requírese autenticación para establecer a disposición do teclado - - - - Set keyboard layout - Establecer a disposición do teclado - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_he.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_he.ts deleted file mode 100644 index a08196e7a..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_he.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_hi_IN.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_hi_IN.ts deleted file mode 100644 index 366866ba7..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_hi_IN.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - अपने उपयोक्ता डेटा को बदलने हेतु प्रमाणीकरण आवश्यक है - - - - Change your own user data - अपना उपयोक्ता डेटा बदलें - - - - Authentication is required to change user data - उपयोक्ता डेटा को बदलने हेतु प्रमाणीकरण आवश्यक है - - - - Manage user accounts - उपयोक्ता खातों का प्रबंधन करें - - - - Authentication is required to enable auto login - स्वतः लॉगिन को सक्रिय करने हेतु प्रमाणीकरण आवश्यक है - - - - Enable Auto Login - स्वतः लॉगिन सक्रिय करें - - - - Authentication is required to disable auto login - स्वतः लॉगिन को निष्क्रिय करने हेतु प्रमाणीकरण आवश्यक है - - - - Disable Auto Login - स्वतः लॉगिन निष्क्रिय करें - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - बिना कूटशब्द के लॉगिन को सक्रिय करने हेतु प्रमाणीकरण आवश्यक है - - - - Enable Login without password - बिना कूटशब्द के लॉगिन को सक्रिय करें - - - - Authentication is required to disable login without password - बिना कूटशब्द के लॉगिन को निष्क्रिय करने हेतु प्रमाणीकरण आवश्यक है - - - - Disable Login without password - बिना कूटशब्द के लॉगिन को निष्क्रिय करें - - - - Authentication is required to set keyboard layout - कुंजीपटल अभिन्यास सेट करने हेतु प्रमाणीकरण आवश्यक है - - - - Set keyboard layout - कुंजीपटल अभिन्यास सेट करें - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_hr.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_hr.ts deleted file mode 100644 index f819206fd..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_hr.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Potrebna je ovjera za promjenu vaših vlastitih korisničkih podataka - - - - Change your own user data - Promijenite vaše vlastite korisničke podatke - - - - Authentication is required to change user data - Potrebna je ovjera za promjenu korisničkih podataka - - - - Manage user accounts - Upravlja računima korisnika - - - - Authentication is required to enable auto login - Potrebna je ovjera za omogućavanje automatske prijave - - - - Enable Auto Login - Omogući automatsku prijavu - - - - Authentication is required to disable auto login - Potrebna je ovjera za onemogućavanje automatske prijave - - - - Disable Auto Login - Onemogući automatsku prijavu - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Potrebna je ovjera za omogućavanje prijave bez lozinke - - - - Enable Login without password - Omogući prijavu bez lozinke - - - - Authentication is required to disable login without password - Potrebna je ovjera za onemogućavanje prijave bez lozinke - - - - Disable Login without password - Onemogući prijavu bez lozinke - - - - Authentication is required to set keyboard layout - Potrebna je ovjera za postavljanje rasporeda tipkovnice - - - - Set keyboard layout - Postavi raspored tipkovnice - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_hu.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_hu.ts deleted file mode 100644 index bb03cf395..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_hu.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Hitelesítés szükséges a felhasználói adatainak módosításához - - - - Change your own user data - Saját felhasználói adatainak módosítása - - - - Authentication is required to change user data - Hitelesítés szükséges a felhasználói adatok módosításához - - - - Manage user accounts - Felhasználói fiókok kezelése - - - - Authentication is required to enable auto login - Hitelesítés szükséges az automatikus bejelentkezés engedélyezéséhez - - - - Enable Auto Login - Automatikus bejelentkezés engedélyezése - - - - Authentication is required to disable auto login - Hitelesítés szükséges az automatikus bejelentkezés kikapcsolásához - - - - Disable Auto Login - Automatikus bejelentkezés kikapcsolása - - - - Authentication is required to enable quick login - Hitelesítés szükséges a gyors bejelentkezés engedélyezéséhez - - - - Enable Quick Login - Gyors bejelentkezés engedélyezése - - - - Authentication is required to disable quick login - Hitelesítés szükséges a gyors bejelentkezés letiltásához - - - - Disable Quick Login - Gyors bejelentkezés letiltása - - - - Authentication is required to enable login without password - Hitelesítés szükséges a jelszó nélküli bejelentkezés engedélyezéséhez - - - - Enable Login without password - Jelszó nélküli bejelentkezés engedélyezése - - - - Authentication is required to disable login without password - Hitelesítés szükséges a jelszó nélküli bejelentkezés kikapcsolásához - - - - Disable Login without password - Jelszó nélküli bejelentkezés kikapcsolása - - - - Authentication is required to set keyboard layout - Hitelesítés szükséges a billentyűzetkiosztás beállításához - - - - Set keyboard layout - Billentyűzetkiosztás beállítása - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_hy.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_hy.ts deleted file mode 100644 index 647d07e0e..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_hy.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_id.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_id.ts deleted file mode 100644 index 6e2159057..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_id.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Otentikasi diperlukan untuk mengubah data pengguna milikmu - - - - Change your own user data - Ubah data penggunamu sendiri - - - - Authentication is required to change user data - Otentikasi diperlukan untuk mengubah data pengguna - - - - Manage user accounts - Kelola akun pengguna - - - - Authentication is required to enable auto login - Otentikasi diperlukan untuk mengaktifkan masuk otomatis - - - - Enable Auto Login - Aktifkan masuk otomatis - - - - Authentication is required to disable auto login - Otentikasi diperlukan untuk menonaktifkan masuk otomatis - - - - Disable Auto Login - Nonaktifkan masuk otomatis - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Otentikasi diperlukan untuk mengaktifkan masuk otomatis tanpa dengan sandi lewat - - - - Enable Login without password - Aktifkan masuk tanpa dengan kata sandi - - - - Authentication is required to disable login without password - Otentikasi diperlukan untuk menonaktifkan masuk otomatis tanpa dengan kata sandi - - - - Disable Login without password - Nonaktifkan masuk otomatis tanpa dengan kata sandi - - - - Authentication is required to set keyboard layout - Otentikasi diperlukan untuk set tata letak papan ketik - - - - Set keyboard layout - Atur tata letak papan ketik - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_id_ID.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_id_ID.ts deleted file mode 100644 index 70e372da6..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_id_ID.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_it.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_it.ts deleted file mode 100644 index 31762f4fb..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_it.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - È necessario autenticarsi per cambiare i propri dati utente - - - - Change your own user data - Cambia i dati dell'utente - - - - Authentication is required to change user data - È necessario autenticarsi per cambiare i dati utente - - - - Manage user accounts - Gestisci gli account utente - - - - Authentication is required to enable auto login - Autenticazione richiesta per abilitare il login automatico - - - - Enable Auto Login - Abilita Login automatico - - - - Authentication is required to disable auto login - Autenticazione richiesta per disabilitare il login automatico - - - - Disable Auto Login - Disabilita Login automatico - - - - Authentication is required to enable quick login - Autenticazione richiesta per abilitare l'accesso rapido. - - - - Enable Quick Login - Abilita l'accesso rapido - - - - Authentication is required to disable quick login - L'autenticazione è richiesta per disabilitare l'accesso rapido. - - - - Disable Quick Login - Disabilita accesso rapido - - - - Authentication is required to enable login without password - Autenticazione richiesta per abilitare il login privo di password - - - - Enable Login without password - Abilita Login senza password - - - - Authentication is required to disable login without password - Autenticazione richiesta per disabilitare il login privo di password - - - - Disable Login without password - Disabilita Login senza password - - - - Authentication is required to set keyboard layout - Autenticazione necessaria per modificare il layout della tastiera - - - - Set keyboard layout - Imposta il layout della tastiera - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ja.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ja.ts deleted file mode 100644 index b58e285a5..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ja.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - 自分自身のユーザーデータを変更するには認証が必要です - - - - Change your own user data - 自分自身のユーザーデータを変更 - - - - Authentication is required to change user data - ユーザーのデータを変更するには認証が必要です - - - - Manage user accounts - ユーザーアカウントを管理 - - - - Authentication is required to enable auto login - 自動ログインを有効にするには認証が必要です - - - - Enable Auto Login - 自動ログインを有効にする - - - - Authentication is required to disable auto login - 自動ログインを無効にするには認証が必要です - - - - Disable Auto Login - 自動ログインを無効にする - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - パスワードなしでのログインを有効にするには認証が必要です - - - - Enable Login without password - パスワードなしでのログインを有効にする - - - - Authentication is required to disable login without password - パスワードなしでのログインを無効にするには認証が必要です - - - - Disable Login without password - パスワードなしでのログインを無効にする - - - - Authentication is required to set keyboard layout - キーボードレイアウトを設定するには認証が必要です - - - - Set keyboard layout - キーボードレイアウトを設定 - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ka.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ka.ts deleted file mode 100644 index 6015c725c..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ka.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_kab.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_kab.ts deleted file mode 100644 index 3d1a1198e..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_kab.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Yetwasra usesteb akken ad tbeddeleḍ isefka udmawanen-inek m. - - - - Change your own user data - Beddel isefka udmawanen inek m - - - - Authentication is required to change user data - Yetwasra usesteb akken ad tbeddeleḍ isefka udmawanen n useqdac - - - - Manage user accounts - sefrek isefka n useqdac - - - - Authentication is required to enable auto login - Yettwasra usesteb akken ad tesremdeḍ anekcum awurman - - - - Enable Auto Login - Sermed anekcum awurman - - - - Authentication is required to disable auto login - Yettwasra usesteb akken ad tsenseḍ anekcum awurman - - - - Disable Auto Login - Sens anekcum awurman - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Yettwasra usesteb akken ad tesremdeḍ anekcum war awal uffir - - - - Enable Login without password - Sermed anekcum war awal uffir - - - - Authentication is required to disable login without password - Yettwasra usesteb akken ad tsenseḍ anekcum war awal uffir - - - - Disable Login without password - Sens anekcum war awal uffir - - - - Authentication is required to set keyboard layout - Yettwasra usesteb akken ad tesremdeḍ taneɣuft n unasiw - - - - Set keyboard layout - Sbadu taneɣruft n unasiw - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_kk.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_kk.ts deleted file mode 100644 index 8cabe996c..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_kk.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_km_KH.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_km_KH.ts deleted file mode 100644 index a6e22db5c..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_km_KH.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_kn_IN.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_kn_IN.ts deleted file mode 100644 index cbdedb176..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_kn_IN.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ko.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ko.ts deleted file mode 100644 index 4abd1a1df..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ko.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - 자신의 사용자 데이터를 변경하려면 인증이 필요합니다 - - - - Change your own user data - 사용자 데이터 변경 - - - - Authentication is required to change user data - 사용자 데이터를 변경하려면 인증이 필요합니다 - - - - Manage user accounts - 사용자 계정 - - - - Authentication is required to enable auto login - 자동 로그인을 활성화하려면 인증이 필요 합니다 - - - - Enable Auto Login - 자동 로그인 사용 - - - - Authentication is required to disable auto login - 자동 로그인을 비활성화하려면 인증이 필요합니다 - - - - Disable Auto Login - 자동 로그인 사용 중지 - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - 비밀번호 없는 로그인을 사용하려면 인증이 필요합니다 - - - - Enable Login without password - 비밀번호 없는 로그인 활성화 - - - - Authentication is required to disable login without password - 비밀번호 없는 로그인을 비활성화 하려면 인증이 필요 합니다 - - - - Disable Login without password - 비밀번호 없는 로그인 비활성화 - - - - Authentication is required to set keyboard layout - 키보드 레이아웃을 설정하려면 인증이 필요합니다 - - - - Set keyboard layout - 키보드 레이아웃 설정 - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ku.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ku.ts deleted file mode 100644 index b5247c4bb..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ku.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ku_IQ.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ku_IQ.ts deleted file mode 100644 index 943ef7ae6..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ku_IQ.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ky.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ky.ts deleted file mode 100644 index 54aa42653..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ky.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ky@Arab.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ky@Arab.ts deleted file mode 100644 index 5f2039d75..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ky@Arab.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_la.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_la.ts deleted file mode 100644 index 992e165e6..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_la.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_lo.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_lo.ts deleted file mode 100644 index b9c0bcf4d..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_lo.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_lt.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_lt.ts deleted file mode 100644 index 98bfe4ab8..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_lt.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Norint keisti asmeninio naudotojo duomenis, reikalingas tapatybės nustatymas - - - - Change your own user data - Keisti asmeninio naudotojo duomenis - - - - Authentication is required to change user data - Norint keisti naudotojo duomenis, reikalingas tapatybės nustatymas - - - - Manage user accounts - Tvarkyti naudotojų paskyras - - - - Authentication is required to enable auto login - Norint įjungti automatinį prisijungimą, reikalingas tapatybės nustatymas - - - - Enable Auto Login - Įjungti automatinį prisijungimą - - - - Authentication is required to disable auto login - Norint išjungti automatinį prisijungimą, reikalingas tapatybės nustatymas - - - - Disable Auto Login - Išjungti automatinį prisijungimą - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Norint įjungti prisijungimą be slaptažodžio, reikalingas tapatybės nustatymas - - - - Enable Login without password - Įjungti prisijungimą be slaptažodžio - - - - Authentication is required to disable login without password - Norint išjungti prisijungimą be slaptažodžio, reikalingas tapatybės nustatymas - - - - Disable Login without password - Išjungti prisijungimą be slaptažodžio - - - - Authentication is required to set keyboard layout - Norint nustatyti klaviatūros išdėstymą, reikalingas tapatybės nustatymas - - - - Set keyboard layout - Nustatyti klaviatūros išdėstymą - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_lv.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_lv.ts deleted file mode 100644 index 6bcbe0a63..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_lv.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Nepieciešama autentifikācija, lai mainītu pats savus lietotāja datus - - - - Change your own user data - Mainīt pašam savus lietotāja datus - - - - Authentication is required to change user data - Nepieciešama autentifikācija, lai mainītu lietotāja datus - - - - Manage user accounts - Pārvaldīt lietotāju kontus - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ml.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ml.ts deleted file mode 100644 index b559ea8a9..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ml.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_mn.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_mn.ts deleted file mode 100644 index 6be771d22..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_mn.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Өөрийн хэрэглэгчийн өгөгдлийг өөрчлөхөд баталгаажуулалт шаардлагатай - - - - Change your own user data - Өөрийн хэрэглэгчийн өгөгдлийг өөрчлөх - - - - Authentication is required to change user data - Хэрэглэгчийн өгөгдлийг өөрчлөхийн тулд баталгаажуулалт шаардлагатай - - - - Manage user accounts - Хэрэглэгчийн бүртгэлийн зохицуулах - - - - Authentication is required to enable auto login - Автоматаар нэвтрэхийг идэвхжүүлэхийн тулд баталгаажуулалт шаардлагатай - - - - Enable Auto Login - Автоматаар нэвтэрхийг идэвхжүүлэх - - - - Authentication is required to disable auto login - Автоматаар нэвтрэхийг цуцлахын тулд баталгаажуулалт шаардлагатай - - - - Disable Auto Login - Автоматаар нэвтэрхийг цуцлах - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Нууц үг ашиглалгүйгээр нэвтэрхийг идэвхжүүлэхийн тулд баталгаажуулалт шаардлагатай - - - - Enable Login without password - Нууц үг ашиглахгүйгээр нэвтрэхийг идэвхжүүлэх - - - - Authentication is required to disable login without password - Нууц үг ашиглалгүйгээр нэвтэрхийг цуцлахын тулд баталгаажуулалт шаардлагатай - - - - Disable Login without password - Нууц үг ашиглахгүйгээр нэвтрэхийг цуцлах - - - - Authentication is required to set keyboard layout - Гарын байрлалыг тохируулхын тулд баталгаажуулалт шаардлагатай - - - - Set keyboard layout - Гарын байрлал тохируулах - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_mr.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_mr.ts deleted file mode 100644 index 4fe5da665..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_mr.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ms.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ms.ts deleted file mode 100644 index 27f8abd26..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ms.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Pengesahihan diperlukan untuk mengubah data pengguna anda sendiri - - - - Change your own user data - Ubah data pengguna anda sendiri - - - - Authentication is required to change user data - Pengesahihan diperlukan untuk mengubah data pengguna - - - - Manage user accounts - Urus akaun pengguna - - - - Authentication is required to enable auto login - Pengesahihan diperlukan untuk membolehkan daftar masuk automatik - - - - Enable Auto Login - Benarkan Daftar Masuk Automatik - - - - Authentication is required to disable auto login - Pengesahihan diperlukan untuk melumpuhkan daftar masuk automatik - - - - Disable Auto Login - Lumpuhkan Daftar Masuk Automatik - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Pengesahihan diperlukan untuk membolehkan daftar masuk tanpa kata laluan - - - - Enable Login without password - Benarkan Daftar masuk tanpa kata laluan - - - - Authentication is required to disable login without password - Pengesahihan diperlukan untuk melumpuhkan daftar masuk tanpa kata laluan - - - - Disable Login without password - Lumpuhkan Daftar masuk tanpa kata laluan - - - - Authentication is required to set keyboard layout - Pengesahihan diperlukan untuk menetapkan bentangan papan kekunci - - - - Set keyboard layout - Tetapkan bentangan papan kekunci - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_nb.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_nb.ts deleted file mode 100644 index c8ba364cd..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_nb.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ne.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ne.ts deleted file mode 100644 index c8664d4a6..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ne.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - तपाईंको प्रयोगकर्ता डेटा परिवर्तन गर्न प्रमाणीकरण आवश्यक छ - - - - Change your own user data - आफ्नो प्रयोगकर्ता डेटा परिवर्तन गर्नुहोस् - - - - Authentication is required to change user data - प्रयोगकर्ता डेटा परिवर्तन गर्न प्रमाणीकरण आवश्यक छ - - - - Manage user accounts - प्रयोगकर्ता खाताहरू व्यवस्थापन गर्नुहोस् - - - - Authentication is required to enable auto login - स्वत: लगइन एनबल गर्न प्रमाणीकरण आवश्यक छ - - - - Enable Auto Login - स्वत: लगइन सक्षम गर्नुहोस् - - - - Authentication is required to disable auto login - स्वत: लगइन असक्षम गर्न प्रमाणीकरण आवश्यक छ - - - - Disable Auto Login - स्वत: लगइन अक्षम गर्नुहोस् - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - पासवर्ड बिना लगइन सक्षम गर्न प्रमाणीकरण आवश्यक छ - - - - Enable Login without password - पासवर्ड बिना लगइन सक्षम गर्नुहोस् - - - - Authentication is required to disable login without password - पासवर्ड बिना लगइन असक्षम गर्न प्रमाणीकरण आवश्यक छ - - - - Disable Login without password - पासवर्ड बिना लगइन असक्षम पार्नुहोस् - - - - Authentication is required to set keyboard layout - किबोर्ड लेआउट सेट गर्न प्रमाणीकरण आवश्यक छ - - - - Set keyboard layout - किबोर्ड लेआउट सेट गर्नुहोस् - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_nl.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_nl.ts deleted file mode 100644 index c94d176f1..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_nl.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Authenticatie vereist om je eigen gebruikersgegevens aan te passen - - - - Change your own user data - Eigen gebruikersgegevens aanpassen - - - - Authentication is required to change user data - Authenticatie vereist om gebruikersgegevens aan te passen - - - - Manage user accounts - Gebruikersaccounts beheren - - - - Authentication is required to enable auto login - Authenticatie vereist om automatisch aanmelden in te schakelen - - - - Enable Auto Login - Automatisch aanmelden inschakelen - - - - Authentication is required to disable auto login - Authenticatie vereist om automatisch aanmelden uit te schakelen - - - - Disable Auto Login - Automatisch aanmelden uitschakelen - - - - Authentication is required to enable quick login - Verificatie vereist om snel aanmelden in te schakelen - - - - Enable Quick Login - Snel aanmelden inschakelen - - - - Authentication is required to disable quick login - Verificatie vereist om snel aanmelden uit te schakelen - - - - Disable Quick Login - Snel aanmelden uitschakelen - - - - Authentication is required to enable login without password - Authenticatie vereist om aanmelden zonder wachtwoord in te schakelen - - - - Enable Login without password - Aanmelden zonder wachtwoord inschakelen - - - - Authentication is required to disable login without password - Authenticatie vereist om aanmelden zonder wachtwoord uit te schakelen - - - - Disable Login without password - Aanmelden zonder wachtwoord uitschakelen - - - - Authentication is required to set keyboard layout - Authenticatie vereist om de toetsenbordindeling te wijzigen - - - - Set keyboard layout - Toetsenbordindeling instellen - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_pa.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_pa.ts deleted file mode 100644 index 703daa6b1..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_pa.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - ਤੁਹਾਡਾ ਯੂਜ਼ਰ ਡਾਟਾ ਬਦਲਣ ਲਈ ਪਰਮਾਣਿਤ ਹੋਣ ਦੀ ਲੋੜ ਹੈ - - - - Change your own user data - ਆਪਣਾ ਯੂਜ਼ਰ ਡਾਟਾ ਬਦਲੋ - - - - Authentication is required to change user data - ਯੂਜ਼ਰ ਡਾਟਾ ਬਦਲਣ ਲਈ ਪਰਮਾਣਿਤ ਹੋਣ ਦੀ ਲੋੜ ਹੈ - - - - Manage user accounts - ਯੂਜ਼ਰ ਅਕਾਊਂਟ ਪਰਬੰਧ - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_pam.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_pam.ts deleted file mode 100644 index 9f2d18aea..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_pam.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_pl.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_pl.ts deleted file mode 100644 index e82a95fd4..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_pl.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Wymagane jest uwierzytelnienie, aby zmienić własne dane - - - - Change your own user data - Zmiana własnych danych - - - - Authentication is required to change user data - Wymagane jest uwierzytelnienie, aby zmienić dane użytkownika - - - - Manage user accounts - Zarządzanie kontami użytkowników - - - - Authentication is required to enable auto login - Wymagane jest uwierzytelnienie, aby włączyć automatyczne logowanie - - - - Enable Auto Login - Włącz automatyczne logowanie - - - - Authentication is required to disable auto login - Wymagane jest uwierzytelnienie, aby wyłączyć automatyczne logowanie - - - - Disable Auto Login - Wyłącz automatyczne logowanie - - - - Authentication is required to enable quick login - Wymagane jest uwierzytelnienie, aby włączyć szybkie logowanie - - - - Enable Quick Login - Włącz szybkie logowanie - - - - Authentication is required to disable quick login - Wymagane jest uwierzytelnienie, aby wyłączyć szybkie logowanie - - - - Disable Quick Login - Wyłącz szybkie logowanie - - - - Authentication is required to enable login without password - Wymagane jest uwierzytelnienie, aby włączyć logowanie bez podawania hasła - - - - Enable Login without password - Włącz logowanie bez podawania hasła - - - - Authentication is required to disable login without password - Wymagane jest uwierzytelnienie, aby wyłączyć logowanie bez podawania hasła - - - - Disable Login without password - Wyłącz logowanie bez podawania hasła - - - - Authentication is required to set keyboard layout - Wymagane jest uwierzytelnienie, aby ustawić układ klawiatury - - - - Set keyboard layout - Ustaw układ klawiatury - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ps.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ps.ts deleted file mode 100644 index 7b4a86b5d..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ps.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_pt.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_pt.ts deleted file mode 100644 index b8215a2e4..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_pt.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - É necessária a autenticação para alterar os seus próprios dados de utilizador - - - - Change your own user data - Alterar os seus próprios dados de utilizador - - - - Authentication is required to change user data - É necessária a autenticação para alterar os dados de utilizador - - - - Manage user accounts - Gerir contas de utilizador - - - - Authentication is required to enable auto login - É necessária a autenticação para ativar o início de sessão automático - - - - Enable Auto Login - Ativar o início de sessão automático - - - - Authentication is required to disable auto login - É necessária a autenticação para desativar o início de sessão automático - - - - Disable Auto Login - Desativar o início de sessão automático - - - - Authentication is required to enable quick login - É necessária autenticação para ativar o início de sessão rápido - - - - Enable Quick Login - Ativar o início de sessão rápido - - - - Authentication is required to disable quick login - É necessária autenticação para desativar o início de sessão rápido - - - - Disable Quick Login - Desativar o início de sessão rápido - - - - Authentication is required to enable login without password - É necessária a autenticação para ativar o início de sessão sem palavra-passe - - - - Enable Login without password - Ativar o início de sessão sem palavra-passe - - - - Authentication is required to disable login without password - É necessária a autenticação para desativar o início de sessão sem palavra-passe - - - - Disable Login without password - Desativar o início de sessão sem palavra-passe - - - - Authentication is required to set keyboard layout - É necessária a autenticação para definir o esquema do teclado - - - - Set keyboard layout - Definir esquema do teclado - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_pt_BR.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_pt_BR.ts deleted file mode 100644 index 0634a1579..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_pt_BR.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - A autenticação é necessária para alterar os dados do usuário - - - - Change your own user data - Alterar seus próprios dados de usuário - - - - Authentication is required to change user data - A autenticação é necessária para alterar os dados do usuário - - - - Manage user accounts - Gerenciar Contas de Usuário - - - - Authentication is required to enable auto login - A autenticação é necessária para ativar o login automático - - - - Enable Auto Login - Login automático - - - - Authentication is required to disable auto login - A autenticação é necessária para desativar o login automático - - - - Disable Auto Login - Login automático - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - A autenticação é necessária para ativar o login sem senha - - - - Enable Login without password - Login sem senha - - - - Authentication is required to disable login without password - A autenticação é necessária para desativar o login sem senha - - - - Disable Login without password - Login sem senha - - - - Authentication is required to set keyboard layout - A autenticação é necessária para alterar o layout de teclado - - - - Set keyboard layout - Definir o layout de teclado - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ro.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ro.ts deleted file mode 100644 index 060bda56b..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ro.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Autentificarea este necesară pentru a vă schimba propriile date de utilizator - - - - Change your own user data - Modificați-vă datele de utilizator - - - - Authentication is required to change user data - Autentificarea este necesară pentru a modifica date de utilizator - - - - Manage user accounts - Administrați conturile de utilizator - - - - Authentication is required to enable auto login - Autentificarea este necesară pentru a activa autentificarea automată - - - - Enable Auto Login - Activați autentificarea automată - - - - Authentication is required to disable auto login - Autentificarea este necesară pentru a dezactiva autentificarea automată - - - - Disable Auto Login - Dezactivați autentificarea automată - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Autentificarea este necesară pentru a activa autentificarea fără parolă - - - - Enable Login without password - Activați autentificarea fără parolă - - - - Authentication is required to disable login without password - Autentificarea este necesară pentru a dezactiva autentificarea fără parolă - - - - Disable Login without password - Dezactivați autentificarea fără parolă - - - - Authentication is required to set keyboard layout - Autentificarea este necesară pentru a modifica aspectul tastaturii - - - - Set keyboard layout - Modificați aspectul tastaturii - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ru.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ru.ts deleted file mode 100644 index 36e754091..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ru.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Для изменения личных пользовательских данных требуется аутентификация - - - - Change your own user data - Изменить личные пользовательские данные - - - - Authentication is required to change user data - Для изменения пользовательских данных требуется аутентификация - - - - Manage user accounts - Управление учётными записями пользователей - - - - Authentication is required to enable auto login - Для активации автоматического входа требуется аутентификация - - - - Enable Auto Login - Активировать автоматический вход - - - - Authentication is required to disable auto login - Для отключения автоматического входа требуется аутентификация - - - - Disable Auto Login - Отключить Автоматический Вход - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Для активации входа без ввода пароля требуется аутентификация - - - - Enable Login without password - Активировать Вход без ввода пароля - - - - Authentication is required to disable login without password - Для отключения входа без ввода пароля требуется аутентификация - - - - Disable Login without password - Отключить Вход без ввода пароля - - - - Authentication is required to set keyboard layout - Для того чтобы задать раскладку клавиатуры требуется аутентификация - - - - Set keyboard layout - Задать раскладку клавиатуры - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ru_UA.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ru_UA.ts deleted file mode 100644 index e1b329bbd..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ru_UA.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_sc.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_sc.ts deleted file mode 100644 index c1c8d4e44..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_sc.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_si.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_si.ts deleted file mode 100644 index d88de362f..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_si.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - ඔබේ පරිශීලක දත්ත වෙනස් කිරීමට සත්‍යාපනය අවශ්‍ය වේ - - - - Change your own user data - ඔබේ පරිශීලක දත්ත වෙනස් කරන්න - - - - Authentication is required to change user data - පරිශීලක දත්ත වෙනස් කිරීම සඳහා සත්‍යාපනය අවශ්‍ය වේ - - - - Manage user accounts - පරිශීලක ගිණුම් කළමනාකරණය කරන්න - - - - Authentication is required to enable auto login - ස්වයංක්‍රීය පිවිසුම සක්‍රීය කිරීම සඳහා සත්‍යාපනය අවශ්‍ය වේ - - - - Enable Auto Login - ස්වයංක්‍රීය පිවිසුම සක්‍රීය කරන්න - - - - Authentication is required to disable auto login - ස්වයංක්‍රීය පිවිසුම අක්‍රිය කිරීමට සත්‍යාපනය අවශ්‍ය වේ - - - - Disable Auto Login - ස්වයංක්‍රීය පිවිසුම අක්‍රීය කරන්න - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - මුරපදය නොමැතිව පිවිසීම සක්‍රිය කිරීම සඳහා සත්‍යාපනය අවශ්‍ය වේ - - - - Enable Login without password - මුරපදය නොමැතිව පිවිසීම සක්‍රීය කරන්න - - - - Authentication is required to disable login without password - මුරපදය නොමැතිව පිවීසීම අක්‍රිය කිරීමට සත්‍යාපනය අවශ්‍ය වේ - - - - Disable Login without password - මුරපදය නොමැතිව පිවිසීම අක්‍රීය කරන්න - - - - Authentication is required to set keyboard layout - යතුරු පුවරුවේ පිරිවිතර සැකසීමට සත්‍යාපනය අවශ්‍ය වේ - - - - Set keyboard layout - යතුරු පුවරුවේ පිරිවිතර සකසන්න - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_sk.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_sk.ts deleted file mode 100644 index a2e44d327..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_sk.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Na zmenu vlastných používateľských údajov je potrebné overenie totožnosti - - - - Change your own user data - Zmeniť svoje vlastné používateľské údaje - - - - Authentication is required to change user data - Na zmenu používateľských údajov je potrebné overenie totožnosti - - - - Manage user accounts - Spravovať používateľské účty - - - - Authentication is required to enable auto login - Na automatické prihlásenie sa vyžaduje overenie - - - - Enable Auto Login - Povoliť automatické prihlásenie - - - - Authentication is required to disable auto login - Na zakázanie automatického prihlásenia sa vyžaduje overenie - - - - Disable Auto Login - Zakázať automatické prihlásenie - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Na povolenie automatického prihlásenia bez hesla sa vyžaduje overenie - - - - Enable Login without password - Povoliť prihlásenie bez hesla - - - - Authentication is required to disable login without password - Na zakázanie automatického prihlásenia bez hesla sa vyžaduje overenie - - - - Disable Login without password - Zakázať prihlásenie bez hesla - - - - Authentication is required to set keyboard layout - Na nastavenie rozloženia klávesnice je potrebné overenie - - - - Set keyboard layout - Nastavte rozloženie klávesnice - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_sl.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_sl.ts deleted file mode 100644 index ff4d3bb36..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_sl.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Za spremembo lastnih podatkov je zahtevana overitev - - - - Change your own user data - Spremenite uporabniške podatke - - - - Authentication is required to change user data - Srememba podatkov uporabnika zahteva overitev - - - - Manage user accounts - Upravljanje uporabniških računov - - - - Authentication is required to enable auto login - Vklop samodejne prijave zahteva overitev - - - - Enable Auto Login - Vklopi samodejno prijavo - - - - Authentication is required to disable auto login - Izklop samodejne prijave zahteva overitev - - - - Disable Auto Login - Izklopi samodejno prijavo - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Prijava brez gesla zahteva overitev - - - - Enable Login without password - Vklopi prijavo brez gesla - - - - Authentication is required to disable login without password - Izklop prijave brez gesla zahteva overitev - - - - Disable Login without password - Izklopi prijavo brez gesla - - - - Authentication is required to set keyboard layout - Sprememba razporeda tipkovnice zahteva overitev - - - - Set keyboard layout - Določi razpored tipkovnice - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_sq.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_sq.ts deleted file mode 100644 index c3ccadb86..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_sq.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Që të ndryshoni të dhënat tuaja të përdoruesit, lypset mirëfilltësim - - - - Change your own user data - Ndryshoni të dhënat tuaja të përdoruesit - - - - Authentication is required to change user data - Që të ndryshoni të dhëna përdoruesi, lypset mirëfilltësim - - - - Manage user accounts - Administroni llogari përdoruesish - - - - Authentication is required to enable auto login - Që të aktivizoni hyrje të automatizuara, lypset mirëfilltësim - - - - Enable Auto Login - Aktivizoni Hyrje të Automatizuara - - - - Authentication is required to disable auto login - Që të çaktivizoni hyrje të automatizuara, lypset mirëfilltësim - - - - Disable Auto Login - Çaktivizoni Hyrje të Automatizuara - - - - Authentication is required to enable quick login - Që të aktivizohet hyrje e shpejtë, lypset mirëfilltësim - - - - Enable Quick Login - Aktivizo Hyrje të Shpejtë - - - - Authentication is required to disable quick login - Që të çaktivizohet hyrje e shpejtë, lypset mirëfilltësim - - - - Disable Quick Login - Çaktivizo Hyrje të Shpejtë - - - - Authentication is required to enable login without password - Që të aktivizoni hyrje pa fjalëkalim, lypset mirëfilltësim - - - - Enable Login without password - Aktivizoni Hyrje pa fjalëkalim - - - - Authentication is required to disable login without password - Që të çaktivizoni hyrje pa fjalëkalim, lypset mirëfilltësim - - - - Disable Login without password - Çaktivizoni Hyrje pa fjalëkalim - - - - Authentication is required to set keyboard layout - Që të caktoni skemë tastiere, lypset mirëfilltësim - - - - Set keyboard layout - Caktoni skemë tastiere - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_sr.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_sr.ts deleted file mode 100644 index b964c119f..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_sr.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Идентификација је неопходна за промену сопствених корисничких података - - - - Change your own user data - Промените сопствене корисничке податке - - - - Authentication is required to change user data - Идентификација је неопходна за промену корисничких података - - - - Manage user accounts - Управљај корисничким налозима - - - - Authentication is required to enable auto login - Идентификација је неопходна да се омогући аутоматско пријављивање - - - - Enable Auto Login - Омогући аутоматско пријављивање - - - - Authentication is required to disable auto login - Идентификација је неопходна да се онемогући аутоматско пријављивање - - - - Disable Auto Login - Онемогући аутоматско пријављивање - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Идентификација је неопходна да се омогући пријављивање без лозинке - - - - Enable Login without password - Омогући пријављивање без лозинке - - - - Authentication is required to disable login without password - Идентификација је неопходна да се онемогући пријављивање без лозинке - - - - Disable Login without password - Онемогући пријављивање без лозинке - - - - Authentication is required to set keyboard layout - Идентификација је неопходна за подешавање распореда тастатуре - - - - Set keyboard layout - Подеси распоред тастатуре - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_sv.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_sv.ts deleted file mode 100644 index 74b9751ff..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_sv.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Autentisering krävs för att ändra ditt egna användardata - - - - Change your own user data - Ändra ditt egna användardata - - - - Authentication is required to change user data - Autentisering krävs för att ändra användardata - - - - Manage user accounts - Hantera användarkonton - - - - Authentication is required to enable auto login - Autentisering krävs för att aktivera automatisk inloggning - - - - Enable Auto Login - Aktivera automatisk inloggning - - - - Authentication is required to disable auto login - Autentisering krävs för att inaktivera automatisk inloggning - - - - Disable Auto Login - Inaktivera automatisk inloggning - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Autentisering krävs för att aktivera inloggning utan lösenord - - - - Enable Login without password - Aktivera inloggning utan lösenord - - - - Authentication is required to disable login without password - Autentisering krävs för att inaktivera inloggning utan lösenord - - - - Disable Login without password - Inaktivera inloggning utan lösenord - - - - Authentication is required to set keyboard layout - Autentisering krävs för att ändra tangentbordslayout - - - - Set keyboard layout - Ändra tangentbordslayout - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_sv_SE.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_sv_SE.ts deleted file mode 100644 index d84e6f51f..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_sv_SE.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_sw.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_sw.ts deleted file mode 100644 index 33d44cba3..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_sw.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Thibitisha inahitaji kugeuza taarifa ya mtumiaji yako - - - - Change your own user data - Geuza taarifa ya mtumiaji yako - - - - Authentication is required to change user data - Thibitisha inahitaji kugeuza taarifa za mtumiaji - - - - Manage user accounts - Simamia akaunti za mtumiaji - - - - Authentication is required to enable auto login - Thibitisha inahitaji kuwezesha kuingia moja kwa moja - - - - Enable Auto Login - Wezesha kuingia moja kwa moja - - - - Authentication is required to disable auto login - Thibitisha inahitaji kulemaza kuingia moja kwa moja - - - - Disable Auto Login - Lemaza kuingia moja kwa moja - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Thibitisha inahitaji kuwezesha kuingia bila nywila - - - - Enable Login without password - Wezesha kuingia bila nywila - - - - Authentication is required to disable login without password - Thibitisha inahitaji kulemaza kuingia bila nywila - - - - Disable Login without password - Lemaza kuingia bila nywila - - - - Authentication is required to set keyboard layout - Thibitisha inahitaji kuchagua mpangilio wa kibodi - - - - Set keyboard layout - Chagua mpangilio wa kibodi - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ta.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ta.ts deleted file mode 100644 index 5bc17ad24..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ta.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_te.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_te.ts deleted file mode 100644 index 794ed5471..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_te.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_th.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_th.ts deleted file mode 100644 index 3a2399164..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_th.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_tr.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_tr.ts deleted file mode 100644 index 7a5ee9ae5..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_tr.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Kullanıcı verilerinizi değiştirmek için kimlik doğrulaması gerekli - - - - Change your own user data - Kullanıcı bilgilerinizi değiştirin - - - - Authentication is required to change user data - Kullanıcı verilerini değiştirmek için kimlik doğrulaması gerekli - - - - Manage user accounts - Kullanıcı hesaplarını yönet - - - - Authentication is required to enable auto login - Otomatik oturum açmayı etkinleştirmek için kimlik doğrulaması gerekli - - - - Enable Auto Login - Otomatik Girişi Etkinleştir - - - - Authentication is required to disable auto login - Otomatik girişi devre dışı bırakmak için kimlik doğrulaması gerekli - - - - Disable Auto Login - Otomatik Giriş Devre Dışı - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Parola olmadan oturum açmak için kimlik doğrulaması gerekli - - - - Enable Login without password - Parola olmadan oturum açmayı etkinleştir - - - - Authentication is required to disable login without password - Parola olmadan oturum açmayı devre dışı bırakmak için kimlik doğrulaması gerekli - - - - Disable Login without password - Parola olmadan oturum açma devre dışı - - - - Authentication is required to set keyboard layout - Klavye düzenini ayarlamak için kimlik doğrulaması gerekli - - - - Set keyboard layout - Klavye düzenini ayarla - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_tzm.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_tzm.ts deleted file mode 100644 index 6767afc3b..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_tzm.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ug.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ug.ts deleted file mode 100644 index 0fd06e846..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ug.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - ئۆزىڭىزنىڭ ئابونت سانلىق مەلۇماتىنى ئۆزگەرتىش ئۈچۈن سالاھىيىتىڭىزنى دەلىللەشكە توغرا كېلىدۇ - - - - Change your own user data - ئۆزىڭىزنىڭ ئابونت سانلىق مەلۇماتىنى ئۆزگەرتىڭ - - - - Authentication is required to change user data - ئابونىت سانلىق مەلۇماتىنى ئۆزگەرتىش ئۈچۈن سالاھىيەت سالاھىتىڭىزنى دەلىىللەڭ - - - - Manage user accounts - ئابونىت ھېسابات نۇمىرىنى باشقۇرۇش - - - - Authentication is required to enable auto login - ئاپتۇماتىك تىزىملاش ئۈچۈن سالاھىتىڭىزنى دەللىللەشكە توغرا كىلىدۇ - - - - Enable Auto Login - ئاپتۇماتىك كىرىشنى ئېچىش - - - - Authentication is required to disable auto login - ئاپتۇماتىك كىرىشنى تاقاش ئۈچۈن سالاھىيەت دەلىللەش كېرەك - - - - Disable Auto Login - ئاپتۇماتىك تىزىملاپ كىرىشنى چەكلەش - - - - Authentication is required to enable quick login - تېزلەتمە كىرىشنى ئېچىش ئۈچۈن سالاھىيەت دەلىللەش كېرەك - - - - Enable Quick Login - تېزلەتمە كىرىشنى ئېچىش - - - - Authentication is required to disable quick login - تېزلەتمە كىرىشنى تاقاش ئۈچۈن سالاھىيەت دەلىللەش كېرەك - - - - Disable Quick Login - تېزلەتمە كىرىشنى تاقاش - - - - Authentication is required to enable login without password - مەخپى نۇمۇرسىز كىرىش ئۈچۈن سالاھىيەت دەلىللەشكە توغرا كىلىدۇ - - - - Enable Login without password - ئابونىت مەخپى شىفىرسىز كىرىش - - - - Authentication is required to disable login without password - مەخپى شىفىرسىز كىرىشنى توىتىتىش ئۈچۈن سالاھىيەت دەللىللەش كېرەك - - - - Disable Login without password - مەخپى شىفىرسىز كىرىشنى چەكلەش - - - - Authentication is required to set keyboard layout - كۇنۇپكا تاختىسى ئورۇنلاشتۇرۇش ئۈچۈن سالاھىيىتىنى تەكشۈرۈشكە توغرا كېلىدۇ - - - - Set keyboard layout - كونۇپكا تاختىىسى تەڭشەش - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_uk.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_uk.ts deleted file mode 100644 index dfaace0a6..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_uk.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Для зміни даних вашого користувача потрібно пройти розпізнавання - - - - Change your own user data - Зміна даних вашого користувача - - - - Authentication is required to change user data - Для зміни даних користувача потрібно пройти розпізнавання - - - - Manage user accounts - Керування обліковими записами - - - - Authentication is required to enable auto login - Для вмикання автоматично входу слід пройти розпізнавання - - - - Enable Auto Login - Вмикання автоматичного входу - - - - Authentication is required to disable auto login - Для вимикання автоматичного входу слід пройти розпізнавання - - - - Disable Auto Login - Вимикання автоматичного входу - - - - Authentication is required to enable quick login - Для вмикання швидкого входу слід пройти розпізнавання - - - - Enable Quick Login - Вмикання швидкого входу - - - - Authentication is required to disable quick login - Для вимикання швидкого входу слід пройти розпізнавання - - - - Disable Quick Login - Вимикання швидкого входу - - - - Authentication is required to enable login without password - Для вмикання можливості входу без пароля слід пройти розпізнавання - - - - Enable Login without password - Вмикання входу без пароля - - - - Authentication is required to disable login without password - Для вимикання можливості входу без пароля слід пройти розпізнавання - - - - Disable Login without password - Вимикання входу без пароля - - - - Authentication is required to set keyboard layout - Для встановлення розкладки клавіатури слід пройти розпізнавання - - - - Set keyboard layout - Встановлення розкладки клавіатури - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_ur.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_ur.ts deleted file mode 100644 index fcaef563b..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_ur.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_uz.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_uz.ts deleted file mode 100644 index 49f8a6ef9..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_uz.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - - - - - Change your own user data - - - - - Authentication is required to change user data - - - - - Manage user accounts - - - - - Authentication is required to enable auto login - - - - - Enable Auto Login - - - - - Authentication is required to disable auto login - - - - - Disable Auto Login - - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - - - - - Enable Login without password - - - - - Authentication is required to disable login without password - - - - - Disable Login without password - - - - - Authentication is required to set keyboard layout - - - - - Set keyboard layout - - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_vi.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_vi.ts deleted file mode 100644 index 291aa4db1..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_vi.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - Cần xác thực để thay đổi dữ liệu người dùng của chính mình - - - - Change your own user data - Thay đổi dữ liệu người dùng của chính mình - - - - Authentication is required to change user data - Cần xác thực để thay đổi dữ liệu người dùng - - - - Manage user accounts - Quản lý tài khoản người dùng - - - - Authentication is required to enable auto login - Cần xác thực để cho phép tự động đăng nhập - - - - Enable Auto Login - Cho phép Tự động Đăng nhập - - - - Authentication is required to disable auto login - Cần xác thực để vô hiệu hóa tự động đăng nhập - - - - Disable Auto Login - Vô hiệu hóa Tự động Đăng nhập - - - - Authentication is required to enable quick login - - - - - Enable Quick Login - - - - - Authentication is required to disable quick login - - - - - Disable Quick Login - - - - - Authentication is required to enable login without password - Cần xác thực để cho phép đăng nhập mà không cần mật mã - - - - Enable Login without password - Kích hoạt đăng nhập không cần mật khẩu - - - - Authentication is required to disable login without password - Cần có xác thực để vô hiệu hóa đăng nhập mà không cần mật khẩu - - - - Disable Login without password - Vô hiệu hóa Đăng nhập mà không cần mật khẩu - - - - Authentication is required to set keyboard layout - Cần xác thực để đặt bố cục bàn phím - - - - Set keyboard layout - Cài đặt bố cục bàn phím - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_zh_CN.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_zh_CN.ts deleted file mode 100644 index 73ff01973..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_zh_CN.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - 修改您的用户数据需要认证 - - - - Change your own user data - 修改您的用户数据 - - - - Authentication is required to change user data - 修改用户数据需要认证 - - - - Manage user accounts - 管理用户帐户 - - - - Authentication is required to enable auto login - 开启自动登录需要认证 - - - - Enable Auto Login - 开启自动登录 - - - - Authentication is required to disable auto login - 关闭自动登录需要认证 - - - - Disable Auto Login - 关闭自动登录 - - - - Authentication is required to enable quick login - 开启快速登录需要认证 - - - - Enable Quick Login - 开启快速登录 - - - - Authentication is required to disable quick login - 关闭快速登录需要认证 - - - - Disable Quick Login - 关闭快速登录 - - - - Authentication is required to enable login without password - 开启无密码登录需要认证 - - - - Enable Login without password - 开启无密码登录 - - - - Authentication is required to disable login without password - 关闭无密码登录需要认证 - - - - Disable Login without password - 关闭无密码登录 - - - - Authentication is required to set keyboard layout - 设置键盘布局需要认证 - - - - Set keyboard layout - 设置键盘布局 - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_zh_HK.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_zh_HK.ts deleted file mode 100644 index 178d0d291..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_zh_HK.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - 修改您的用戶數據需要認證 - - - - Change your own user data - 修改您的用戶數據 - - - - Authentication is required to change user data - 修改用戶數據需要認證 - - - - Manage user accounts - 管理用戶帳戶 - - - - Authentication is required to enable auto login - 開啟自動登錄需要認證 - - - - Enable Auto Login - 開啟自動登錄 - - - - Authentication is required to disable auto login - 關閉自動登錄需要認證 - - - - Disable Auto Login - 關閉自動登錄 - - - - Authentication is required to enable quick login - 開啟快速登錄需要認證 - - - - Enable Quick Login - 開啟快速登錄 - - - - Authentication is required to disable quick login - 關閉快速登錄需要認證 - - - - Disable Quick Login - 關閉快速登錄 - - - - Authentication is required to enable login without password - 開啟無密碼登錄需要認證 - - - - Enable Login without password - 開啟無密碼登錄 - - - - Authentication is required to disable login without password - 關閉無密碼登錄需要認證 - - - - Disable Login without password - 關閉無密碼登錄 - - - - Authentication is required to set keyboard layout - 設置鍵盤佈局需要認證 - - - - Set keyboard layout - 設置鍵盤佈局 - - - \ No newline at end of file diff --git a/misc/ts/com.deepin.daemon.accounts.policy/policy_zh_TW.ts b/misc/ts/com.deepin.daemon.accounts.policy/policy_zh_TW.ts deleted file mode 100644 index 9601c1aaa..000000000 --- a/misc/ts/com.deepin.daemon.accounts.policy/policy_zh_TW.ts +++ /dev/null @@ -1,95 +0,0 @@ - - - policy - - - Authentication is required to change your own user data - 若要變更您自身的使用者資料需要通過認證 - - - - Change your own user data - 變更您自身的使用者資料 - - - - Authentication is required to change user data - 若要變更使用者資料需要通過認證 - - - - Manage user accounts - 管理使用者帳戶 - - - - Authentication is required to enable auto login - 啟用自動登入需要身份核對 - - - - Enable Auto Login - 啟用自動登入 - - - - Authentication is required to disable auto login - 停用自動登入需要身份核對 - - - - Disable Auto Login - 停用自動登入 - - - - Authentication is required to enable quick login - 開啟快速登入需要認證 - - - - Enable Quick Login - 開啟快速登入 - - - - Authentication is required to disable quick login - 關閉快速登入需要認證 - - - - Disable Quick Login - 關閉快速登入 - - - - Authentication is required to enable login without password - 啟用無密碼登入需要身份核對 - - - - Enable Login without password - 啟用無密碼登入 - - - - Authentication is required to disable login without password - 停用無密碼登入需要身份核對 - - - - Disable Login without password - 停用無密碼登入 - - - - Authentication is required to set keyboard layout - 設定鍵盤配置需要身份核對 - - - - Set keyboard layout - 設定鍵盤配置 - - - \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy.ts new file mode 100644 index 000000000..ef05ded06 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Authentication is required to add fingerprint password + + + + Add fingerprint password + Add fingerprint password + + + + Authentication is required to clear fingerprint passwords + Authentication is required to clear fingerprint passwords + + + + Clear fingerprint passwords + Clear fingerprint passwords + + + + Authentication is required to rename fingerprint password + Authentication is required to rename fingerprint password + + + + Rename fingerprint password + Rename fingerprint password + + + + Password is required to perform this action + Password is required to perform this action + + + + Manage fingerprint passwords + Manage fingerprint passwords + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ady.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ady.ts new file mode 100644 index 000000000..8d360570e --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ady.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_af.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_af.ts new file mode 100644 index 000000000..2606787f1 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_af.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_af_ZA.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_af_ZA.ts new file mode 100644 index 000000000..7c16058c7 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_af_ZA.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ak.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ak.ts new file mode 100644 index 000000000..50889b38a --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ak.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_am.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_am.ts new file mode 100644 index 000000000..7dd2b6516 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_am.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_am_ET.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_am_ET.ts new file mode 100644 index 000000000..a22629853 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_am_ET.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ar.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ar.ts new file mode 100644 index 000000000..c9d8c9fdf --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ar.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + المصادقة ضرورية لإضافة كلمة مرور بالبصمة + + + + Add fingerprint password + إضافة كلمة مرور ببصمة الأصبع + + + + Authentication is required to clear fingerprint passwords + المصادقة ضرورية لحذف كلمات المرور بالبصمة + + + + Clear fingerprint passwords + حذف كلمات المرور بالبصمة + + + + Authentication is required to rename fingerprint password + المصادقة ضرورية لإعادة تسمية كلمة المرور بالبصمة + + + + Rename fingerprint password + إعادة تسمية كلمة المرور بالبصمة + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ar_EG.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ar_EG.ts new file mode 100644 index 000000000..9df82e85d --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ar_EG.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ast.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ast.ts new file mode 100644 index 000000000..574168288 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ast.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_az.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_az.ts new file mode 100644 index 000000000..c8cb98f45 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_az.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Barmaq izi şifrəsini əlavə etmək üçün doğrulama tələb edilir + + + + Add fingerprint password + Barmaq izi şifrəsi əlavə etmək + + + + Authentication is required to clear fingerprint passwords + Barmaq izi şifrəsini silmək üçün doğrulama tələb edilir + + + + Clear fingerprint passwords + Barmaq izi şifrəsini silmək + + + + Authentication is required to rename fingerprint password + Barmaq izi şifrəsinin adını dəyişmək üçün doğrulama tələb edilir + + + + Rename fingerprint password + Barmaq izi şifrəsinin adını dəyişmək + + + + Password is required to perform this action + Bu əməlin icra edilməsi üçün şifrə tələb olunur + + + + Manage fingerprint passwords + Barmaq izi şifrələrinin idarə edilməsi + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_bg.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_bg.ts new file mode 100644 index 000000000..e93d960de --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_bg.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_bn.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_bn.ts new file mode 100644 index 000000000..51f35aab3 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_bn.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_bo.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_bo.ts new file mode 100644 index 000000000..738f881c2 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_bo.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + མཛུབ་རིས་སྣོན་པར་ར་སྤྲོད་བྱེད་དགོས། + + + + Add fingerprint password + མཛུབ་རིས་གསང་ཨང་སྣོན་པ། + + + + Authentication is required to clear fingerprint passwords + མཛུབ་རིས་མེད་པ་བཟོ་ཚེ་ར་སྤྲོད་བྱེད་དགོས། + + + + Clear fingerprint passwords + མཛུབ་རིས་གསང་ཨང་མེད་པར་བཟོ་བ། + + + + Authentication is required to rename fingerprint password + མཛུབ་རིས་བསྐྱར་དུ་འདོགས་ཚེ་ར་སྤྲོད་བྱེད་དགོས། + + + + Rename fingerprint password + མཛུབ་རིས་མིང་བསྐྱར་དུ་འདོགས་པ། + + + + Password is required to perform this action + གསང་ཨང་བཅུག་རྗེས་བཀོལ་སྤྱོད་འདི་ལག་བསྟར་བྱེད་པ། + + + + Manage fingerprint passwords + མཛུབ་རིས་གསང་ཨང་དོ་དམ། + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_bqi.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_bqi.ts new file mode 100644 index 000000000..7c12da9c2 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_bqi.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_br.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_br.ts new file mode 100644 index 000000000..86637fefa --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_br.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ca.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ca.ts new file mode 100644 index 000000000..6ce0e07cc --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ca.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Cal autenticació per afegir una contrasenya d'empremta. + + + + Add fingerprint password + Afegiu una contrasenya d'empremta + + + + Authentication is required to clear fingerprint passwords + Cal autenticació per netejar contrasenyes d'empremta. + + + + Clear fingerprint passwords + Neteja les contrasenyes d'empremta + + + + Authentication is required to rename fingerprint password + Cal autenticació per canviar de nom una contrasenya d'empremta. + + + + Rename fingerprint password + Canvia de nom la contrasenya d'empremta + + + + Password is required to perform this action + Cal la contrasenya per realitzar aquesta acció + + + + Manage fingerprint passwords + Gestiona les contrasenyes d'empremta + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_cgg.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_cgg.ts new file mode 100644 index 000000000..5c4cdd01e --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_cgg.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_cs.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_cs.ts new file mode 100644 index 000000000..0dc99e7dc --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_cs.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Pro přidání hesla zastupovaného otiskem prstu je požadováno ověření se + + + + Add fingerprint password + Přidat heslo zastupované otiskem prstu + + + + Authentication is required to clear fingerprint passwords + Pro smazání hesel zastupovaných otiskem prstu je požadováno ověření se + + + + Clear fingerprint passwords + Smazat hesla zastupovaná otiskem prstu + + + + Authentication is required to rename fingerprint password + Pro přejmenování hesla, zastupovaného otiskem prstu, je požadováno ověření se + + + + Rename fingerprint password + Přejmenovat heslo zastupované otiskem prstu + + + + Password is required to perform this action + Pro provedení této akce je zapotřebí zadat heslo + + + + Manage fingerprint passwords + Spravovat hesla zastupovaná otiskem prstu + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_da.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_da.ts new file mode 100644 index 000000000..7f980006b --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_da.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Der kræves autentifikation for at tilføje fingeraftryksadgangskode + + + + Add fingerprint password + Tilføj fingeraftryksadgangskode + + + + Authentication is required to clear fingerprint passwords + Der kræves autentifikation for at rydde fingeraftryksadgangskoder + + + + Clear fingerprint passwords + Ryd fingeraftryksadgangskoder + + + + Authentication is required to rename fingerprint password + Der kræves autentifikation for at omdøbe fingeraftryksadgangskode + + + + Rename fingerprint password + Omdøb fingeraftryksadgangskode + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_de.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_de.ts new file mode 100644 index 000000000..720712006 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_de.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Zum Hinzufügen des Fingerabdruckpassworts ist eine Authentifizierung erforderlich + + + + Add fingerprint password + Fingerabdruckpasswort hinzufügen + + + + Authentication is required to clear fingerprint passwords + Zum Löschen von Fingerabdruckpasswörtern ist eine Authentifizierung erforderlich + + + + Clear fingerprint passwords + Fingerabdruckpasswörter löschen + + + + Authentication is required to rename fingerprint password + Zum Umbenennen des Fingerabdruckpassworts ist eine Authentifizierung erforderlich + + + + Rename fingerprint password + Fingerabdruckpasswort umbenennen + + + + Password is required to perform this action + Zur Durchführung dieser Aktion ist ein Passwort erforderlich + + + + Manage fingerprint passwords + Fingerabdruckpasswörter verwalten + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_de_CH.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_de_CH.ts new file mode 100644 index 000000000..6330c61d0 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_de_CH.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_de_DE.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_de_DE.ts new file mode 100644 index 000000000..8dfc2e688 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_de_DE.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Sie müssen sich authentifizieren, um das Anmelden per Fingerabdruck hinzuzufügen + + + + Add fingerprint password + Fingerabdruck-Daten hinzufügen + + + + Authentication is required to clear fingerprint passwords + Sie müssen sich authentifizieren, um die Fingerabdruck-Daten zu löschen + + + + Clear fingerprint passwords + Fingerabdruck-Daten löschen + + + + Authentication is required to rename fingerprint password + Sie müssen sich authentifizieren, um Fingerabdruck-Daten neu zu benennen + + + + Rename fingerprint password + Fingerabdruck-Daten neu benennen + + + + Password is required to perform this action + Sie müssen das Passwort eingeben, um diese Aktion auszuführen + + + + Manage fingerprint passwords + Fingerabdruck-Daten verwalten + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_el.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_el.ts new file mode 100644 index 000000000..eed9bdcb1 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_el.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Απαιτείται πιστοποίηση για προσθήκη κωδικού αποτυπώματος + + + + Add fingerprint password + Προσθήκη κωδικού αποτυπώματος + + + + Authentication is required to clear fingerprint passwords + Απαιτείται πιστοποίηση για διαγραφή κωδικών αποτυπώματος + + + + Clear fingerprint passwords + Διαγραφή κωδικών αποτυπωμάτων + + + + Authentication is required to rename fingerprint password + Απαιτείται πιστοποίηση για μετονομασία κωδικού αποτυπώματος + + + + Rename fingerprint password + Μετονομασία κωδικού αποτυπώματος + + + + Password is required to perform this action + Απαιτείται κωδικός για εκτέλεση αυτής της ενέργειας + + + + Manage fingerprint passwords + Διαχείρηση κωδικών αποτυπωμάτων + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_el_GR.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_el_GR.ts new file mode 100644 index 000000000..4c6054be4 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_el_GR.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_en_AU.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_en_AU.ts new file mode 100644 index 000000000..50e7d9547 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_en_AU.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Authentication is required to add fingerprint password + + + + Add fingerprint password + Add fingerprint password + + + + Authentication is required to clear fingerprint passwords + Authentication is required to clear fingerprint passwords + + + + Clear fingerprint passwords + Clear fingerprint passwords + + + + Authentication is required to rename fingerprint password + Authentication is required to rename fingerprint password + + + + Rename fingerprint password + Rename fingerprint password + + + + Password is required to perform this action + Password is required to perform this action + + + + Manage fingerprint passwords + Manage fingerprint passwords + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_en_GB.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_en_GB.ts new file mode 100644 index 000000000..1beedc81f --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_en_GB.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_en_NO.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_en_NO.ts new file mode 100644 index 000000000..bb3d647ff --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_en_NO.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_en_US.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_en_US.ts new file mode 100644 index 000000000..c29aa7fad --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_en_US.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Authentication is required to add fingerprint password + + + + Add fingerprint password + Add fingerprint password + + + + Authentication is required to clear fingerprint passwords + Authentication is required to clear fingerprint passwords + + + + Clear fingerprint passwords + Clear fingerprint passwords + + + + Authentication is required to rename fingerprint password + Authentication is required to rename fingerprint password + + + + Rename fingerprint password + Rename fingerprint password + + + + Password is required to perform this action + Password is required to perform this action + + + + Manage fingerprint passwords + Manage fingerprint passwords + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_eo.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_eo.ts new file mode 100644 index 000000000..f63003848 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_eo.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_es.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_es.ts new file mode 100644 index 000000000..d4e1e8597 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_es.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Se requiere autenticación para añadir contraseña de huella dactilar + + + + Add fingerprint password + Añadir contraseña de huella dactilar + + + + Authentication is required to clear fingerprint passwords + Se requiere autenticación para borrar contraseñas de huellas dactilares. + + + + Clear fingerprint passwords + Borrar contraseñas de huellas dactilares + + + + Authentication is required to rename fingerprint password + Se requiere autenticación para renombrar la contraseña huella dactilar + + + + Rename fingerprint password + Renombrar contraseña de huella dactilar + + + + Password is required to perform this action + Se requiere contraseña para realizar esta acción + + + + Manage fingerprint passwords + Administrar contraseñas de huellas digitales + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_es_MX.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_es_MX.ts new file mode 100644 index 000000000..725288301 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_es_MX.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_et.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_et.ts new file mode 100644 index 000000000..4c5b1cd3c --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_et.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_eu.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_eu.ts new file mode 100644 index 000000000..afd82886a --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_eu.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_fa.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_fa.ts new file mode 100644 index 000000000..c2a6b54aa --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_fa.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + برای اضافه کردن رمزعبور اثر انگشت ، احراز هویت لازم است + + + + Add fingerprint password + اضافه کردن رمزعبور اثر انگشت + + + + Authentication is required to clear fingerprint passwords + برای پاک کردن رمزهای عبور اثر انگشت ، احراز هویت لازم است + + + + Clear fingerprint passwords + رمزهای عبور اثر انگشت را پاک کن + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_fi.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_fi.ts new file mode 100644 index 000000000..373b74b95 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_fi.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Sormenjälkitunnuksen lisääminen edellyttää todennusta + + + + Add fingerprint password + Lisää sormenjälki salasanaksi + + + + Authentication is required to clear fingerprint passwords + Sormenjälkien tyhjentäminen edellyttää todennusta + + + + Clear fingerprint passwords + Tyhjennä sormenjäljet + + + + Authentication is required to rename fingerprint password + Nimeä sormenjälki uudelleen, tämä vaatii tunnistautumisen + + + + Rename fingerprint password + Nimeä sormenjäljen salasana uudelleen + + + + Password is required to perform this action + Tämän suorittamiseen tarvitaan salasana + + + + Manage fingerprint passwords + Hallitse sormenjälkien tunnuksia + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_fil.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_fil.ts new file mode 100644 index 000000000..dfbee5f23 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_fil.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_fr.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_fr.ts new file mode 100644 index 000000000..089f7bb81 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_fr.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Une authentification est requise pour ajouter une empreinte digitale comme mot de passe + + + + Add fingerprint password + Ajouter une empreinte digitale comme mot de passe + + + + Authentication is required to clear fingerprint passwords + Une authentification est requise pour effacer les empreintes digitales enregistrées + + + + Clear fingerprint passwords + Effacer les empreintes digitales enregistrées + + + + Authentication is required to rename fingerprint password + Une authentification est requise pour changer le mot de passe d'une empreinte digitale + + + + Rename fingerprint password + Changer le mot de passe d'une empreinte digitale + + + + Password is required to perform this action + Mot de passe requis pour effectuer cette action + + + + Manage fingerprint passwords + Gérer les empreintes digitales + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_gl.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_gl.ts new file mode 100644 index 000000000..fa7b561c5 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_gl.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_gl_ES.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_gl_ES.ts new file mode 100644 index 000000000..d4ab6f0d3 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_gl_ES.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Requírese autenticación para engadir un contrasinal para a pegada dixital + + + + Add fingerprint password + Engadir un contrasinal para a pegada dixital + + + + Authentication is required to clear fingerprint passwords + Requírese autenticación para eliminar os contrasinais das pegadas dixitais + + + + Clear fingerprint passwords + Eliminar os contrasinais das pegadas dixitais + + + + Authentication is required to rename fingerprint password + Requírese autenticación para mudar o contrasinal da pegada dixital + + + + Rename fingerprint password + Mudar o contrasinal da pegada dixital + + + + Password is required to perform this action + Requírese un contrasinal para realizar esta acción + + + + Manage fingerprint passwords + Xestionar contrasinais de pegadas dixitais + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_he.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_he.ts new file mode 100644 index 000000000..99558abce --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_he.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_hi_IN.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_hi_IN.ts new file mode 100644 index 000000000..284ed6b24 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_hi_IN.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_hr.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_hr.ts new file mode 100644 index 000000000..ab22a6eb6 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_hr.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Potrebna je ovjera za dodavanje lozinke otiska prsta + + + + Add fingerprint password + Dodaj lozinku otiska prsta + + + + Authentication is required to clear fingerprint passwords + Potrebna je ovjera za čišćenje lozinki otiska prsta + + + + Clear fingerprint passwords + Očisti lozinke otiska prsta + + + + Authentication is required to rename fingerprint password + Potrebna je ovjera za preimenovanje lozinke otiska prsta + + + + Rename fingerprint password + Preimenuj lozinku otiska prsta + + + + Password is required to perform this action + Potrebna je lozinka da bi ste izveli ovu radnju + + + + Manage fingerprint passwords + Upravljajte lozinkama otiska prsta + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_hu.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_hu.ts new file mode 100644 index 000000000..bb87933d2 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_hu.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Hitelesítés szükséges az ujjlenyomat azonosítók hozzáadásához + + + + Add fingerprint password + Ujjlenyomat azonosító hozzáadása + + + + Authentication is required to clear fingerprint passwords + Hitelesítés szükséges az ujjlenyomat azonosítók törléséhez + + + + Clear fingerprint passwords + Ujjlenyomatok törlése + + + + Authentication is required to rename fingerprint password + Hitelesítés szükséges az ujjlenyomat azonosító átnevezéséhez + + + + Rename fingerprint password + Ujjlenyomat azonosító átnevezése + + + + Password is required to perform this action + A művelet végrehajtásához jelszó szükséges + + + + Manage fingerprint passwords + Ujjlenyomat azonosítók kezelése + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_hy.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_hy.ts new file mode 100644 index 000000000..47960a52e --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_hy.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_id.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_id.ts new file mode 100644 index 000000000..72f6de7eb --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_id.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Otentikasi diperlukan untuk menambahkan password sidik jari + + + + Add fingerprint password + Tambah password sidik jari + + + + Authentication is required to clear fingerprint passwords + Otentikasi diperlukan untuk membersihkan password sidik jari + + + + Clear fingerprint passwords + Bersihkan password sidik jari + + + + Authentication is required to rename fingerprint password + Otentikasi diperlukan untuk mengganti nama password sidik jari + + + + Rename fingerprint password + Ubah nama password sidik jari + + + + Password is required to perform this action + Kata sandi diperlukan untuk melakukan tindakan ini + + + + Manage fingerprint passwords + Kelola password sidik jari + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_id_ID.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_id_ID.ts new file mode 100644 index 000000000..4676d00c1 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_id_ID.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_it.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_it.ts new file mode 100644 index 000000000..d6622b2a1 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_it.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Autenticazione richiesta per aggiungere l'impronta digitale come password + + + + Add fingerprint password + Aggiungi impronta digitale come password + + + + Authentication is required to clear fingerprint passwords + Autenticazione richiesta per eliminare l'impronta digitale come password + + + + Clear fingerprint passwords + Cancella impronte digitali utilizzare come password + + + + Authentication is required to rename fingerprint password + Autenticazione richiesta per rinominare l'impronta digitale + + + + Rename fingerprint password + Rinomina l'impronta digitale + + + + Password is required to perform this action + Password richiesta per questa operazione + + + + Manage fingerprint passwords + Gestisci le impronte digitali + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ja.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ja.ts new file mode 100644 index 000000000..45209f007 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ja.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + 指紋パスワードを追加するには認証が必要です + + + + Add fingerprint password + 指紋パスワードを追加 + + + + Authentication is required to clear fingerprint passwords + 指紋パスワードを削除するには認証が必要です + + + + Clear fingerprint passwords + 指紋パスワードを削除 + + + + Authentication is required to rename fingerprint password + 指紋パスワードの名前を変更するには認証が必要です + + + + Rename fingerprint password + 指紋パスワードの名前を変更 + + + + Password is required to perform this action + この操作にはパスワードが必要です + + + + Manage fingerprint passwords + 指紋パスワードを管理 + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ka.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ka.ts new file mode 100644 index 000000000..32fbd5b66 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ka.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_kab.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_kab.ts new file mode 100644 index 000000000..4d6f7e510 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_kab.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Asesteb yettusra i tmerna n wawal uffir n udsil umḍin + + + + Add fingerprint password + Rnu awal uffir n udsil umḍin + + + + Authentication is required to clear fingerprint passwords + Asesteb yettusra i usfaḍ n wawalen uffiren n udsil umḍin + + + + Clear fingerprint passwords + Sfeḍ wawalen uffiren n udsil umḍin + + + + Authentication is required to rename fingerprint password + Asesteb yettusra i ubeddel n yisem + + + + Rename fingerprint password + Beddl isem i wawal uffir n udsil umḍin + + + + Password is required to perform this action + Yettusra wawal uffir i uselken n tigawt-a + + + + Manage fingerprint passwords + Sefrek awalen uffiren n udsil umḍin + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_kk.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_kk.ts new file mode 100644 index 000000000..579babc1d --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_kk.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_km_KH.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_km_KH.ts new file mode 100644 index 000000000..3edefba36 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_km_KH.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_kn_IN.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_kn_IN.ts new file mode 100644 index 000000000..6ae92ddd9 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_kn_IN.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ko.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ko.ts new file mode 100644 index 000000000..b6cb3f219 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ko.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + 지문 암호를 추가하려면 인증이 필요합니다 + + + + Add fingerprint password + 지문 암호 추가 + + + + Authentication is required to clear fingerprint passwords + 지문 암호를 지우려면 인증이 필요합니다 + + + + Clear fingerprint passwords + 지문 암호 지우기 + + + + Authentication is required to rename fingerprint password + 지문 암호의 이름을 변경하려면 인증이 필요함 + + + + Rename fingerprint password + 지문 암호 이름 변경 + + + + Password is required to perform this action + 이 작업을 수행하려면 암호가 필요함 + + + + Manage fingerprint passwords + 지문 암호 관리 + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ku.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ku.ts new file mode 100644 index 000000000..b7ab0e75b --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ku.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ku_IQ.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ku_IQ.ts new file mode 100644 index 000000000..f7048771f --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ku_IQ.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ky.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ky.ts new file mode 100644 index 000000000..801791138 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ky.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ky@Arab.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ky@Arab.ts new file mode 100644 index 000000000..33073200e --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ky@Arab.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_la.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_la.ts new file mode 100644 index 000000000..6e102ba94 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_la.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_lo.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_lo.ts new file mode 100644 index 000000000..a54d47921 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_lo.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_lt.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_lt.ts new file mode 100644 index 000000000..df512e50d --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_lt.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Norint pridėti piršto atspaudo slaptažodį, reikalingas tapatybės nustatymas + + + + Add fingerprint password + Pridėti piršto atspaudo slaptažodį + + + + Authentication is required to clear fingerprint passwords + Norint išvalyti piršto atspaudo slaptažodžius, reikalingas tapatybės nustatymas + + + + Clear fingerprint passwords + Išvalyti piršto atspaudo slaptažodžius + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_lv.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_lv.ts new file mode 100644 index 000000000..4b67bd2bd --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_lv.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ml.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ml.ts new file mode 100644 index 000000000..422b4d0c0 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ml.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_mn.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_mn.ts new file mode 100644 index 000000000..8ad8d7c44 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_mn.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_mr.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_mr.ts new file mode 100644 index 000000000..6a9309f22 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_mr.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ms.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ms.ts new file mode 100644 index 000000000..419b6161f --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ms.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Pengesahihan diperlukan untuk menambah kata laluan cap jari + + + + Add fingerprint password + Tambah kata laluan cap jari + + + + Authentication is required to clear fingerprint passwords + Pengesahihan diperlukan untuk mengosongkan kata laluan cap jari + + + + Clear fingerprint passwords + Kosongkan kata laluan cap jari + + + + Authentication is required to rename fingerprint password + Pengesahihan diperlukan untuk menamakan semula kata laluan cap jari + + + + Rename fingerprint password + Namakan semula kata laluan cap jari + + + + Password is required to perform this action + Kata laluan diperlukan untuk membuat tindakan ini + + + + Manage fingerprint passwords + Urus kata laluan cap jari + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_nb.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_nb.ts new file mode 100644 index 000000000..13bb14ace --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_nb.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ne.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ne.ts new file mode 100644 index 000000000..24a2b41cc --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ne.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_nl.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_nl.ts new file mode 100644 index 000000000..eab74e2f7 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_nl.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Authenticatie vereist om vingerafdrukken toe te voegen + + + + Add fingerprint password + Wachtwoord voor vingerafdrukken toevoegen + + + + Authentication is required to clear fingerprint passwords + Authenticatie vereist om vingerafdrukken te wissen + + + + Clear fingerprint passwords + Vingerafdrukken wissen + + + + Authentication is required to rename fingerprint password + Authenticatie is vereist om vingerafdruknamen te wijzigen + + + + Rename fingerprint password + Vingerafdruknamen wijzigen + + + + Password is required to perform this action + Voer je wachtwoord in om deze actie uit te voeren + + + + Manage fingerprint passwords + Vingerafdrukwachtwoorden beheren + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_pa.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_pa.ts new file mode 100644 index 000000000..124e57547 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_pa.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_pam.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_pam.ts new file mode 100644 index 000000000..649872860 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_pam.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_pl.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_pl.ts new file mode 100644 index 000000000..6adcc8d96 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_pl.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Wymagane jest uwierzytelnienie do dodania hasła odcisku palca + + + + Add fingerprint password + Dodaj hasło odcisku palca + + + + Authentication is required to clear fingerprint passwords + Wymagane jest uwierzytelnienie do wyczyszczenia haseł odcisków palców + + + + Clear fingerprint passwords + Wyczyść hasła odcisków palców + + + + Authentication is required to rename fingerprint password + Wymagane jest uwierzytelnienie do zmiany nazwy hasła odcisku palca + + + + Rename fingerprint password + Zmień nazwę hasła odcisku palca + + + + Password is required to perform this action + Do wykonania tej czynności wymagane jest hasło + + + + Manage fingerprint passwords + Zarządzaj hasłami odcisków palców + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ps.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ps.ts new file mode 100644 index 000000000..ea0731003 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ps.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_pt.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_pt.ts new file mode 100644 index 000000000..806683130 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_pt.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + É necessária a autenticação para adicionar palavra-passe de impressão digital + + + + Add fingerprint password + Adicionar palavra-passe de impressão digital + + + + Authentication is required to clear fingerprint passwords + É necessária a autenticação para limpar palavras-passe de impressões digitais + + + + Clear fingerprint passwords + Limpar palavras-passe de impressão digital + + + + Authentication is required to rename fingerprint password + É necessária a autenticação para renomear a palavra-passe de impressão digital + + + + Rename fingerprint password + Renomear a palavra-passe de impressão digital + + + + Password is required to perform this action + Para realizar esta ação é necessária uma palavra-passe + + + + Manage fingerprint passwords + Gerir as palavras-passe das impressões digitais + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_pt_BR.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_pt_BR.ts new file mode 100644 index 000000000..9ec839ab5 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_pt_BR.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + A autenticação é necessária para adicionar a impressão digital + + + + Add fingerprint password + Adicionar impressão digital + + + + Authentication is required to clear fingerprint passwords + A autenticação é necessária para remover as impressões digitais + + + + Clear fingerprint passwords + Remover as impressões digitais + + + + Authentication is required to rename fingerprint password + A autenticação é necessária para renomear a impressão digital + + + + Rename fingerprint password + Renomear impressão digital + + + + Password is required to perform this action + A senha é necessária para executar esta ação + + + + Manage fingerprint passwords + Gerenciar senhas por impressão digital + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_qu.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_qu.ts new file mode 100644 index 000000000..75a0aab3f --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_qu.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ro.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ro.ts new file mode 100644 index 000000000..1d52070dc --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ro.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Autentificare necesară pentru adăugare parolă amprentă + + + + Add fingerprint password + Adaugă parolă amprentă + + + + Authentication is required to clear fingerprint passwords + Autentificare necesară pentru ştergere parolă amprentă + + + + Clear fingerprint passwords + Ștergere parolă amprentă + + + + Authentication is required to rename fingerprint password + Autentificare necesară pentru redenumire parolă amprentă + + + + Rename fingerprint password + Redenumește parolă cu amprentă + + + + Password is required to perform this action + Parolă necesară să efectuați această acțiune + + + + Manage fingerprint passwords + Administrează parole cu amprentă + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ru.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ru.ts new file mode 100644 index 000000000..f77b65099 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ru.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Требуется аутентификация для добавления пароля по отпечатку пальца + + + + Add fingerprint password + Добавить пароль по отпечатку пальца + + + + Authentication is required to clear fingerprint passwords + Требуется аутентификация для очистки паролей по отпечатку пальца + + + + Clear fingerprint passwords + Очистка паролей по отпечатку пальца + + + + Authentication is required to rename fingerprint password + Требуется аутентификация для переименования пароля отпечатка пальца + + + + Rename fingerprint password + Переименовать пароль отпечатка пальца + + + + Password is required to perform this action + Необходим пароль для выполнения этого действия + + + + Manage fingerprint passwords + Управление паролями отпечатков пальцев + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ru_UA.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ru_UA.ts new file mode 100644 index 000000000..5d03bf1c6 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ru_UA.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sc.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sc.ts new file mode 100644 index 000000000..34ca6c1fd --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sc.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_si.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_si.ts new file mode 100644 index 000000000..77ddceb7b --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_si.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + ඇඟිලි සලකුණු මුරපදය එක් කිරීමට සත්‍යාපනය අවශ්‍ය වේ + + + + Add fingerprint password + ඇඟිලි සලකුණු මුරපදය එක් කරන්න + + + + Authentication is required to clear fingerprint passwords + ඇඟිලි සලකුණු මුරපදය ඉවත් කිරීමට සත්‍යාපනය අවශ්‍ය වේ + + + + Clear fingerprint passwords + ඇඟිලි සලකුණු මුරපදය ඉවත් කරන්න + + + + Authentication is required to rename fingerprint password + ඇඟිලි සලකුණු මුරපදය නැවත නම් කිරීම සඳහා සත්‍යාපනය අවශ්‍ය වේ + + + + Rename fingerprint password + ඇඟිලි සලකුණු මුරපදය නැවත නම් කරන්න + + + + Password is required to perform this action + මෙම ක්‍රියාව සිදු කිරීම සඳහා මුරපදය අවශ්‍ය වේ + + + + Manage fingerprint passwords + ඇඟිලි සලකුණු මුරපද කළමනාකරණය කරන්න + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sk.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sk.ts new file mode 100644 index 000000000..0ea88f4d8 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sk.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Na pridanie hesla pomocou odtlačku prsta je potrebné overenie + + + + Add fingerprint password + Pridať heslo pomocou odtlačku prsta + + + + Authentication is required to clear fingerprint passwords + Na vymazanie hesiel odtlačkov prstov je potrebné overenie + + + + Clear fingerprint passwords + Vymazať heslá odtlačkov prstov + + + + Authentication is required to rename fingerprint password + Na premenovanie hesla odtlačkov prstov sa vyžaduje overenie + + + + Rename fingerprint password + Premenovať heslo odtlačku prstov + + + + Password is required to perform this action + Na vykonanie tejto akcie je potrebné heslo + + + + Manage fingerprint passwords + Spravovať heslá odtlačkov prstov + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sl.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sl.ts new file mode 100644 index 000000000..73f902f69 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sl.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Dodajanje prstnega odtisa zahteva overitev + + + + Add fingerprint password + Dodaj prstni odtis + + + + Authentication is required to clear fingerprint passwords + Odstranjevanje prstnega odtsia zahteva overitev + + + + Clear fingerprint passwords + Odstrani prstni odtis + + + + Authentication is required to rename fingerprint password + Preimenovanje prstnega odtisa zahteva overitev + + + + Rename fingerprint password + Preimenuj prstni odtis + + + + Password is required to perform this action + To dejanje zahteva overitev + + + + Manage fingerprint passwords + Upravljanje prstnih odtisov + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sq.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sq.ts new file mode 100644 index 000000000..3062c87fb --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sq.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Që të shtoni fjalëkalim shenjash gishti, lypset mirëfilltësim + + + + Add fingerprint password + Shtoni fjalëkalim shenjash gishti + + + + Authentication is required to clear fingerprint passwords + Që të spastrohen fjalëkalime shenjash gishti, lypset mirëfilltësim + + + + Clear fingerprint passwords + Spastro fjalëkalime shenjash gishti + + + + Authentication is required to rename fingerprint password + Që të riemërtoni fjalëkalim shenjash gishti, lypset mirëfilltësim + + + + Rename fingerprint password + Riemërtoni fjalëkalim shenjash gishti + + + + Password is required to perform this action + Që të kryeni këtë veprim, lypset fjalëkalim + + + + Manage fingerprint passwords + Administroni fjalëkalime shenjash gishtash + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sr.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sr.ts new file mode 100644 index 000000000..a6b39b83f --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sr.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Идентификација је неопходна да додате отисак лозинку + + + + Add fingerprint password + Додај отисак лозинку + + + + Authentication is required to clear fingerprint passwords + Идентификација је неопходна да обришете отисак лозинку + + + + Clear fingerprint passwords + Обриши отисак лозинку + + + + Authentication is required to rename fingerprint password + Идентификација је неопходна да преименујете отисак лозинку + + + + Rename fingerprint password + Преименуј отисак лозинку + + + + Password is required to perform this action + Лозинка је потребна за овај поступак + + + + Manage fingerprint passwords + Управљај отисак лозинкама + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sv.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sv.ts new file mode 100644 index 000000000..662c0859d --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sv.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Autentisering krävs för att lägga till fingeravtryck + + + + Add fingerprint password + Lägg till fingeravtryck + + + + Authentication is required to clear fingerprint passwords + Autentisiering krävs för att radera fingeravtryck + + + + Clear fingerprint passwords + Radera fingeravtryck + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sv_SE.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sv_SE.ts new file mode 100644 index 000000000..0f1b63a45 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sv_SE.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sw.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sw.ts new file mode 100644 index 000000000..f1179796b --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_sw.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ta.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ta.ts new file mode 100644 index 000000000..11979be37 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ta.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_te.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_te.ts new file mode 100644 index 000000000..32526b28b --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_te.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_th.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_th.ts new file mode 100644 index 000000000..593318c1b --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_th.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_tr.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_tr.ts new file mode 100644 index 000000000..e3de59b71 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_tr.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Parmak izi parolası eklemek için kimlik doğrulaması gerekli + + + + Add fingerprint password + Parmak izi parolası ekle + + + + Authentication is required to clear fingerprint passwords + Parmak izi parolalarını silmek için kimlik doğrulaması gerekli + + + + Clear fingerprint passwords + Parmak izi parolalarını temizle + + + + Authentication is required to rename fingerprint password + Parmak izi parolasını yeniden adlandırmak için kimlik doğrulaması gerekli + + + + Rename fingerprint password + Parmak izi parolasını yeniden adlandır + + + + Password is required to perform this action + Bu işlemi gerçekleştirmek için parola gerekli + + + + Manage fingerprint passwords + Parmak izi parolalarını yönet + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_tzm.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_tzm.ts new file mode 100644 index 000000000..22c35269a --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_tzm.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ug.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ug.ts new file mode 100644 index 000000000..4692d67b6 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ug.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + بارماق ئىزىنى قوشۇش دەلىللەشنى تەلەپ قىلىدۇ + + + + Add fingerprint password + بارماق ئىزى پارولى قوشۇڭ + + + + Authentication is required to clear fingerprint passwords + بارماق ئىزىنى ئېلىۋېتىش دەلىللەشنى تەلەپ قىلىدۇ + + + + Clear fingerprint passwords + بارماق ئىزى پارولىنى ئېلىۋېتىش + + + + Authentication is required to rename fingerprint password + بارماق ئىزىنىنىڭ نامىنى ئۆزگەرتىش دەلىللەشنى تەلەپ قىلىدۇ + + + + Rename fingerprint password + بارماق ئىزى پارولىنىڭ نامىنى ئۆزگەرتىش + + + + Password is required to perform this action + بۇ مەشغۇلاتنى قىلىش ئۈچۈن پارول كىرگۈزۈڭ + + + + Manage fingerprint passwords + بارماق ئىزى پارولىنى باشقۇرۇش + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_uk.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_uk.ts new file mode 100644 index 000000000..55941602a --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_uk.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Для додавання пароля до відбитка слід пройти розпізнавання + + + + Add fingerprint password + Додавання пароля до відбитка + + + + Authentication is required to clear fingerprint passwords + Для вилучення паролів до відбитків слід пройти розпізнавання + + + + Clear fingerprint passwords + Вилучення паролів до відбитків + + + + Authentication is required to rename fingerprint password + Для зміни пароля до відбитка слід пройти розпізнавання + + + + Rename fingerprint password + Зміна пароля до відбитка + + + + Password is required to perform this action + Для виконання цієї дії слід вказати пароль + + + + Manage fingerprint passwords + Керування паролями до відбитків + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ur.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ur.ts new file mode 100644 index 000000000..a5b944a81 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_ur.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_uz.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_uz.ts new file mode 100644 index 000000000..57fa80c6d --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_uz.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + + + + + Add fingerprint password + + + + + Authentication is required to clear fingerprint passwords + + + + + Clear fingerprint passwords + + + + + Authentication is required to rename fingerprint password + + + + + Rename fingerprint password + + + + + Password is required to perform this action + + + + + Manage fingerprint passwords + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_vi.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_vi.ts new file mode 100644 index 000000000..fe0c08535 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_vi.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + Yêu cầu xác thực để thêm vân tay + + + + Add fingerprint password + Thêm dấu vân tay + + + + Authentication is required to clear fingerprint passwords + Yêu cầu xác thực để xoá dấu vân tay + + + + Clear fingerprint passwords + Xoá dấu vân tay + + + + Authentication is required to rename fingerprint password + Yêu cầu xác thực để đổi tên mật khẩu vân tay + + + + Rename fingerprint password + Đổi tên mật khẩu vân tay + + + + Password is required to perform this action + Mật khẩu là cần thiết để thực hiện hành động này + + + + Manage fingerprint passwords + Quản lý mật khẩu vân tay + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_zh_CN.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_zh_CN.ts new file mode 100644 index 000000000..8833e41c0 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_zh_CN.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + 添加指纹需要认证 + + + + Add fingerprint password + 添加指纹密码 + + + + Authentication is required to clear fingerprint passwords + 清除指纹需要认证 + + + + Clear fingerprint passwords + 清除指纹密码 + + + + Authentication is required to rename fingerprint password + 重命名指纹需要认证 + + + + Rename fingerprint password + 重命名指纹密码 + + + + Password is required to perform this action + 请输入密码以执行该操作 + + + + Manage fingerprint passwords + 管理指纹密码 + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_zh_HK.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_zh_HK.ts new file mode 100644 index 000000000..8427c1e4b --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_zh_HK.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + 添加指紋需要認證 + + + + Add fingerprint password + 添加指紋密碼 + + + + Authentication is required to clear fingerprint passwords + 清除指紋需要認證 + + + + Clear fingerprint passwords + 清除指紋密碼 + + + + Authentication is required to rename fingerprint password + 重命名指紋需要認證 + + + + Rename fingerprint password + 重命名指紋密碼 + + + + Password is required to perform this action + 請輸入密碼以執行該操作 + + + + Manage fingerprint passwords + 管理指紋密碼 + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Fprintd1.policy/policy_zh_TW.ts b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_zh_TW.ts new file mode 100644 index 000000000..938b87b38 --- /dev/null +++ b/misc/ts/org.deepin.dde.Fprintd1.policy/policy_zh_TW.ts @@ -0,0 +1,45 @@ + + + policy + + + Authentication is required to add fingerprint password + 需要身份驗證才可新增指紋密碼 + + + + Add fingerprint password + 新增指紋密碼 + + + + Authentication is required to clear fingerprint passwords + 需要身份驗證才可清除指紋密碼 + + + + Clear fingerprint passwords + 清除指紋密碼 + + + + Authentication is required to rename fingerprint password + 重命名指紋需要認證 + + + + Rename fingerprint password + 重命名指紋密碼 + + + + Password is required to perform this action + 請輸入密碼以執行該操作 + + + + Manage fingerprint passwords + 管理指紋密碼 + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy.ts new file mode 100644 index 000000000..0e51ddf68 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy.ts @@ -0,0 +1,27 @@ + + + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ady.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ady.ts new file mode 100644 index 000000000..45ae97bcc --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ady.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_af.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_af.ts new file mode 100644 index 000000000..53939e677 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_af.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_af_ZA.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_af_ZA.ts new file mode 100644 index 000000000..b3953f28e --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_af_ZA.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ak.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ak.ts new file mode 100644 index 000000000..a45609866 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ak.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_am.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_am.ts new file mode 100644 index 000000000..ebeded23e --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_am.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_am_ET.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_am_ET.ts new file mode 100644 index 000000000..c3d24089e --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_am_ET.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ar.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ar.ts new file mode 100644 index 000000000..d39279a47 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ar.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ar_EG.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ar_EG.ts new file mode 100644 index 000000000..04c140601 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ar_EG.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ast.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ast.ts new file mode 100644 index 000000000..4ba0064c6 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ast.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_az.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_az.ts new file mode 100644 index 000000000..9244a6af4 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_az.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + GRUB tənzimləmələrini dəyişdirmək üçün kimlik doğrulaması tələb olunur + + + + Change the grub configuration + GRUB tənzimləməsini dəyişmək + + + + Authentication is required to prepare grub display resolution detection + GRUB ekran icazəsini aşkarlamaq üçün kimlik doğrulaması tələb olunur + + + + Prepare grub display resolution detection + Ekran icazəsinin aşkarlanmasına hazırlıq + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_bg.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_bg.ts new file mode 100644 index 000000000..9313eb2e7 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_bg.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_bn.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_bn.ts new file mode 100644 index 000000000..ba7f3a50c --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_bn.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_bo.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_bo.ts new file mode 100644 index 000000000..1ea084035 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_bo.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + འགོ་སློང་འདེམས་བྱང་གི་སྒྲིག་འགོད་བཟོ་བཅོས་བྱེད་དགོས་ན་བདེན་དཔང་ར་སྤྲོད་བྱེད་དགོས། + + + + Change the grub configuration + འགོ་སློང་འདེམས་བྱང་གི་སྒྲིག་འགོད་བཟོ་བཅོས། + + + + Authentication is required to prepare grub display resolution detection + གྲ་སྒྲིག་འགོ་སློང་འདེམས་བྱང་གི་མངོན་སྟོན་འབྱེད་ཕྱོད་དཔྱད་འཇལ་བྱེད་ཚེ་ར་སྤྲོད་བྱེད་དགོས། + + + + Prepare grub display resolution detection + གྲ་སྒྲིག་འགོ་སློང་འདེམས་བྱང་གི་མངོན་སྟོན་འབྱེད་ཕྱོད་དཔྱད་འཇལ། + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_bqi.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_bqi.ts new file mode 100644 index 000000000..b0f8a10a4 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_bqi.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_br.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_br.ts new file mode 100644 index 000000000..e223afec5 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_br.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ca.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ca.ts new file mode 100644 index 000000000..880494911 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ca.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + Cal autenticació per canviar la configuració del grub. + + + + Change the grub configuration + Canvieu la configuració del grub + + + + Authentication is required to prepare grub display resolution detection + Cal autenticació per preparar la detecció de la resolució de pantalla per al grub. + + + + Prepare grub display resolution detection + Preparació de la detecció de la resolució de pantalla per al grub + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_cgg.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_cgg.ts new file mode 100644 index 000000000..60a6edde5 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_cgg.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_cs.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_cs.ts new file mode 100644 index 000000000..a6b14480c --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_cs.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_da.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_da.ts new file mode 100644 index 000000000..b203fe972 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_da.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_de.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_de.ts new file mode 100644 index 000000000..7cbe2694e --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_de.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_de_CH.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_de_CH.ts new file mode 100644 index 000000000..4a9694bce --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_de_CH.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_de_DE.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_de_DE.ts new file mode 100644 index 000000000..4a615614c --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_de_DE.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_el.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_el.ts new file mode 100644 index 000000000..afda14490 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_el.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_el_GR.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_el_GR.ts new file mode 100644 index 000000000..d3fe34126 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_el_GR.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_en_AU.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_en_AU.ts new file mode 100644 index 000000000..7047db530 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_en_AU.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_en_GB.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_en_GB.ts new file mode 100644 index 000000000..f3bcf77bc --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_en_GB.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_en_NO.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_en_NO.ts new file mode 100644 index 000000000..fb33a30c5 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_en_NO.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_en_US.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_en_US.ts new file mode 100644 index 000000000..8e08a5166 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_en_US.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_eo.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_eo.ts new file mode 100644 index 000000000..28d0f86a4 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_eo.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_es.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_es.ts new file mode 100644 index 000000000..ff86dca17 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_es.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + Se requiere autenticación para modificar la configuración del grub + + + + Change the grub configuration + Cambiar la configuración del grub + + + + Authentication is required to prepare grub display resolution detection + Se requiere autenticación para preparar la detección de resolución de pantalla del grub + + + + Prepare grub display resolution detection + Preparar detección de resolución de pantalla de grub + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_es_419.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_es_419.ts new file mode 100644 index 000000000..465e15f3d --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_es_419.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub2 configuration + Se requiere autenticación para cambiar la configuración de grub2 + + + + Change the grub2 configuration + Cambiar la configuración del grub2 + + + + Authentication is required to prepare grub2 display resolution detection + + + + + Prepare grub2 display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_es_MX.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_es_MX.ts new file mode 100644 index 000000000..433ee9d1c --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_es_MX.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub2 configuration + + + + + Change the grub2 configuration + + + + + Authentication is required to prepare grub2 display resolution detection + + + + + Prepare grub2 display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_et.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_et.ts new file mode 100644 index 000000000..4503930d7 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_et.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_eu.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_eu.ts new file mode 100644 index 000000000..ea69ca6ac --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_eu.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_fa.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_fa.ts new file mode 100644 index 000000000..8385b4731 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_fa.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_fi.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_fi.ts new file mode 100644 index 000000000..27e99dcb4 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_fi.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + Todennus vaaditaan grub-kokoonpanon muuttamiseen + + + + Change the grub configuration + Muuta grub-kokoonpanoa + + + + Authentication is required to prepare grub display resolution detection + Todennus vaaditaan grub-näytön resoluution tunnistamisen valmistelemiseksi + + + + Prepare grub display resolution detection + Valmistele grub-näytön resoluution tunnistus + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_fil.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_fil.ts new file mode 100644 index 000000000..d86184926 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_fil.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_fr.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_fr.ts new file mode 100644 index 000000000..549c22669 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_fr.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_gl.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_gl.ts new file mode 100644 index 000000000..f7cc5bf5e --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_gl.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_gl_ES.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_gl_ES.ts new file mode 100644 index 000000000..728d5e953 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_gl_ES.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_he.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_he.ts new file mode 100644 index 000000000..081dd023d --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_he.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_hi_IN.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_hi_IN.ts new file mode 100644 index 000000000..ce83e2e98 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_hi_IN.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_hr.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_hr.ts new file mode 100644 index 000000000..a6aec1b47 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_hr.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_hu.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_hu.ts new file mode 100644 index 000000000..0e92b4816 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_hu.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + Hitelesítés szükséges a grub konfiguráció módosításához + + + + Change the grub configuration + Módosítsa a grub konfigurációt + + + + Authentication is required to prepare grub display resolution detection + Hitelesítés szükséges a grub képernyőfelbontás érzékeléshez + + + + Prepare grub display resolution detection + Grub képernyőfelbontás érzékelése + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_hy.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_hy.ts new file mode 100644 index 000000000..7c7375173 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_hy.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_id.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_id.ts new file mode 100644 index 000000000..6d46de413 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_id.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_id_ID.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_id_ID.ts new file mode 100644 index 000000000..c468907bd --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_id_ID.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_it.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_it.ts new file mode 100644 index 000000000..f4f9a4b5f --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_it.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ja.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ja.ts new file mode 100644 index 000000000..b2a04dec7 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ja.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ka.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ka.ts new file mode 100644 index 000000000..1c408548c --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ka.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_kab.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_kab.ts new file mode 100644 index 000000000..c8ddb3c89 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_kab.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_kk.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_kk.ts new file mode 100644 index 000000000..8afb3d6f5 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_kk.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_km_KH.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_km_KH.ts new file mode 100644 index 000000000..845c9d78d --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_km_KH.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_kn_IN.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_kn_IN.ts new file mode 100644 index 000000000..a67548631 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_kn_IN.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ko.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ko.ts new file mode 100644 index 000000000..e4d4e4cbf --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ko.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ku.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ku.ts new file mode 100644 index 000000000..a0c28ee77 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ku.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ku_IQ.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ku_IQ.ts new file mode 100644 index 000000000..aeb0021bc --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ku_IQ.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ky.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ky.ts new file mode 100644 index 000000000..9d71bf151 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ky.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ky@Arab.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ky@Arab.ts new file mode 100644 index 000000000..3bf02eb99 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ky@Arab.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_la.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_la.ts new file mode 100644 index 000000000..eb6788f15 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_la.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_lo.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_lo.ts new file mode 100644 index 000000000..91be0eb2c --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_lo.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_lt.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_lt.ts new file mode 100644 index 000000000..67ea2e012 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_lt.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_lv.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_lv.ts new file mode 100644 index 000000000..eff984a43 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_lv.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ml.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ml.ts new file mode 100644 index 000000000..7111c9951 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ml.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_mn.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_mn.ts new file mode 100644 index 000000000..e1729f22f --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_mn.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_mr.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_mr.ts new file mode 100644 index 000000000..3f881b5d6 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_mr.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ms.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ms.ts new file mode 100644 index 000000000..e81c4a9a9 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ms.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_nb.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_nb.ts new file mode 100644 index 000000000..20538454f --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_nb.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ne.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ne.ts new file mode 100644 index 000000000..179f217e0 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ne.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_nl.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_nl.ts new file mode 100644 index 000000000..3ca6bb448 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_nl.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + Verificatie vereist om de grub-instellingen aan te passen + + + + Change the grub configuration + Grub-instellingen aanpassen + + + + Authentication is required to prepare grub display resolution detection + Verificatie vereist om de grub-schermresolutiedetectie voor te bereiden + + + + Prepare grub display resolution detection + Grub-schermresolutiedetectie voorbereiden + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_pa.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_pa.ts new file mode 100644 index 000000000..b2fb08091 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_pa.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_pam.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_pam.ts new file mode 100644 index 000000000..f4516175f --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_pam.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_pl.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_pl.ts new file mode 100644 index 000000000..97d9c440f --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_pl.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + Wymagane jest uwierzytelnienie, aby zmienić konfigurację grub + + + + Change the grub configuration + Zmień konfigurację grub + + + + Authentication is required to prepare grub display resolution detection + Wymagane jest uwierzytelnienie do wykrywania rozdzielczości grub + + + + Prepare grub display resolution detection + Wykrywanie rozdzielczości wyświetlacza grub2 + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ps.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ps.ts new file mode 100644 index 000000000..212544d5d --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ps.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_pt.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_pt.ts new file mode 100644 index 000000000..c55c04395 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_pt.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_pt_BR.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_pt_BR.ts new file mode 100644 index 000000000..d88f1100a --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_pt_BR.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + A autenticação é necessária para alterar a configuração do grub + + + + Change the grub configuration + Alterar configuração do grub + + + + Authentication is required to prepare grub display resolution detection + A autenticação é necessária para a detecção da resolução de exibição do grub + + + + Prepare grub display resolution detection + Prepare a detecção da resolução da tela do grub + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_qu.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_qu.ts new file mode 100644 index 000000000..d3cb43e83 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_qu.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ro.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ro.ts new file mode 100644 index 000000000..bd0eee6c9 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ro.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ru.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ru.ts new file mode 100644 index 000000000..41f743b9b --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ru.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ru_UA.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ru_UA.ts new file mode 100644 index 000000000..0abef31a5 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ru_UA.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_sc.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_sc.ts new file mode 100644 index 000000000..b80b85d00 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_sc.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_si.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_si.ts new file mode 100644 index 000000000..94d173f0d --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_si.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_sk.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_sk.ts new file mode 100644 index 000000000..d81a1476b --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_sk.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_sl.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_sl.ts new file mode 100644 index 000000000..6a9c192e3 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_sl.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_sq.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_sq.ts new file mode 100644 index 000000000..f5d096f52 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_sq.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + Që të ndryshoni formësim për grub, duhet bërë mirëfilltësimi + + + + Change the grub configuration + Ndryshoni formësimin për grub + + + + Authentication is required to prepare grub display resolution detection + Që të përgatitet pikasje qartësie ekrani nga grub, duhet bërë mirëfilltësimi + + + + Prepare grub display resolution detection + Përgatit pikasje qartësie ekrani nga grub + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_sr.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_sr.ts new file mode 100644 index 000000000..364c4ad26 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_sr.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_sv.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_sv.ts new file mode 100644 index 000000000..4d7343f46 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_sv.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_sv_SE.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_sv_SE.ts new file mode 100644 index 000000000..7183a0169 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_sv_SE.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_sw.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_sw.ts new file mode 100644 index 000000000..1abf48fe6 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_sw.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ta.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ta.ts new file mode 100644 index 000000000..1342bc214 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ta.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_te.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_te.ts new file mode 100644 index 000000000..68eb04140 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_te.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_th.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_th.ts new file mode 100644 index 000000000..af6838b5a --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_th.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_tr.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_tr.ts new file mode 100644 index 000000000..c1d135a26 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_tr.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_tzm.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_tzm.ts new file mode 100644 index 000000000..c9d18ee74 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_tzm.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ug.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ug.ts new file mode 100644 index 000000000..9bebc802c --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ug.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + قوزغىتىش تىزىملىكىنىڭ سەپلىمىسىنى ئۆزگەرتىش ئۈچۈن دەلىللىشىڭىز كېرەك + + + + Change the grub configuration + قوزغىتىش تىزىملىكىنىڭ سەپلىمىسىنى ئۆزگەرتىش + + + + Authentication is required to prepare grub display resolution detection + كۆرسىتىش ئېنىقلىق دەرىجىسىنى تەكشۈرۈشنى ئالدىن قوزغىتىش ئۈچۈن دەلىللىشىڭىز كېرەك + + + + Prepare grub display resolution detection + كۆرسىتىش ئېنىقلىق دەرىجىسىنى تەكشۈرۈشنى ئالدىن قوزغىتىش + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_uk.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_uk.ts new file mode 100644 index 000000000..c5a4f11c5 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_uk.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + Для зміни налаштувань grub слід пройти розпізнавання + + + + Change the grub configuration + Зміна налаштувань grub + + + + Authentication is required to prepare grub display resolution detection + Для приготування до виявлення роздільності дисплея у grub слід пройти розпізнавання + + + + Prepare grub display resolution detection + Приготування до виявлення роздільної здатності дисплея у grub + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_ur.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_ur.ts new file mode 100644 index 000000000..2caac1dea --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_ur.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_uz.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_uz.ts new file mode 100644 index 000000000..d6e11f6f8 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_uz.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_vi.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_vi.ts new file mode 100644 index 000000000..6991af00b --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_vi.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + + + + + Change the grub configuration + + + + + Authentication is required to prepare grub display resolution detection + + + + + Prepare grub display resolution detection + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_zh_CN.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_zh_CN.ts new file mode 100644 index 000000000..4775f2528 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_zh_CN.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + 修改启动菜单配置需要认证 + + + + Change the grub configuration + 修改启动菜单配置 + + + + Authentication is required to prepare grub display resolution detection + 预备启动菜单显示分辨率探测需要认证 + + + + Prepare grub display resolution detection + 预备启动菜单显示分辨率探测 + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_zh_HK.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_zh_HK.ts new file mode 100644 index 000000000..c04a4fb37 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_zh_HK.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + 修改啟動菜單配置需要認證 + + + + Change the grub configuration + 修改啟動菜單配置 + + + + Authentication is required to prepare grub display resolution detection + 預備啟動菜單顯示解像度探測需要認證 + + + + Prepare grub display resolution detection + 預備啟動菜單顯示解像度探測 + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.Grub2.policy/policy_zh_TW.ts b/misc/ts/org.deepin.dde.Grub2.policy/policy_zh_TW.ts new file mode 100644 index 000000000..f122e85e4 --- /dev/null +++ b/misc/ts/org.deepin.dde.Grub2.policy/policy_zh_TW.ts @@ -0,0 +1,25 @@ + + + policy + + + Authentication is required to change the grub configuration + 修改啟動選單配置需要認證 + + + + Change the grub configuration + 修改啟動選單配置 + + + + Authentication is required to prepare grub display resolution detection + 預備啟動選單顯示解析度探測需要認證 + + + + Prepare grub display resolution detection + 預備啟動選單顯示解析度探測 + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy.ts new file mode 100644 index 000000000..f077e8475 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Authentication is required to change your own user data + + + + Change your own user data + Change your own user data + + + + Authentication is required to change user data + Authentication is required to change user data + + + + Manage user accounts + Manage user accounts + + + + Authentication is required to enable auto login + Authentication is required to enable auto login + + + + Enable Auto Login + Enable Auto Login + + + + Authentication is required to disable auto login + Authentication is required to disable auto login + + + + Disable Auto Login + Disable Auto Login + + + + Authentication is required to enable quick login + Authentication is required to enable quick login + + + + Enable Quick Login + Enable Quick Login + + + + Authentication is required to disable quick login + Authentication is required to disable quick login + + + + Disable Quick Login + Disable Quick Login + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Authentication is required to enable login without password + + + + Enable Login without password + Enable Login without password + + + + Authentication is required to disable login without password + Authentication is required to disable login without password + + + + Disable Login without password + Disable Login without password + + + + Authentication is required to set keyboard layout + Authentication is required to set keyboard layout + + + + Set keyboard layout + Set keyboard layout + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ady.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ady.ts new file mode 100644 index 000000000..844f06e15 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ady.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_af.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_af.ts new file mode 100644 index 000000000..e741189c1 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_af.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_af_ZA.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_af_ZA.ts new file mode 100644 index 000000000..2392a60b3 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_af_ZA.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ak.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ak.ts new file mode 100644 index 000000000..7f63d56f0 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ak.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_am.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_am.ts new file mode 100644 index 000000000..3bfefe9c2 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_am.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_am_ET.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_am_ET.ts new file mode 100644 index 000000000..5bb4ea873 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_am_ET.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + ማረጋገጫ ያስፈልጋል የ እርስዎን ተጠቃሚ ዳታ ማሰናጃ ለ መቀየር + + + + Change your own user data + የ እርስዎን ተጠቃሚ ዳታ ማሰናጃ መቀየሪያ + + + + Authentication is required to change user data + ማረጋገጫ ያስፈልጋል የ ተጠቃሚ ዳታ ማሰናጃ ለ መቀየር + + + + Manage user accounts + የተጠቃሚ መግለጫዎች አስተዳዳሪ + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ar.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ar.ts new file mode 100644 index 000000000..629be0997 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ar.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + المصادقة مطلوبة لتغيير ملكية بيانات المستخدم الخاصة بك + + + + Change your own user data + تغيير ملكية بيانات المستخدم الخاصة بك + + + + Authentication is required to change user data + المصادقة مطلوبة لتغيير بيانات المستخدم + + + + Manage user accounts + إدارة حسابات المستخدمين + + + + Authentication is required to enable auto login + المصادقة مطلوبة لتمكين تسجيل الدخول التلقائي + + + + Enable Auto Login + تمكين تسجيل الدخول التلقائي + + + + Authentication is required to disable auto login + المصادقة مطلوبة لتعطيل تسجيل الدخول التلقائي + + + + Disable Auto Login + تعطيل تسجيل الدخول التلقائي + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + المصادقة مطلوبة لتمكين تسجيل الدخول بدون كلمة المرور + + + + Enable Login without password + تمكين تسجيل الدخول بدون كلمة المرور + + + + Authentication is required to disable login without password + المصادقة مطلوبة لتعطيل تسجيل الدخول بدون كلمة المرور + + + + Disable Login without password + تعطيل تسجيل الدخول بدون كلمة المرور + + + + Authentication is required to set keyboard layout + المصادقة مطلوبة لإعداد تخطيط لوحة المفاتيح + + + + Set keyboard layout + إعداد لوحة المفاتيح + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ar_EG.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ar_EG.ts new file mode 100644 index 000000000..711da02af --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ar_EG.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ast.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ast.ts new file mode 100644 index 000000000..8ad25a239 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ast.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Ríquese l'autenticación pa camudar los tos datos d'usuariu + + + + Change your own user data + Camudar los tos datos d'usuariu + + + + Authentication is required to change user data + Ríquese l'autenticación pa camudar los datos d'usuariu + + + + Manage user accounts + Xestionar cuentes d'usuariu + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_az.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_az.ts new file mode 100644 index 000000000..80cb536af --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_az.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Sizə aid istifadəçi məlumatlarınızı dəyişmək üçün doğrulama tələb edilir + + + + Change your own user data + Öz istifadəçi məlumatlarınızı dəyişin + + + + Authentication is required to change user data + İstifadəçi məlumatlarını dəyişmək üçün doğrulama tələb edilir + + + + Manage user accounts + İstifadəçi hesablarının idarə edilməsi + + + + Authentication is required to enable auto login + Avtomatik giriş üçün doğrulama tələb edilir + + + + Enable Auto Login + Avtomatik girişi aktiv etmək + + + + Authentication is required to disable auto login + Avtomatik girişi söndürmək üçün doğrulama tələb edilir + + + + Disable Auto Login + Avtomatik girişi söndürmək + + + + Authentication is required to enable quick login + Kimlik doğrulaması avtomatik girişi aktiv etmək üçün tələb olunur + + + + Enable Quick Login + Sürətli girişi aktiv edin + + + + Authentication is required to disable quick login + Kimlik doğrulaması avtomatik girişi söndürmək üçün tələb olunur + + + + Disable Quick Login + Sürətli girişi söndürün + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Şifrəsiz girişi aktiv etmək üçün doğrulama tələb edilir + + + + Enable Login without password + Şifrəsiz girişi aktiv etmək + + + + Authentication is required to disable login without password + Şifrəsiz girişi söndürmək üçün doğrulama tələb edilir + + + + Disable Login without password + Şifrəsiz girişi söndürmək + + + + Authentication is required to set keyboard layout + Klaviatura qatını təyin etmək üçün doğrulama tələb edilir + + + + Set keyboard layout + Klaviatura qatını təyin etmək + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_bg.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_bg.ts new file mode 100644 index 000000000..54a386966 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_bg.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Удостоверяването изисква да смените вашите потребителски данни + + + + Change your own user data + Променете вашите потребителски данни + + + + Authentication is required to change user data + Удостоверяването изисква промяна на потребителските данни + + + + Manage user accounts + Управление на потребителските акаунти + + + + Authentication is required to enable auto login + Необходима е идентификация за включване на автоматичното влизане + + + + Enable Auto Login + Включи автоматично влизане + + + + Authentication is required to disable auto login + Необходима е идентификация за изключване на автоматичното влизане + + + + Disable Auto Login + Изключи автоматичното влизане + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Необходима е идентификация за разрешаване на влизане без парола + + + + Enable Login without password + Разрешаване на влизане без парола + + + + Authentication is required to disable login without password + Необходима е идентификация за изключване на влизането без парола + + + + Disable Login without password + Изключване на влизането без парола + + + + Authentication is required to set keyboard layout + Изисква се идентификация за да зададете клавиатурна подредба + + + + Set keyboard layout + Задаване на клавиатурна подредба + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_bn.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_bn.ts new file mode 100644 index 000000000..e59aef171 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_bn.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + আপনার নিজস্ব ব্যবহারকারী তথ্যাবলী পরিবর্তন করার জন্য প্রমাণীকরণের প্রয়োজন + + + + Change your own user data + আপনার নিজস্ব ব্যবহারকারী তথ্যাবলী পরিবর্তন করুন + + + + Authentication is required to change user data + ব্যবহারকারী তথ্যাবলী পরিবর্তন করার জন্য প্রমাণীকরণের প্রয়োজন + + + + Manage user accounts + ব্যবহারকারী অ্যাকাউন্টগুলি ব্যবস্থাপনা করুন + + + + Authentication is required to enable auto login + স্বয়ংক্রিয় লগইন চালু করার জন্য প্রমাণীকরণের প্রয়োজন + + + + Enable Auto Login + স্বয়ংক্রিয় লগইন চালু করুন + + + + Authentication is required to disable auto login + স্বয়ংক্রিয় লগইন বন্ধ করতে প্রমাণীকরণ প্রয়োজন + + + + Disable Auto Login + স্বয়ংক্রিয় লগইন বন্ধ করুন + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + পাসওয়ার্ড ছাড়া লগইন চালু করার জন্য প্রমাণীকরণ প্রয়োজন + + + + Enable Login without password + পাসওয়ার্ড ছাড়া লগইন চালু করুন + + + + Authentication is required to disable login without password + পাসওয়ার্ড ছাড়া লগইন বন্ধ করার জন্য প্রমাণীকরণ প্রয়োজন + + + + Disable Login without password + পাসওয়ার্ড ছাড়া লগইন বন্ধ করুন + + + + Authentication is required to set keyboard layout + কীবোর্ড লেআউট সেট করতে প্রমাণীকরণের প্রয়োজন + + + + Set keyboard layout + কীবোর্ড লেআউট সেট করুন + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_bo.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_bo.ts new file mode 100644 index 000000000..f86bcf9a2 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_bo.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + ཁྱོད་ཀྱི་སྤྱོད་མཁན་གཞི་གྲངས་བཟོ་བཅོས་བྱེད་ཚེ་ར་སྤྲོད་བྱེད་དགོས། + + + + Change your own user data + ཁྱོད་ཀྱི་སྤྱོད་མཁན་གཞི་གྲངས་བཟོ་བཅོས་བྱེད་པ། + + + + Authentication is required to change user data + སྤྱོད་མཁན་གཞི་གྲངས་བཟོ་བཅོས་བྱེད་ཚེ་ར་སྤྲོད་བྱེད་དགོས། + + + + Manage user accounts + སྤྱོད་མཁན་གྱི་རྩིས་ཁྲ་དོ་དམ། + + + + Authentication is required to enable auto login + ཐོ་རང་འཇུག་བྱེད་པར་ར་སྤྲོད་བྱེད་དགོས། + + + + Enable Auto Login + ཐོ་རང་འཇུག་བྱེད་པ། + + + + Authentication is required to disable auto login + ཐོ་རང་འཇུག་སྒོ་རྒྱག་ཚེ་ར་སྤྲོད་བྱེད་དགོས། + + + + Disable Auto Login + ཐོ་རང་འཇུག་སྒོ་རྒྱག་པ། + + + + Authentication is required to enable quick login + འཕྲལ་དུ་ཐོ་འཇུག་པར་ར་སྤྲོད་བྱེད་དགོས། + + + + Enable Quick Login + འཕྲུལ་དུ་ཐོ་འཇུག + + + + Authentication is required to disable quick login + འཕྲལ་དུ་ཐོ་འཇུག་པར་ར་སྤྲོད་བྱེད་མི་དགོས། + + + + Disable Quick Login + འཕྲུལ་དུ་ཐོ་འཇུག་ཅེས་པ་སྒོ་རྒྱག་པ། + + + + Authentication is required to enable WeChat code login + སྐད་འཕྲིན་བཤེར་ནས་ཐོ་འཇུག་པར་ར་སྤྲོད་བྱེད་དགོས། + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + སྐད་འཕྲིན་བཤེར་ནས་ཐོ་འཇུག་པར་ར་སྤྲོད་བྱེད་དགོས། + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + གསང་ཨང་མེད་པར་ཐོ་འཇུག་བྱེད་ཚེ་ར་སྤྲོད་བྱེད་དགོས། + + + + Enable Login without password + གསང་ཨང་མེད་པར་ཐོ་འཇུག་བྱེད་པ། + + + + Authentication is required to disable login without password + གསང་ཨང་མེད་པར་ཐོ་འཇུག་བྱེད་པ་སྒོ་རྒྱག་ཚེ་ར་སྤྲོད་བྱེད་དགོས། + + + + Disable Login without password + གསང་ཨང་མེད་པར་ཐོ་འཇུག་བྱེད་པ་སྒོ་རྒྱག་པ། + + + + Authentication is required to set keyboard layout + མཐེབ་གཞོང་བཀོད་པ་སྒྲིག་འགོད་བྱེད་ཚེ་ར་སྤྲོད་བྱེད་དགོས། + + + + Set keyboard layout + མཐེབ་གཞོང་བཀོད་པ་སྒྲིག་འགོད་བྱེད་པ། + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_bqi.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_bqi.ts new file mode 100644 index 000000000..02fa94a4b --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_bqi.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_br.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_br.ts new file mode 100644 index 000000000..107d66245 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_br.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ca.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ca.ts new file mode 100644 index 000000000..e9b2574be --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ca.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Cal autenticació per canviar les dades d'usuari pròpies. + + + + Change your own user data + Canvieu les dades d'usuari pròpies + + + + Authentication is required to change user data + Cal autenticació per canviar les dades d'usuari. + + + + Manage user accounts + Gestioneu els comptes d'usuari + + + + Authentication is required to enable auto login + Cal autenticació per habilitar l'entrada automàtica. + + + + Enable Auto Login + Habilita l'entrada automàtica. + + + + Authentication is required to disable auto login + Cal autenticació per inhabilitar l'entrada automàtica. + + + + Disable Auto Login + Inhabilita l'entrada automàtica. + + + + Authentication is required to enable quick login + Cal autenticació per habilitar l'inici de sessió ràpid. + + + + Enable Quick Login + Activa l'inici de sessió ràpid + + + + Authentication is required to disable quick login + Cal autenticació per desactivar l'inici de sessió ràpid. + + + + Disable Quick Login + Desactiva l'inici de sessió ràpid + + + + Authentication is required to enable WeChat code login + Cal autenticació per habilitar l'entrada amb el codi de WeChat. + + + + Enable WeChat Code Login + Habilita el codi d'inici de sessió del WeChat + + + + Authentication is required to disable WeChat code login + Cal autenticació per inhabilitar l'entrada amb el codi de WeChat. + + + + Disable WeChat Code Login + Inhabilita el codi d'inici de sessió del WeChat + + + + Authentication is required to enable login without password + Cal autenticació per habilitar l'entrada sense contrasenya. + + + + Enable Login without password + Habilita l'entrada sense contrasenya. + + + + Authentication is required to disable login without password + Cal autenticació per inhabilitar l'entrada sense contrasenya. + + + + Disable Login without password + Inhabilita l'entrada sense contrasenya. + + + + Authentication is required to set keyboard layout + Cal autenticació per establir la disposició del teclat. + + + + Set keyboard layout + Establiu la disposició del teclat. + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_cgg.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_cgg.ts new file mode 100644 index 000000000..fafcfaf6b --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_cgg.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_cs.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_cs.ts new file mode 100644 index 000000000..226892c2c --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_cs.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Pro změnu svých vlastních údajů je vyžadováno ověření se + + + + Change your own user data + Změnit si své vlastní údaje + + + + Authentication is required to change user data + Pro změnu údajů o uživateli je vyžadováno ověření se + + + + Manage user accounts + Spravovat uživatelské účty + + + + Authentication is required to enable auto login + Pro povolení automatického přihlašování je požadováno ověření se + + + + Enable Auto Login + Povolit automatické přihlašování + + + + Authentication is required to disable auto login + Pro zakázání automatického přihlašování je požadováno ověření se + + + + Disable Auto Login + Zakázat automatické přihlašování + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Pro povolení přihlašování bez hesla je požadováno ověření se + + + + Enable Login without password + Povolit přihlašování bez hesla + + + + Authentication is required to disable login without password + Pro zakázání přihlašování bez hesla je požadováno ověření se + + + + Disable Login without password + Zakázat přihlašování bez hesla + + + + Authentication is required to set keyboard layout + Pro nastavení rozložení klávesnice je vyžadováno ověření se + + + + Set keyboard layout + Nastavit rozložení klávesnice + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_da.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_da.ts new file mode 100644 index 000000000..103bad088 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_da.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Der kræves autentifikation for at ændre dine egne brugerdata + + + + Change your own user data + Ændr dine egne brugerdata + + + + Authentication is required to change user data + Der kræves autentifikation for at ændre brugerdata + + + + Manage user accounts + Håndter brugerkonti + + + + Authentication is required to enable auto login + Der kræves autentifikation for at aktivere automatisk login + + + + Enable Auto Login + Aktivér automatisk login + + + + Authentication is required to disable auto login + Der kræves autentifikation for at deaktivere automatisk login + + + + Disable Auto Login + Deaktivér automatisk login + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Der kræves autentifikation for at aktivere login uden adgangskode + + + + Enable Login without password + Aktivér login uden adgangskode + + + + Authentication is required to disable login without password + Der kræves autentifikation for at deaktivere login uden adgangskode + + + + Disable Login without password + Deaktivér login uden adgangskode + + + + Authentication is required to set keyboard layout + Der kræves autentifikation for at sætte tastaturlayout + + + + Set keyboard layout + Sæt tastaturlayout + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_de.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_de.ts new file mode 100644 index 000000000..3fe1bc022 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_de.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Zum Ändern Ihrer eigenen Benutzerdaten ist eine Authentifizierung erforderlich + + + + Change your own user data + Ändern Ihrer eigenen Benutzerdaten + + + + Authentication is required to change user data + Zum Ändern von Benutzerdaten ist eine Authentifizierung erforderlich + + + + Manage user accounts + Benutzerkonten verwalten + + + + Authentication is required to enable auto login + Zum Aktivieren der automatischen Anmeldung ist eine Authentifizierung erforderlich + + + + Enable Auto Login + Automatische Anmeldung aktivieren + + + + Authentication is required to disable auto login + Zum Deaktivieren der automatischen Anmeldung ist eine Authentifizierung erforderlich + + + + Disable Auto Login + Automatische Anmeldung deaktivieren + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Zum Aktivieren der Anmeldung ohne Passwort ist eine Authentifizierung erforderlich + + + + Enable Login without password + Anmeldung ohne Passwort aktivieren + + + + Authentication is required to disable login without password + Zum Deaktivieren der Anmeldung ohne Passwort ist eine Authentifizierung erforderlich + + + + Disable Login without password + Anmeldung ohne Passwort deaktivieren + + + + Authentication is required to set keyboard layout + Zum Festlegen der Tastaturbelegung ist eine Authentifizierung erforderlich + + + + Set keyboard layout + Tastaturbelegung festlegen + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_de_CH.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_de_CH.ts new file mode 100644 index 000000000..b4bdb5bad --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_de_CH.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_de_DE.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_de_DE.ts new file mode 100644 index 000000000..eef8bff13 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_de_DE.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Sie müssen sich authentifizieren, um ihre Benutzerdaten zu ändern + + + + Change your own user data + Ändern Sie ihre Benutzerdaten + + + + Authentication is required to change user data + Sie müssen sich authentifizieren, um Benutzerdaten zu ändern + + + + Manage user accounts + Benutzerkonten verwalten + + + + Authentication is required to enable auto login + Sie müssen sich authentifizieren, um Auto-LogIn einzurichten + + + + Enable Auto Login + Auto-LogIn Einrichten + + + + Authentication is required to disable auto login + Sie müssen sich authentifizieren, um Auto-LogIn abzuschalten + + + + Disable Auto Login + Auto-LogIn abschalten + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Sie müssen sich authentifizieren, um LogIn ohne Passwort einzurichten + + + + Enable Login without password + LogIn ohne Passwort einrichten + + + + Authentication is required to disable login without password + Sie müssen sich authentifizieren, um LogIn ohne Passwort abzuschalten + + + + Disable Login without password + LogIn ohne Passwort abschalten + + + + Authentication is required to set keyboard layout + Sie müssen sich authentifizieren, um das Tastatur-Layout einzustellen + + + + Set keyboard layout + Tastatur-Layout einstellen + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_el.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_el.ts new file mode 100644 index 000000000..a7993b0f6 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_el.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Απαιτείται πιστοποίηση για αλλαγή των δικών σας δεδομένων χρήστη + + + + Change your own user data + Αλλάξτε τα δεδομένα χρήστη σας + + + + Authentication is required to change user data + Απαιτείται πιστοποίηση για αλλαγή των δεδομένων χρήστη + + + + Manage user accounts + Διαχείριση λογαριασμών χρηστών + + + + Authentication is required to enable auto login + Απαιτείται πιστοποίηση για ενεργοποίηση αυτόματης εισόδου + + + + Enable Auto Login + Ενεργοποίηση Αυτόματης Εισόδου + + + + Authentication is required to disable auto login + Απαιτείται πιστοποίηση για απενεργοποίηση αυτόματης εισόδου + + + + Disable Auto Login + Απενεργοποίηση Αυτόματης Εισόδου + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Απαιτείται πιστοποίηση για ενεργοποίηση εισόδου χωρίς κωδικό + + + + Enable Login without password + Ενεργοποίηση Εισόδου χωρίς κωδικό + + + + Authentication is required to disable login without password + Απαιτείται πιστοποίηση για απενεργοποίηση εισόδου χωρίς κωδικό + + + + Disable Login without password + Απενεργοποίηση Εισόδου χωρίς κωδικό + + + + Authentication is required to set keyboard layout + Απαιτείται πιστοποίηση για να θέσετε τη διάταξη του πληκτρολογίου + + + + Set keyboard layout + Θέστε διάταξης πληκτρολογίου + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_el_GR.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_el_GR.ts new file mode 100644 index 000000000..8d020b326 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_el_GR.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_en_AU.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_en_AU.ts new file mode 100644 index 000000000..0a9723ccb --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_en_AU.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Authentication is required to change your own user data + + + + Change your own user data + Change your own user data + + + + Authentication is required to change user data + Authentication is required to change user data + + + + Manage user accounts + Manage user accounts + + + + Authentication is required to enable auto login + Authentication is required to enable auto-login + + + + Enable Auto Login + Enable Auto Login + + + + Authentication is required to disable auto login + Authentication is required to disable auto-login + + + + Disable Auto Login + Disable Auto Login + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Authentication is required to enable login without password + + + + Enable Login without password + Enable Login without password + + + + Authentication is required to disable login without password + Authentication is required to disable login without password + + + + Disable Login without password + Disable Login without password + + + + Authentication is required to set keyboard layout + Authentication is required to set keyboard layout + + + + Set keyboard layout + Set keyboard layout + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_en_GB.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_en_GB.ts new file mode 100644 index 000000000..d10a6da3f --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_en_GB.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Authentication is required to change your own user data + + + + Change your own user data + Change your own user data + + + + Authentication is required to change user data + Authentication is required to change user data + + + + Manage user accounts + Manage user accounts + + + + Authentication is required to enable auto login + Authentication is required to enable auto login + + + + Enable Auto Login + Enable auto login + + + + Authentication is required to disable auto login + Authentication is required to disable auto login + + + + Disable Auto Login + Disable auto login + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Authentication is required to enable logging in without a password + + + + Enable Login without password + Enable logging in without a password + + + + Authentication is required to disable login without password + Authentication is required to disable logging in without a password + + + + Disable Login without password + Disable logging in without a password + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_en_NO.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_en_NO.ts new file mode 100644 index 000000000..4b51d850f --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_en_NO.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_en_US.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_en_US.ts new file mode 100644 index 000000000..a40c694c9 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_en_US.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Authentication is required to change your own user data + + + + Change your own user data + Change your own user data + + + + Authentication is required to change user data + Authentication is required to change user data + + + + Manage user accounts + Manage user accounts + + + + Authentication is required to enable auto login + Authentication is required to enable auto login + + + + Enable Auto Login + Enable Auto Login + + + + Authentication is required to disable auto login + Authentication is required to disable auto login + + + + Disable Auto Login + Disable Auto Login + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Authentication is required to enable login without password + + + + Enable Login without password + Enable Login without password + + + + Authentication is required to disable login without password + Authentication is required to disable login without password + + + + Disable Login without password + Disable Login without password + + + + Authentication is required to set keyboard layout + Authentication is required to set keyboard layout + + + + Set keyboard layout + Set keyboard layout + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_eo.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_eo.ts new file mode 100644 index 000000000..3fa6984b5 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_eo.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Aŭtentigo bezonatas por ŝanĝi viajn proprajn uzantodatumojn + + + + Change your own user data + Ŝanĝi viajn proprajn uzantodatumojn + + + + Authentication is required to change user data + Aŭtentigo bezonatas por ŝanĝi uzantodatumojn + + + + Manage user accounts + Administri uzantokontojn + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_es.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_es.ts new file mode 100644 index 000000000..a5982002d --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_es.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Se requiere autenticación para cambiar sus datos de usuario + + + + Change your own user data + Cambiar sus datos de usuario + + + + Authentication is required to change user data + Se requiere autenticación para cambiar datos de usuario + + + + Manage user accounts + Gestionar cuentas de usuario + + + + Authentication is required to enable auto login + Se requiere autenticación para habilitar el inicio de sesión automático + + + + Enable Auto Login + Habilitar inicio de sesión automático + + + + Authentication is required to disable auto login + Se requiere autenticación para desactivar el inicio de sesión automático + + + + Disable Auto Login + Desactivar inicio de sesión automático + + + + Authentication is required to enable quick login + Se requiere autenticación para permitir el inicio de sesión rápido + + + + Enable Quick Login + Habilitar inicio de sesión rápido + + + + Authentication is required to disable quick login + Se requiere autenticación para deshabilitar el inicio de sesión rápido + + + + Disable Quick Login + Deshabilitar el inicio de sesión rápido + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Se requiere autenticación para habilitar el inicio de sesión sin contraseña + + + + Enable Login without password + Habilitar inicio de sesión sin contraseña + + + + Authentication is required to disable login without password + Se requiere autenticación para desactivar el inicio de sesión sin contraseña + + + + Disable Login without password + Desactivar inicio de sesión sin contraseña + + + + Authentication is required to set keyboard layout + Se requiere autenticación para establecer la distribución del teclado + + + + Set keyboard layout + Establecer distribución del teclado + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_es_419.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_es_419.ts new file mode 100644 index 000000000..6e2babfe3 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_es_419.ts @@ -0,0 +1,75 @@ + + + policy + + + Authentication is required to change your own user data + Se requiere autenticación para modificar su propia data de usuario + + + + Change your own user data + Modifique su propia data de usuario + + + + Authentication is required to change user data + Se requiere autenticación para modificar la data de usuario + + + + Manage user accounts + Administrar las cuentas de usuario + + + + Authentication is required to enable auto login + Se requiere autenticación para habilitar inicio de sesión automático + + + + Enable Auto Login + Habilitar inicio de sesión automático + + + + Authentication is required to disable auto login + Se requiere autenticación para deshabilitar inicio de sesión automático + + + + Disable Auto Login + Deshabilitar inicio de sesión automático + + + + Authentication is required to enable login without password + Se requiere autenticación para habilitar inicio de sesión sin contraseña + + + + Enable Login without password + Habilitar inicio de sesión sin contraseña + + + + Authentication is required to disable login without password + Se requiere autenticación para deshabilitar inicio de sesión sin contraseña + + + + Disable Login without password + Deshabilitar inicio de sesión sin contraseña + + + + Authentication is required to set keyboard layout + Se requiere autenticación para establecer distribución del teclado + + + + Set keyboard layout + Establecer distribución del teclado + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_es_MX.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_es_MX.ts new file mode 100644 index 000000000..40daf39f4 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_es_MX.ts @@ -0,0 +1,75 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_et.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_et.ts new file mode 100644 index 000000000..a8f62e393 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_et.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_eu.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_eu.ts new file mode 100644 index 000000000..64624d87d --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_eu.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_fa.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_fa.ts new file mode 100644 index 000000000..b0824157b --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_fa.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + احراز هویت برای تغییر اطلاعات کاربری شما لازم است + + + + Change your own user data + تغییر اطلاعات کاربری شما + + + + Authentication is required to change user data + احراز هویت برای تغییر اطلاعات کاربر لازم است + + + + Manage user accounts + مدیریت حساب کاربران + + + + Authentication is required to enable auto login + احراز هویت برای فعالسازی ورود خودکار لازم است + + + + Enable Auto Login + فعالسازی ورود خودکار + + + + Authentication is required to disable auto login + احراز هویت برای غیرفعالسازی ورود خودکار لازم است + + + + Disable Auto Login + غیرفعالسازی ورود خودکار + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + احراز هویت برای فعالسازی ورود بدون رمزعبور لازم است + + + + Enable Login without password + فعالسازی ورود بدون رمزعبور + + + + Authentication is required to disable login without password + احراز هویت برای غیرفعالسازی ورود بدون رمزعبور لازم است + + + + Disable Login without password + غیرفعالسازی ورود بدون رمز + + + + Authentication is required to set keyboard layout + احراز هویت برای انتخاب طرح بندی صفحه کلید لازم است + + + + Set keyboard layout + انتخاب طرح بندی صفحه کلید + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_fi.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_fi.ts new file mode 100644 index 000000000..b16b0126e --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_fi.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Omien käyttäjätietojen muuttaminen vaatii tunnistautumisen + + + + Change your own user data + Muuta omia käyttäjätietojasi + + + + Authentication is required to change user data + Käyttäjätietojen muuttaminen vaatii tunnistautumisen + + + + Manage user accounts + Hallitse käyttäjätilejä + + + + Authentication is required to enable auto login + Automaattisen kirjautumisen käyttöönotto vaatii tunnistautumisen + + + + Enable Auto Login + Käytä automaattista kirjautumista + + + + Authentication is required to disable auto login + Automaattisen kirjautumisen poisto vaatii tunnistautumisen + + + + Disable Auto Login + Poista automaattinen kirjautuminen + + + + Authentication is required to enable quick login + Tunnistautuminen vaaditaan nopeaan kirjautumiseen + + + + Enable Quick Login + Käytä nopeaa kirjautumista + + + + Authentication is required to disable quick login + Tunnistautuminen vaaditaan nopean kirjautumisen poistamiseksi + + + + Disable Quick Login + Poista nopea kirjautuminen + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Kirjautumisen käyttöönotto ilman salasanaa vaatii tunnistautumisen + + + + Enable Login without password + Salli kirjautuminen ilman salasanaa + + + + Authentication is required to disable login without password + Kirjautumisen käytöstäpoisto ilman salasanaa vaatii tunnistautumisen + + + + Disable Login without password + Poista kirjautuminen ilman salasanaa + + + + Authentication is required to set keyboard layout + Näppäimistön asetukset vaatii tunnistautumisen + + + + Set keyboard layout + Aseta näppäimistöasettelu + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_fil.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_fil.ts new file mode 100644 index 000000000..1856c4da7 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_fil.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_fr.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_fr.ts new file mode 100644 index 000000000..40ba83b99 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_fr.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Vous devez vous authentifier pour modifier vos données utilisateur + + + + Change your own user data + Modifier vos données utilisateur + + + + Authentication is required to change user data + Il est nécessaire de s'authentifier pour modifier des données utilisateur + + + + Manage user accounts + Gérer les comptes des utilisateurs + + + + Authentication is required to enable auto login + Il est nécessaire de s'authentifier pour activer la connexion automatique + + + + Enable Auto Login + Activer la connexion automatique + + + + Authentication is required to disable auto login + Il est nécessaire de s'authentifier pour désactiver la connexion automatique + + + + Disable Auto Login + Désactiver la connexion automatique + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Il est nécessaire de s'authentifier pour activer la connexion sans mot de passe + + + + Enable Login without password + Activer la connexion sans mot de passe + + + + Authentication is required to disable login without password + Il est nécessaire de s'authentifier pour désactiver la connexion sans mot de passe + + + + Disable Login without password + Désactiver la connexion sans mot de passe + + + + Authentication is required to set keyboard layout + L'authentification est nécessaire pour définir la disposition du clavier + + + + Set keyboard layout + Définir la disposition du clavier + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_gl.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_gl.ts new file mode 100644 index 000000000..fe89d12f1 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_gl.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_gl_ES.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_gl_ES.ts new file mode 100644 index 000000000..37bdb2959 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_gl_ES.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Requírese autenticación para cambiar os seus datos de usuario + + + + Change your own user data + Cambiar os seus datos de usuario + + + + Authentication is required to change user data + Requírese autenticación para cambiar os datos de usuario + + + + Manage user accounts + Xestionar as contas de usuario + + + + Authentication is required to enable auto login + Requírese autenticación para habilitar o inicio automático + + + + Enable Auto Login + Habilitar o inicio automático + + + + Authentication is required to disable auto login + Requírese autenticación para inhabilitar o inicio automático + + + + Disable Auto Login + Inhabilitar o inicio automático + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Requírese autenticación para habilitar o inicio sen contrasinal + + + + Enable Login without password + Habilitar o inicio sen contrasinal + + + + Authentication is required to disable login without password + Requírese autenticación para inhabilitar o inicio sen contrasinal + + + + Disable Login without password + Inhabilitar o incio sen contrasinal + + + + Authentication is required to set keyboard layout + Requírese autenticación para establecer a disposición do teclado + + + + Set keyboard layout + Establecer a disposición do teclado + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_he.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_he.ts new file mode 100644 index 000000000..db8782461 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_he.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_hi_IN.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_hi_IN.ts new file mode 100644 index 000000000..e0dada2aa --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_hi_IN.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + अपने उपयोक्ता डेटा को बदलने हेतु प्रमाणीकरण आवश्यक है + + + + Change your own user data + अपना उपयोक्ता डेटा बदलें + + + + Authentication is required to change user data + उपयोक्ता डेटा को बदलने हेतु प्रमाणीकरण आवश्यक है + + + + Manage user accounts + उपयोक्ता खातों का प्रबंधन करें + + + + Authentication is required to enable auto login + स्वतः लॉगिन को सक्रिय करने हेतु प्रमाणीकरण आवश्यक है + + + + Enable Auto Login + स्वतः लॉगिन सक्रिय करें + + + + Authentication is required to disable auto login + स्वतः लॉगिन को निष्क्रिय करने हेतु प्रमाणीकरण आवश्यक है + + + + Disable Auto Login + स्वतः लॉगिन निष्क्रिय करें + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + बिना कूटशब्द के लॉगिन को सक्रिय करने हेतु प्रमाणीकरण आवश्यक है + + + + Enable Login without password + बिना कूटशब्द के लॉगिन को सक्रिय करें + + + + Authentication is required to disable login without password + बिना कूटशब्द के लॉगिन को निष्क्रिय करने हेतु प्रमाणीकरण आवश्यक है + + + + Disable Login without password + बिना कूटशब्द के लॉगिन को निष्क्रिय करें + + + + Authentication is required to set keyboard layout + कुंजीपटल अभिन्यास सेट करने हेतु प्रमाणीकरण आवश्यक है + + + + Set keyboard layout + कुंजीपटल अभिन्यास सेट करें + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_hr.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_hr.ts new file mode 100644 index 000000000..f64166439 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_hr.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Potrebna je ovjera za promjenu vaših vlastitih korisničkih podataka + + + + Change your own user data + Promijenite vaše vlastite korisničke podatke + + + + Authentication is required to change user data + Potrebna je ovjera za promjenu korisničkih podataka + + + + Manage user accounts + Upravlja računima korisnika + + + + Authentication is required to enable auto login + Potrebna je ovjera za omogućavanje automatske prijave + + + + Enable Auto Login + Omogući automatsku prijavu + + + + Authentication is required to disable auto login + Potrebna je ovjera za onemogućavanje automatske prijave + + + + Disable Auto Login + Onemogući automatsku prijavu + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Potrebna je ovjera za omogućavanje prijave bez lozinke + + + + Enable Login without password + Omogući prijavu bez lozinke + + + + Authentication is required to disable login without password + Potrebna je ovjera za onemogućavanje prijave bez lozinke + + + + Disable Login without password + Onemogući prijavu bez lozinke + + + + Authentication is required to set keyboard layout + Potrebna je ovjera za postavljanje rasporeda tipkovnice + + + + Set keyboard layout + Postavi raspored tipkovnice + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_hu.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_hu.ts new file mode 100644 index 000000000..70051e32d --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_hu.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Hitelesítés szükséges a felhasználói adatainak módosításához + + + + Change your own user data + Saját felhasználói adatainak módosítása + + + + Authentication is required to change user data + Hitelesítés szükséges a felhasználói adatok módosításához + + + + Manage user accounts + Felhasználói fiókok kezelése + + + + Authentication is required to enable auto login + Hitelesítés szükséges az automatikus bejelentkezés engedélyezéséhez + + + + Enable Auto Login + Automatikus bejelentkezés engedélyezése + + + + Authentication is required to disable auto login + Hitelesítés szükséges az automatikus bejelentkezés kikapcsolásához + + + + Disable Auto Login + Automatikus bejelentkezés kikapcsolása + + + + Authentication is required to enable quick login + Hitelesítés szükséges a gyors bejelentkezés engedélyezéséhez + + + + Enable Quick Login + Gyors bejelentkezés engedélyezése + + + + Authentication is required to disable quick login + Hitelesítés szükséges a gyors bejelentkezés letiltásához + + + + Disable Quick Login + Gyors bejelentkezés letiltása + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Hitelesítés szükséges a jelszó nélküli bejelentkezés engedélyezéséhez + + + + Enable Login without password + Jelszó nélküli bejelentkezés engedélyezése + + + + Authentication is required to disable login without password + Hitelesítés szükséges a jelszó nélküli bejelentkezés kikapcsolásához + + + + Disable Login without password + Jelszó nélküli bejelentkezés kikapcsolása + + + + Authentication is required to set keyboard layout + Hitelesítés szükséges a billentyűzetkiosztás beállításához + + + + Set keyboard layout + Billentyűzetkiosztás beállítása + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_hy.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_hy.ts new file mode 100644 index 000000000..0149d1f76 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_hy.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_id.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_id.ts new file mode 100644 index 000000000..000346179 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_id.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Otentikasi diperlukan untuk mengubah data pengguna milikmu + + + + Change your own user data + Ubah data penggunamu sendiri + + + + Authentication is required to change user data + Otentikasi diperlukan untuk mengubah data pengguna + + + + Manage user accounts + Kelola akun pengguna + + + + Authentication is required to enable auto login + Otentikasi diperlukan untuk mengaktifkan masuk otomatis + + + + Enable Auto Login + Aktifkan masuk otomatis + + + + Authentication is required to disable auto login + Otentikasi diperlukan untuk menonaktifkan masuk otomatis + + + + Disable Auto Login + Nonaktifkan masuk otomatis + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Otentikasi diperlukan untuk mengaktifkan masuk otomatis tanpa dengan sandi lewat + + + + Enable Login without password + Aktifkan masuk tanpa dengan kata sandi + + + + Authentication is required to disable login without password + Otentikasi diperlukan untuk menonaktifkan masuk otomatis tanpa dengan kata sandi + + + + Disable Login without password + Nonaktifkan masuk otomatis tanpa dengan kata sandi + + + + Authentication is required to set keyboard layout + Otentikasi diperlukan untuk set tata letak papan ketik + + + + Set keyboard layout + Atur tata letak papan ketik + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_id_ID.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_id_ID.ts new file mode 100644 index 000000000..b90395848 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_id_ID.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_it.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_it.ts new file mode 100644 index 000000000..61815d6a1 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_it.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + È necessario autenticarsi per cambiare i propri dati utente + + + + Change your own user data + Cambia i dati dell'utente + + + + Authentication is required to change user data + È necessario autenticarsi per cambiare i dati utente + + + + Manage user accounts + Gestisci gli account utente + + + + Authentication is required to enable auto login + Autenticazione richiesta per abilitare il login automatico + + + + Enable Auto Login + Abilita Login automatico + + + + Authentication is required to disable auto login + Autenticazione richiesta per disabilitare il login automatico + + + + Disable Auto Login + Disabilita Login automatico + + + + Authentication is required to enable quick login + Autenticazione richiesta per abilitare l'accesso rapido. + + + + Enable Quick Login + Abilita l'accesso rapido + + + + Authentication is required to disable quick login + L'autenticazione è richiesta per disabilitare l'accesso rapido. + + + + Disable Quick Login + Disabilita accesso rapido + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Autenticazione richiesta per abilitare il login privo di password + + + + Enable Login without password + Abilita Login senza password + + + + Authentication is required to disable login without password + Autenticazione richiesta per disabilitare il login privo di password + + + + Disable Login without password + Disabilita Login senza password + + + + Authentication is required to set keyboard layout + Autenticazione necessaria per modificare il layout della tastiera + + + + Set keyboard layout + Imposta il layout della tastiera + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ja.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ja.ts new file mode 100644 index 000000000..e2c1c2f23 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ja.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + 自分自身のユーザーデータを変更するには認証が必要です + + + + Change your own user data + 自分自身のユーザーデータを変更 + + + + Authentication is required to change user data + ユーザーのデータを変更するには認証が必要です + + + + Manage user accounts + ユーザーアカウントを管理 + + + + Authentication is required to enable auto login + 自動ログインを有効にするには認証が必要です + + + + Enable Auto Login + 自動ログインを有効にする + + + + Authentication is required to disable auto login + 自動ログインを無効にするには認証が必要です + + + + Disable Auto Login + 自動ログインを無効にする + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + パスワードなしでのログインを有効にするには認証が必要です + + + + Enable Login without password + パスワードなしでのログインを有効にする + + + + Authentication is required to disable login without password + パスワードなしでのログインを無効にするには認証が必要です + + + + Disable Login without password + パスワードなしでのログインを無効にする + + + + Authentication is required to set keyboard layout + キーボードレイアウトを設定するには認証が必要です + + + + Set keyboard layout + キーボードレイアウトを設定 + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ka.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ka.ts new file mode 100644 index 000000000..69008dccc --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ka.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_kab.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_kab.ts new file mode 100644 index 000000000..22c0113d5 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_kab.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Yetwasra usesteb akken ad tbeddeleḍ isefka udmawanen-inek m. + + + + Change your own user data + Beddel isefka udmawanen inek m + + + + Authentication is required to change user data + Yetwasra usesteb akken ad tbeddeleḍ isefka udmawanen n useqdac + + + + Manage user accounts + sefrek isefka n useqdac + + + + Authentication is required to enable auto login + Yettwasra usesteb akken ad tesremdeḍ anekcum awurman + + + + Enable Auto Login + Sermed anekcum awurman + + + + Authentication is required to disable auto login + Yettwasra usesteb akken ad tsenseḍ anekcum awurman + + + + Disable Auto Login + Sens anekcum awurman + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Yettwasra usesteb akken ad tesremdeḍ anekcum war awal uffir + + + + Enable Login without password + Sermed anekcum war awal uffir + + + + Authentication is required to disable login without password + Yettwasra usesteb akken ad tsenseḍ anekcum war awal uffir + + + + Disable Login without password + Sens anekcum war awal uffir + + + + Authentication is required to set keyboard layout + Yettwasra usesteb akken ad tesremdeḍ taneɣuft n unasiw + + + + Set keyboard layout + Sbadu taneɣruft n unasiw + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_kk.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_kk.ts new file mode 100644 index 000000000..0d8cf109c --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_kk.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_km_KH.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_km_KH.ts new file mode 100644 index 000000000..813c97518 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_km_KH.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_kn_IN.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_kn_IN.ts new file mode 100644 index 000000000..84c288757 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_kn_IN.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ko.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ko.ts new file mode 100644 index 000000000..663bd26d3 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ko.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + 자신의 사용자 데이터를 변경하려면 인증이 필요합니다 + + + + Change your own user data + 사용자 데이터 변경 + + + + Authentication is required to change user data + 사용자 데이터를 변경하려면 인증이 필요합니다 + + + + Manage user accounts + 사용자 계정 + + + + Authentication is required to enable auto login + 자동 로그인을 활성화하려면 인증이 필요 합니다 + + + + Enable Auto Login + 자동 로그인 사용 + + + + Authentication is required to disable auto login + 자동 로그인을 비활성화하려면 인증이 필요합니다 + + + + Disable Auto Login + 자동 로그인 사용 중지 + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + 비밀번호 없는 로그인을 사용하려면 인증이 필요합니다 + + + + Enable Login without password + 비밀번호 없는 로그인 활성화 + + + + Authentication is required to disable login without password + 비밀번호 없는 로그인을 비활성화 하려면 인증이 필요 합니다 + + + + Disable Login without password + 비밀번호 없는 로그인 비활성화 + + + + Authentication is required to set keyboard layout + 키보드 레이아웃을 설정하려면 인증이 필요합니다 + + + + Set keyboard layout + 키보드 레이아웃 설정 + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ku.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ku.ts new file mode 100644 index 000000000..78d900066 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ku.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ku_IQ.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ku_IQ.ts new file mode 100644 index 000000000..b4ffb8b49 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ku_IQ.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ky.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ky.ts new file mode 100644 index 000000000..8378f7562 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ky.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ky@Arab.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ky@Arab.ts new file mode 100644 index 000000000..44338eea7 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ky@Arab.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_la.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_la.ts new file mode 100644 index 000000000..68ab24dfa --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_la.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_lo.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_lo.ts new file mode 100644 index 000000000..303de3161 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_lo.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_lt.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_lt.ts new file mode 100644 index 000000000..834cd01c8 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_lt.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Norint keisti asmeninio naudotojo duomenis, reikalingas tapatybės nustatymas + + + + Change your own user data + Keisti asmeninio naudotojo duomenis + + + + Authentication is required to change user data + Norint keisti naudotojo duomenis, reikalingas tapatybės nustatymas + + + + Manage user accounts + Tvarkyti naudotojų paskyras + + + + Authentication is required to enable auto login + Norint įjungti automatinį prisijungimą, reikalingas tapatybės nustatymas + + + + Enable Auto Login + Įjungti automatinį prisijungimą + + + + Authentication is required to disable auto login + Norint išjungti automatinį prisijungimą, reikalingas tapatybės nustatymas + + + + Disable Auto Login + Išjungti automatinį prisijungimą + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Norint įjungti prisijungimą be slaptažodžio, reikalingas tapatybės nustatymas + + + + Enable Login without password + Įjungti prisijungimą be slaptažodžio + + + + Authentication is required to disable login without password + Norint išjungti prisijungimą be slaptažodžio, reikalingas tapatybės nustatymas + + + + Disable Login without password + Išjungti prisijungimą be slaptažodžio + + + + Authentication is required to set keyboard layout + Norint nustatyti klaviatūros išdėstymą, reikalingas tapatybės nustatymas + + + + Set keyboard layout + Nustatyti klaviatūros išdėstymą + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_lv.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_lv.ts new file mode 100644 index 000000000..f8fb15787 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_lv.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Nepieciešama autentifikācija, lai mainītu pats savus lietotāja datus + + + + Change your own user data + Mainīt pašam savus lietotāja datus + + + + Authentication is required to change user data + Nepieciešama autentifikācija, lai mainītu lietotāja datus + + + + Manage user accounts + Pārvaldīt lietotāju kontus + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ml.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ml.ts new file mode 100644 index 000000000..3c7404a7b --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ml.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_mn.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_mn.ts new file mode 100644 index 000000000..32f1f5e38 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_mn.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Өөрийн хэрэглэгчийн өгөгдлийг өөрчлөхөд баталгаажуулалт шаардлагатай + + + + Change your own user data + Өөрийн хэрэглэгчийн өгөгдлийг өөрчлөх + + + + Authentication is required to change user data + Хэрэглэгчийн өгөгдлийг өөрчлөхийн тулд баталгаажуулалт шаардлагатай + + + + Manage user accounts + Хэрэглэгчийн бүртгэлийн зохицуулах + + + + Authentication is required to enable auto login + Автоматаар нэвтрэхийг идэвхжүүлэхийн тулд баталгаажуулалт шаардлагатай + + + + Enable Auto Login + Автоматаар нэвтэрхийг идэвхжүүлэх + + + + Authentication is required to disable auto login + Автоматаар нэвтрэхийг цуцлахын тулд баталгаажуулалт шаардлагатай + + + + Disable Auto Login + Автоматаар нэвтэрхийг цуцлах + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Нууц үг ашиглалгүйгээр нэвтэрхийг идэвхжүүлэхийн тулд баталгаажуулалт шаардлагатай + + + + Enable Login without password + Нууц үг ашиглахгүйгээр нэвтрэхийг идэвхжүүлэх + + + + Authentication is required to disable login without password + Нууц үг ашиглалгүйгээр нэвтэрхийг цуцлахын тулд баталгаажуулалт шаардлагатай + + + + Disable Login without password + Нууц үг ашиглахгүйгээр нэвтрэхийг цуцлах + + + + Authentication is required to set keyboard layout + Гарын байрлалыг тохируулхын тулд баталгаажуулалт шаардлагатай + + + + Set keyboard layout + Гарын байрлал тохируулах + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_mr.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_mr.ts new file mode 100644 index 000000000..cb833d9d1 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_mr.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ms.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ms.ts new file mode 100644 index 000000000..b2596d7a4 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ms.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Pengesahihan diperlukan untuk mengubah data pengguna anda sendiri + + + + Change your own user data + Ubah data pengguna anda sendiri + + + + Authentication is required to change user data + Pengesahihan diperlukan untuk mengubah data pengguna + + + + Manage user accounts + Urus akaun pengguna + + + + Authentication is required to enable auto login + Pengesahihan diperlukan untuk membolehkan daftar masuk automatik + + + + Enable Auto Login + Benarkan Daftar Masuk Automatik + + + + Authentication is required to disable auto login + Pengesahihan diperlukan untuk melumpuhkan daftar masuk automatik + + + + Disable Auto Login + Lumpuhkan Daftar Masuk Automatik + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Pengesahihan diperlukan untuk membolehkan daftar masuk tanpa kata laluan + + + + Enable Login without password + Benarkan Daftar masuk tanpa kata laluan + + + + Authentication is required to disable login without password + Pengesahihan diperlukan untuk melumpuhkan daftar masuk tanpa kata laluan + + + + Disable Login without password + Lumpuhkan Daftar masuk tanpa kata laluan + + + + Authentication is required to set keyboard layout + Pengesahihan diperlukan untuk menetapkan bentangan papan kekunci + + + + Set keyboard layout + Tetapkan bentangan papan kekunci + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_nb.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_nb.ts new file mode 100644 index 000000000..552d8e143 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_nb.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ne.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ne.ts new file mode 100644 index 000000000..a196bf8a9 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ne.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + तपाईंको प्रयोगकर्ता डेटा परिवर्तन गर्न प्रमाणीकरण आवश्यक छ + + + + Change your own user data + आफ्नो प्रयोगकर्ता डेटा परिवर्तन गर्नुहोस् + + + + Authentication is required to change user data + प्रयोगकर्ता डेटा परिवर्तन गर्न प्रमाणीकरण आवश्यक छ + + + + Manage user accounts + प्रयोगकर्ता खाताहरू व्यवस्थापन गर्नुहोस् + + + + Authentication is required to enable auto login + स्वत: लगइन एनबल गर्न प्रमाणीकरण आवश्यक छ + + + + Enable Auto Login + स्वत: लगइन सक्षम गर्नुहोस् + + + + Authentication is required to disable auto login + स्वत: लगइन असक्षम गर्न प्रमाणीकरण आवश्यक छ + + + + Disable Auto Login + स्वत: लगइन अक्षम गर्नुहोस् + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + पासवर्ड बिना लगइन सक्षम गर्न प्रमाणीकरण आवश्यक छ + + + + Enable Login without password + पासवर्ड बिना लगइन सक्षम गर्नुहोस् + + + + Authentication is required to disable login without password + पासवर्ड बिना लगइन असक्षम गर्न प्रमाणीकरण आवश्यक छ + + + + Disable Login without password + पासवर्ड बिना लगइन असक्षम पार्नुहोस् + + + + Authentication is required to set keyboard layout + किबोर्ड लेआउट सेट गर्न प्रमाणीकरण आवश्यक छ + + + + Set keyboard layout + किबोर्ड लेआउट सेट गर्नुहोस् + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_nl.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_nl.ts new file mode 100644 index 000000000..9be666458 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_nl.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Authenticatie vereist om je eigen gebruikersgegevens aan te passen + + + + Change your own user data + Eigen gebruikersgegevens aanpassen + + + + Authentication is required to change user data + Authenticatie vereist om gebruikersgegevens aan te passen + + + + Manage user accounts + Gebruikersaccounts beheren + + + + Authentication is required to enable auto login + Authenticatie vereist om automatisch aanmelden in te schakelen + + + + Enable Auto Login + Automatisch aanmelden inschakelen + + + + Authentication is required to disable auto login + Authenticatie vereist om automatisch aanmelden uit te schakelen + + + + Disable Auto Login + Automatisch aanmelden uitschakelen + + + + Authentication is required to enable quick login + Verificatie vereist om snel aanmelden in te schakelen + + + + Enable Quick Login + Snel aanmelden inschakelen + + + + Authentication is required to disable quick login + Verificatie vereist om snel aanmelden uit te schakelen + + + + Disable Quick Login + Snel aanmelden uitschakelen + + + + Authentication is required to enable WeChat code login + Verificatie vereist om inloggen met WeChat-code in te schakelen + + + + Enable WeChat Code Login + Inloggen met WeChat-code inschakelen + + + + Authentication is required to disable WeChat code login + Verificatie vereist om inloggen met WeChat-code uit te schakelen + + + + Disable WeChat Code Login + Inloggen met WeChat-code uitschakelen + + + + Authentication is required to enable login without password + Authenticatie vereist om aanmelden zonder wachtwoord in te schakelen + + + + Enable Login without password + Aanmelden zonder wachtwoord inschakelen + + + + Authentication is required to disable login without password + Authenticatie vereist om aanmelden zonder wachtwoord uit te schakelen + + + + Disable Login without password + Aanmelden zonder wachtwoord uitschakelen + + + + Authentication is required to set keyboard layout + Authenticatie vereist om de toetsenbordindeling te wijzigen + + + + Set keyboard layout + Toetsenbordindeling instellen + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_pa.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_pa.ts new file mode 100644 index 000000000..6f41c11cc --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_pa.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + ਤੁਹਾਡਾ ਯੂਜ਼ਰ ਡਾਟਾ ਬਦਲਣ ਲਈ ਪਰਮਾਣਿਤ ਹੋਣ ਦੀ ਲੋੜ ਹੈ + + + + Change your own user data + ਆਪਣਾ ਯੂਜ਼ਰ ਡਾਟਾ ਬਦਲੋ + + + + Authentication is required to change user data + ਯੂਜ਼ਰ ਡਾਟਾ ਬਦਲਣ ਲਈ ਪਰਮਾਣਿਤ ਹੋਣ ਦੀ ਲੋੜ ਹੈ + + + + Manage user accounts + ਯੂਜ਼ਰ ਅਕਾਊਂਟ ਪਰਬੰਧ + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_pam.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_pam.ts new file mode 100644 index 000000000..51c3abff1 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_pam.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_pl.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_pl.ts new file mode 100644 index 000000000..557facf23 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_pl.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Wymagane jest uwierzytelnienie, aby zmienić własne dane + + + + Change your own user data + Zmiana własnych danych + + + + Authentication is required to change user data + Wymagane jest uwierzytelnienie, aby zmienić dane użytkownika + + + + Manage user accounts + Zarządzanie kontami użytkowników + + + + Authentication is required to enable auto login + Wymagane jest uwierzytelnienie, aby włączyć automatyczne logowanie + + + + Enable Auto Login + Włącz automatyczne logowanie + + + + Authentication is required to disable auto login + Wymagane jest uwierzytelnienie, aby wyłączyć automatyczne logowanie + + + + Disable Auto Login + Wyłącz automatyczne logowanie + + + + Authentication is required to enable quick login + Wymagane jest uwierzytelnienie, aby włączyć szybkie logowanie + + + + Enable Quick Login + Włącz szybkie logowanie + + + + Authentication is required to disable quick login + Wymagane jest uwierzytelnienie, aby wyłączyć szybkie logowanie + + + + Disable Quick Login + Wyłącz szybkie logowanie + + + + Authentication is required to enable WeChat code login + Wymagane jest uwierzytelnienie, aby włączyć logowanie kodem WeChat + + + + Enable WeChat Code Login + Włącz logowanie kodem WeChat + + + + Authentication is required to disable WeChat code login + Wymagane jest uwierzytelnienie, aby wyłączyć logowanie kodem WeChat + + + + Disable WeChat Code Login + Wyłącz logowanie kodem WeChat + + + + Authentication is required to enable login without password + Wymagane jest uwierzytelnienie, aby włączyć logowanie bez podawania hasła + + + + Enable Login without password + Włącz logowanie bez podawania hasła + + + + Authentication is required to disable login without password + Wymagane jest uwierzytelnienie, aby wyłączyć logowanie bez podawania hasła + + + + Disable Login without password + Wyłącz logowanie bez podawania hasła + + + + Authentication is required to set keyboard layout + Wymagane jest uwierzytelnienie, aby ustawić układ klawiatury + + + + Set keyboard layout + Ustaw układ klawiatury + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ps.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ps.ts new file mode 100644 index 000000000..17cf4a629 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ps.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_pt.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_pt.ts new file mode 100644 index 000000000..2cbe338b0 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_pt.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + É necessária a autenticação para alterar os seus próprios dados de utilizador + + + + Change your own user data + Alterar os seus próprios dados de utilizador + + + + Authentication is required to change user data + É necessária a autenticação para alterar os dados de utilizador + + + + Manage user accounts + Gerir contas de utilizador + + + + Authentication is required to enable auto login + É necessária a autenticação para ativar o início de sessão automático + + + + Enable Auto Login + Ativar o início de sessão automático + + + + Authentication is required to disable auto login + É necessária a autenticação para desativar o início de sessão automático + + + + Disable Auto Login + Desativar o início de sessão automático + + + + Authentication is required to enable quick login + É necessária autenticação para ativar o início de sessão rápido + + + + Enable Quick Login + Ativar o início de sessão rápido + + + + Authentication is required to disable quick login + É necessária autenticação para desativar o início de sessão rápido + + + + Disable Quick Login + Desativar o início de sessão rápido + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + É necessária a autenticação para ativar o início de sessão sem palavra-passe + + + + Enable Login without password + Ativar o início de sessão sem palavra-passe + + + + Authentication is required to disable login without password + É necessária a autenticação para desativar o início de sessão sem palavra-passe + + + + Disable Login without password + Desativar o início de sessão sem palavra-passe + + + + Authentication is required to set keyboard layout + É necessária a autenticação para definir o esquema do teclado + + + + Set keyboard layout + Definir esquema do teclado + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_pt_BR.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_pt_BR.ts new file mode 100644 index 000000000..9c414f5c3 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_pt_BR.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + A autenticação é necessária para alterar os dados do usuário + + + + Change your own user data + Alterar seus próprios dados de usuário + + + + Authentication is required to change user data + A autenticação é necessária para alterar os dados do usuário + + + + Manage user accounts + Gerenciar Contas de Usuário + + + + Authentication is required to enable auto login + A autenticação é necessária para ativar o login automático + + + + Enable Auto Login + Login automático + + + + Authentication is required to disable auto login + A autenticação é necessária para desativar o login automático + + + + Disable Auto Login + Login automático + + + + Authentication is required to enable quick login + A autenticação é necessária para ativar o login rápido + + + + Enable Quick Login + Ativar login rápido + + + + Authentication is required to disable quick login + A autenticação é necessária para desativar o login rápido + + + + Disable Quick Login + Desativar login rápido + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + A autenticação é necessária para ativar o login sem senha + + + + Enable Login without password + Login sem senha + + + + Authentication is required to disable login without password + A autenticação é necessária para desativar o login sem senha + + + + Disable Login without password + Login sem senha + + + + Authentication is required to set keyboard layout + A autenticação é necessária para alterar o layout de teclado + + + + Set keyboard layout + Definir layout de teclado + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_qu.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_qu.ts new file mode 100644 index 000000000..8afad9be3 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_qu.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ro.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ro.ts new file mode 100644 index 000000000..5697f0f36 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ro.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Autentificarea este necesară pentru a vă schimba propriile date de utilizator + + + + Change your own user data + Modificați-vă datele de utilizator + + + + Authentication is required to change user data + Autentificarea este necesară pentru a modifica date de utilizator + + + + Manage user accounts + Administrați conturile de utilizator + + + + Authentication is required to enable auto login + Autentificarea este necesară pentru a activa autentificarea automată + + + + Enable Auto Login + Activați autentificarea automată + + + + Authentication is required to disable auto login + Autentificarea este necesară pentru a dezactiva autentificarea automată + + + + Disable Auto Login + Dezactivați autentificarea automată + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Autentificarea este necesară pentru a activa autentificarea fără parolă + + + + Enable Login without password + Activați autentificarea fără parolă + + + + Authentication is required to disable login without password + Autentificarea este necesară pentru a dezactiva autentificarea fără parolă + + + + Disable Login without password + Dezactivați autentificarea fără parolă + + + + Authentication is required to set keyboard layout + Autentificarea este necesară pentru a modifica aspectul tastaturii + + + + Set keyboard layout + Modificați aspectul tastaturii + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ru.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ru.ts new file mode 100644 index 000000000..5c3b7b6ff --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ru.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Для изменения личных пользовательских данных требуется аутентификация + + + + Change your own user data + Изменить личные пользовательские данные + + + + Authentication is required to change user data + Для изменения пользовательских данных требуется аутентификация + + + + Manage user accounts + Управление учётными записями пользователей + + + + Authentication is required to enable auto login + Для активации автоматического входа требуется аутентификация + + + + Enable Auto Login + Активировать автоматический вход + + + + Authentication is required to disable auto login + Для отключения автоматического входа требуется аутентификация + + + + Disable Auto Login + Отключить Автоматический Вход + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Для активации входа без ввода пароля требуется аутентификация + + + + Enable Login without password + Активировать Вход без ввода пароля + + + + Authentication is required to disable login without password + Для отключения входа без ввода пароля требуется аутентификация + + + + Disable Login without password + Отключить Вход без ввода пароля + + + + Authentication is required to set keyboard layout + Для того чтобы задать раскладку клавиатуры требуется аутентификация + + + + Set keyboard layout + Задать раскладку клавиатуры + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ru_UA.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ru_UA.ts new file mode 100644 index 000000000..47d6b1d48 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ru_UA.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_sc.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_sc.ts new file mode 100644 index 000000000..5890985f3 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_sc.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_si.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_si.ts new file mode 100644 index 000000000..feaf216f8 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_si.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + ඔබේ පරිශීලක දත්ත වෙනස් කිරීමට සත්‍යාපනය අවශ්‍ය වේ + + + + Change your own user data + ඔබේ පරිශීලක දත්ත වෙනස් කරන්න + + + + Authentication is required to change user data + පරිශීලක දත්ත වෙනස් කිරීම සඳහා සත්‍යාපනය අවශ්‍ය වේ + + + + Manage user accounts + පරිශීලක ගිණුම් කළමනාකරණය කරන්න + + + + Authentication is required to enable auto login + ස්වයංක්‍රීය පිවිසුම සක්‍රීය කිරීම සඳහා සත්‍යාපනය අවශ්‍ය වේ + + + + Enable Auto Login + ස්වයංක්‍රීය පිවිසුම සක්‍රීය කරන්න + + + + Authentication is required to disable auto login + ස්වයංක්‍රීය පිවිසුම අක්‍රිය කිරීමට සත්‍යාපනය අවශ්‍ය වේ + + + + Disable Auto Login + ස්වයංක්‍රීය පිවිසුම අක්‍රීය කරන්න + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + මුරපදය නොමැතිව පිවිසීම සක්‍රිය කිරීම සඳහා සත්‍යාපනය අවශ්‍ය වේ + + + + Enable Login without password + මුරපදය නොමැතිව පිවිසීම සක්‍රීය කරන්න + + + + Authentication is required to disable login without password + මුරපදය නොමැතිව පිවීසීම අක්‍රිය කිරීමට සත්‍යාපනය අවශ්‍ය වේ + + + + Disable Login without password + මුරපදය නොමැතිව පිවිසීම අක්‍රීය කරන්න + + + + Authentication is required to set keyboard layout + යතුරු පුවරුවේ පිරිවිතර සැකසීමට සත්‍යාපනය අවශ්‍ය වේ + + + + Set keyboard layout + යතුරු පුවරුවේ පිරිවිතර සකසන්න + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_sk.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_sk.ts new file mode 100644 index 000000000..c7f51e9d0 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_sk.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Na zmenu vlastných používateľských údajov je potrebné overenie totožnosti + + + + Change your own user data + Zmeniť svoje vlastné používateľské údaje + + + + Authentication is required to change user data + Na zmenu používateľských údajov je potrebné overenie totožnosti + + + + Manage user accounts + Spravovať používateľské účty + + + + Authentication is required to enable auto login + Na automatické prihlásenie sa vyžaduje overenie + + + + Enable Auto Login + Povoliť automatické prihlásenie + + + + Authentication is required to disable auto login + Na zakázanie automatického prihlásenia sa vyžaduje overenie + + + + Disable Auto Login + Zakázať automatické prihlásenie + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Na povolenie automatického prihlásenia bez hesla sa vyžaduje overenie + + + + Enable Login without password + Povoliť prihlásenie bez hesla + + + + Authentication is required to disable login without password + Na zakázanie automatického prihlásenia bez hesla sa vyžaduje overenie + + + + Disable Login without password + Zakázať prihlásenie bez hesla + + + + Authentication is required to set keyboard layout + Na nastavenie rozloženia klávesnice je potrebné overenie + + + + Set keyboard layout + Nastavte rozloženie klávesnice + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_sl.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_sl.ts new file mode 100644 index 000000000..31b940bda --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_sl.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Za spremembo lastnih podatkov je zahtevana overitev + + + + Change your own user data + Spremenite uporabniške podatke + + + + Authentication is required to change user data + Srememba podatkov uporabnika zahteva overitev + + + + Manage user accounts + Upravljanje uporabniških računov + + + + Authentication is required to enable auto login + Vklop samodejne prijave zahteva overitev + + + + Enable Auto Login + Vklopi samodejno prijavo + + + + Authentication is required to disable auto login + Izklop samodejne prijave zahteva overitev + + + + Disable Auto Login + Izklopi samodejno prijavo + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Prijava brez gesla zahteva overitev + + + + Enable Login without password + Vklopi prijavo brez gesla + + + + Authentication is required to disable login without password + Izklop prijave brez gesla zahteva overitev + + + + Disable Login without password + Izklopi prijavo brez gesla + + + + Authentication is required to set keyboard layout + Sprememba razporeda tipkovnice zahteva overitev + + + + Set keyboard layout + Določi razpored tipkovnice + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_sq.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_sq.ts new file mode 100644 index 000000000..1561f363d --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_sq.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Që të ndryshoni të dhënat tuaja të përdoruesit, lypset mirëfilltësim + + + + Change your own user data + Ndryshoni të dhënat tuaja të përdoruesit + + + + Authentication is required to change user data + Që të ndryshoni të dhëna përdoruesi, lypset mirëfilltësim + + + + Manage user accounts + Administroni llogari përdoruesish + + + + Authentication is required to enable auto login + Që të aktivizoni hyrje të automatizuara, lypset mirëfilltësim + + + + Enable Auto Login + Aktivizoni Hyrje të Automatizuara + + + + Authentication is required to disable auto login + Që të çaktivizoni hyrje të automatizuara, lypset mirëfilltësim + + + + Disable Auto Login + Çaktivizoni Hyrje të Automatizuara + + + + Authentication is required to enable quick login + Që të aktivizohet hyrje e shpejtë, lypset mirëfilltësim + + + + Enable Quick Login + Aktivizo Hyrje të Shpejtë + + + + Authentication is required to disable quick login + Që të çaktivizohet hyrje e shpejtë, lypset mirëfilltësim + + + + Disable Quick Login + Çaktivizo Hyrje të Shpejtë + + + + Authentication is required to enable WeChat code login + Që të aktivizohet hyrje me kod WeChat, lypset të bëhet mirëfilltësimi + + + + Enable WeChat Code Login + Aktivizo Hyrje me Kod WeChat + + + + Authentication is required to disable WeChat code login + Që të çaktivizohet hyrje me kod WeChat, lypset të bëhet mirëfilltësimi + + + + Disable WeChat Code Login + Çaktivizo Hyrje me Kod WeChat + + + + Authentication is required to enable login without password + Që të aktivizoni hyrje pa fjalëkalim, lypset mirëfilltësim + + + + Enable Login without password + Aktivizoni Hyrje pa fjalëkalim + + + + Authentication is required to disable login without password + Që të çaktivizoni hyrje pa fjalëkalim, lypset mirëfilltësim + + + + Disable Login without password + Çaktivizoni Hyrje pa fjalëkalim + + + + Authentication is required to set keyboard layout + Që të caktoni skemë tastiere, lypset mirëfilltësim + + + + Set keyboard layout + Caktoni skemë tastiere + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_sr.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_sr.ts new file mode 100644 index 000000000..fda4b7143 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_sr.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Идентификација је неопходна за промену сопствених корисничких података + + + + Change your own user data + Промените сопствене корисничке податке + + + + Authentication is required to change user data + Идентификација је неопходна за промену корисничких података + + + + Manage user accounts + Управљај корисничким налозима + + + + Authentication is required to enable auto login + Идентификација је неопходна да се омогући аутоматско пријављивање + + + + Enable Auto Login + Омогући аутоматско пријављивање + + + + Authentication is required to disable auto login + Идентификација је неопходна да се онемогући аутоматско пријављивање + + + + Disable Auto Login + Онемогући аутоматско пријављивање + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Идентификација је неопходна да се омогући пријављивање без лозинке + + + + Enable Login without password + Омогући пријављивање без лозинке + + + + Authentication is required to disable login without password + Идентификација је неопходна да се онемогући пријављивање без лозинке + + + + Disable Login without password + Онемогући пријављивање без лозинке + + + + Authentication is required to set keyboard layout + Идентификација је неопходна за подешавање распореда тастатуре + + + + Set keyboard layout + Подеси распоред тастатуре + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_sv.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_sv.ts new file mode 100644 index 000000000..8accda582 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_sv.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Autentisering krävs för att ändra ditt egna användardata + + + + Change your own user data + Ändra ditt egna användardata + + + + Authentication is required to change user data + Autentisering krävs för att ändra användardata + + + + Manage user accounts + Hantera användarkonton + + + + Authentication is required to enable auto login + Autentisering krävs för att aktivera automatisk inloggning + + + + Enable Auto Login + Aktivera automatisk inloggning + + + + Authentication is required to disable auto login + Autentisering krävs för att inaktivera automatisk inloggning + + + + Disable Auto Login + Inaktivera automatisk inloggning + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Autentisering krävs för att aktivera inloggning utan lösenord + + + + Enable Login without password + Aktivera inloggning utan lösenord + + + + Authentication is required to disable login without password + Autentisering krävs för att inaktivera inloggning utan lösenord + + + + Disable Login without password + Inaktivera inloggning utan lösenord + + + + Authentication is required to set keyboard layout + Autentisering krävs för att ändra tangentbordslayout + + + + Set keyboard layout + Ändra tangentbordslayout + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_sv_SE.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_sv_SE.ts new file mode 100644 index 000000000..78e08eb4c --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_sv_SE.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_sw.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_sw.ts new file mode 100644 index 000000000..2f5f3112e --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_sw.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Thibitisha inahitaji kugeuza taarifa ya mtumiaji yako + + + + Change your own user data + Geuza taarifa ya mtumiaji yako + + + + Authentication is required to change user data + Thibitisha inahitaji kugeuza taarifa za mtumiaji + + + + Manage user accounts + Simamia akaunti za mtumiaji + + + + Authentication is required to enable auto login + Thibitisha inahitaji kuwezesha kuingia moja kwa moja + + + + Enable Auto Login + Wezesha kuingia moja kwa moja + + + + Authentication is required to disable auto login + Thibitisha inahitaji kulemaza kuingia moja kwa moja + + + + Disable Auto Login + Lemaza kuingia moja kwa moja + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Thibitisha inahitaji kuwezesha kuingia bila nywila + + + + Enable Login without password + Wezesha kuingia bila nywila + + + + Authentication is required to disable login without password + Thibitisha inahitaji kulemaza kuingia bila nywila + + + + Disable Login without password + Lemaza kuingia bila nywila + + + + Authentication is required to set keyboard layout + Thibitisha inahitaji kuchagua mpangilio wa kibodi + + + + Set keyboard layout + Chagua mpangilio wa kibodi + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ta.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ta.ts new file mode 100644 index 000000000..5879c1efa --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ta.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_te.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_te.ts new file mode 100644 index 000000000..8367ecd35 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_te.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_th.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_th.ts new file mode 100644 index 000000000..bb6ecfad2 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_th.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_tr.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_tr.ts new file mode 100644 index 000000000..108ee0014 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_tr.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Kullanıcı verilerinizi değiştirmek için kimlik doğrulaması gerekli + + + + Change your own user data + Kullanıcı bilgilerinizi değiştirin + + + + Authentication is required to change user data + Kullanıcı verilerini değiştirmek için kimlik doğrulaması gerekli + + + + Manage user accounts + Kullanıcı hesaplarını yönet + + + + Authentication is required to enable auto login + Otomatik oturum açmayı etkinleştirmek için kimlik doğrulaması gerekli + + + + Enable Auto Login + Otomatik Girişi Etkinleştir + + + + Authentication is required to disable auto login + Otomatik girişi devre dışı bırakmak için kimlik doğrulaması gerekli + + + + Disable Auto Login + Otomatik Giriş Devre Dışı + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Parola olmadan oturum açmak için kimlik doğrulaması gerekli + + + + Enable Login without password + Parola olmadan oturum açmayı etkinleştir + + + + Authentication is required to disable login without password + Parola olmadan oturum açmayı devre dışı bırakmak için kimlik doğrulaması gerekli + + + + Disable Login without password + Parola olmadan oturum açma devre dışı + + + + Authentication is required to set keyboard layout + Klavye düzenini ayarlamak için kimlik doğrulaması gerekli + + + + Set keyboard layout + Klavye düzenini ayarla + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_tzm.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_tzm.ts new file mode 100644 index 000000000..5194bd98f --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_tzm.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ug.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ug.ts new file mode 100644 index 000000000..375fb4f2d --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ug.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + ئۆزىڭىزنىڭ ئابونت سانلىق مەلۇماتىنى ئۆزگەرتىش ئۈچۈن سالاھىيىتىڭىزنى دەلىللەشكە توغرا كېلىدۇ + + + + Change your own user data + ئۆزىڭىزنىڭ ئابونت سانلىق مەلۇماتىنى ئۆزگەرتىڭ + + + + Authentication is required to change user data + ئابونىت سانلىق مەلۇماتىنى ئۆزگەرتىش ئۈچۈن سالاھىيەت سالاھىتىڭىزنى دەلىىللەڭ + + + + Manage user accounts + ئابونىت ھېسابات نۇمىرىنى باشقۇرۇش + + + + Authentication is required to enable auto login + ئاپتۇماتىك تىزىملاش ئۈچۈن سالاھىتىڭىزنى دەللىللەشكە توغرا كىلىدۇ + + + + Enable Auto Login + ئاپتۇماتىك كىرىشنى ئېچىش + + + + Authentication is required to disable auto login + ئاپتۇماتىك كىرىشنى تاقاش ئۈچۈن سالاھىيەت دەلىللەش كېرەك + + + + Disable Auto Login + ئاپتۇماتىك تىزىملاپ كىرىشنى چەكلەش + + + + Authentication is required to enable quick login + تېزلەتمە كىرىشنى ئېچىش ئۈچۈن سالاھىيەت دەلىللەش كېرەك + + + + Enable Quick Login + تېزلەتمە كىرىشنى ئېچىش + + + + Authentication is required to disable quick login + تېزلەتمە كىرىشنى تاقاش ئۈچۈن سالاھىيەت دەلىللەش كېرەك + + + + Disable Quick Login + تېزلەتمە كىرىشنى تاقاش + + + + Authentication is required to enable WeChat code login + ئۈندىداردا سايىلەپ كىرىشنى ئېچىش ئۈچۈن سالاھىيەت دەلىللەش كېرەك + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + ئۈندىداردا سايىلەپ كىرىشنى تاقاش ئۈچۈن سالاھىيەت دەلىللەش كېرەك + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + مەخپى نۇمۇرسىز كىرىش ئۈچۈن سالاھىيەت دەلىللەشكە توغرا كىلىدۇ + + + + Enable Login without password + ئابونىت مەخپى شىفىرسىز كىرىش + + + + Authentication is required to disable login without password + مەخپى شىفىرسىز كىرىشنى توىتىتىش ئۈچۈن سالاھىيەت دەللىللەش كېرەك + + + + Disable Login without password + مەخپى شىفىرسىز كىرىشنى چەكلەش + + + + Authentication is required to set keyboard layout + كۇنۇپكا تاختىسى ئورۇنلاشتۇرۇش ئۈچۈن سالاھىيىتىنى تەكشۈرۈشكە توغرا كېلىدۇ + + + + Set keyboard layout + كونۇپكا تاختىىسى تەڭشەش + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_uk.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_uk.ts new file mode 100644 index 000000000..a6b3176ee --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_uk.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Для зміни даних вашого користувача потрібно пройти розпізнавання + + + + Change your own user data + Зміна даних вашого користувача + + + + Authentication is required to change user data + Для зміни даних користувача потрібно пройти розпізнавання + + + + Manage user accounts + Керування обліковими записами + + + + Authentication is required to enable auto login + Для вмикання автоматично входу слід пройти розпізнавання + + + + Enable Auto Login + Вмикання автоматичного входу + + + + Authentication is required to disable auto login + Для вимикання автоматичного входу слід пройти розпізнавання + + + + Disable Auto Login + Вимикання автоматичного входу + + + + Authentication is required to enable quick login + Для вмикання швидкого входу слід пройти розпізнавання + + + + Enable Quick Login + Вмикання швидкого входу + + + + Authentication is required to disable quick login + Для вимикання швидкого входу слід пройти розпізнавання + + + + Disable Quick Login + Вимикання швидкого входу + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Для вмикання можливості входу без пароля слід пройти розпізнавання + + + + Enable Login without password + Вмикання входу без пароля + + + + Authentication is required to disable login without password + Для вимикання можливості входу без пароля слід пройти розпізнавання + + + + Disable Login without password + Вимикання входу без пароля + + + + Authentication is required to set keyboard layout + Для встановлення розкладки клавіатури слід пройти розпізнавання + + + + Set keyboard layout + Встановлення розкладки клавіатури + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_ur.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_ur.ts new file mode 100644 index 000000000..17ee7727a --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_ur.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_uz.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_uz.ts new file mode 100644 index 000000000..31c1ffaa2 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_uz.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + + + + + Change your own user data + + + + + Authentication is required to change user data + + + + + Manage user accounts + + + + + Authentication is required to enable auto login + + + + + Enable Auto Login + + + + + Authentication is required to disable auto login + + + + + Disable Auto Login + + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + + + + + Enable Login without password + + + + + Authentication is required to disable login without password + + + + + Disable Login without password + + + + + Authentication is required to set keyboard layout + + + + + Set keyboard layout + + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_vi.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_vi.ts new file mode 100644 index 000000000..904f381e3 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_vi.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + Cần xác thực để thay đổi dữ liệu người dùng của chính mình + + + + Change your own user data + Thay đổi dữ liệu người dùng của chính mình + + + + Authentication is required to change user data + Cần xác thực để thay đổi dữ liệu người dùng + + + + Manage user accounts + Quản lý tài khoản người dùng + + + + Authentication is required to enable auto login + Cần xác thực để cho phép tự động đăng nhập + + + + Enable Auto Login + Cho phép Tự động Đăng nhập + + + + Authentication is required to disable auto login + Cần xác thực để vô hiệu hóa tự động đăng nhập + + + + Disable Auto Login + Vô hiệu hóa Tự động Đăng nhập + + + + Authentication is required to enable quick login + + + + + Enable Quick Login + + + + + Authentication is required to disable quick login + + + + + Disable Quick Login + + + + + Authentication is required to enable WeChat code login + + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + Cần xác thực để cho phép đăng nhập mà không cần mật mã + + + + Enable Login without password + Kích hoạt đăng nhập không cần mật khẩu + + + + Authentication is required to disable login without password + Cần có xác thực để vô hiệu hóa đăng nhập mà không cần mật khẩu + + + + Disable Login without password + Vô hiệu hóa Đăng nhập mà không cần mật khẩu + + + + Authentication is required to set keyboard layout + Cần xác thực để đặt bố cục bàn phím + + + + Set keyboard layout + Cài đặt bố cục bàn phím + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_zh_CN.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_zh_CN.ts new file mode 100644 index 000000000..0f3dcae8e --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_zh_CN.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + 修改您的用户数据需要认证 + + + + Change your own user data + 修改您的用户数据 + + + + Authentication is required to change user data + 修改用户数据需要认证 + + + + Manage user accounts + 管理用户帐户 + + + + Authentication is required to enable auto login + 开启自动登录需要认证 + + + + Enable Auto Login + 开启自动登录 + + + + Authentication is required to disable auto login + 关闭自动登录需要认证 + + + + Disable Auto Login + 关闭自动登录 + + + + Authentication is required to enable quick login + 开启快速登录需要认证 + + + + Enable Quick Login + 开启快速登录 + + + + Authentication is required to disable quick login + 关闭快速登录需要认证 + + + + Disable Quick Login + 关闭快速登录 + + + + Authentication is required to enable WeChat code login + 开启微信扫码登录需要认证 + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + 关闭微信扫码登录需要认证 + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + 开启无密码登录需要认证 + + + + Enable Login without password + 开启无密码登录 + + + + Authentication is required to disable login without password + 关闭无密码登录需要认证 + + + + Disable Login without password + 关闭无密码登录 + + + + Authentication is required to set keyboard layout + 设置键盘布局需要认证 + + + + Set keyboard layout + 设置键盘布局 + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_zh_HK.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_zh_HK.ts new file mode 100644 index 000000000..8825949a7 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_zh_HK.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + 修改您的用戶數據需要認證 + + + + Change your own user data + 修改您的用戶數據 + + + + Authentication is required to change user data + 修改用戶數據需要認證 + + + + Manage user accounts + 管理用戶帳戶 + + + + Authentication is required to enable auto login + 開啟自動登錄需要認證 + + + + Enable Auto Login + 開啟自動登錄 + + + + Authentication is required to disable auto login + 關閉自動登錄需要認證 + + + + Disable Auto Login + 關閉自動登錄 + + + + Authentication is required to enable quick login + 開啟快速登錄需要認證 + + + + Enable Quick Login + 開啟快速登錄 + + + + Authentication is required to disable quick login + 關閉快速登錄需要認證 + + + + Disable Quick Login + 關閉快速登錄 + + + + Authentication is required to enable WeChat code login + 開啟微信掃碼登錄需要認證 + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + 關閉微信掃碼登錄需要認證 + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + 開啟無密碼登錄需要認證 + + + + Enable Login without password + 開啟無密碼登錄 + + + + Authentication is required to disable login without password + 關閉無密碼登錄需要認證 + + + + Disable Login without password + 關閉無密碼登錄 + + + + Authentication is required to set keyboard layout + 設置鍵盤佈局需要認證 + + + + Set keyboard layout + 設置鍵盤佈局 + + + \ No newline at end of file diff --git a/misc/ts/org.deepin.dde.accounts1.policy/policy_zh_TW.ts b/misc/ts/org.deepin.dde.accounts1.policy/policy_zh_TW.ts new file mode 100644 index 000000000..3a249d3c9 --- /dev/null +++ b/misc/ts/org.deepin.dde.accounts1.policy/policy_zh_TW.ts @@ -0,0 +1,115 @@ + + + policy + + + Authentication is required to change your own user data + 若要變更您自身的使用者資料需要通過認證 + + + + Change your own user data + 變更您自身的使用者資料 + + + + Authentication is required to change user data + 若要變更使用者資料需要通過認證 + + + + Manage user accounts + 管理使用者帳戶 + + + + Authentication is required to enable auto login + 啟用自動登入需要身份核對 + + + + Enable Auto Login + 啟用自動登入 + + + + Authentication is required to disable auto login + 停用自動登入需要身份核對 + + + + Disable Auto Login + 停用自動登入 + + + + Authentication is required to enable quick login + 開啟快速登入需要認證 + + + + Enable Quick Login + 開啟快速登入 + + + + Authentication is required to disable quick login + 關閉快速登入需要認證 + + + + Disable Quick Login + 關閉快速登入 + + + + Authentication is required to enable WeChat code login + 開啟微信掃碼登入需要認證 + + + + Enable WeChat Code Login + + + + + Authentication is required to disable WeChat code login + 關閉微信掃碼登入需要認證 + + + + Disable WeChat Code Login + + + + + Authentication is required to enable login without password + 啟用無密碼登入需要身份核對 + + + + Enable Login without password + 啟用無密碼登入 + + + + Authentication is required to disable login without password + 停用無密碼登入需要身份核對 + + + + Disable Login without password + 停用無密碼登入 + + + + Authentication is required to set keyboard layout + 設定鍵盤配置需要身份核對 + + + + Set keyboard layout + 設定鍵盤配置 + + + \ No newline at end of file diff --git a/misc/udev-rules/80-deepin-fprintd.rules b/misc/udev-rules/80-deepin-fprintd.rules index d3d3554ab..7063a40c9 100644 --- a/misc/udev-rules/80-deepin-fprintd.rules +++ b/misc/udev-rules/80-deepin-fprintd.rules @@ -1 +1 @@ -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_interface", ACTION=="add|remove", ENV{LIBFPRINT_DRIVER}!="" RUN+="/usr/bin/dbus-send --system --dest=com.deepin.daemon.Fprintd --print-reply /com/deepin/daemon/Fprintd com.deepin.daemon.Fprintd.TriggerUDevEvent" +SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_interface", ACTION=="add|remove", ENV{LIBFPRINT_DRIVER}!="", RUN+="/usr/bin/dbus-send --system --dest=org.deepin.dde.Fprintd1 --print-reply /org/deepin/dde/Fprintd1 org.deepin.dde.Fprintd1.TriggerUDevEvent" diff --git a/network/README.md b/network/README.md deleted file mode 100644 index 959b8e6a6..000000000 --- a/network/README.md +++ /dev/null @@ -1,739 +0,0 @@ -**描述**: deepin 网络后端, 主要是对 NetworkManager DBus 接口进行包装, -提供全面的网络管理功能, 包括有线, 无线, PPPoE 拨号连接, 3G上网卡, -VPN(已支持 L2TP, PPTP, OpenConnect, OpenVPN, StrongSwan, VPNC等至少6 -种 VPN 类型), 系统代理等功能. - -**名词解释**: - -- 字段(Setting): NetworkManager 网络连接原生支持的字段, 如 - `NM_SETTING_WIRED_SETTING_NAME`(802-3-ethernet) -- 键值(Key): NetworkManager 网络连接原生支持的键值, 如 - `NM_SETTING_WIRED_MTU`(mtu) -- 虚拟字段(Section 或 Vsection): 为方便用户配置网络, deepin 网络后 - 端自定义的虚拟字段, 其值一般以 "vs-" 开头. 简单的理解, 前端控制中心网络编辑页面所显示的分类 - 段落即分别对应一个虚拟字段, 如 `NM_SETTING_VS_GENERAL`("vs-general", 显 - 示名称为 "General") -- 虚拟键值(Virtual Key): 为方便用户配置网络, deepin 网络后端自定义的虚 - 拟键值, 其值一般以 "vk-" 开头. 如为了方便配置 3G/4G 网络, 默认在前端 - 显示`NM_SETTING_VK_MOBILE_COUNTRY`("vk-mobile-country", 显示名称为 - "Country or region"), - `NM_SETTING_VK_MOBILE_PROVIDER`("vk-mobile-provider", 显示名称为 - "Provider") 和`NM_SETTING_VK_MOBILE_PLAN`("vk-mobile-plan", 显示名称 - 为 "Plan") 等几个虚拟键值, 而不是让用户手动配置 APN 等专业信息. - - 另虚拟键值包括三类: - 1. wrapper, 对其他原生键值进行包装, 这种情况下前端只显示 wrapper 虚 - 拟键值, 而隐藏对应的原生键值, 一般有两种用途: - 1. 改善键值设置时的交互方式, 例如"vk-no-permission" 对 - `NM_SETTING_CONNECTION_PERMISSIONS` 进行包装, 把原来需要用户手 - 动输入用户名进行设置权限的交互方式改为开关(ktypeBoolean) - 1. 将某一个原生键分拆为多个虚拟子键(child key), 如 - `NM_SETTING_IP4_CONFIG_ADDRESSES` 被分拆成了 - "vk-addresses-address", "vk-addresses-mask" 和 - "vk-addresses-gateway" - 1. enable-wrapper, 对其他键值的可用性添加开关, 如 "vk-enable-mtu" - 1. controller, 纯控制型虚拟键, 一般没有相关的原生键, 如 - "vk-vpn-missing-plugin", 用来在前端显示所缺少的 VPN 插件包. - -## 目录结构 - -- **examples**: 调用 deepin 网络后端 DBus 接口的 shell, python 脚本示 - 例. - -- **nm**: 定义 NetworkManager 常量的子库, 具体参考其 - [README](./nm/README.md). - -- **nm_generator**: 辅助 NetworkManager Go 代码生成器, 后缀名 - 为'*_gen.go' 的文件均由其生成, 包括 `nm/nm_consts_gen.go` 和 - `nm_setting_beans_gen.go`, 具体参考其 - [README](./nm_generator/README.md). - -- **agent.go**: 实现 NetworkManager secret agent 的主要文件, 主要用于 - 处理密码弹出框等问题, 相关文档可参考 `nm_generator/nm_docs`, 代码逻 - 辑可参考 - [applet-agent.c](https://github.com/GNOME/network-manager-applet/blob/master/src/applet-agent.c). - -- **connection_session.go**: ConnectionSession DBus 接口主要文件, 用于 - 给前端提供接口来编辑网络连接, 配合 GetKey, SetKey, AvailableKeys, - GetAvailableValues 等接口, 前端可以生成相关的控件界面, 并根据后端信 - 号按需进行展示. - -- **manager_accesspoint.go**: 处理 WiFi 热点及相关 DBus 接口. - -- **manager_active.go**, **dbus_watcher.go**: 手动注册 DBus watcher监 - 听 NetworkManager 所有激活连接的状态变更以避免调用 dbus-factory 接口 - 一定概率导致信号不同步的问题, 同时提供了接口用来获取当前激活连接的相 - 关信息. - -- **manager_config.go**: 处理 deepin 网络后端的配置文件 - (~/.config/deepin/network.json), 主要保存一些网络开关状态和 VPN 自动 - 连接的配置. - -- **manager_connection.go**: 创建/激活/删除网络连接及相关 DBus 接口. - -- **manager_device.go**: 处理网卡设备及相关 DBus 接口. - -- **manager.go**: 主 Manager DBus 对象. - -- **manager_proxy.go**: 处理系统代理及相关 DBus 接口. - -- **manager_switch.go**: 处理设备开关及相关 DBus 接口. deepin 为每个网 - 卡都单独提供一个虚拟开关, 同时会兼容 NetworkManager 本身的逻辑流程. - -- **nm_custom_type.go**: 自定义的一些字符串格式的网络设备类型和网络连 - 接类型, 主要方便与前端交互. - -- **nm_key_xxx.go**: 通过 NetworkManager DBus 接口编辑网络连接时的一些辅 - 助方法, 同时自定义了对应的键值类型, 包括添加了一些包装类型, 如 - `ktypeWrapperIpv4Addresses`, 用于方便处理相关逻辑. `nm_generator` 基 - 本是围绕这部分内容生成 NetworkManager 键值的 getter, setter. - -- **nm_setting_virtual_key.go**: 定义虚拟键值(virtual key) 及相关 - 逻辑代码, 另外某些 "controller" 类型的虚拟键的 getter, setter, available - key 即 available value 等逻辑代码也会定义到这里. - -- **nm_setting_virtual_section.go**: 定义虚拟字段(virtual section) 及 - 相关逻辑代码, 包括获取虚拟字段对应的原生字段列表, 判断虚拟字段对应的 - 前端控件默认是否展开等. - -- **nm_setting_beans_gen.go**: 通过 `nm_generator` 生成的辅助代码, 因 - 为 NetworkManager 的字段键值比较多, 所以代码量比较大, 主要包括下面集 - 中类型: - - - 虚拟字段列表及显示名称(翻译文本) - - 虚拟键值列表, 包括前端展示时所用到的控件类型, 显示名称(翻译文本) - 和取值范围(可选) - - 虚拟键值和原生键值的 getter 和 setter 代码 - - generalXXX 开头的通用辅助方法, 如 `generalGetSettingKeyType`, - `generalGetSettingAvailableKeys`, `generalGetSettingDefaultValue` - 等 - -- **nm_setting_beans_extend.go**: 因为 `nm_generator` 会把 - NetworkManager 支持的所有字段(Setting)和键值(Key)都生成出来, 然后可 - 能部分字段用不到, 为了保证编译通过, 需要补充 - getSettingXXXAvailableKeys, getSettingXXXAvailableValues, - checkSettingXXXValues 等空方法. - -- **nm_setting_xxx.go**: 放置 NetworkManager 字段(Setting)相关的逻辑代 - 码, 主要包括 getSettingXXXAvailableKeys, - getSettingXXXAvailableValues 和 checkSettingXXXValues. - -- **nm_setting_vpn.go**: 放置 VPN 通用逻辑代码, 一部分用来处理 VPN 密 - 码弹出框(一般调用 VPN 自己的密码弹出框, 如 - `/usr/lib/NetworkManager/nm-xxx-auth-dialog`), 另一部分特殊处理 VPN - 子键, 将其保存到 `NM_SETTING_VPN_DATA` 和 `NM_SETTING_VPN_SECRETS`这 - 两个键(string dictionary)里面. - -- **nm_setting_vpn_xxx.go**: 放置特定 VPN 相关的逻辑代码, 主要是 - getSettingVpnXXXAvailableKeys, getSettingVpnXXXAvailableValues, - checkSettingVpnXXXValues. - -- **state_handler.go**: 监听网络设备状态变更并按需弹出系统通知. - -- **utils_xxx.go**: 一些辅助方法, 如处理 IPv6 地址, 读写 gnome-keyring, - 包装系统通知接口, 包装 NetworkManager 和 ModemManager DBus 接口等. - -## NetworkManager DBus 接口简介 - -- `/org/freedesktop/NetworkManager`: NetworkManager DBus 主接口, 可用获 - 取当前网络状态, 设备列表, 连接列表, 用户权限等 -- `/org/freedesktop/NetworkManager/Devices/XXX`: 特定网络设备接口 -- `/org/freedesktop/NetworkManager/Settings`: 配置文件相关接口 -- `/org/freedesktop/NetworkManager/Settings/XXX`: 特定配置文件接口 -- `/org/freedesktop/NetworkManager/AccessPoint/XXX`: WiFi 热点接口 -- `/org/freedesktop/NetworkManager/ActiveConnection/XXX`: 已激活连接 - 接口 -- `/org/freedesktop/NetworkManager/IP4Config/XXX`: 当前分配的 IP4 地址接 - 口 -- `/org/freedesktop/NetworkManager/IP6Config/XXX`: 当前分配的 IP6 地址接 - 口 - -具体请参考 `nm_generator/nm_docs`. - -## deepin 网络后端 DBus 接口简介 - -**DBus 参数命名规范**: -- `uuid`: string 类型, 表示配置文件唯一的 UUID 值 -- `apPath`: dbus.ObjectPath 类型, 表示 AccessPoint 对应的 DBus 路径, 如 - /org/freedesktop/NetworkManager/AccessPoint/XXX -- `devPath`: dbus.ObjectPath 类型, 表示网络设备对应的 DBus 路径, 如 - /org/freedesktop/NetworkManager/Devices/XXX -- `cpath`: dbus.ObjectPath 类型, 表示配置文件对应的 DBus 路径, 如 - /org/freedesktop/NetworkManager/Settings/XXX -- `connType`: string 类型, 表示配置文件类型, 如 - `connectionWired`("wired"), 全部定义位于 `nm_custom_type.go`. -- `xxxJSON`: JSON string 类型, 为了方便前后端交互, 同时减少 DBus 参数数 - 量, deepin 网络后端用了很多 JSON string 类型的参数 - -### com.deepin.daemon.Network - -- 当前网络状态 - - `GetActiveConnectionInfo() (acinfosJSON string)` - - **prop** `State uint32` - - **prop** `Devices string` - - **prop** `Connections string` - - **prop** `ActiveConnections string` - -- 网络开关 - - `EnableDevice(devPath dbus.ObjectPath, enabled bool)` - - `IsDeviceEnabled(devPath dbus.ObjectPath) (enabled bool)` - - `SetDeviceManaged(devPathOrIfc string, managed bool)` - - **prop-rw** `NetworkingEnabled bool` - - **prop-rw** `VpnEnabled bool` - - **signal** `DeviceEnabled func(devPath string, enabled bool)` - -- 编辑网络连接 - - `CreateConnection(connType string, devPath dbus.ObjectPath) (session *ConnectionSession)` - - `CreateConnectionForAccessPoint(apPath, devPath dbus.ObjectPath) (session *ConnectionSession)` - - `DeleteConnection(uuid string)` - - `EditConnection(uuid string, devPath dbus.ObjectPath) (session *ConnectionSession)` - - `GetSupportedConnectionTypes() (types []string)` - -- 激活网络连接 - - `ActivateConnection(uuid string, devPath dbus.ObjectPath) (cpath dbus.ObjectPath)` - - `DeactivateConnection(uuid string)` - - `DisconnectDevice(devPath dbus.ObjectPath)` - - `GetWiredConnectionUuid(wiredDevPath dbus.ObjectPath) (uuid string)` - -- WiFi AccessPoint - - `ActivateAccessPoint(uuid string, apPath, devPath dbus.ObjectPath) (cpath dbus.ObjectPath)` - - `GetAccessPoints(path dbus.ObjectPath) (apsJSON string)` - - **signal** `AccessPointAdded func(devPath, apJSON string)` - - **signal** `AccessPointRemoved func(devPath, apJSON string)` - - **signal** `AccessPointPropertiesChanged func(devPath, apJSON string)` - -- WiFi Hotspot 热点 - - `DisableWirelessHotspotMode(devPath dbus.ObjectPath)` - - `EnableWirelessHotspotMode(devPath dbus.ObjectPath)` - - `IsWirelessHotspotModeEnabled(devPath dbus.ObjectPath) (enabled bool)` - -- 弹出密码输入框 - - `CancelSecret(path string, settingName string)` - - `FeedSecret(path string, settingName, keyValue string, autoConnect bool)` - - **signal** `NeedSecrets func(connPath, settingName, connectionId string, autoConnect bool)` - - **signal** `NeedSecretsFinished func(connPath, settingName string)` - -- 系统代理 - - `GetAutoProxy() (proxyAuto string)` - - `GetProxy(proxyType string) (host, port string)` - - `GetProxyIgnoreHosts() (ignoreHosts string)` - - `GetProxyMethod() (proxyMode string)` - - `SetAutoProxy(proxyAuto string)` - - `SetProxy(proxyType, host, port string)` - - `SetProxyIgnoreHosts(ignoreHosts string)` - - `SetProxyMethod(proxyMode string)` - -### com.deepin.daemon.Network.ConnectionSession - -- DBus 属性 - - **prop** `ConnectionPath dbus.ObjectPath` - - **prop** `Uuid string` - - **prop** `Type string` - - **prop** `AllowDelete bool` - - **prop** `AllowEditConnectionId bool` - - **prop** `AvailableVirtualSections []string` - - **prop** `AvailableSections []string` - - **prop** `AvailableKeys map[string][]string` - - **prop** `Errors sessionErrors` - -- DBus 信号 - - **signal** `ConnectionDataChanged func()` - -- DBus 接口 - - `GetAllKeys() (infoJSON string)` - - `GetAvailableValues(section, key string) (valuesJSON string)` - - `GetKeyName(section, key string) (name string)` - - `GetKey(section, key string) (valueJSON string)` - - `SetKey(section, key, valueJSON string)` - - `IsDefaultExpandedSection(vsection string) bool` - - `Save() (ok bool)` - - `Close()` - -- Debug 辅助接口 - - `DebugGetConnectionData() connectionData` - - `DebugGetErrors() sessionErrors` - - `DebugListKeyDetail() (info string)` - -详细 DBus 接口信息请参考 -[godoc 文档](https://godoc.org/github.com/linuxdeepin/dde-daemon/network). - -## HACKING 实践 - -### 添加一个虚拟键值 - -1. 编辑 `nm_generator/nm_virtual_sections.yml`, 在适当位置添加虚拟键值 - 的定义, 如 - - ``` - - KeyValue: vk-autoconnect - Section: connection - DisplayName: Automatically connect - WidgetType: EditLineSwitchButton - VKeyInfo: - VirtualKeyName: NM_SETTING_VK_CONNECTION_AUTOCONNECT - Type: ktypeBoolean - VkType: vkTypeWrapper - RelatedKeys: - - NM_SETTING_CONNECTION_AUTOCONNECT - ChildKey: false - Optional: false - ``` - -1. 运行 `make gen-nm-code` 重新生成代码 - -1. 编辑 `nm_setting_connection.go`, 实现 - `getSettingVkConnectionAutoconnect` 和 - `logicSetSettingVkConnectionAutoconnect` - -1. 编辑 getSettingXXXAvailableKeys 控制何时显现该虚拟键 - -1. 如果需要检测用户输入信息的有效性, 还需要在 - checkSettingXXXValues 添加相关代码 - -1. 如果控件类型为 `EditLineComboBox` 或 `EditLineEditComboBox`, 还需要 - 在 getSettingXXXAvailableValues 返回有效值列表 - -1. 处理国际化 - -### 支持新的 VPN 类型 - -1. 以 OpenVPN 为例, 查看 network-manager-openvpn 源码, 检索 - `src/nm-openvpn-service.c` 找到所有 VPN 键值名称, 并将它们定义到 - `nm_generator/nm_vpn_alias_settings.yml` 和 - `nm/nm_extends_consts.go` - -1. 编辑 `nm_generator/nm_virtual_sections.yml`, 在 - `NM_SETTING_VS_VPN`虚拟字段下将需要展现到前端的键值按顺序补充完整, - 如果有必要还可用添加其他虚拟字段, 如 - `NM_SETTING_VS_VPN_OPENVPN_PROXIES` - -1. 如果要为某些 VPN 键值添加 logic setter, 则编辑 - `nm_generator/nm_logicset_keys.yml` - -1. 运行 `make gen-nm-code` 重新生成代码 - -1. 新建文件 `nm_setting_vpn_openvpn.go` 将相关代码补充完整 - -1. 编辑 `nm_custom_type.go`, 添加自定义 VPN 类型 - `connectionVpnOpenvpn`, 同时补充实现 `getCustomConnectionType`, - `isVsectionExpandedDefault`, `doGetRelatedVsections` 和 - `doGetRelatedSectionsOfVsection` - -1. 编辑 `nm_setting_virtual_key.go`, 补充实现 - `getLocalSupportedVpnTypes`, `getVpnNameFile`, - `logicSetSettingVkVpnType` 和 `getSettingVkVpnMissingPlugin` - -1. 处理国际化 - -## go test 单元测试 - -普通单元测试执行 `go test` 即可, 如果要执行 dev_test.go 里的内容则需要 -添加 `dev` tag: - -1. 获取当前系统支持的 VPN 类型 - - ```sh - go test -tags dev -gocheck.f TestLocalSupportedVpnTypes - ``` - -1. 单独执行网络后端 - ```sh - env DDE_DEBUG=t go test -tags dev -gocheck.f TestMain - ``` - -## 自动化测试 - -目前配合 ansbile/docker/openwrt 等技术, 易经实现 deepin 网络功能自动化 -测试, 具体请参考 -[deepin-network-tests](https://github.com/x-deepin/deepin-network-tests) - -如果要通过 iperf3 等工具测试网卡驱动的稳定性, 则参考 [network-testing-experiments](https://github.com/x-deepin/network-testing-experiments) - -## DBus 脚本示例 - -1. python 脚本调用网络 DBus 接口示例, 连接 WiFi 网络 - - [examples/python/main.py](./examples/python/main.py) - -1. shell 脚本调用网络 DBus 接口示例, 设置有线网卡静态 IP 地址 - - [examples/set_wired_static_ip.sh](./examples/set_wired_static_ip.sh) - -1. 根据有线网卡地址获取其对应配置的 UUID - - ```sh - macaddr_to_uuid() { - local md5="$(printf "$1" | md5sum | awk '{print $1}' | tr 'A-Z' 'a-z')" - echo "${md5:0:8}-${md5:8:4}-${md5:12:4}-${md5:16:4}-${md5:20:12}" - } - $ macaddr_to_uuid "00:12:34:56:ab:cd" - > 086e214c-1f20-bca4-9816-c0a11c8c0e02 - ``` - -1. 监听 NetworkManager 服务的运行状态 - - ```sh - dbus-monitor --system sender=org.freedesktop.DBus,member=NameOwnerChanged - ``` - -1. 监听 NetworkManager 配置文件的变更 - - ```sh - dbus-monitor --system sender=org.freedesktop.NetworkManager,interface=org.freedesktop.NetworkManager.Settings - ``` - -1. 开关 NetworkManager 飞行模式 - - ```sh - dbus-send --system --type=method_call --print-reply \ - --dest=org.freedesktop.NetworkManager /org/freedesktop/NetworkManager \ - org.freedesktop.DBus.Properties.Get \ - string:"org.freedesktop.NetworkManager" string:"NetworkingEnabled" - dbus-send --system --type=method_call --print-reply \ - --dest=org.freedesktop.NetworkManager /org/freedesktop/NetworkManager \ - org.freedesktop.NetworkManager.Enable boolean:"false" - ``` - -1. 开关 NetworkManager WiFi 无线网络功能 - - ```sh - dbus-send --system --type=method_call --print-reply \ - --dest=org.freedesktop.NetworkManager /org/freedesktop/NetworkManager \ - org.freedesktop.DBus.Properties.Set string:"org.freedesktop.NetworkManager" \ - string:"WirelessEnabled" variant:boolean:"false" - ``` - -1. 设置 NetworkManager 设备托管状态 - - ```sh - dbus-send --system --type=method_call --print-reply \ - --dest=org.freedesktop.NetworkManager /org/freedesktop/NetworkManager/Devices/0 \ - org.freedesktop.DBus.Properties.Set string:"org.freedesktop.NetworkManager.Device" \ - string:"Managed" variant:boolean:"false" - ``` - -1. 获取 deepin 网络后端提供的所有网络设备信息 - - ```sh - dbus-send --print-reply --dest=com.deepin.daemon.Network \ - /com/deepin/daemon/Network org.freedesktop.DBus.Properties.Get \ - string:"com.deepin.daemon.Network" string:"Devices" - ``` - -1. 设置 deepin 网络后端提供的 WiFi 无线, VPN 等开关状态 - - ```sh - dbus-send --print-reply --type=method_call \ - --dest=com.deepin.daemon.Network /com/deepin/daemon/Network \ - org.freedesktop.DBus.Properties.Set \ - string:"com.deepin.daemon.Network" string:"NetworkingEnabled" variant:boolean:"true" - dbus-send --print-reply --type=method_call \ - --dest=com.deepin.daemon.Network /com/deepin/daemon/Network \ - org.freedesktop.DBus.Properties.Set \ - string:"com.deepin.daemon.Network" string:"WirelessEnabled" variant:boolean:"true" - dbus-send --print-reply --type=method_call \ - --dest=com.deepin.daemon.Network /com/deepin/daemon/Network \ - org.freedesktop.DBus.Properties.Set \ - string:"com.deepin.daemon.Network" string:"VpnEnabled" variant:boolean:"true" - ``` - -## 相关网络配置文件 - -- **/etc/NetworkManager/system-connections/**: NetworkManager 的所有连 - 接对应的配置文件所在目录, 可以手动创建配置文件放置到该目录下, 并确保 - 文件权限为 0600, 然后重启 NetworkManager 就可以让其生效 - - ```sh - sudo systemctl restart NetworkManager - ``` - -- **/etc/NetworkManager/NetworkManager.conf**: NetworkManager 自身的配 - 置文件, 可以配置 DHCP, DNS 等选项, 如: - - 1. 将网络 wlan0 设置为未托管 - ``` - [keyfile] - unmanaged-devices=interface-name:wlan0 - ``` - - 1. 在 syslog 显示更详细的 NetworkManager 日志 - ``` - [logging] - level=DEBUG - ``` - - 具体请参考 `man NetworkManager.conf` - -- **/etc/network/interfaces**: Linux 系统默认的网络接口配置文件, 一般 - 不再直接编辑该文件, 否则可能导致 NetworkManager 异常, 例如如果在 - interfaces 文件里配置了某个网卡, NetworkManager 便无法正常托管该网卡 - -- **/etc/resolv.conf**: DNS 配置文件 - -## 相关网络工具 - -简单介绍一些网络工具以便调试时使用: - -- nmcli, NetworkManager 自带的终端配置工具, 使用方便, 功能强大 - - 1. 查看 NetworkManager 当前的状态 - - ```sh - nmcli general - ``` - - 1. 查看网卡状态 - - ```sh - nmcli device - ``` - - 1. 监听 NetworkManager 变更 - - ```sh - nmcli monitor - ``` - - 1. 设置网卡的托管状态 - - ```sh - nmcli device set wlan0 managed yes - ``` - - 1. 创建一个 WiFi 连接 - - ```sh - nmcli connection add type wifi ifname '*' con-name 'test-ssid' ssid test-ssid - nmcli connection modify test-ssid wifi-sec.key-mgmt wpa-psk - nmcli connection modify test-ssid wifi-sec.psk password - ``` - - 1. 连接指定 WiFi 网络 - - ```sh - nmcli device wifi connect "test-ssid" password "password" - ``` - - 1. 显示特定连接详细信息 - - ```sh - nmcli conn list uuid 1ad8d2a5-d84f-4775-92e8-fae4e7273a76 - ``` - - 1. 手动激活某个连接, 如果失败则打印详细日志 - - ```sh - nmcli -p con up id "Wired Connection" iface eth0 - ``` - -- nmtui, NetworkManager 1.0 后新添加的终端配置工具, 提供 ncurses 界面, - 使用比较方便 - -- nm-connection-editor, network-manaager-gnome 包提供的配置工具, 简单 - 易用, 需要注意安装 network-manaager-gnome 后会开机自动运行nm-applet, - 建议手动将 nm-applet 禁用, 否则可能和 deepin 网络后端有冲突 - -- mmcli, ModemManager 终端工具 - - - 列出当前所有的 modem 设备 - - ```sh - mmcli -L - ``` - - - 监听 modem 设备列表变更 - - ```sh - mmcli -M - ``` - -- usb-modeswitch, 通过更改 USB Modem 设备 ID 从而使其匹配到正确的驱动, - 很多 3G/4G USB 网卡通过配置 usb-modeswitch 来修复无法识别的问题 - -- dbus-send, dbus-monitor, 终端 DBus 工具 - - 1. 获取 deepin 网络后端 DBus 接口 XML 配置 - - ```sh - dbus-send --type=method_call --print-reply --dest=com.deepin.daemon.Network /com/deepin/daemon/Network org.freedesktop.DBus.Introspectable.Introspect | sed 1d | sed -e '1s/^ string "//' | sed '$s/"$//' - ``` - - 1. 监听 WiFi 热点信号强度变化 - - ```sh - dbus-monitor --system sender=org.freedesktop.NetworkManager,interface=org.freedesktop.NetworkManager.AccessPoint,member=PropertiesChanged - ``` - -- qdbus, Qt 提供的终端 DBus 工具, 和 dbus-send 类似, 但更加易用, 补全 - 功能强大 - - ```sh - qdbus --literal --system org.freedesktop.NetworkManager /org/freedesktop/NetworkManager org.freedesktop.NetworkManager.state - ``` - -- d-feet, 方便易用的 DBus GUI 查看工具 - -- dhclient, NetworkManager 默认的 DHCP 工具 - - - 重新为 wlan0 分配 IP 地址, 可以解决某些情况 DHCP 分配 IP 地址成功 - 但无法访问网络的问题 - ```sh - sudo dhclient -x wlan0 - sudo dhclient wlan0 - ``` - -- iperf3, 网络性能测试工具, 可以用来测试网卡驱动是否稳定 - - - 服务端 - - ```sh - iperf -s - ``` - - - 客户端 - - ```sh - iperf -c - ``` - -- rfkill, 无线网络控制开关工具 - - ```sh - rfkill list all - rfkill unblock all - ``` - -- iw, 无线网卡配置工具 - - - 扫描 WiFi 网络 - - ```sh - sudo iw dev wlan0 scan - ``` - - - 查看无线网卡是否支持 AP 热点模式 - - ```sh - sudo iw phy0 info | grep '* AP' - ``` - - - 查看无线网卡是否支持 P2P/P2p-Client 模式 - - ```sh - sudo iw phy0 info | grep '* P2P' - ``` -- iwconfig, 无线网卡接口配置工具 - - - 切换无线网卡工作模式 - ```sh - sudo /sbin/ifconfig wlan0 down - sudo /sbin/doiwconfig wlan0 mode monitor - sudo /sbin/doifconfig wlan0 up - ``` - - - 获取无线网卡速率 - - ```sh - /sbin/iwconfig wlan0 | grep 'Bit Rate' | awk '{print $2}' | awk -F= '{print $2}' - ``` - -- lshw, 系统硬件检索工具 - - - 获取网卡设备信息 - - ```sh - sudo lshw -class network - sudo lshw -class network -businfo - ``` - - - 获取网卡驱动信息 - - ```sh - sudo lshw -xml | xpath -q -e "//node[@id='network' and ./capabilities/capability[@id='wireless']]/configuration/setting[@id='driver']/@value" | cut -d"\"" -f2 - ``` - -- dmidecode, 另一款系统信息检索工具 - -- lspci, PCI 设备检索工具, 同时会显示对应加载的内核驱动. 建议使用时添 - 加 `-vvnn` 选项, 从而可以定位设备对应的唯一 ID - -- lsusb, USB 设备检索工具 - -- usb-devices, USB 设备检索工具, 会显示对应加载的内核驱动 - -## 常见网络问题 - -1. 无线网卡 rfkill 硬开关为关闭状态导致网络不可用 - - 一般是网卡驱动问题, 需要更换驱动或调整驱动参数. - -1. 无线网卡 rfkill 软开关为关闭状态导致网络不可用 - - 一般是用户不小心手动关闭无线网卡开关导致, 一般键盘上有相应的快捷键, - 重新打开即可, 也可以调用 rkill 命令: - - ```sh - sudo rfkill unblock all - ``` - -1. 无线网卡异常, 频繁提示密码错误或过一段时间网卡会断开重连一次或网速 - 很慢 - - 一般是网卡驱动问题, 需要更换驱动或调整驱动参数. - - 对于频繁提示密码错误的问题, 也可能是 wpa_supplicant 的 Bug 导致, 需 - 要跟踪上游最新的状态. - -1. 有线网卡无法正常连接, 一直显示正在连接 - - 可能是 DHCP 分配 IP 出现了问题, 可能是路由器 DHCP 的问题, 也可能是 - 局域网内有多个 DHCP 服务导致. - -1. 网卡驱动正常, 用其他网络工具如 wicd 也能正常访问, 但 NetworkManager - 下无法显示该网卡 - - 可能是 NetworkManager 将该网卡标记了未托管状态, 需要确保 - /etc/network/interfaces 即 /etc/NetworkManager/NetworkManager.conf - 没有对该网卡做特殊配置. - -1. 无法通过 WiFi 连接 PPPoE 拨号网络 - - 目前 NetworkManager 未实现该功能, 请使用原生的 pppoeconf 命令, 提供 - 了 ncurses 终端界面. - -1. 设置系统代理, 但并未生效 - - 目前 deepin 仅支持 GNOME gsettings 系统代理和环境变量系统代理, 如果 - 目标网络应用不支持这两者系统代理便无法生效. - -1. 插入 3G/4G modem 上网卡后无法识别 - - 一般 modem 上网卡插入后需要等待 10s 左右才能识别, 可以通过 `mmcli - -M` 命令进行监听设备识别情况, 如果一直无法识别, 则可能 Linux 暂不支 - 持该设备, 部分 modem 上网卡可以通过 usb-modeswitch 更改设备类型达到 - 正常识别的目的. - -1. 为 3G/4G 上网卡选择套餐后无法保存 - - 可能是缺乏 mobile-broadband-provider-info 包导致. - -1. 苹果手机(iPhone) USB 热点可以显示, 但无法使用 - - 可能是缺乏相关包导致, 包括 libimobiledevice, usbmuxd, libusbmuxd, - 也可能是 usbmuxd, libusbmuxd 版本不兼容导致 - -## 参考资料 - -- NetworkManager - - [NetworkManager Developer 主页](https://developer.gnome.org/NetworkManager/) - - [NetworkManager 在线文档](https://developer.gnome.org/NetworkManager/unstable/index.html) - - [NetworkManager 新版本变更日志](https://cgit.freedesktop.org/NetworkManager/NetworkManager/plain/NEWS) - - [NetworkManager Debugging](https://wiki.gnome.org/Projects/NetworkManager/Debugging) - - [NetworkManager Bug 列表](https://bugzilla.gnome.org/browse.cgi?product=NetworkManager) -- wpa_supplicant - - [wpa_supplicant 项目主页](https://w1.fi/wpa_supplicant/) - - [wpa_supplicant 邮件列表](http://lists.infradead.org/pipermail/hostap/) - - [Ubuntu/wpa_supplicant Bug 列表](https://launchpad.net/ubuntu/+source/wpasupplicant/+bugs) -- Package - - [debian NetworkManager 打包源码](https://anonscm.debian.org/cgit/pkg-utopia/) - - [ubuntu NetworkManager 打包源码](https://code.launchpad.net/~network-manager/network-manager/ubuntu) diff --git a/network/examples/python/gen_dbus_code.sh b/network/examples/python/gen_dbus_code.sh deleted file mode 100755 index 23343145b..000000000 --- a/network/examples/python/gen_dbus_code.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -output_dir="./dbus_gen" -mkdir -p "${output_dir}" - -# com.deepin.daemon.Network -dbus-send --type=method_call --print-reply --dest=com.deepin.daemon.Network /com/deepin/daemon/Network org.freedesktop.DBus.Introspectable.Introspect | sed 1d | sed -e '1s/^ string "//' | sed '$s/"$//' > "${output_dir}"/dbus_dde_daemon_network.xml -python3 -m dbus2any -t pydbusclient.tpl -x "${output_dir}"/dbus_dde_daemon_network.xml > "${output_dir}"/com_deepin_daemon_Network.py - -if [ $? -ne 0 ]; then - echo "run 'sudo pip3 install dbus2any' and Fix dbus2any templates missing issue manually" - echo " dbus2any_tpl_dir=/usr/lib/python3.5/site-packages/dbus2any/templates # or maybe /usr/local/lib/python3.5/dist-packages/dbus2any/templates" - echo " sudo mkdir \${dbus2any_tpl_dir}" - echo " curl https://raw.githubusercontent.com/hugosenari/dbus2any/master/dbus2any/templates/pydbusclient.tpl | sudo tee \${dbus2any_tpl_dir}/pydbusclient.tpl" - exit 1 -fi - -# com.deepin.daemon.ConnectionSession -session_path=$(dbus-send --type=method_call --print-reply --dest=com.deepin.daemon.Network /com/deepin/daemon/Network com.deepin.daemon.Network.CreateConnection string:"vpn-openvpn" objpath:"/" | sed 1d | sed -e 's/ object path "//' | sed -e 's/"$//') -dbus-send --type=method_call --print-reply --dest=com.deepin.daemon.Network ${session_path} org.freedesktop.DBus.Introspectable.Introspect | sed 1d | sed -e '1s/^ string "//' | sed '$s/"$//' > "${output_dir}"/dbus_dde_daemon_network_connectionsession.xml -python3 -m dbus2any -t pydbusclient.tpl -x "${output_dir}"/dbus_dde_daemon_network_connectionsession.xml > "${output_dir}"/com_deepin_daemon_Network_ConnectionSession.py -dbus-send --type=method_call --print-reply --dest=com.deepin.daemon.Network ${session_path} com.deepin.daemon.ConnectionSession.Close - -echo 'Done' diff --git a/network/manager.go b/network/manager.go deleted file mode 100644 index ce0878fe5..000000000 --- a/network/manager.go +++ /dev/null @@ -1,823 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package network - -import ( - "net/http" - "os" - "os/exec" - "sync" - "time" - - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/common/dsync" - "github.com/linuxdeepin/dde-daemon/network/nm" - "github.com/linuxdeepin/dde-daemon/network/proxychains" - "github.com/linuxdeepin/dde-daemon/session/common" - airplanemode "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.airplanemode" - sessionmanager "github.com/linuxdeepin/go-dbus-factory/com.deepin.sessionmanager" - ipwatchd "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.ipwatchd" - sysNetwork "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.network" - configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" - nmdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.networkmanager" - secrets "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.secrets" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/dbusutil/proxy" - "github.com/linuxdeepin/go-lib/keyfile" - "github.com/linuxdeepin/go-lib/strv" - dutils "github.com/linuxdeepin/go-lib/utils" -) - -const ( - dbusServiceName = "com.deepin.daemon.Network" - dbusPath = "/com/deepin/daemon/Network" - dbusInterface = "com.deepin.daemon.Network" -) - -const ( - daemonConfigPath = "org.deepin.dde.daemon" - networkConfigPath = "org.deepin.dde.daemon.network" - dsettingsProtalAuthEnable = "protalAuthEnable" - dsettingsResetWifiOSDEnableTimeout = "resetWifiOSDEnableTimeout" - dsettingsDisableFailureNotify = "disableFailureNotify" - - networkCoreDsgConfigPath = "/usr/share/dsg/configs/org.deepin.dde.network/org.deepin.dde.network.json" - networkCoreConfigPath = "org.deepin.dde.network" - ddeNetworkCoreConfigPath = networkCoreConfigPath - dsettingsLoadServiceFromNM = "LoadServiceFromNM" - dsettingsEnableConnectivity= "enableConnectivity" -) - -const checkRepeatTime = 1 * time.Second - -type connectionData map[string]map[string]dbus.Variant - -var globalSessionActive bool - -//go:generate dbusutil-gen em -type Manager,SecretAgent - -// Manager is the main DBus object for network module. -type Manager struct { - sysSigLoop *dbusutil.SignalLoop - service *dbusutil.Service - sysNetwork sysNetwork.Network - airplane airplanemode.AirplaneMode - sysIPWatchD ipwatchd.IPWatchD - nmObjManager nmdbus.ObjectManager - PropsMu sync.RWMutex - sessionManager sessionmanager.SessionManager - currentSessionPath dbus.ObjectPath - currentSession login1.Session - - // update by manager.go - State uint32 // global networking state - connectivityLock sync.Mutex - Connectivity uint32 - - NetworkingEnabled bool `prop:"access:rw"` // airplane mode for NetworkManager - VpnEnabled bool `prop:"access:rw"` - - // hidden properties - wirelessEnabled bool - wwanEnabled bool - wiredEnabled bool - - delayEnableVpn bool - delayVpnLock sync.Mutex - - // update by manager_devices.go - devicesLock sync.Mutex - devices map[string][]*device - Devices string // array of device objects and marshaled by json - - accessPointsLock sync.Mutex - accessPoints map[dbus.ObjectPath][]*accessPoint - - // update by manager_connections.go - connectionsLock sync.Mutex - connections map[string]connectionSlice - Connections string // array of connection information and marshaled by json - - // update by manager_active.go - activeConnectionsLock sync.Mutex - activeConnections map[dbus.ObjectPath]*activeConnection - ActiveConnections string // array of connections that activated and marshaled by json - - secretAgent *SecretAgent - stateHandler *stateHandler - proxyChainsManager *proxychains.Manager - - sessionSigLoop *dbusutil.SignalLoop - syncConfig *dsync.Config - - portalLastDetectionTime time.Time - - WirelessAccessPoints string `prop:"access:r"` //用于读取AP - debugChangeAPBand string //调用接口切换ap频段 - checkAPStrengthTimer *time.Timer - protalAuthBrowserOpened bool // PORTAL认证中状态 - - acinfosJSON string - - // to identify if vpn support multi connections - multiVpn map[string]bool - - connectionSettingsLock sync.Mutex - - // dsg config : org.deepin.dde.daemon.network - protalAuthEnable bool - wifiOSDEnable bool - disableFailureNotify bool - resetWifiOSDEnableTimeout uint32 - resetWifiOSDEnableTimer *time.Timer - delayShowWifiOSD *time.Timer - - // dsg config : org.deepin.dde.network : LoadServiceFromNM - loadServiceFromNM bool - enableLocalConnectivity bool - - //nolint - signals *struct { - AccessPointAdded, AccessPointRemoved, AccessPointPropertiesChanged struct { - devPath, apJSON string - } - DeviceEnabled struct { - devPath string - enabled bool - } - ActiveConnectionInfoChanged struct { - } - IPConflict struct { - ip string - mac string - } - ProxyMethodChanged struct { - method string - } - } -} - -func (*Manager) GetInterfaceName() string { - return dbusInterface -} - -// initialize slice code manually to make i18n works -func initSlices() { - initProxyGsettings() - initNmStateReasons() -} - -func NewManager(service *dbusutil.Service) (m *Manager) { - m = &Manager{ - service: service, - } - - return -} - -func (m *Manager) init() { - logger.Info("initialize network") - - systemBus, err := dbus.SystemBus() - if err != nil { - return - } - - m.multiVpn = make(map[string]bool) - - sessionBus := m.service.Conn() - m.sessionSigLoop = dbusutil.NewSignalLoop(sessionBus, 10) - m.sessionSigLoop.Start() - - m.sysSigLoop = sysSigLoop - m.initDbusObjects() - - disableNotify() - defer enableNotify() - - m.sessionManager = sessionmanager.NewSessionManager(sessionBus) - m.currentSessionPath, err = m.sessionManager.CurrentSessionPath().Get(0) - if err != nil { - logger.Warning("get sessionManager CurrentSessionPath failed:", err) - } - m.currentSession, err = login1.NewSession(systemBus, m.currentSessionPath) - if err != nil { - logger.Error("Failed to connect self session:", err) - return - } - - sysService, err := dbusutil.NewSystemService() - if err != nil { - logger.Warning(err) - return - } - - // TODO(jouyouyun): improve in future - // Sometimes the 'org.freedesktop.secrets' is not exists, this would block the 'init' function, so move to goroutine - go func() { - secServiceObj := secrets.NewService(sessionBus) - sa, err := newSecretAgent(secServiceObj, m) - if err != nil { - logger.Warning(err) - return - } - m.secretAgent = sa - - logger.Debug("unique name on system bus:", systemBus.Names()[0]) - err = sysService.Export("/org/freedesktop/NetworkManager/SecretAgent", sa) - if err != nil { - logger.Warning(err) - return - } - - // register secret agent - nmAgentManager := nmdbus.NewAgentManager(systemBus) - err = nmAgentManager.Register(0, "com.deepin.daemon.network.SecretAgent") - if err != nil { - logger.Debug("failed to register secret agent:", err) - } else { - logger.Debug("register secret agent ok") - } - }() - - // 初始化配置 - m.resetWifiOSDEnableTimeout = 300 - ds := configManager.NewConfigManager(m.sysSigLoop.Conn()) - configManagerPath, err := ds.AcquireManager(0, daemonConfigPath, networkConfigPath, "") - if err == nil { - networkConfigManager, err := configManager.NewManager(m.sysSigLoop.Conn(), configManagerPath) - if err == nil { - getProtalAuthEnable := func() { - v, err := networkConfigManager.Value(0, dsettingsProtalAuthEnable) - if err != nil { - logger.Warning(err) - return - } - m.protalAuthEnable = v.Value().(bool) - } - - getDisableFailureNotify := func() { - v, err := networkConfigManager.Value(0, dsettingsDisableFailureNotify) - if err != nil { - logger.Warning(err) - return - } - m.disableFailureNotify = v.Value().(bool) - } - - getResetWifiOSDEnableTimeout := func() { - v, err := networkConfigManager.Value(0, dsettingsResetWifiOSDEnableTimeout) - if err != nil { - logger.Warning(err) - return - } - switch vv := v.Value().(type) { - case float64: - m.resetWifiOSDEnableTimeout = uint32(vv) - case int64: - m.resetWifiOSDEnableTimeout = uint32(vv) - default: - logger.Warning("type is wrong!") - } - } - - getProtalAuthEnable() - getResetWifiOSDEnableTimeout() - getDisableFailureNotify() - - networkConfigManager.InitSignalExt(m.sysSigLoop, true) - _, err = networkConfigManager.ConnectValueChanged(func(key string) { - if key == dsettingsProtalAuthEnable { - getProtalAuthEnable() - } else if key == dsettingsResetWifiOSDEnableTimeout { - getResetWifiOSDEnableTimeout() - } else if key == dsettingsDisableFailureNotify { - getDisableFailureNotify() - } - }) - if err != nil { - logger.Warning(err) - } - } else { - logger.Warning(err) - } - } else { - logger.Warning(err) - } - - m.loadServiceFromNM = m.getLoadServiceFromNM(ds) - logger.Info("[init], DConfig data of LoadServiceFromNM : ", m.loadServiceFromNM) - m.loadEnableConnectivity(ds) - // 初始化配置 - m.wifiOSDEnable = true - m.resetWifiOSDEnableTimer = time.AfterFunc(time.Duration(m.resetWifiOSDEnableTimeout)*time.Millisecond, func() { - logger.Debug("reset wifi OSD enable") - m.wifiOSDEnable = true - }) - m.resetWifiOSDEnableTimer.Stop() - - globalSessionActive = m.isSessionActive() - logger.Debugf("current session activated state: %v", globalSessionActive) - - // initialize device and connection handlers - m.sysNetwork = sysNetwork.NewNetwork(systemBus) - m.airplane = airplanemode.NewAirplaneMode(systemBus) - m.loadMultiVpn() - m.initConnectionManage() - m.initDeviceManage() - m.initActiveConnectionManage() - m.initNMObjManager(systemBus) - m.stateHandler = newStateHandler(m.sysSigLoop, m) - m.initSysNetwork(systemBus) - m.initIPConflictManager(systemBus) - - // monitor enable state - m.airplane.InitSignalExt(m.sysSigLoop, true) - - // airplane osd - err = m.airplane.Enabled().ConnectChanged(func(hasValue bool, value bool) { - // has value - if !hasValue { - return - } - - // 显示飞行模式OSD时不显示WIFI连接OSD,200毫秒后恢复显示WIFI的OSD - m.wifiOSDEnable = false - if m.delayShowWifiOSD != nil { - m.delayShowWifiOSD.Stop() - } - m.resetWifiOSDEnableTimer.Stop() - m.resetWifiOSDEnableTimer.Reset(time.Duration(m.resetWifiOSDEnableTimeout) * time.Millisecond) - - // if enabled is true, airplane is on - if value { - showOSD("AirplaneModeOn") - // if enabled is false, airplane is off - } else { - showOSD("AirplaneModeOff") - } - }) - if err != nil { - logger.Warning(err) - } - - // wlan osd - err = m.airplane.WifiEnabled().ConnectChanged(func(hasValue bool, value bool) { - if !hasValue { - return - } - - // 停止上次的定时器 - if m.delayShowWifiOSD != nil { - m.delayShowWifiOSD.Stop() - } - - // 如果刚刚显示了飞行模式的OSD则直接退出不显示WIFI的OSD - if !m.wifiOSDEnable { - return - } - - // 等待150毫秒接收airplane.Enabled改变信号 - m.delayShowWifiOSD = time.AfterFunc(time.Duration(m.resetWifiOSDEnableTimeout-50)*time.Millisecond, func() { - // 禁用WIFI网络OSD时退出 - if !m.wifiOSDEnable { - return - } - - // if enabled is true, wifi rfkill block is true - // so wlan is off - if value { - showOSD("WLANOff") - // if enabled is false, wifi is off - } else { - showOSD("WLANOn") - } - }) - }) - if err != nil { - logger.Warning(err) - } - - // update property "State" - err = nmManager.PropState().ConnectChanged(func(hasValue bool, value uint32) { - m.updatePropState() - // get network state - avail, err := isNetworkAvailable() - if err != nil { - logger.Warningf("get network state failed, err: %v", err) - return - } - // check network state - if !avail { - return - } - // check if current pri - typ, err := nmManager.PrimaryConnectionType().Get(0) - if err != nil { - logger.Warningf("get primary type failed, err: %v", err) - return - } - // check if primary type is already vpn - if typ == nm.NM_SETTING_VPN_SETTING_NAME { - logger.Debug("current primary typ is already vpn, dont need to reactive once") - return - } - logger.Debugf("current primary typ is %v, prop changed: %v need to reactive vpn", typ, value) - // get delay vpn state - delay := m.getDelayEnableVpn() - // if vpn enable is true, but network disconnect last time, try to auto connect vpn. - // delay is marked as true when trying to enable vpn state but network cant be available, - // so need to retry enable vpn and try to auto connect vpn. - if !delay && !m.VpnEnabled { - return - } - m.setVpnEnable(true) - }) - if err != nil { - logger.Warning(err) - } - m.updatePropState() - - // update property Connectivity - _ = nmManager.Connectivity().ConnectChanged(func(hasValue bool, value uint32) { - logger.Debug("connectivity state changed ", hasValue, value) - if hasValue && value == nm.NM_CONNECTIVITY_PORTAL && m.protalAuthEnable && !m.enableLocalConnectivity { - go m.doPortalAuthentication() - } - m.setPropConnectivity(value) - }) - // get connectivity - connectivity, err := nmManager.Connectivity().Get(0) - if err != nil { - logger.Warningf("get connectivity failed, err: %v", err) - } - m.setPropConnectivity(connectivity) - go func() { - time.Sleep(3 * time.Second) - m.checkConnectivity() - }() - - // 调整nmDev的状态 - m.adjustDeviceStatus() - // move to power module - // connect computer suspend signal - // _, err = loginManager.ConnectPrepareForSleep(func(active bool) { - // if active { - // // suspend - // disableNotify() - // } else { - // // restore - // enableNotify() - - // _ = m.RequestWirelessScan() - // } - // }) - // if err != nil { - // logger.Warning(err) - // } - - m.syncConfig = dsync.NewConfig("network", &syncConfig{m: m}, - m.sessionSigLoop, dbusPath, logger) -} - -func (m *Manager) loadEnableConnectivity(ds configManager.ConfigManager) { - networkCoreConfigManagerPath, err := ds.AcquireManager(0, networkCoreConfigPath, ddeNetworkCoreConfigPath, "") - if err != nil { - logger.Warning(err) - return; - } - - networkCoreConfigManager, err := configManager.NewManager(m.sysSigLoop.Conn(), networkCoreConfigManagerPath) - if err != nil { - logger.Warning(err) - return; - } - - getDEnableLocalConnectivity := func() bool { - v, err := networkCoreConfigManager.Value(0, dsettingsEnableConnectivity) - if err != nil { - logger.Warning(err) - return false - } - return v.Value().(bool) - } - - m.enableLocalConnectivity = getDEnableLocalConnectivity() - logger.Info("DConfig data of enableConnectivity : ", m.enableLocalConnectivity) - networkCoreConfigManager.InitSignalExt(m.sysSigLoop, true) - _, err = networkCoreConfigManager.ConnectValueChanged(func(key string) { - if key == dsettingsEnableConnectivity { - m.enableLocalConnectivity = getDEnableLocalConnectivity() - logger.Info("DConfig data changed of enableConnectivity : ", m.enableLocalConnectivity) - } - }) - - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) getLoadServiceFromNM(ds configManager.ConfigManager) (ret bool) { - if dutils.IsFileExist(networkCoreDsgConfigPath) { - configManagerPath, err := ds.AcquireManager(0, networkCoreConfigPath, ddeNetworkCoreConfigPath, "") - if err != nil { - logger.Warning(err) - return - } - ddeNetworkCoreConfigManager, err := configManager.NewManager(m.sysSigLoop.Conn(), configManagerPath) - if err != nil { - logger.Warning(err) - return - } - getDSettingsLoadServiceFromNM := func() bool { - v, err := ddeNetworkCoreConfigManager.Value(0, dsettingsLoadServiceFromNM) - if err != nil { - logger.Warning(err) - return false - } - return v.Value().(bool) - } - - ret = getDSettingsLoadServiceFromNM() - } else { - logger.Warning("[init] DConfig file not exist : /usr/share/dsg/configs/org.deepin.dde.network/org.deepin.dde.network.json") - } - - return -} - -func (m *Manager) destroy() { - logger.Info("destroy network") - m.multiVpn = nil - m.sessionSigLoop.Stop() - m.syncConfig.Destroy() - m.nmObjManager.RemoveHandler(proxy.RemoveAllHandlers) - m.sysNetwork.RemoveHandler(proxy.RemoveAllHandlers) - destroyDbusObjects() - destroyStateHandler(m.stateHandler) - m.clearDevices() - m.clearAccessPoints() - m.clearConnections() - m.clearActiveConnections() - - // reset dbus properties - m.setPropNetworkingEnabled(false) - m.updatePropState() - - if m.checkAPStrengthTimer != nil { - m.checkAPStrengthTimer.Stop() - m.checkAPStrengthTimer = nil - } -} - -func watchNetworkManagerRestart(m *Manager) { - _, err := dbusDaemon.ConnectNameOwnerChanged(func(name, oldOwner, newOwner string) { - if name == "org.freedesktop.NetworkManager" { - // if a new dbus session was installed, the name and newOwner - // will be no empty, if a dbus session was uninstalled, the - // name and oldOwner will be not empty - if len(newOwner) != 0 { - // network-manager is starting - logger.Info("network-manager is starting") - time.Sleep(1 * time.Second) - m.init() - } else { - // network-manager stopped - logger.Info("network-manager stopped") - m.destroy() - } - } - }) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) initSysNetwork(sysBus *dbus.Conn) { - m.sysNetwork.InitSignalExt(m.sysSigLoop, true) - err := common.ActivateSysDaemonService(m.sysNetwork.ServiceName_()) - if err != nil { - logger.Warning(err) - } - - _, err = m.sysNetwork.ConnectDeviceEnabled(func(devPath dbus.ObjectPath, enabled bool) { - err := m.service.Emit(manager, "DeviceEnabled", string(devPath), enabled) - if err != nil { - logger.Warning(err) - } - }) - if err != nil { - logger.Warning(err) - } - - vpnEnabled, err := m.sysNetwork.VpnEnabled().Get(0) - if err != nil { - logger.Warning(err) - } else { - // set vpn enable - m.setVpnEnable(vpnEnabled) - } - err = m.sysNetwork.VpnEnabled().ConnectChanged(func(hasValue bool, value bool) { - if !hasValue { - return - } - - m.PropsMu.Lock() - m.setPropVpnEnabled(value) - m.PropsMu.Unlock() - }) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) initNMObjManager(systemBus *dbus.Conn) { - objManager := nmdbus.NewObjectManager(systemBus) - m.nmObjManager = objManager - objManager.InitSignalExt(m.sysSigLoop, true) - _, err := objManager.ConnectInterfacesAdded(func(objectPath dbus.ObjectPath, - interfacesAndProperties map[string]map[string]dbus.Variant) { - _, ok := interfacesAndProperties["org.freedesktop.NetworkManager.Connection.Active"] - if ok { - // add active connection - m.activeConnectionsLock.Lock() - defer m.activeConnectionsLock.Unlock() - - logger.Debug("add active connection", objectPath) - aConn := m.newActiveConnection(objectPath) - m.activeConnections[objectPath] = aConn - m.updatePropActiveConnections() - } - }) - if err != nil { - logger.Warning(err) - } - _, err = objManager.ConnectInterfacesRemoved(func(objectPath dbus.ObjectPath, interfaces []string) { - if strv.Strv(interfaces).Contains("org.freedesktop.NetworkManager.Connection.Active") { - // remove active connection - m.activeConnectionsLock.Lock() - defer m.activeConnectionsLock.Unlock() - - logger.Debug("remove active connection", objectPath) - delete(m.activeConnections, objectPath) - m.updatePropActiveConnections() - } - }) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) doPortalAuthentication() { - err := exec.Command("pgrep", "startdde").Run() - if err != nil { - return - } - - sincePortalDetection := time.Since(m.portalLastDetectionTime) - // 处于认证中状态无需再次打开认证窗口 - if sincePortalDetection < checkRepeatTime || m.protalAuthBrowserOpened { - return - } - - // http client to get url - client := &http.Client{ - CheckRedirect: func(req *http.Request, via []*http.Request) error { - return http.ErrUseLastResponse - }, - } - // get url - detectUrl := "http://detectportal.deepin.com" - res, err := client.Get(detectUrl) - if err != nil { - logger.Warningf("get remote http failed ,err: %v", err) - return - } - // get portal addr from response - portal, err := getRedirectFromResponse(res, detectUrl) - if err != nil { - logger.Warningf("get redirect hosts failed, err: %v", err) - return - } - logger.Debugf("portal addr is %v", portal) - err = exec.Command(`xdg-open`, portal).Run() - if err != nil { - logger.Warningf("xdg open windows failed, err: %v", err) - return - } - m.portalLastDetectionTime = time.Now() - m.protalAuthBrowserOpened = true -} - -// auto connect vpn -func (m *Manager) autoConnectVpn() { - // get vpn list from NetworkManager/Settings - uuidList, err := getAutoConnectConnUuidListByConnType("vpn") - if err != nil { - logger.Warningf("get vpn conn uuid list failed, err: %v", err) - return - } - logger.Debugf("all auto connect vpn is %v", uuidList) - // auto connect vpn list - for _, uuid := range uuidList { - _, err := m.activateConnection(uuid, "/") - if err != nil { - logger.Warningf("activate connection vpn failed, err: %v", err) - } - } -} - -// set vpn enable -func (m *Manager) setVpnEnable(vpnEnabled bool) { - // if vpn enable is true, check if network is available. - if vpnEnabled { - // get network available state - avail, err := isNetworkAvailable() - if err != nil { - logger.Warning(err) - return - } - // check if network is available - if avail { - logger.Debug("network available is true") - // if network available is true and enable is true, - // set vpn enable and emit signal immediately. - m.setPropVpnEnabled(true) - // reset delay vpn enable - m.setDelayEnableVpn(false) - // auto connect vpn - m.autoConnectVpn() - } else { - logger.Debug("network available is false") - // mark delayEnableVpn as true - m.setDelayEnableVpn(true) - } - } else { - logger.Debug("set vpn enable false") - // reset delay enable vpn as false - m.setDelayEnableVpn(false) - } -} - -// load if vpn support multi connections -func (m *Manager) loadMultiVpn() { - // all vpn plugins dir - pathSl := []string{os.Getenv("NM_VPN_PLUGIN_DIR"), "/usr/lib/NetworkManager/VPN", "/etc/NetworkManager/VPN"} - - // read file - kf := keyfile.NewKeyFile() - for _, path := range pathSl { - // dont care about read error - if err := kf.LoadFromFile(path); err != nil { - continue - } - // get service name, service must exist - service, err := kf.GetString("VPN Connection", "service") - if err != nil { - logger.Warningf("cant read service from file %s, err: %v", path, err) - continue - } - // if service exist already, should ignore - if _, ok := m.multiVpn[service]; ok { - continue - } - // get if support vpn multi connections, key may not exist - exist, err := kf.GetBool("VPN Connection", "supports-multiple-connections") - if err != nil { - continue - } - // store - m.multiVpn[service] = exist - } -} - -// set delay enable vpn -func (m *Manager) setDelayEnableVpn(enable bool) { - m.delayVpnLock.Lock() - m.delayEnableVpn = enable - m.delayVpnLock.Unlock() -} - -// get delay enable vpn -func (m *Manager) getDelayEnableVpn() bool { - m.delayVpnLock.Lock() - enable := m.delayEnableVpn - m.delayVpnLock.Unlock() - return enable -} - -// checkConnectivity This function may block for a long time, -// is recommended for use in Goroutine -func (m *Manager) checkConnectivity() { - connectivity, err := nmManager.CheckConnectivity(0) - if err != nil { - logger.Warning(err) - return - } - if connectivity == nm.NM_CONNECTIVITY_PORTAL && m.protalAuthEnable && !m.enableLocalConnectivity { - m.doPortalAuthentication() - } -} diff --git a/network/manager_stub.go b/network/manager_stub.go deleted file mode 100644 index cb6e3f174..000000000 --- a/network/manager_stub.go +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package network - -import ( - "errors" - - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/network/nm" - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (m *Manager) networkingEnabledWriteCb(write *dbusutil.PropertyWrite) *dbus.Error { - // currently not need - return nil -} - -func (m *Manager) vpnEnabledWriteCb(write *dbusutil.PropertyWrite) *dbus.Error { - enabled, ok := write.Value.(bool) - if !ok { - err := errors.New("type of value is not bool") - logger.Warning(err) - return dbusutil.ToError(err) - } - - // FIXME: - // 由于断开是VPN是在system中完成,断开会触发VPN自动连接重试,这里提前先调整状态 - // 避免自动重连 - if !enabled { - m.setPropVpnEnabled(enabled) - } - - err := m.sysNetwork.VpnEnabled().Set(0, enabled) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - // if vpn enable state is set as true, try to auto connect vpn. - // when vpn enable state is set as false, close all vpn connections in system/network module. - if enabled { - err := enableNetworking() - if err != nil { - logger.Warning(err) - return nil - } - m.setVpnEnable(true) - } - - return nil -} - -func (m *Manager) updatePropActiveConnections() { - activeConnections, _ := marshalJSON(m.activeConnections) - m.setPropActiveConnections(activeConnections) -} - -func (m *Manager) updatePropState() { - state := nmGetManagerState() - m.setPropState(state) -} - -func (m *Manager) updatePropDevices() { - filteredDevices := make(map[string][]*device) - for key, devices := range m.devices { - filteredDevices[key] = make([]*device, 0) - for _, d := range devices { - ignoreIphoneUsbDevice := d.UsbDevice && - d.State <= nm.NM_DEVICE_STATE_UNAVAILABLE && - d.Driver == "ipheth" - if !ignoreIphoneUsbDevice { - filteredDevices[key] = append(filteredDevices[key], d) - } - } - } - devices, _ := marshalJSON(filteredDevices) - m.setPropDevices(devices) -} - -func (m *Manager) updatePropConnections() { - connections, _ := marshalJSON(m.connections) - m.setPropConnections(connections) -} - -func (m *Manager) updatePropWirelessAccessPoints() { - aps, _ := marshalJSON(m.accessPoints) - m.setPropWirelessAccessPoints(aps) -} diff --git a/network/module.go b/network/module.go deleted file mode 100644 index 82c45c61e..000000000 --- a/network/module.go +++ /dev/null @@ -1,150 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package network - -import ( - "time" - - "github.com/linuxdeepin/go-lib/log" - libnotify "github.com/linuxdeepin/go-lib/notify" - "github.com/linuxdeepin/dde-daemon/loader" - "github.com/linuxdeepin/dde-daemon/network/proxychains" -) - -var ( - logger = log.NewLogger("daemon/network") - manager *Manager -) - -func init() { - loader.Register(newModule(logger)) - proxychains.SetLogger(logger) -} - -func HandlePrepareForSleep(sleep bool) { - if manager == nil { - logger.Warning("Module 'network' has not start") - return - } - if sleep { - // suspend - disableNotify() - return - } - // wakeup - enableNotify() - //value decided the strategy of the wirelessScan - _ = manager.RequestWirelessScan() - time.AfterFunc(3*time.Second, func() { - manager.clearAccessPoints() - }) -} - -type Module struct { - *loader.ModuleBase -} - -func newModule(logger *log.Logger) *Module { - module := new(Module) - module.ModuleBase = loader.NewModuleBase("network", module, logger) - return module -} - -func (d *Module) GetDependencies() []string { - return []string{} -} - -func (d *Module) start() error { - service := loader.GetService() - manager = NewManager(service) - manager.init() - - managerServerObj, err := service.NewServerObject(dbusPath, manager, manager.syncConfig) - if err != nil { - return err - } - - err = managerServerObj.SetWriteCallback(manager, "NetworkingEnabled", manager.networkingEnabledWriteCb) - if err != nil { - return err - } - err = managerServerObj.SetWriteCallback(manager, "VpnEnabled", manager.vpnEnabledWriteCb) - if err != nil { - return err - } - - err = managerServerObj.Export() - if err != nil { - logger.Error("failed to export manager:", err) - manager = nil - return err - } - - manager.proxyChainsManager = proxychains.NewManager(service) - err = service.Export(proxychains.DBusPath, manager.proxyChainsManager) - if err != nil { - logger.Warning("failed to export proxyChainsManager:", err) - manager.proxyChainsManager = nil - return err - } - - err = service.RequestName(dbusServiceName) - if err != nil { - return err - } - - err = manager.syncConfig.Register() - if err != nil { - logger.Warning("Failed to register sync service:", err) - } - - initDBusDaemon() - watchNetworkManagerRestart(manager) - return nil -} - -func (d *Module) Start() error { - libnotify.Init("dde-session-daemon") - if manager != nil { - return nil - } - - initSlices() // initialize slice code - initSysSignalLoop() - initNotifyManager() - return d.start() -} - -func (d *Module) Stop() error { - if manager == nil { - return nil - } - - service := loader.GetService() - - err := service.ReleaseName(dbusServiceName) - if err != nil { - logger.Warning(err) - } - - manager.destroy() - destroyDBusDaemon() - sysSigLoop.Stop() - err = service.StopExport(manager) - if err != nil { - logger.Warning(err) - } - - if manager.proxyChainsManager != nil { - err = service.StopExport(manager.proxyChainsManager) - if err != nil { - logger.Warning(err) - } - manager.proxyChainsManager = nil - } - - manager = nil - return nil -} diff --git a/network/proxychains/config.go b/network/proxychains/config.go deleted file mode 100644 index 8bb281c59..000000000 --- a/network/proxychains/config.go +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package proxychains - -import ( - "encoding/json" - "io/ioutil" -) - -type Config struct { - Enable bool - Type string - IP string - Port uint32 - User string - Password string -} - -func loadConfig(file string) (*Config, error) { - data, err := ioutil.ReadFile(file) - if err != nil { - return nil, err - } - - var cfg Config - err = json.Unmarshal(data, &cfg) - if err != nil { - return nil, err - } - - return &cfg, nil -} - -func (cfg *Config) save(file string) error { - data, err := json.Marshal(cfg) - if err != nil { - return err - } - return ioutil.WriteFile(file, data, 0600) -} diff --git a/network/proxychains/utils_notify.go b/network/proxychains/utils_notify.go deleted file mode 100644 index 5d5726f00..000000000 --- a/network/proxychains/utils_notify.go +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package proxychains - -import ( - dbus "github.com/godbus/dbus" - notifications "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.notifications" - . "github.com/linuxdeepin/go-lib/gettext" -) - -var ( - notification notifications.Notifications - notifyIconProxyEnabled = "notification-network-proxy-enabled" - notifyIconProxyDisabled = "notification-network-proxy-disabled" -) - -func init() { - sessionBus, err := dbus.SessionBus() - if err != nil { - notification = nil - return - } - notification = notifications.NewNotifications(sessionBus) -} - -func createNotify(appName string) func(string, string, string) { - var nid uint32 = 0 - return func(icon, summary, body string) { - if notification == nil { - logger.Warning("notification is nil") - logger.Debugf("%s %s %s", icon, summary, body) - return - } - var err error - nid, err = notification.Notify(0, appName, nid, - icon, summary, body, nil, nil, -1) - if err != nil { - logger.Warning(err) - return - } - } -} - -var notify = createNotify("dde-control-center") - -func notifyAppProxyEnabled() { - notify(notifyIconProxyEnabled, Tr("Network"), Tr("Application proxy is set successfully")) -} -func notifyAppProxyEnableFailed() { - notify(notifyIconProxyDisabled, Tr("Network"), Tr("Failed to set the application proxy")) -} diff --git a/network/sync_config.go b/network/sync_config.go deleted file mode 100644 index 3973ab4d1..000000000 --- a/network/sync_config.go +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package network - -import ( - "encoding/json" - - "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/common/dsync" -) - -type syncConfig struct { - m *Manager -} - -const ( - daemonSysService = "com.deepin.daemon.Daemon" - daemonSysPath = "/com/deepin/daemon/Daemon" - daemonSysIFC = daemonSysService - - methodSysNetGetConnections = daemonSysIFC + ".NetworkGetConnections" - methodSysNetSetConnections = daemonSysIFC + ".NetworkSetConnections" -) - -func (sc *syncConfig) Get() (interface{}, error) { - obj, err := getDaemonSysBus() - if err != nil { - return nil, err - } - var data []byte - err = obj.Call(methodSysNetGetConnections, 0).Store(&data) - if err != nil { - return nil, err - } - var info dsync.NetworkData - err = json.Unmarshal(data, &info) - if err != nil { - return nil, err - } - return &info, nil -} - -func (sc *syncConfig) Set(data []byte) error { - obj, err := getDaemonSysBus() - if err != nil { - return err - } - return obj.Call(methodSysNetSetConnections, 0, data).Store() -} - -func getDaemonSysBus() (dbus.BusObject, error) { - conn, err := dbus.SystemBus() - if err != nil { - return nil, err - } - return conn.Object(daemonSysService, daemonSysPath), nil -} diff --git a/network/utils.go b/network/utils.go deleted file mode 100644 index 0cb4ad68e..000000000 --- a/network/utils.go +++ /dev/null @@ -1,312 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package network - -import ( - "encoding/json" - "errors" - "fmt" - "io" - "net/http" - "net/url" - "os" - "os/exec" - "strings" - "time" - - dbus "github.com/godbus/dbus" - nmdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.networkmanager" - "github.com/linuxdeepin/go-gir/gio-2.0" - "github.com/linuxdeepin/go-lib/utils" - "github.com/linuxdeepin/dde-daemon/iw" - "github.com/linuxdeepin/dde-daemon/network/nm" -) - -func isStringInArray(s string, list []string) bool { - for _, i := range list { - if i == s { - return true - } - } - return false -} - -func isDBusPathInArray(path dbus.ObjectPath, pathList []dbus.ObjectPath) bool { - for _, i := range pathList { - if i == path { - return true - } - } - return false -} - -func isInterfaceNil(v interface{}) bool { - return utils.IsInterfaceNil(v) -} - -func marshalJSON(v interface{}) (jsonStr string, err error) { - b, err := json.Marshal(v) - if err != nil { - logger.Error(err) - return - } - jsonStr = string(b) - return -} - -// convert local path to uri, etc "/the/path" -> "file:///the/path" -func toUriPath(path string) (uriPath string) { - return utils.EncodeURI(path, utils.SCHEME_FILE) -} - -// convert uri to local path, etc "file:///the/path" -> "/the/path" -func toLocalPath(path string) (localPath string) { - return utils.DecodeURI(path) -} - -// convert local path to uri, etc "/the/path" -> "file:///the/path" -func toUriPathFor8021x(path string) (uriPath string) { - // the uri for 8021x cert files is specially, we just need append - // suffix "file://" for it - if !utils.IsURI(path) { - uriPath = "file://" + path - } else { - uriPath = path - } - return -} - -// convert uri to local path, etc "file:///the/path" -> "/the/path" -func toLocalPathFor8021x(path string) (uriPath string) { - // the uri for 8021x cert files is specially, we just need remove - // suffix "file://" from it - if utils.IsURI(path) { - uriPath = strings.TrimPrefix(path, "file://") - } else { - uriPath = path - } - return -} - -// byte array should end with null byte -func strToByteArrayPath(path string) (bytePath []byte) { - bytePath = []byte(path) - bytePath = append(bytePath, 0) - return -} -func byteArrayToStrPath(bytePath []byte) (path string) { - if len(bytePath) < 1 { - return - } - path = string(bytePath[:len(bytePath)-1]) - return -} - -// strToUuid convert any given string to md5, and then to uuid, for -// example, a device address string "00:12:34:56:ab:cd" will be -// converted to "086e214c-1f20-bca4-9816-c0a11c8c0e02" -func strToUuid(str string) (uuid string) { - md5, _ := utils.SumStrMd5(str) - return doStrToUuid(md5) -} -func doStrToUuid(str string) (uuid string) { - str = strings.ToLower(str) - for i := 0; i < len(str); i++ { - if (str[i] >= '0' && str[i] <= '9') || - (str[i] >= 'a' && str[i] <= 'f') { - uuid = uuid + string(str[i]) - } - } - if len(uuid) < 32 { - misslen := 32 - len(uuid) - uuid = strings.Repeat("0", misslen) + uuid - } - uuid = fmt.Sprintf("%s-%s-%s-%s-%s", uuid[0:8], uuid[8:12], uuid[12:16], uuid[16:20], uuid[20:32]) - return -} - -// execute program and read or write to it stdin/stdout pipe -func execWithIO(name string, arg ...string) (process *os.Process, stdin io.WriteCloser, stdout, stderr io.ReadCloser, err error) { - cmd := exec.Command(name, arg...) - stdin, _ = cmd.StdinPipe() - stdout, _ = cmd.StdoutPipe() - stderr, _ = cmd.StderrPipe() - - err = cmd.Start() - if err != nil { - return - } - go func() { - err = cmd.Wait() - if err != nil { - logger.Warning("failed to wait cmd:", err) - return - } - }() - process = cmd.Process - return -} - -func isWirelessDeviceSupportHotspot(macAddress string) bool { - devices, err := iw.ListWirelessInfo() - if err != nil { - logger.Warning("Failed to detect hotspot:", macAddress, err) - return false - } - dev := devices.Get(macAddress) - if dev == nil { - logger.Warning("Failed to find device:", macAddress) - return false - } - return dev.SupportedHotspot() -} - -func getAutoConnectConnUuidListByConnType(connType string) ([]string, error) { - var uuidSlice []string - // get connections slice from settings - connPaths, err := nmSettings.ListConnections(0) - if err != nil { - logger.Warningf("get network connections failed, err: %v", err) - return nil, err - } - // get system bus - systemBus, err := dbus.SystemBus() - if err != nil { - logger.Warning(err) - return nil, err - } - // get uuid list from list according to type - for _, connPath := range connPaths { - conn, err := nmdbus.NewConnectionSettings(systemBus, connPath) - if err != nil { - logger.Warning(err) - continue - } - settings, err := conn.GetSettings(0) - if err != nil { - logger.Warning(err) - continue - } - // check if type is wanted - if getSettingConnectionType(settings) != connType { - continue - } - // check if is auto connect - autoConnect := getSettingConnectionAutoconnect(settings) - if !autoConnect { - continue - } - // add uuid - uuid := getSettingConnectionUuid(settings) - if uuid != "" { - uuidSlice = append(uuidSlice, uuid) - } - } - return uuidSlice, nil -} - -func isNetworkAvailable() (bool, error) { - state, err := nmManager.PropState().Get(0) - if err != nil { - return false, err - } - return state >= nm.NM_STATE_CONNECTED_SITE, nil -} - -func enableNetworking() error { - enabled, err := nmManager.NetworkingEnabled().Get(0) - if err != nil { - return err - } - - if enabled { - return nil - } - - return nmManager.Enable(0, true) -} - -func (m *Manager) isSessionActive() bool { - if m.currentSession == nil { - logger.Error("currentSession is null") - return false - } - active, err := m.currentSession.Active().Get(dbus.FlagNoAutoStart) - if err != nil { - logger.Error("Failed to get self active:", err) - return false - } - return active -} - -// 解析重定向地址 -func getRedirectFromResponse(resp *http.Response, detectUrl string) (string, error) { - if resp == nil { - return "", errors.New("response is nil") - } - // 当前返回的是否为重定向 - if resp.StatusCode != 302 { - return "", errors.New("response is not redirect") - } - // 是否包含location - location := resp.Header.Get("Location") - if location == "" { - return "", errors.New("response has no location") - } - // 默认返回整个location - urlMsg, err := url.Parse(location) - if err != nil { - logger.Warningf("parse location failed, err: %v", err) - // 解析失败则返回原来的location,不对location做处理 - return location, nil - } - // 判断url参数 - if len(urlMsg.RawQuery) > 0 { - // 获取解析参数 - paramSl, err := url.ParseQuery(urlMsg.RawQuery) - if err != nil { - // 解析失败则返回原location - logger.Warningf("parse params failed, err: %v", err) - return location, nil - } - // 获取url信息 - redirectUrl := paramSl.Get("url") - // 认证后的跳转到地址如果为之前的请求地址,则删除该地址,否则不删除 - if strings.Contains(redirectUrl, detectUrl) { - paramSl.Del("url") - // 参数更新 - urlMsg.RawQuery = paramSl.Encode() - return urlMsg.String(), nil - } - } - return location, nil -} - -func (m *Manager) isConnectivityByHttp() bool { - client := &http.Client{ - Timeout: time.Duration(15 * time.Second), - } - gs := gio.NewSettings("com.deepin.dde.network-utils") - defer gs.Unref() - - urls := gs.GetStrv("network-checker-urls") - if len(urls) == 0 { - urls = append(urls, "http://detect.uniontech.com/") - } - for _, url := range urls { - if resp, err := client.Head(url); err == nil { - if resp.StatusCode >= 200 && resp.StatusCode <= 206 { - return true - } - } - } - return false -} - -func showOSD(signal string) { - logger.Debug("show OSD", signal) - sessionDBus, _ := dbus.SessionBus() - go sessionDBus.Object("com.deepin.dde.osd", "/").Call("com.deepin.dde.osd.ShowOSD", 0, signal) -} \ No newline at end of file diff --git a/network/utils_notify.go b/network/utils_notify.go deleted file mode 100644 index 991786972..000000000 --- a/network/utils_notify.go +++ /dev/null @@ -1,289 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package network - -import ( - "container/list" - "sync" - "time" - - "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/network/nm" - notifications "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.notifications" - . "github.com/linuxdeepin/go-lib/gettext" -) - -const ( - notifyIconNetworkOffline = "notification-network-offline" - notifyIconWiredConnected = "notification-network-wired-connected" - notifyIconWiredDisconnected = "notification-network-wired-disconnected" - notifyIconWiredError = notifyIconWiredDisconnected - notifyIconWirelessConnected = "notification-network-wireless-full" - notifyIconWirelessDisconnected = "notification-network-wireless-disconnected" - notifyIconWirelessDisabled = "notification-network-wireless-disabled" - notifyIconWirelessError = notifyIconWirelessDisconnected - notifyIconVpnConnected = "notification-network-vpn-connected" - notifyIconVpnDisconnected = "notification-network-vpn-disconnected" - notifyIconProxyEnabled = "notification-network-proxy-enabled" - notifyIconProxyDisabled = "notification-network-proxy-disabled" - notifyIconNetworkConnected = notifyIconWiredConnected - notifyIconNetworkDisconnected = notifyIconWiredDisconnected - notifyIconMobile2gConnected = "notification-network-mobile-2g-connected" - notifyIconMobile2gDisconnected = "notification-network-mobile-2g-disconnected" - notifyIconMobile3gConnected = "notification-network-mobile-3g-connected" - notifyIconMobile3gDisconnected = "notification-network-mobile-3g-disconnected" - notifyIconMobile4gConnected = "notification-network-mobile-4g-connected" - notifyIconMobile4gDisconnected = "notification-network-mobile-4g-disconnected" - notifyIconMobileUnknownConnected = "notification-network-mobile-unknown-connected" - notifyIconMobileUnknownDisconnected = "notification-network-mobile-unknown-disconnected" -) - -var ( - notifyEnabled = true - notification notifications.Notifications - notifyId uint32 - notifyIdMu sync.Mutex - globalNotifyManager *NotifyManager -) - -func initNotifyManager() { - globalNotifyManager = newNotifyManager() - go globalNotifyManager.loop() -} - -func enableNotify() { - go func() { - time.Sleep(5 * time.Second) - notifyEnabled = true - }() -} -func disableNotify() { - notifyEnabled = false -} - -type notifyMsgQueue list.List - -func newNotifyMsgQueue() *notifyMsgQueue { - l := list.New() - return (*notifyMsgQueue)(l) -} - -func (q *notifyMsgQueue) toList() *list.List { - return (*list.List)(q) -} - -type notifyMsg struct { - icon string - summary string - body string -} - -// 入队列 -func (q *notifyMsgQueue) enqueue(val *notifyMsg) { - q.toList().PushBack(val) -} - -// 出队列 -func (q *notifyMsgQueue) dequeue() *notifyMsg { - l := q.toList() - elem := l.Front() - if elem == nil { - return nil - } - val := l.Remove(elem) - return val.(*notifyMsg) -} - -type NotifyManager struct { - queue *notifyMsgQueue - mu sync.Mutex - cond *sync.Cond -} - -func newNotifyManager() *NotifyManager { - sm := &NotifyManager{} - sm.queue = newNotifyMsgQueue() - sm.cond = sync.NewCond(&sm.mu) - return sm -} - -func (nm *NotifyManager) addMsg(msg *notifyMsg) { - nm.mu.Lock() - nm.queue.enqueue(msg) - nm.cond.Signal() - nm.mu.Unlock() -} - -func (nm *NotifyManager) loop() { - for { - nm.mu.Lock() - msg := nm.queue.dequeue() - - if msg == nil { - nm.cond.Wait() - } else { - _notify(msg.icon, msg.summary, msg.body) - } - nm.mu.Unlock() - - if msg != nil { - time.Sleep(1500 * time.Millisecond) // sleep 1.5 seconds - } - } -} - -func notify(icon, summary, body string) { - if manager != nil && manager.isSessionActive() { - globalNotifyManager.addMsg(¬ifyMsg{ - icon: icon, - summary: summary, - body: body, - }) - } -} - -func _notify(icon, summary, body string) { - logger.Debugf("notify icon: %q, summary: %q, body: %q", icon, summary, body) - if !notifyEnabled { - logger.Debug("notify disabled") - return - } - notifyIdMu.Lock() - nid := notifyId - notifyIdMu.Unlock() - - nid, err := notification.Notify(0, "dde-control-center", nid, - icon, summary, body, nil, nil, -1) - if err != nil { - logger.Warning(err) - return - } - - notifyIdMu.Lock() - notifyId = nid - notifyIdMu.Unlock() -} - -func notifyAirplanModeEnabled() { - notify(notifyIconNetworkOffline, Tr("Disconnected"), Tr("Airplane mode enabled.")) -} - -func notifyWiredCableUnplugged() { - notify(notifyIconWiredError, Tr("Disconnected"), deviceErrorTable[CUSTOM_NM_DEVICE_STATE_REASON_CABLE_UNPLUGGED]) -} - -func notifyApModeNotSupport() { - notify(notifyIconWirelessError, Tr("Disconnected"), Tr("Access Point mode is not supported by this device.")) -} - -func notifyWirelessHardSwitchOff() { - notify(notifyIconWirelessDisabled, Tr("Network"), Tr("The hardware switch of WLAN Card is off, please switch on as necessary.")) -} - -func notifyProxyEnabled() { - notify(notifyIconProxyEnabled, Tr("Network"), Tr("System proxy is set successfully.")) -} -func notifyProxyDisabled() { - notify(notifyIconProxyDisabled, Tr("Network"), Tr("System proxy has been cancelled.")) -} - -func notifyVpnConnected(id string) { - notify(notifyIconVpnConnected, Tr("Connected"), id) -} -func notifyVpnDisconnected(id string) { - notify(notifyIconVpnDisconnected, Tr("Disconnected"), id) -} -func notifyVpnFailed(id string, reason uint32) { - notify(notifyIconVpnDisconnected, Tr("Disconnected"), vpnErrorTable[reason]) -} - -func getMobileConnectedNotifyIcon(mobileNetworkType string) (icon string) { - switch mobileNetworkType { - case moblieNetworkType4G: - icon = notifyIconMobile4gConnected - case moblieNetworkType3G: - icon = notifyIconMobile3gConnected - case moblieNetworkType2G: - icon = notifyIconMobile2gConnected - case moblieNetworkTypeUnknown: - icon = notifyIconMobileUnknownConnected - default: - icon = notifyIconMobileUnknownConnected - } - return -} -func getMobileDisconnectedNotifyIcon(mobileNetworkType string) (icon string) { - switch mobileNetworkType { - case moblieNetworkType4G: - icon = notifyIconMobile4gDisconnected - case moblieNetworkType3G: - icon = notifyIconMobile3gDisconnected - case moblieNetworkType2G: - icon = notifyIconMobile2gDisconnected - case moblieNetworkTypeUnknown: - icon = notifyIconMobileUnknownDisconnected - default: - icon = notifyIconMobileUnknownDisconnected - } - return -} - -func generalGetNotifyConnectedIcon(devType uint32, devPath dbus.ObjectPath) (icon string) { - switch devType { - case nm.NM_DEVICE_TYPE_ETHERNET: - icon = notifyIconWiredConnected - case nm.NM_DEVICE_TYPE_WIFI: - icon = notifyIconWirelessConnected - case nm.NM_DEVICE_TYPE_MODEM: - var mobileNetworkType string - dev := manager.getDevice(devPath) - if dev != nil { - manager.devicesLock.Lock() - defer manager.devicesLock.Unlock() - mobileNetworkType = dev.MobileNetworkType - } - icon = getMobileConnectedNotifyIcon(mobileNetworkType) - default: - icon = notifyIconNetworkConnected - } - return -} -func generalGetNotifyDisconnectedIcon(devType uint32, devPath dbus.ObjectPath) (icon string) { - switch devType { - case nm.NM_DEVICE_TYPE_ETHERNET: - icon = notifyIconWiredDisconnected - case nm.NM_DEVICE_TYPE_WIFI: - icon = notifyIconWirelessDisconnected - case nm.NM_DEVICE_TYPE_MODEM: - var mobileNetworkType string - dev := manager.getDevice(devPath) - if dev != nil { - manager.devicesLock.Lock() - mobileNetworkType = dev.MobileNetworkType - manager.devicesLock.Unlock() - } - icon = getMobileDisconnectedNotifyIcon(mobileNetworkType) - default: - logger.Warning("lost default notify icon for device", getCustomDeviceType(devType)) - icon = notifyIconNetworkDisconnected - } - return -} - -func notifyDeviceRemoved(devPath dbus.ObjectPath) { - var devType uint32 - dev := manager.getDevice(devPath) - if dev != nil { - manager.devicesLock.Lock() - devType = dev.nmDevType - manager.devicesLock.Unlock() - } - if !isDeviceTypeValid(devType) { - return - } - icon := generalGetNotifyDisconnectedIcon(devType, devPath) - msg := deviceErrorTable[nm.NM_DEVICE_STATE_REASON_REMOVED] - notify(icon, Tr("Disconnected"), msg) -} diff --git a/network/utils_test.go b/network/utils_test.go deleted file mode 100644 index e2762e6f8..000000000 --- a/network/utils_test.go +++ /dev/null @@ -1,391 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package network - -import ( - "testing" - - "github.com/linuxdeepin/dde-daemon/network/nm" - C "gopkg.in/check.v1" -) - -func Test(t *testing.T) { C.TestingT(t) } - -type testWrapper struct{} - -func init() { - C.Suite(&testWrapper{}) -} - -func (*testWrapper) TestGetSetConnectionData(c *C.C) { - testConnectionId := "idname" - testConnectionUuid := "8e2f9aa2-42b8-47d5-b040-ae82c53fa1f2" - testConnectionType := "802-3-ethernet" - - data := make(connectionData) - - addSetting(data, nm.NM_SETTING_CONNECTION_SETTING_NAME) - setSettingConnectionId(data, testConnectionId) - setSettingConnectionUuid(data, testConnectionUuid) - setSettingConnectionType(data, testConnectionType) - - c.Check(getSettingConnectionId(data), C.Equals, testConnectionId) - c.Check(getSettingConnectionUuid(data), C.Equals, testConnectionUuid) - c.Check(getSettingConnectionType(data), C.Equals, testConnectionType) -} - -func (*testWrapper) TestConvertMacAddressToString(c *C.C) { - tests := []struct { - test []byte - result string - }{ - {[]byte{0, 0, 0, 0, 0, 0}, "00:00:00:00:00:00"}, - {[]byte{0, 18, 52, 86, 120, 171}, "00:12:34:56:78:AB"}, - } - for _, t := range tests { - c.Check(t.result, C.Equals, convertMacAddressToString(t.test)) - } -} - -func (*testWrapper) TestConvertMacAddressToArrayByte(c *C.C) { - tests := []struct { - test string - result []byte - }{ - {"00:00:00:00:00:00", []byte{0, 0, 0, 0, 0, 0}}, - {"00:12:34:56:78:AB", []byte{0, 18, 52, 86, 120, 171}}, - } - for _, t := range tests { - c.Check(t.result, C.DeepEquals, convertMacAddressToArrayByte(t.test)) - } -} - -func (*testWrapper) TestConvertIpv4PrefixToNetMask(c *C.C) { - tests := []struct { - test uint32 - result string - }{ - {0, "0.0.0.0"}, - {1, "128.0.0.0"}, - {2, "192.0.0.0"}, - {3, "224.0.0.0"}, - {4, "240.0.0.0"}, - {5, "248.0.0.0"}, - {6, "252.0.0.0"}, - {7, "254.0.0.0"}, - {8, "255.0.0.0"}, - {9, "255.128.0.0"}, - {10, "255.192.0.0"}, - {11, "255.224.0.0"}, - {12, "255.240.0.0"}, - {13, "255.248.0.0"}, - {14, "255.252.0.0"}, - {15, "255.254.0.0"}, - {16, "255.255.0.0"}, - {17, "255.255.128.0"}, - {18, "255.255.192.0"}, - {19, "255.255.224.0"}, - {20, "255.255.240.0"}, - {21, "255.255.248.0"}, - {22, "255.255.252.0"}, - {23, "255.255.254.0"}, - {24, "255.255.255.0"}, - {25, "255.255.255.128"}, - {26, "255.255.255.192"}, - {27, "255.255.255.224"}, - {28, "255.255.255.240"}, - {29, "255.255.255.248"}, - {30, "255.255.255.252"}, - {31, "255.255.255.254"}, - {32, "255.255.255.255"}, - } - for _, t := range tests { - c.Check(t.result, C.Equals, convertIpv4PrefixToNetMask(t.test)) - } -} - -func (*testWrapper) TestConvertIpv4NetMaskToPrefix(c *C.C) { - tests := []struct { - test string - result uint32 - }{ - {"0.0.0.0", 0}, - {"128.0.0.0", 1}, - {"192.0.0.0", 2}, - {"224.0.0.0", 3}, - {"240.0.0.0", 4}, - {"248.0.0.0", 5}, - {"252.0.0.0", 6}, - {"254.0.0.0", 7}, - {"255.0.0.0", 8}, - {"255.128.0.0", 9}, - {"255.192.0.0", 10}, - {"255.224.0.0", 11}, - {"255.240.0.0", 12}, - {"255.248.0.0", 13}, - {"255.252.0.0", 14}, - {"255.254.0.0", 15}, - {"255.255.0.0", 16}, - {"255.255.128.0", 17}, - {"255.255.192.0", 18}, - {"255.255.224.0", 19}, - {"255.255.240.0", 20}, - {"255.255.248.0", 21}, - {"255.255.252.0", 22}, - {"255.255.254.0", 23}, - {"255.255.255.0", 24}, - {"255.255.255.128", 25}, - {"255.255.255.192", 26}, - {"255.255.255.224", 27}, - {"255.255.255.240", 28}, - {"255.255.255.248", 29}, - {"255.255.255.252", 30}, - {"255.255.255.254", 31}, - {"255.255.255.255", 32}, - } - for _, t := range tests { - c.Check(t.result, C.Equals, convertIpv4NetMaskToPrefix(t.test)) - } - - // test error mask address - _, err := convertIpv4NetMaskToPrefixCheck("255.255.255.250") - c.Check(err, C.NotNil) - _, err = convertIpv4NetMaskToPrefixCheck("255.255.100.2") - c.Check(err, C.NotNil) - _, err = convertIpv4NetMaskToPrefixCheck("255.100.0.0") - c.Check(err, C.NotNil) - _, err = convertIpv4NetMaskToPrefixCheck("191.0.0.0") - c.Check(err, C.NotNil) -} - -func (*testWrapper) TestConvertIpv6AddressToString(c *C.C) { - tests := []struct { - test []byte - result string - }{ - {[]byte{0x12, 0x34, 0x23, 0x45, 0x34, 0x56, 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0xaa, 0xaa, 0xff, 0xff}, "1234:2345:3456:4444:5555:6666:AAAA:FFFF"}, - {[]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, "0000:0000:0000:0000:0000:0000:0000:0000"}, - } - for _, t := range tests { - c.Check(t.result, C.Equals, convertIpv6AddressToString(t.test)) - } -} - -func (*testWrapper) TestConvertIpv6AddressToArrayByte(c *C.C) { - tests := []struct { - test string - result []byte - }{ - {"1234:2345:3456:4444:5555:6666:AAAA:FFFF", []byte{0x12, 0x34, 0x23, 0x45, 0x34, 0x56, 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0xaa, 0xaa, 0xff, 0xff}}, - {"0000:0000:0000:0000:0000:0000:0000:0000", []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, - } - for _, t := range tests { - c.Check(t.result, C.DeepEquals, convertIpv6AddressToArrayByte(t.test)) - } - - // check error ipv6 format - _, err := convertIpv6AddressToArrayByteCheck("-1234:2345:3456:4444:5555:6666:aaAA:ffFF") - c.Check(err, C.NotNil) - _, err = convertIpv6AddressToArrayByteCheck("1234:2345:3456:4444:5555:6666:aaAA:ffFh") - c.Check(err, C.NotNil) -} - -func (*testWrapper) TestExpandIpv6Address(c *C.C) { - tests := []struct { - test string - result string - }{ - {"1234:2345:3456:4444:5555:6666:AAAA:FFFF", "1234:2345:3456:4444:5555:6666:AAAA:FFFF"}, - {"0000:0000:0000:0000:0000:0000:0000:0000", "0000:0000:0000:0000:0000:0000:0000:0000"}, - {"0::0", "0000:0000:0000:0000:0000:0000:0000:0000"}, - {"2001:DB8:2de::e13", "2001:0DB8:02de:0000:0000:0000:0000:0e13"}, - {"::ffff:874B:2B34", "0000:0000:0000:0000:0000:ffff:874B:2B34"}, - } - for _, t := range tests { - r, _ := expandIpv6Address(t.test) - c.Check(t.result, C.Equals, r) - } - - // check error ipv6 format - _, err := expandIpv6Address("2001::25de::cade") - c.Check(err, C.NotNil) -} - -func (*testWrapper) TestGetterAndSetterForVirtualKey(c *C.C) { - data := newWirelessConnectionData("", "", nil, "none", "") - - err := logicSetSettingVkWirelessSecurityKeyMgmt(data, "none") - if err != nil { - logger.Warning("failed to set VkWirelessMgmt") - return - } - c.Check("none", C.Equals, getSettingVkWirelessSecurityKeyMgmt(data)) - - err = logicSetSettingVkWirelessSecurityKeyMgmt(data, "wep") - if err != nil { - logger.Warning("failed to set VkWirelessMgmt") - return - } - c.Check("wep", C.Equals, getSettingVkWirelessSecurityKeyMgmt(data)) - - err = logicSetSettingVkWirelessSecurityKeyMgmt(data, "wpa-psk") - if err != nil { - logger.Warning("failed to set VkWirelessMgmt") - return - } - c.Check("wpa-psk", C.Equals, getSettingVkWirelessSecurityKeyMgmt(data)) - - err = logicSetSettingVkWirelessSecurityKeyMgmt(data, "wpa-eap") - if err != nil { - logger.Warning("failed to set VkWirelessMgmt") - return - } - c.Check("wpa-eap", C.Equals, getSettingVkWirelessSecurityKeyMgmt(data)) -} - -func (*testWrapper) TestToUriPathFor8021x(c *C.C) { - tests := []struct { - test string - result string - }{ - {"/the/path", "file:///the/path"}, - {"file:///the/path", "file:///the/path"}, - {"/the/path/中文", "file:///the/path/中文"}, - {"file:///the/path/中文", "file:///the/path/中文"}, - {"/the/path/%E4%B8%AD%E6%96%87", "file:///the/path/%E4%B8%AD%E6%96%87"}, - } - for _, t := range tests { - c.Check(t.result, C.Equals, toUriPathFor8021x(t.test)) - } -} -func (*testWrapper) TestToLocalPathFor8021x(c *C.C) { - tests := []struct { - test string - result string - }{ - {"/the/path", "/the/path"}, - {"file:///the/path", "/the/path"}, - {"file:///the/path/%E4%B8%AD%E6%96%87", "/the/path/%E4%B8%AD%E6%96%87"}, - {"/the/path/中文", "/the/path/中文"}, - {"file:///the/path/中文", "/the/path/中文"}, - {"/the/path/%E4%B8%AD%E6%96%87", "/the/path/%E4%B8%AD%E6%96%87"}, - } - for _, t := range tests { - c.Check(t.result, C.Equals, toLocalPathFor8021x(t.test)) - } -} - -func (*testWrapper) TestToUriPath(c *C.C) { - tests := []struct { - test string - result string - }{ - {"/the/path", "file:///the/path"}, - {"file:///the/path", "file:///the/path"}, - {"/the/path/中文", "file:///the/path/%E4%B8%AD%E6%96%87"}, - {"file:///the/path/中文", "file:///the/path/%E4%B8%AD%E6%96%87"}, - } - for _, t := range tests { - c.Check(t.result, C.Equals, toUriPath(t.test)) - } -} -func (*testWrapper) TestToLocalPath(c *C.C) { - tests := []struct { - test string - result string - }{ - {"/the/path", "/the/path"}, - {"file:///the/path", "/the/path"}, - {"file:///the/path/%E4%B8%AD%E6%96%87", "/the/path/中文"}, - {"/the/path/中文", "/the/path/中文"}, - {"file:///the/path/中文", "/the/path/中文"}, - {"/the/path/%E4%B8%AD%E6%96%87", "/the/path/%E4%B8%AD%E6%96%87"}, - } - for _, t := range tests { - c.Check(t.result, C.Equals, toLocalPath(t.test)) - } -} - -func (*testWrapper) TestStrToByteArrayPath(c *C.C) { - tests := []struct { - test string - result []byte - }{ - {"/the/path", []byte{0x2f, 0x74, 0x68, 0x65, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x0}}, - {"/the/path/中文", []byte{0x2f, 0x74, 0x68, 0x65, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x2f, 0xe4, 0xb8, 0xad, 0xe6, 0x96, 0x87, 0x0}}, - } - for _, t := range tests { - c.Check(t.result, C.DeepEquals, strToByteArrayPath(t.test)) - } -} -func (*testWrapper) TestByteArrayToStrPath(c *C.C) { - tests := []struct { - test []byte - result string - }{ - {[]byte{}, ""}, - {[]byte{0x0}, ""}, - {[]byte{0x2f, 0x74, 0x68, 0x65, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x0}, "/the/path"}, - {[]byte{0x2f, 0x74, 0x68, 0x65, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x2f, 0xe4, 0xb8, 0xad, 0xe6, 0x96, 0x87, 0x0}, "/the/path/中文"}, - } - for _, t := range tests { - c.Check(t.result, C.Equals, byteArrayToStrPath(t.test)) - } -} - -func (*testWrapper) TestStrToUuid(c *C.C) { - data := []struct { - addr, uuid string - }{ - {"", "d41d8cd9-8f00-b204-e980-0998ecf8427e"}, - {"你好", "7eca689f-0d33-89d9-dea6-6ae112e5cfd7"}, - {"12:34:56:ab:cd:ef", "fdeaa9e5-b0a9-d05a-4c5a-624d6375bc0b"}, - {"fe:dc:ba:65:43:21", "9d9bc082-cc1b-ddbb-c502-46d7499954d8"}, - {"12:34:56:AB:CD:EF", "e2667717-e697-702d-7167-4bb2c5b9f58a"}, - {"123456abcdef", "6f3b8ded-65bd-7a4d-b116-25ac84e579bb"}, - {"12:34:56:ab:cd:xy", "c3701a18-6af4-aa02-7c54-53c09ea75e62"}, - {":34:56:ab:cd:ef", "2f2aab1d-d983-2df8-fe91-8598e79fc009"}, - {"123456abcdef1234abcd123456abcdef", "2fc8f109-cc40-de78-b0c4-1744b9ea62f0"}, - {"123456abcdef1234abcd123456abcdef1234", "18a1eaac-9a1e-3828-8191-511317dc2921"}, - } - for _, d := range data { - c.Check(d.uuid, C.Equals, strToUuid(d.addr)) - } -} - -func (*testWrapper) TestDoStrToUuid(c *C.C) { - data := []struct { - addr, uuid string - }{ - {"", "00000000-0000-0000-0000-000000000000"}, - {"你好", "00000000-0000-0000-0000-000000000000"}, - {"12:34:56:ab:cd:ef", "00000000-0000-0000-0000-123456abcdef"}, - {"fe:dc:ba:65:43:21", "00000000-0000-0000-0000-fedcba654321"}, - {"12:34:56:AB:CD:EF", "00000000-0000-0000-0000-123456abcdef"}, - {"123456abcdef", "00000000-0000-0000-0000-123456abcdef"}, - {"12:34:56:ab:cd:xy", "00000000-0000-0000-0000-00123456abcd"}, - {":34:56:ab:cd:ef", "00000000-0000-0000-0000-003456abcdef"}, - {"123456abcdef1234abcd123456abcdef", "123456ab-cdef-1234-abcd-123456abcdef"}, - {"123456abcdef1234abcd123456abcdef1234", "123456ab-cdef-1234-abcd-123456abcdef"}, - } - for _, d := range data { - c.Check(d.uuid, C.Equals, doStrToUuid(d.addr)) - } -} - -func (*testWrapper) TestFixupDeviceDesc(c *C.C) { - data := []struct { - desc, fixedDesc string - }{ - {"Intel Corporation 82567LM Gigabit Network Connection", "Intel 82567LM Gigabit"}, - {"Intel Corporation PRO/Wireless 5100 AGN [Shiloh] Network Connection", "Intel PRO/Wireless 5100 AGN [Shiloh]"}, - {"Ralink Technology, Corp. RT5370 Wireless Adapter", "Ralink RT5370"}, - {"Realtek RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (Motherboard)", "Realtek RTL8111/8168/8411 Gigabit"}, - {"Kontron (Industrial Computer Source / ICS Advent) DM9601 Fast Ethernet Adapter", "Kontron DM9601"}, - } - for _, d := range data { - c.Check(fixupDeviceDesc(d.desc), C.Equals, d.fixedDesc) - } -} diff --git a/network1/README.md b/network1/README.md new file mode 100644 index 000000000..7eb5bd25c --- /dev/null +++ b/network1/README.md @@ -0,0 +1,739 @@ +**描述**: deepin 网络后端, 主要是对 NetworkManager DBus 接口进行包装, +提供全面的网络管理功能, 包括有线, 无线, PPPoE 拨号连接, 3G上网卡, +VPN(已支持 L2TP, PPTP, OpenConnect, OpenVPN, StrongSwan, VPNC等至少6 +种 VPN 类型), 系统代理等功能. + +**名词解释**: + +- 字段(Setting): NetworkManager 网络连接原生支持的字段, 如 + `NM_SETTING_WIRED_SETTING_NAME`(802-3-ethernet) +- 键值(Key): NetworkManager 网络连接原生支持的键值, 如 + `NM_SETTING_WIRED_MTU`(mtu) +- 虚拟字段(Section 或 Vsection): 为方便用户配置网络, deepin 网络后 + 端自定义的虚拟字段, 其值一般以 "vs-" 开头. 简单的理解, 前端控制中心网络编辑页面所显示的分类 + 段落即分别对应一个虚拟字段, 如 `NM_SETTING_VS_GENERAL`("vs-general", 显 + 示名称为 "General") +- 虚拟键值(Virtual Key): 为方便用户配置网络, deepin 网络后端自定义的虚 + 拟键值, 其值一般以 "vk-" 开头. 如为了方便配置 3G/4G 网络, 默认在前端 + 显示`NM_SETTING_VK_MOBILE_COUNTRY`("vk-mobile-country", 显示名称为 + "Country or region"), + `NM_SETTING_VK_MOBILE_PROVIDER`("vk-mobile-provider", 显示名称为 + "Provider") 和`NM_SETTING_VK_MOBILE_PLAN`("vk-mobile-plan", 显示名称 + 为 "Plan") 等几个虚拟键值, 而不是让用户手动配置 APN 等专业信息. + + 另虚拟键值包括三类: + 1. wrapper, 对其他原生键值进行包装, 这种情况下前端只显示 wrapper 虚 + 拟键值, 而隐藏对应的原生键值, 一般有两种用途: + 1. 改善键值设置时的交互方式, 例如"vk-no-permission" 对 + `NM_SETTING_CONNECTION_PERMISSIONS` 进行包装, 把原来需要用户手 + 动输入用户名进行设置权限的交互方式改为开关(ktypeBoolean) + 1. 将某一个原生键分拆为多个虚拟子键(child key), 如 + `NM_SETTING_IP4_CONFIG_ADDRESSES` 被分拆成了 + "vk-addresses-address", "vk-addresses-mask" 和 + "vk-addresses-gateway" + 1. enable-wrapper, 对其他键值的可用性添加开关, 如 "vk-enable-mtu" + 1. controller, 纯控制型虚拟键, 一般没有相关的原生键, 如 + "vk-vpn-missing-plugin", 用来在前端显示所缺少的 VPN 插件包. + +## 目录结构 + +- **examples**: 调用 deepin 网络后端 DBus 接口的 shell, python 脚本示 + 例. + +- **nm**: 定义 NetworkManager 常量的子库, 具体参考其 + [README](./nm/README.md). + +- **nm_generator**: 辅助 NetworkManager Go 代码生成器, 后缀名 + 为'*_gen.go' 的文件均由其生成, 包括 `nm/nm_consts_gen.go` 和 + `nm_setting_beans_gen.go`, 具体参考其 + [README](./nm_generator/README.md). + +- **agent.go**: 实现 NetworkManager secret agent 的主要文件, 主要用于 + 处理密码弹出框等问题, 相关文档可参考 `nm_generator/nm_docs`, 代码逻 + 辑可参考 + [applet-agent.c](https://github.com/GNOME/network-manager-applet/blob/master/src/applet-agent.c). + +- **connection_session.go**: ConnectionSession DBus 接口主要文件, 用于 + 给前端提供接口来编辑网络连接, 配合 GetKey, SetKey, AvailableKeys, + GetAvailableValues 等接口, 前端可以生成相关的控件界面, 并根据后端信 + 号按需进行展示. + +- **manager_accesspoint.go**: 处理 WiFi 热点及相关 DBus 接口. + +- **manager_active.go**, **dbus_watcher.go**: 手动注册 DBus watcher监 + 听 NetworkManager 所有激活连接的状态变更以避免调用 dbus-factory 接口 + 一定概率导致信号不同步的问题, 同时提供了接口用来获取当前激活连接的相 + 关信息. + +- **manager_config.go**: 处理 deepin 网络后端的配置文件 + (~/.config/deepin/network.json), 主要保存一些网络开关状态和 VPN 自动 + 连接的配置. + +- **manager_connection.go**: 创建/激活/删除网络连接及相关 DBus 接口. + +- **manager_device.go**: 处理网卡设备及相关 DBus 接口. + +- **manager.go**: 主 Manager DBus 对象. + +- **manager_proxy.go**: 处理系统代理及相关 DBus 接口. + +- **manager_switch.go**: 处理设备开关及相关 DBus 接口. deepin 为每个网 + 卡都单独提供一个虚拟开关, 同时会兼容 NetworkManager 本身的逻辑流程. + +- **nm_custom_type.go**: 自定义的一些字符串格式的网络设备类型和网络连 + 接类型, 主要方便与前端交互. + +- **nm_key_xxx.go**: 通过 NetworkManager DBus 接口编辑网络连接时的一些辅 + 助方法, 同时自定义了对应的键值类型, 包括添加了一些包装类型, 如 + `ktypeWrapperIpv4Addresses`, 用于方便处理相关逻辑. `nm_generator` 基 + 本是围绕这部分内容生成 NetworkManager 键值的 getter, setter. + +- **nm_setting_virtual_key.go**: 定义虚拟键值(virtual key) 及相关 + 逻辑代码, 另外某些 "controller" 类型的虚拟键的 getter, setter, available + key 即 available value 等逻辑代码也会定义到这里. + +- **nm_setting_virtual_section.go**: 定义虚拟字段(virtual section) 及 + 相关逻辑代码, 包括获取虚拟字段对应的原生字段列表, 判断虚拟字段对应的 + 前端控件默认是否展开等. + +- **nm_setting_beans_gen.go**: 通过 `nm_generator` 生成的辅助代码, 因 + 为 NetworkManager 的字段键值比较多, 所以代码量比较大, 主要包括下面集 + 中类型: + + - 虚拟字段列表及显示名称(翻译文本) + - 虚拟键值列表, 包括前端展示时所用到的控件类型, 显示名称(翻译文本) + 和取值范围(可选) + - 虚拟键值和原生键值的 getter 和 setter 代码 + - generalXXX 开头的通用辅助方法, 如 `generalGetSettingKeyType`, + `generalGetSettingAvailableKeys`, `generalGetSettingDefaultValue` + 等 + +- **nm_setting_beans_extend.go**: 因为 `nm_generator` 会把 + NetworkManager 支持的所有字段(Setting)和键值(Key)都生成出来, 然后可 + 能部分字段用不到, 为了保证编译通过, 需要补充 + getSettingXXXAvailableKeys, getSettingXXXAvailableValues, + checkSettingXXXValues 等空方法. + +- **nm_setting_xxx.go**: 放置 NetworkManager 字段(Setting)相关的逻辑代 + 码, 主要包括 getSettingXXXAvailableKeys, + getSettingXXXAvailableValues 和 checkSettingXXXValues. + +- **nm_setting_vpn.go**: 放置 VPN 通用逻辑代码, 一部分用来处理 VPN 密 + 码弹出框(一般调用 VPN 自己的密码弹出框, 如 + `/usr/lib/NetworkManager/nm-xxx-auth-dialog`), 另一部分特殊处理 VPN + 子键, 将其保存到 `NM_SETTING_VPN_DATA` 和 `NM_SETTING_VPN_SECRETS`这 + 两个键(string dictionary)里面. + +- **nm_setting_vpn_xxx.go**: 放置特定 VPN 相关的逻辑代码, 主要是 + getSettingVpnXXXAvailableKeys, getSettingVpnXXXAvailableValues, + checkSettingVpnXXXValues. + +- **state_handler.go**: 监听网络设备状态变更并按需弹出系统通知. + +- **utils_xxx.go**: 一些辅助方法, 如处理 IPv6 地址, 读写 gnome-keyring, + 包装系统通知接口, 包装 NetworkManager 和 ModemManager DBus 接口等. + +## NetworkManager DBus 接口简介 + +- `/org/freedesktop/NetworkManager`: NetworkManager DBus 主接口, 可用获 + 取当前网络状态, 设备列表, 连接列表, 用户权限等 +- `/org/freedesktop/NetworkManager/Devices/XXX`: 特定网络设备接口 +- `/org/freedesktop/NetworkManager/Settings`: 配置文件相关接口 +- `/org/freedesktop/NetworkManager/Settings/XXX`: 特定配置文件接口 +- `/org/freedesktop/NetworkManager/AccessPoint/XXX`: WiFi 热点接口 +- `/org/freedesktop/NetworkManager/ActiveConnection/XXX`: 已激活连接 + 接口 +- `/org/freedesktop/NetworkManager/IP4Config/XXX`: 当前分配的 IP4 地址接 + 口 +- `/org/freedesktop/NetworkManager/IP6Config/XXX`: 当前分配的 IP6 地址接 + 口 + +具体请参考 `nm_generator/nm_docs`. + +## deepin 网络后端 DBus 接口简介 + +**DBus 参数命名规范**: +- `uuid`: string 类型, 表示配置文件唯一的 UUID 值 +- `apPath`: dbus.ObjectPath 类型, 表示 AccessPoint 对应的 DBus 路径, 如 + /org/freedesktop/NetworkManager/AccessPoint/XXX +- `devPath`: dbus.ObjectPath 类型, 表示网络设备对应的 DBus 路径, 如 + /org/freedesktop/NetworkManager/Devices/XXX +- `cpath`: dbus.ObjectPath 类型, 表示配置文件对应的 DBus 路径, 如 + /org/freedesktop/NetworkManager/Settings/XXX +- `connType`: string 类型, 表示配置文件类型, 如 + `connectionWired`("wired"), 全部定义位于 `nm_custom_type.go`. +- `xxxJSON`: JSON string 类型, 为了方便前后端交互, 同时减少 DBus 参数数 + 量, deepin 网络后端用了很多 JSON string 类型的参数 + +### org.deepin.dde.Network1 + +- 当前网络状态 + - `GetActiveConnectionInfo() (acinfosJSON string)` + - **prop** `State uint32` + - **prop** `Devices string` + - **prop** `Connections string` + - **prop** `ActiveConnections string` + +- 网络开关 + - `EnableDevice(devPath dbus.ObjectPath, enabled bool)` + - `IsDeviceEnabled(devPath dbus.ObjectPath) (enabled bool)` + - `SetDeviceManaged(devPathOrIfc string, managed bool)` + - **prop-rw** `NetworkingEnabled bool` + - **prop-rw** `VpnEnabled bool` + - **signal** `DeviceEnabled func(devPath string, enabled bool)` + +- 编辑网络连接 + - `CreateConnection(connType string, devPath dbus.ObjectPath) (session *ConnectionSession)` + - `CreateConnectionForAccessPoint(apPath, devPath dbus.ObjectPath) (session *ConnectionSession)` + - `DeleteConnection(uuid string)` + - `EditConnection(uuid string, devPath dbus.ObjectPath) (session *ConnectionSession)` + - `GetSupportedConnectionTypes() (types []string)` + +- 激活网络连接 + - `ActivateConnection(uuid string, devPath dbus.ObjectPath) (cpath dbus.ObjectPath)` + - `DeactivateConnection(uuid string)` + - `DisconnectDevice(devPath dbus.ObjectPath)` + - `GetWiredConnectionUuid(wiredDevPath dbus.ObjectPath) (uuid string)` + +- WiFi AccessPoint + - `ActivateAccessPoint(uuid string, apPath, devPath dbus.ObjectPath) (cpath dbus.ObjectPath)` + - `GetAccessPoints(path dbus.ObjectPath) (apsJSON string)` + - **signal** `AccessPointAdded func(devPath, apJSON string)` + - **signal** `AccessPointRemoved func(devPath, apJSON string)` + - **signal** `AccessPointPropertiesChanged func(devPath, apJSON string)` + +- WiFi Hotspot 热点 + - `DisableWirelessHotspotMode(devPath dbus.ObjectPath)` + - `EnableWirelessHotspotMode(devPath dbus.ObjectPath)` + - `IsWirelessHotspotModeEnabled(devPath dbus.ObjectPath) (enabled bool)` + +- 弹出密码输入框 + - `CancelSecret(path string, settingName string)` + - `FeedSecret(path string, settingName, keyValue string, autoConnect bool)` + - **signal** `NeedSecrets func(connPath, settingName, connectionId string, autoConnect bool)` + - **signal** `NeedSecretsFinished func(connPath, settingName string)` + +- 系统代理 + - `GetAutoProxy() (proxyAuto string)` + - `GetProxy(proxyType string) (host, port string)` + - `GetProxyIgnoreHosts() (ignoreHosts string)` + - `GetProxyMethod() (proxyMode string)` + - `SetAutoProxy(proxyAuto string)` + - `SetProxy(proxyType, host, port string)` + - `SetProxyIgnoreHosts(ignoreHosts string)` + - `SetProxyMethod(proxyMode string)` + +### org.deepin.dde.Network1.ConnectionSession + +- DBus 属性 + - **prop** `ConnectionPath dbus.ObjectPath` + - **prop** `Uuid string` + - **prop** `Type string` + - **prop** `AllowDelete bool` + - **prop** `AllowEditConnectionId bool` + - **prop** `AvailableVirtualSections []string` + - **prop** `AvailableSections []string` + - **prop** `AvailableKeys map[string][]string` + - **prop** `Errors sessionErrors` + +- DBus 信号 + - **signal** `ConnectionDataChanged func()` + +- DBus 接口 + - `GetAllKeys() (infoJSON string)` + - `GetAvailableValues(section, key string) (valuesJSON string)` + - `GetKeyName(section, key string) (name string)` + - `GetKey(section, key string) (valueJSON string)` + - `SetKey(section, key, valueJSON string)` + - `IsDefaultExpandedSection(vsection string) bool` + - `Save() (ok bool)` + - `Close()` + +- Debug 辅助接口 + - `DebugGetConnectionData() connectionData` + - `DebugGetErrors() sessionErrors` + - `DebugListKeyDetail() (info string)` + +详细 DBus 接口信息请参考 +[godoc 文档](https://godoc.org/github.com/linuxdeepin/dde-daemon/network). + +## HACKING 实践 + +### 添加一个虚拟键值 + +1. 编辑 `nm_generator/nm_virtual_sections.yml`, 在适当位置添加虚拟键值 + 的定义, 如 + + ``` + - KeyValue: vk-autoconnect + Section: connection + DisplayName: Automatically connect + WidgetType: EditLineSwitchButton + VKeyInfo: + VirtualKeyName: NM_SETTING_VK_CONNECTION_AUTOCONNECT + Type: ktypeBoolean + VkType: vkTypeWrapper + RelatedKeys: + - NM_SETTING_CONNECTION_AUTOCONNECT + ChildKey: false + Optional: false + ``` + +1. 运行 `make gen-nm-code` 重新生成代码 + +1. 编辑 `nm_setting_connection.go`, 实现 + `getSettingVkConnectionAutoconnect` 和 + `logicSetSettingVkConnectionAutoconnect` + +1. 编辑 getSettingXXXAvailableKeys 控制何时显现该虚拟键 + +1. 如果需要检测用户输入信息的有效性, 还需要在 + checkSettingXXXValues 添加相关代码 + +1. 如果控件类型为 `EditLineComboBox` 或 `EditLineEditComboBox`, 还需要 + 在 getSettingXXXAvailableValues 返回有效值列表 + +1. 处理国际化 + +### 支持新的 VPN 类型 + +1. 以 OpenVPN 为例, 查看 network-manager-openvpn 源码, 检索 + `src/nm-openvpn-service.c` 找到所有 VPN 键值名称, 并将它们定义到 + `nm_generator/nm_vpn_alias_settings.yml` 和 + `nm/nm_extends_consts.go` + +1. 编辑 `nm_generator/nm_virtual_sections.yml`, 在 + `NM_SETTING_VS_VPN`虚拟字段下将需要展现到前端的键值按顺序补充完整, + 如果有必要还可用添加其他虚拟字段, 如 + `NM_SETTING_VS_VPN_OPENVPN_PROXIES` + +1. 如果要为某些 VPN 键值添加 logic setter, 则编辑 + `nm_generator/nm_logicset_keys.yml` + +1. 运行 `make gen-nm-code` 重新生成代码 + +1. 新建文件 `nm_setting_vpn_openvpn.go` 将相关代码补充完整 + +1. 编辑 `nm_custom_type.go`, 添加自定义 VPN 类型 + `connectionVpnOpenvpn`, 同时补充实现 `getCustomConnectionType`, + `isVsectionExpandedDefault`, `doGetRelatedVsections` 和 + `doGetRelatedSectionsOfVsection` + +1. 编辑 `nm_setting_virtual_key.go`, 补充实现 + `getLocalSupportedVpnTypes`, `getVpnNameFile`, + `logicSetSettingVkVpnType` 和 `getSettingVkVpnMissingPlugin` + +1. 处理国际化 + +## go test 单元测试 + +普通单元测试执行 `go test` 即可, 如果要执行 dev_test.go 里的内容则需要 +添加 `dev` tag: + +1. 获取当前系统支持的 VPN 类型 + + ```sh + go test -tags dev -gocheck.f TestLocalSupportedVpnTypes + ``` + +1. 单独执行网络后端 + ```sh + env DDE_DEBUG=t go test -tags dev -gocheck.f TestMain + ``` + +## 自动化测试 + +目前配合 ansbile/docker/openwrt 等技术, 易经实现 deepin 网络功能自动化 +测试, 具体请参考 +[deepin-network-tests](https://github.com/x-deepin/deepin-network-tests) + +如果要通过 iperf3 等工具测试网卡驱动的稳定性, 则参考 [network-testing-experiments](https://github.com/x-deepin/network-testing-experiments) + +## DBus 脚本示例 + +1. python 脚本调用网络 DBus 接口示例, 连接 WiFi 网络 + + [examples/python/main.py](./examples/python/main.py) + +1. shell 脚本调用网络 DBus 接口示例, 设置有线网卡静态 IP 地址 + + [examples/set_wired_static_ip.sh](./examples/set_wired_static_ip.sh) + +1. 根据有线网卡地址获取其对应配置的 UUID + + ```sh + macaddr_to_uuid() { + local md5="$(printf "$1" | md5sum | awk '{print $1}' | tr 'A-Z' 'a-z')" + echo "${md5:0:8}-${md5:8:4}-${md5:12:4}-${md5:16:4}-${md5:20:12}" + } + $ macaddr_to_uuid "00:12:34:56:ab:cd" + > 086e214c-1f20-bca4-9816-c0a11c8c0e02 + ``` + +1. 监听 NetworkManager 服务的运行状态 + + ```sh + dbus-monitor --system sender=org.freedesktop.DBus,member=NameOwnerChanged + ``` + +1. 监听 NetworkManager 配置文件的变更 + + ```sh + dbus-monitor --system sender=org.freedesktop.NetworkManager,interface=org.freedesktop.NetworkManager.Settings + ``` + +1. 开关 NetworkManager 飞行模式 + + ```sh + dbus-send --system --type=method_call --print-reply \ + --dest=org.freedesktop.NetworkManager /org/freedesktop/NetworkManager \ + org.freedesktop.DBus.Properties.Get \ + string:"org.freedesktop.NetworkManager" string:"NetworkingEnabled" + dbus-send --system --type=method_call --print-reply \ + --dest=org.freedesktop.NetworkManager /org/freedesktop/NetworkManager \ + org.freedesktop.NetworkManager.Enable boolean:"false" + ``` + +1. 开关 NetworkManager WiFi 无线网络功能 + + ```sh + dbus-send --system --type=method_call --print-reply \ + --dest=org.freedesktop.NetworkManager /org/freedesktop/NetworkManager \ + org.freedesktop.DBus.Properties.Set string:"org.freedesktop.NetworkManager" \ + string:"WirelessEnabled" variant:boolean:"false" + ``` + +1. 设置 NetworkManager 设备托管状态 + + ```sh + dbus-send --system --type=method_call --print-reply \ + --dest=org.freedesktop.NetworkManager /org/freedesktop/NetworkManager/Devices/0 \ + org.freedesktop.DBus.Properties.Set string:"org.freedesktop.NetworkManager.Device" \ + string:"Managed" variant:boolean:"false" + ``` + +1. 获取 deepin 网络后端提供的所有网络设备信息 + + ```sh + dbus-send --print-reply --dest=org.deepin.dde.Network1 \ + /org/deepin/dde/Network1 org.freedesktop.DBus.Properties.Get \ + string:"org.deepin.dde.Network1" string:"Devices" + ``` + +1. 设置 deepin 网络后端提供的 WiFi 无线, VPN 等开关状态 + + ```sh + dbus-send --print-reply --type=method_call \ + --dest=org.deepin.dde.Network1 /org/deepin/dde/Network1 \ + org.freedesktop.DBus.Properties.Set \ + string:"org.deepin.dde.Network1" string:"NetworkingEnabled" variant:boolean:"true" + dbus-send --print-reply --type=method_call \ + --dest=org.deepin.dde.Network1 /org/deepin/dde/Network1 \ + org.freedesktop.DBus.Properties.Set \ + string:"org.deepin.dde.Network1" string:"WirelessEnabled" variant:boolean:"true" + dbus-send --print-reply --type=method_call \ + --dest=org.deepin.dde.Network1 /org/deepin/dde/Network1 \ + org.freedesktop.DBus.Properties.Set \ + string:"org.deepin.dde.Network1" string:"VpnEnabled" variant:boolean:"true" + ``` + +## 相关网络配置文件 + +- **/etc/NetworkManager/system-connections/**: NetworkManager 的所有连 + 接对应的配置文件所在目录, 可以手动创建配置文件放置到该目录下, 并确保 + 文件权限为 0600, 然后重启 NetworkManager 就可以让其生效 + + ```sh + sudo systemctl restart NetworkManager + ``` + +- **/etc/NetworkManager/NetworkManager.conf**: NetworkManager 自身的配 + 置文件, 可以配置 DHCP, DNS 等选项, 如: + + 1. 将网络 wlan0 设置为未托管 + ``` + [keyfile] + unmanaged-devices=interface-name:wlan0 + ``` + + 1. 在 syslog 显示更详细的 NetworkManager 日志 + ``` + [logging] + level=DEBUG + ``` + + 具体请参考 `man NetworkManager.conf` + +- **/etc/network/interfaces**: Linux 系统默认的网络接口配置文件, 一般 + 不再直接编辑该文件, 否则可能导致 NetworkManager 异常, 例如如果在 + interfaces 文件里配置了某个网卡, NetworkManager 便无法正常托管该网卡 + +- **/etc/resolv.conf**: DNS 配置文件 + +## 相关网络工具 + +简单介绍一些网络工具以便调试时使用: + +- nmcli, NetworkManager 自带的终端配置工具, 使用方便, 功能强大 + + 1. 查看 NetworkManager 当前的状态 + + ```sh + nmcli general + ``` + + 1. 查看网卡状态 + + ```sh + nmcli device + ``` + + 1. 监听 NetworkManager 变更 + + ```sh + nmcli monitor + ``` + + 1. 设置网卡的托管状态 + + ```sh + nmcli device set wlan0 managed yes + ``` + + 1. 创建一个 WiFi 连接 + + ```sh + nmcli connection add type wifi ifname '*' con-name 'test-ssid' ssid test-ssid + nmcli connection modify test-ssid wifi-sec.key-mgmt wpa-psk + nmcli connection modify test-ssid wifi-sec.psk password + ``` + + 1. 连接指定 WiFi 网络 + + ```sh + nmcli device wifi connect "test-ssid" password "password" + ``` + + 1. 显示特定连接详细信息 + + ```sh + nmcli conn list uuid 1ad8d2a5-d84f-4775-92e8-fae4e7273a76 + ``` + + 1. 手动激活某个连接, 如果失败则打印详细日志 + + ```sh + nmcli -p con up id "Wired Connection" iface eth0 + ``` + +- nmtui, NetworkManager 1.0 后新添加的终端配置工具, 提供 ncurses 界面, + 使用比较方便 + +- nm-connection-editor, network-manaager-gnome 包提供的配置工具, 简单 + 易用, 需要注意安装 network-manaager-gnome 后会开机自动运行nm-applet, + 建议手动将 nm-applet 禁用, 否则可能和 deepin 网络后端有冲突 + +- mmcli, ModemManager 终端工具 + + - 列出当前所有的 modem 设备 + + ```sh + mmcli -L + ``` + + - 监听 modem 设备列表变更 + + ```sh + mmcli -M + ``` + +- usb-modeswitch, 通过更改 USB Modem 设备 ID 从而使其匹配到正确的驱动, + 很多 3G/4G USB 网卡通过配置 usb-modeswitch 来修复无法识别的问题 + +- dbus-send, dbus-monitor, 终端 DBus 工具 + + 1. 获取 deepin 网络后端 DBus 接口 XML 配置 + + ```sh + dbus-send --type=method_call --print-reply --dest=org.deepin.dde.Network1 /org/deepin/dde/Network1 org.freedesktop.DBus.Introspectable.Introspect | sed 1d | sed -e '1s/^ string "//' | sed '$s/"$//' + ``` + + 1. 监听 WiFi 热点信号强度变化 + + ```sh + dbus-monitor --system sender=org.freedesktop.NetworkManager,interface=org.freedesktop.NetworkManager.AccessPoint,member=PropertiesChanged + ``` + +- qdbus, Qt 提供的终端 DBus 工具, 和 dbus-send 类似, 但更加易用, 补全 + 功能强大 + + ```sh + qdbus --literal --system org.freedesktop.NetworkManager /org/freedesktop/NetworkManager org.freedesktop.NetworkManager.state + ``` + +- d-feet, 方便易用的 DBus GUI 查看工具 + +- dhclient, NetworkManager 默认的 DHCP 工具 + + - 重新为 wlan0 分配 IP 地址, 可以解决某些情况 DHCP 分配 IP 地址成功 + 但无法访问网络的问题 + ```sh + sudo dhclient -x wlan0 + sudo dhclient wlan0 + ``` + +- iperf3, 网络性能测试工具, 可以用来测试网卡驱动是否稳定 + + - 服务端 + + ```sh + iperf -s + ``` + + - 客户端 + + ```sh + iperf -c + ``` + +- rfkill, 无线网络控制开关工具 + + ```sh + rfkill list all + rfkill unblock all + ``` + +- iw, 无线网卡配置工具 + + - 扫描 WiFi 网络 + + ```sh + sudo iw dev wlan0 scan + ``` + + - 查看无线网卡是否支持 AP 热点模式 + + ```sh + sudo iw phy0 info | grep '* AP' + ``` + + - 查看无线网卡是否支持 P2P/P2p-Client 模式 + + ```sh + sudo iw phy0 info | grep '* P2P' + ``` +- iwconfig, 无线网卡接口配置工具 + + - 切换无线网卡工作模式 + ```sh + sudo /sbin/ifconfig wlan0 down + sudo /sbin/doiwconfig wlan0 mode monitor + sudo /sbin/doifconfig wlan0 up + ``` + + - 获取无线网卡速率 + + ```sh + /sbin/iwconfig wlan0 | grep 'Bit Rate' | awk '{print $2}' | awk -F= '{print $2}' + ``` + +- lshw, 系统硬件检索工具 + + - 获取网卡设备信息 + + ```sh + sudo lshw -class network + sudo lshw -class network -businfo + ``` + + - 获取网卡驱动信息 + + ```sh + sudo lshw -xml | xpath -q -e "//node[@id='network' and ./capabilities/capability[@id='wireless']]/configuration/setting[@id='driver']/@value" | cut -d"\"" -f2 + ``` + +- dmidecode, 另一款系统信息检索工具 + +- lspci, PCI 设备检索工具, 同时会显示对应加载的内核驱动. 建议使用时添 + 加 `-vvnn` 选项, 从而可以定位设备对应的唯一 ID + +- lsusb, USB 设备检索工具 + +- usb-devices, USB 设备检索工具, 会显示对应加载的内核驱动 + +## 常见网络问题 + +1. 无线网卡 rfkill 硬开关为关闭状态导致网络不可用 + + 一般是网卡驱动问题, 需要更换驱动或调整驱动参数. + +1. 无线网卡 rfkill 软开关为关闭状态导致网络不可用 + + 一般是用户不小心手动关闭无线网卡开关导致, 一般键盘上有相应的快捷键, + 重新打开即可, 也可以调用 rkill 命令: + + ```sh + sudo rfkill unblock all + ``` + +1. 无线网卡异常, 频繁提示密码错误或过一段时间网卡会断开重连一次或网速 + 很慢 + + 一般是网卡驱动问题, 需要更换驱动或调整驱动参数. + + 对于频繁提示密码错误的问题, 也可能是 wpa_supplicant 的 Bug 导致, 需 + 要跟踪上游最新的状态. + +1. 有线网卡无法正常连接, 一直显示正在连接 + + 可能是 DHCP 分配 IP 出现了问题, 可能是路由器 DHCP 的问题, 也可能是 + 局域网内有多个 DHCP 服务导致. + +1. 网卡驱动正常, 用其他网络工具如 wicd 也能正常访问, 但 NetworkManager + 下无法显示该网卡 + + 可能是 NetworkManager 将该网卡标记了未托管状态, 需要确保 + /etc/network/interfaces 即 /etc/NetworkManager/NetworkManager.conf + 没有对该网卡做特殊配置. + +1. 无法通过 WiFi 连接 PPPoE 拨号网络 + + 目前 NetworkManager 未实现该功能, 请使用原生的 pppoeconf 命令, 提供 + 了 ncurses 终端界面. + +1. 设置系统代理, 但并未生效 + + 目前 deepin 仅支持 GNOME gsettings 系统代理和环境变量系统代理, 如果 + 目标网络应用不支持这两者系统代理便无法生效. + +1. 插入 3G/4G modem 上网卡后无法识别 + + 一般 modem 上网卡插入后需要等待 10s 左右才能识别, 可以通过 `mmcli + -M` 命令进行监听设备识别情况, 如果一直无法识别, 则可能 Linux 暂不支 + 持该设备, 部分 modem 上网卡可以通过 usb-modeswitch 更改设备类型达到 + 正常识别的目的. + +1. 为 3G/4G 上网卡选择套餐后无法保存 + + 可能是缺乏 mobile-broadband-provider-info 包导致. + +1. 苹果手机(iPhone) USB 热点可以显示, 但无法使用 + + 可能是缺乏相关包导致, 包括 libimobiledevice, usbmuxd, libusbmuxd, + 也可能是 usbmuxd, libusbmuxd 版本不兼容导致 + +## 参考资料 + +- NetworkManager + - [NetworkManager Developer 主页](https://developer.gnome.org/NetworkManager/) + - [NetworkManager 在线文档](https://developer.gnome.org/NetworkManager/unstable/index.html) + - [NetworkManager 新版本变更日志](https://cgit.freedesktop.org/NetworkManager/NetworkManager/plain/NEWS) + - [NetworkManager Debugging](https://wiki.gnome.org/Projects/NetworkManager/Debugging) + - [NetworkManager Bug 列表](https://bugzilla.gnome.org/browse.cgi?product=NetworkManager) +- wpa_supplicant + - [wpa_supplicant 项目主页](https://w1.fi/wpa_supplicant/) + - [wpa_supplicant 邮件列表](http://lists.infradead.org/pipermail/hostap/) + - [Ubuntu/wpa_supplicant Bug 列表](https://launchpad.net/ubuntu/+source/wpasupplicant/+bugs) +- Package + - [debian NetworkManager 打包源码](https://anonscm.debian.org/cgit/pkg-utopia/) + - [ubuntu NetworkManager 打包源码](https://code.launchpad.net/~network-manager/network-manager/ubuntu) diff --git a/network/decode_ssid.go b/network1/decode_ssid.go similarity index 100% rename from network/decode_ssid.go rename to network1/decode_ssid.go diff --git a/network/examples/python/README.md b/network1/examples/python/README.md similarity index 100% rename from network/examples/python/README.md rename to network1/examples/python/README.md diff --git a/network/examples/python/dbus_gen/com_deepin_daemon_Network.py b/network1/examples/python/dbus_gen/com_deepin_daemon_Network.py similarity index 99% rename from network/examples/python/dbus_gen/com_deepin_daemon_Network.py rename to network1/examples/python/dbus_gen/com_deepin_daemon_Network.py index bd64f2e79..f3c315a55 100644 --- a/network/examples/python/dbus_gen/com_deepin_daemon_Network.py +++ b/network1/examples/python/dbus_gen/com_deepin_daemon_Network.py @@ -22,7 +22,7 @@ class Network(object): ''' - com.deepin.daemon.Network + org.deepin.dde.Network1 Usage: ------ @@ -35,7 +35,7 @@ class Network(object): def __init__(self, bus_name, object_path, interface=None, bus=None): '''Constructor''' - self._dbus_interface_name = interface or "com.deepin.daemon.Network" + self._dbus_interface_name = interface or "org.deepin.dde.Network1" self._dbus_object_path = object_path self._dbus_name = bus_name diff --git a/network/examples/python/dbus_gen/com_deepin_daemon_Network_ConnectionSession.py b/network1/examples/python/dbus_gen/com_deepin_daemon_Network_ConnectionSession.py similarity index 100% rename from network/examples/python/dbus_gen/com_deepin_daemon_Network_ConnectionSession.py rename to network1/examples/python/dbus_gen/com_deepin_daemon_Network_ConnectionSession.py diff --git a/network/examples/python/dbus_gen/dbus_dde_daemon_network.xml b/network1/examples/python/dbus_gen/dbus_dde_daemon_network.xml similarity index 99% rename from network/examples/python/dbus_gen/dbus_dde_daemon_network.xml rename to network1/examples/python/dbus_gen/dbus_dde_daemon_network.xml index be9a7a259..5ac5364d7 100644 --- a/network/examples/python/dbus_gen/dbus_dde_daemon_network.xml +++ b/network1/examples/python/dbus_gen/dbus_dde_daemon_network.xml @@ -1,5 +1,5 @@ - + diff --git a/network/examples/python/dbus_gen/dbus_dde_daemon_network_connectionsession.xml b/network1/examples/python/dbus_gen/dbus_dde_daemon_network_connectionsession.xml similarity index 100% rename from network/examples/python/dbus_gen/dbus_dde_daemon_network_connectionsession.xml rename to network1/examples/python/dbus_gen/dbus_dde_daemon_network_connectionsession.xml diff --git a/network1/examples/python/gen_dbus_code.sh b/network1/examples/python/gen_dbus_code.sh new file mode 100755 index 000000000..7d3a66c9a --- /dev/null +++ b/network1/examples/python/gen_dbus_code.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +output_dir="./dbus_gen" +mkdir -p "${output_dir}" + +# org.deepin.dde.Network1 +dbus-send --type=method_call --print-reply --dest=org.deepin.dde.Network1 /org/deepin/dde/Network1 org.freedesktop.DBus.Introspectable.Introspect | sed 1d | sed -e '1s/^ string "//' | sed '$s/"$//' > "${output_dir}"/dbus_dde_daemon_network.xml +python3 -m dbus2any -t pydbusclient.tpl -x "${output_dir}"/dbus_dde_daemon_network.xml > "${output_dir}"/com_deepin_daemon_Network.py + +if [ $? -ne 0 ]; then + echo "run 'sudo pip3 install dbus2any' and Fix dbus2any templates missing issue manually" + echo " dbus2any_tpl_dir=/usr/lib/python3.5/site-packages/dbus2any/templates # or maybe /usr/local/lib/python3.5/dist-packages/dbus2any/templates" + echo " sudo mkdir \${dbus2any_tpl_dir}" + echo " curl https://raw.githubusercontent.com/hugosenari/dbus2any/master/dbus2any/templates/pydbusclient.tpl | sudo tee \${dbus2any_tpl_dir}/pydbusclient.tpl" + exit 1 +fi + +# com.deepin.daemon.ConnectionSession +session_path=$(dbus-send --type=method_call --print-reply --dest=org.deepin.dde.Network1 /org/deepin/dde/Network1 org.deepin.dde.Network1.CreateConnection string:"vpn-openvpn" objpath:"/" | sed 1d | sed -e 's/ object path "//' | sed -e 's/"$//') +dbus-send --type=method_call --print-reply --dest=org.deepin.dde.Network1 ${session_path} org.freedesktop.DBus.Introspectable.Introspect | sed 1d | sed -e '1s/^ string "//' | sed '$s/"$//' > "${output_dir}"/dbus_dde_daemon_network_connectionsession.xml +python3 -m dbus2any -t pydbusclient.tpl -x "${output_dir}"/dbus_dde_daemon_network_connectionsession.xml > "${output_dir}"/com_deepin_daemon_Network_ConnectionSession.py +dbus-send --type=method_call --print-reply --dest=org.deepin.dde.Network1 ${session_path} com.deepin.daemon.ConnectionSession.Close + +echo 'Done' diff --git a/network/examples/python/main.py b/network1/examples/python/main.py similarity index 85% rename from network/examples/python/main.py rename to network1/examples/python/main.py index b4914103c..7e0e71e9b 100755 --- a/network/examples/python/main.py +++ b/network1/examples/python/main.py @@ -10,7 +10,7 @@ from dbus_gen.com_deepin_daemon_Network import Network from dbus_gen.com_deepin_daemon_Network_ConnectionSession import ConnectionSession -dbus_network = Network('com.deepin.daemon.Network', '/com/deepin/daemon/Network') +dbus_network = Network('org.deepin.dde.Network1', '/org/deepin/dde/Network1') wifi_ssid = "test" wifi_psk = "12345678" @@ -19,7 +19,7 @@ dbus_network.EnableDevice(utils_dbus.get_default_wireless_device(), True) session_path = utils_dbus.create_connection('wireless', utils_dbus.get_default_wireless_device()) -dbus_session = ConnectionSession('com.deepin.daemon.Network', session_path) +dbus_session = ConnectionSession('org.deepin.dde.Network1', session_path) uuid = dbus_session.Uuid dbus_session.SetKey('802-11-wireless', 'ssid', json.dump(wifi_ssid)) dbus_session.SetKey('802-11-wireless-security', 'vk-key-mgmt', json.dumps("wpa-psk")) diff --git a/network/examples/python/utils_dbus.py b/network1/examples/python/utils_dbus.py similarity index 96% rename from network/examples/python/utils_dbus.py rename to network1/examples/python/utils_dbus.py index 109367d28..81274f930 100644 --- a/network/examples/python/utils_dbus.py +++ b/network1/examples/python/utils_dbus.py @@ -8,7 +8,7 @@ from dbus_gen.com_deepin_daemon_Network import Network from dbus_gen.com_deepin_daemon_Network_ConnectionSession import ConnectionSession -dbus_network = Network('com.deepin.daemon.Network', '/com/deepin/daemon/Network') +dbus_network = Network('org.deepin.dde.Network1', '/org/deepin/dde/Network1') def get_network_devices(): return json.loads(dbus_network.Devices) diff --git a/network/examples/set_wired_static_ip.sh b/network1/examples/set_wired_static_ip.sh similarity index 93% rename from network/examples/set_wired_static_ip.sh rename to network1/examples/set_wired_static_ip.sh index dab57c7d7..d0cea06d1 100755 --- a/network/examples/set_wired_static_ip.sh +++ b/network1/examples/set_wired_static_ip.sh @@ -3,8 +3,8 @@ # 设置第一块有线网卡的IP地址为10.1.11.231、掩码为255.255.255.0、网关为 # 10.1.11.1、域名服务器为8.8.8.8 -dbus_name="com.deepin.daemon.Network" -dbus_path="/com/deepin/daemon/Network" +dbus_name="org.deepin.dde.Network1" +dbus_path="/org/deepin/dde/Network1" dev_name="/org/freedesktop/NetworkManager/Devices/0" ip_addr='"10.1.11.231"' diff --git a/network/exported_methods_auto.go b/network1/exported_methods_auto.go similarity index 100% rename from network/exported_methods_auto.go rename to network1/exported_methods_auto.go diff --git a/network1/manager.go b/network1/manager.go new file mode 100644 index 000000000..431ba8180 --- /dev/null +++ b/network1/manager.go @@ -0,0 +1,823 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package network + +import ( + "net/http" + "os" + "os/exec" + "sync" + "time" + + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/common/dsync" + "github.com/linuxdeepin/dde-daemon/network1/nm" + "github.com/linuxdeepin/dde-daemon/network1/proxychains" + "github.com/linuxdeepin/dde-daemon/session/common" + configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" + sessionmanager "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.sessionmanager1" + secrets "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.secrets" + airplanemode "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.airplanemode1" + ipwatchd "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.ipwatchd1" + sysNetwork "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.network1" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" + nmdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.networkmanager" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/dbusutil/proxy" + "github.com/linuxdeepin/go-lib/keyfile" + "github.com/linuxdeepin/go-lib/strv" + dutils "github.com/linuxdeepin/go-lib/utils" +) + +const ( + dbusServiceName = "org.deepin.dde.Network1" + dbusPath = "/org/deepin/dde/Network1" + dbusInterface = dbusServiceName +) + +const ( + daemonConfigPath = "org.deepin.dde.daemon" + networkConfigPath = "org.deepin.dde.daemon.network" + dsettingsProtalAuthEnable = "protalAuthEnable" + dsettingsResetWifiOSDEnableTimeout = "resetWifiOSDEnableTimeout" + dsettingsDisableFailureNotify = "disableFailureNotify" + + networkCoreDsgConfigPath = "/usr/share/dsg/configs/org.deepin.dde.network/org.deepin.dde.network.json" + networkCoreConfigPath = "org.deepin.dde.network" + ddeNetworkCoreConfigPath = networkCoreConfigPath + dsettingsLoadServiceFromNM = "LoadServiceFromNM" + dsettingsEnableConnectivity = "enableConnectivity" +) + +const checkRepeatTime = 1 * time.Second + +type connectionData map[string]map[string]dbus.Variant + +var globalSessionActive bool + +//go:generate dbusutil-gen em -type Manager,SecretAgent + +// Manager is the main DBus object for network module. +type Manager struct { + sysSigLoop *dbusutil.SignalLoop + service *dbusutil.Service + sysNetwork sysNetwork.Network + airplane airplanemode.AirplaneMode + sysIPWatchD ipwatchd.IPWatchD + nmObjManager nmdbus.ObjectManager + PropsMu sync.RWMutex + sessionManager sessionmanager.SessionManager + currentSessionPath dbus.ObjectPath + currentSession login1.Session + + // update by manager.go + State uint32 // global networking state + connectivityLock sync.Mutex + Connectivity uint32 + + NetworkingEnabled bool `prop:"access:rw"` // airplane mode for NetworkManager + VpnEnabled bool `prop:"access:rw"` + + // hidden properties + wirelessEnabled bool + wwanEnabled bool + wiredEnabled bool + + delayEnableVpn bool + delayVpnLock sync.Mutex + + // update by manager_devices.go + devicesLock sync.Mutex + devices map[string][]*device + Devices string // array of device objects and marshaled by json + + accessPointsLock sync.Mutex + accessPoints map[dbus.ObjectPath][]*accessPoint + + // update by manager_connections.go + connectionsLock sync.Mutex + connections map[string]connectionSlice + Connections string // array of connection information and marshaled by json + + // update by manager_active.go + activeConnectionsLock sync.Mutex + activeConnections map[dbus.ObjectPath]*activeConnection + ActiveConnections string // array of connections that activated and marshaled by json + + secretAgent *SecretAgent + stateHandler *stateHandler + proxyChainsManager *proxychains.Manager + + sessionSigLoop *dbusutil.SignalLoop + syncConfig *dsync.Config + + portalLastDetectionTime time.Time + + WirelessAccessPoints string `prop:"access:r"` //用于读取AP + debugChangeAPBand string //调用接口切换ap频段 + checkAPStrengthTimer *time.Timer + protalAuthBrowserOpened bool // PORTAL认证中状态 + + acinfosJSON string + + // to identify if vpn support multi connections + multiVpn map[string]bool + + connectionSettingsLock sync.Mutex + + // dsg config : org.deepin.dde.daemon.network + protalAuthEnable bool + wifiOSDEnable bool + disableFailureNotify bool + resetWifiOSDEnableTimeout uint32 + resetWifiOSDEnableTimer *time.Timer + delayShowWifiOSD *time.Timer + + // dsg config : org.deepin.dde.network : LoadServiceFromNM + loadServiceFromNM bool + enableLocalConnectivity bool + + //nolint + signals *struct { + AccessPointAdded, AccessPointRemoved, AccessPointPropertiesChanged struct { + devPath, apJSON string + } + DeviceEnabled struct { + devPath string + enabled bool + } + ActiveConnectionInfoChanged struct { + } + IPConflict struct { + ip string + mac string + } + ProxyMethodChanged struct { + method string + } + } +} + +func (*Manager) GetInterfaceName() string { + return dbusInterface +} + +// initialize slice code manually to make i18n works +func initSlices() { + initProxyGsettings() + initNmStateReasons() +} + +func NewManager(service *dbusutil.Service) (m *Manager) { + m = &Manager{ + service: service, + } + + return +} + +func (m *Manager) init() { + logger.Info("initialize network") + + systemBus, err := dbus.SystemBus() + if err != nil { + return + } + + m.multiVpn = make(map[string]bool) + + sessionBus := m.service.Conn() + m.sessionSigLoop = dbusutil.NewSignalLoop(sessionBus, 10) + m.sessionSigLoop.Start() + + m.sysSigLoop = sysSigLoop + m.initDbusObjects() + + disableNotify() + defer enableNotify() + + m.sessionManager = sessionmanager.NewSessionManager(sessionBus) + m.currentSessionPath, err = m.sessionManager.CurrentSessionPath().Get(0) + if err != nil { + logger.Warning("get sessionManager CurrentSessionPath failed:", err) + } + m.currentSession, err = login1.NewSession(systemBus, m.currentSessionPath) + if err != nil { + logger.Error("Failed to connect self session:", err) + return + } + + sysService, err := dbusutil.NewSystemService() + if err != nil { + logger.Warning(err) + return + } + + // TODO(jouyouyun): improve in future + // Sometimes the 'org.freedesktop.secrets' is not exists, this would block the 'init' function, so move to goroutine + go func() { + secServiceObj := secrets.NewService(sessionBus) + sa, err := newSecretAgent(secServiceObj, m) + if err != nil { + logger.Warning(err) + return + } + m.secretAgent = sa + + logger.Debug("unique name on system bus:", systemBus.Names()[0]) + err = sysService.Export("/org/freedesktop/NetworkManager/SecretAgent", sa) + if err != nil { + logger.Warning(err) + return + } + + // register secret agent + nmAgentManager := nmdbus.NewAgentManager(systemBus) + err = nmAgentManager.Register(0, "org.deepin.dde.Network1.SecretAgent") + if err != nil { + logger.Debug("failed to register secret agent:", err) + } else { + logger.Debug("register secret agent ok") + } + }() + + // 初始化配置 + m.resetWifiOSDEnableTimeout = 300 + ds := configManager.NewConfigManager(m.sysSigLoop.Conn()) + configManagerPath, err := ds.AcquireManager(0, daemonConfigPath, networkConfigPath, "") + if err == nil { + networkConfigManager, err := configManager.NewManager(m.sysSigLoop.Conn(), configManagerPath) + if err == nil { + getProtalAuthEnable := func() { + v, err := networkConfigManager.Value(0, dsettingsProtalAuthEnable) + if err != nil { + logger.Warning(err) + return + } + m.protalAuthEnable = v.Value().(bool) + } + + getDisableFailureNotify := func() { + v, err := networkConfigManager.Value(0, dsettingsDisableFailureNotify) + if err != nil { + logger.Warning(err) + return + } + m.disableFailureNotify = v.Value().(bool) + } + + getResetWifiOSDEnableTimeout := func() { + v, err := networkConfigManager.Value(0, dsettingsResetWifiOSDEnableTimeout) + if err != nil { + logger.Warning(err) + return + } + switch vv := v.Value().(type) { + case float64: + m.resetWifiOSDEnableTimeout = uint32(vv) + case int64: + m.resetWifiOSDEnableTimeout = uint32(vv) + default: + logger.Warning("type is wrong!") + } + } + + getProtalAuthEnable() + getResetWifiOSDEnableTimeout() + getDisableFailureNotify() + + networkConfigManager.InitSignalExt(m.sysSigLoop, true) + _, err = networkConfigManager.ConnectValueChanged(func(key string) { + if key == dsettingsProtalAuthEnable { + getProtalAuthEnable() + } else if key == dsettingsResetWifiOSDEnableTimeout { + getResetWifiOSDEnableTimeout() + } else if key == dsettingsDisableFailureNotify { + getDisableFailureNotify() + } + }) + if err != nil { + logger.Warning(err) + } + } else { + logger.Warning(err) + } + } else { + logger.Warning(err) + } + + m.loadServiceFromNM = m.getLoadServiceFromNM(ds) + logger.Info("[init], DConfig data of LoadServiceFromNM : ", m.loadServiceFromNM) + m.loadEnableConnectivity(ds) + // 初始化配置 + m.wifiOSDEnable = true + m.resetWifiOSDEnableTimer = time.AfterFunc(time.Duration(m.resetWifiOSDEnableTimeout)*time.Millisecond, func() { + logger.Debug("reset wifi OSD enable") + m.wifiOSDEnable = true + }) + m.resetWifiOSDEnableTimer.Stop() + + globalSessionActive = m.isSessionActive() + logger.Debugf("current session activated state: %v", globalSessionActive) + + // initialize device and connection handlers + m.sysNetwork = sysNetwork.NewNetwork(systemBus) + m.airplane = airplanemode.NewAirplaneMode(systemBus) + m.loadMultiVpn() + m.initConnectionManage() + m.initDeviceManage() + m.initActiveConnectionManage() + m.initNMObjManager(systemBus) + m.stateHandler = newStateHandler(m.sysSigLoop, m) + m.initSysNetwork(systemBus) + m.initIPConflictManager(systemBus) + + // monitor enable state + m.airplane.InitSignalExt(m.sysSigLoop, true) + + // airplane osd + err = m.airplane.Enabled().ConnectChanged(func(hasValue bool, value bool) { + // has value + if !hasValue { + return + } + + // 显示飞行模式OSD时不显示WIFI连接OSD,200毫秒后恢复显示WIFI的OSD + m.wifiOSDEnable = false + if m.delayShowWifiOSD != nil { + m.delayShowWifiOSD.Stop() + } + m.resetWifiOSDEnableTimer.Stop() + m.resetWifiOSDEnableTimer.Reset(time.Duration(m.resetWifiOSDEnableTimeout) * time.Millisecond) + + // if enabled is true, airplane is on + if value { + showOSD("AirplaneModeOn") + // if enabled is false, airplane is off + } else { + showOSD("AirplaneModeOff") + } + }) + if err != nil { + logger.Warning(err) + } + + // wlan osd + err = m.airplane.WifiEnabled().ConnectChanged(func(hasValue bool, value bool) { + if !hasValue { + return + } + + // 停止上次的定时器 + if m.delayShowWifiOSD != nil { + m.delayShowWifiOSD.Stop() + } + + // 如果刚刚显示了飞行模式的OSD则直接退出不显示WIFI的OSD + if !m.wifiOSDEnable { + return + } + + // 等待150毫秒接收airplane.Enabled改变信号 + m.delayShowWifiOSD = time.AfterFunc(time.Duration(m.resetWifiOSDEnableTimeout-50)*time.Millisecond, func() { + // 禁用WIFI网络OSD时退出 + if !m.wifiOSDEnable { + return + } + + // if enabled is true, wifi rfkill block is true + // so wlan is off + if value { + showOSD("WLANOff") + // if enabled is false, wifi is off + } else { + showOSD("WLANOn") + } + }) + }) + if err != nil { + logger.Warning(err) + } + + // update property "State" + err = nmManager.PropState().ConnectChanged(func(hasValue bool, value uint32) { + m.updatePropState() + // get network state + avail, err := isNetworkAvailable() + if err != nil { + logger.Warningf("get network state failed, err: %v", err) + return + } + // check network state + if !avail { + return + } + // check if current pri + typ, err := nmManager.PrimaryConnectionType().Get(0) + if err != nil { + logger.Warningf("get primary type failed, err: %v", err) + return + } + // check if primary type is already vpn + if typ == nm.NM_SETTING_VPN_SETTING_NAME { + logger.Debug("current primary typ is already vpn, dont need to reactive once") + return + } + logger.Debugf("current primary typ is %v, prop changed: %v need to reactive vpn", typ, value) + // get delay vpn state + delay := m.getDelayEnableVpn() + // if vpn enable is true, but network disconnect last time, try to auto connect vpn. + // delay is marked as true when trying to enable vpn state but network cant be available, + // so need to retry enable vpn and try to auto connect vpn. + if !delay && !m.VpnEnabled { + return + } + m.setVpnEnable(true) + }) + if err != nil { + logger.Warning(err) + } + m.updatePropState() + + // update property Connectivity + _ = nmManager.Connectivity().ConnectChanged(func(hasValue bool, value uint32) { + logger.Debug("connectivity state changed ", hasValue, value) + if hasValue && value == nm.NM_CONNECTIVITY_PORTAL && m.protalAuthEnable && !m.enableLocalConnectivity { + go m.doPortalAuthentication() + } + m.setPropConnectivity(value) + }) + // get connectivity + connectivity, err := nmManager.Connectivity().Get(0) + if err != nil { + logger.Warningf("get connectivity failed, err: %v", err) + } + m.setPropConnectivity(connectivity) + go func() { + time.Sleep(3 * time.Second) + m.checkConnectivity() + }() + + // 调整nmDev的状态 + m.adjustDeviceStatus() + // move to power module + // connect computer suspend signal + // _, err = loginManager.ConnectPrepareForSleep(func(active bool) { + // if active { + // // suspend + // disableNotify() + // } else { + // // restore + // enableNotify() + + // _ = m.RequestWirelessScan() + // } + // }) + // if err != nil { + // logger.Warning(err) + // } + + m.syncConfig = dsync.NewConfig("network", &syncConfig{m: m}, + m.sessionSigLoop, dbusPath, logger) +} + +func (m *Manager) loadEnableConnectivity(ds configManager.ConfigManager) { + networkCoreConfigManagerPath, err := ds.AcquireManager(0, networkCoreConfigPath, ddeNetworkCoreConfigPath, "") + if err != nil { + logger.Warning(err) + return + } + + networkCoreConfigManager, err := configManager.NewManager(m.sysSigLoop.Conn(), networkCoreConfigManagerPath) + if err != nil { + logger.Warning(err) + return + } + + getDEnableLocalConnectivity := func() bool { + v, err := networkCoreConfigManager.Value(0, dsettingsEnableConnectivity) + if err != nil { + logger.Warning(err) + return false + } + return v.Value().(bool) + } + + m.enableLocalConnectivity = getDEnableLocalConnectivity() + logger.Info("DConfig data of enableConnectivity : ", m.enableLocalConnectivity) + networkCoreConfigManager.InitSignalExt(m.sysSigLoop, true) + _, err = networkCoreConfigManager.ConnectValueChanged(func(key string) { + if key == dsettingsEnableConnectivity { + m.enableLocalConnectivity = getDEnableLocalConnectivity() + logger.Info("DConfig data changed of enableConnectivity : ", m.enableLocalConnectivity) + } + }) + + if err != nil { + logger.Warning(err) + } +} + +func (m *Manager) getLoadServiceFromNM(ds configManager.ConfigManager) (ret bool) { + if dutils.IsFileExist(networkCoreDsgConfigPath) { + configManagerPath, err := ds.AcquireManager(0, networkCoreConfigPath, ddeNetworkCoreConfigPath, "") + if err != nil { + logger.Warning(err) + return + } + ddeNetworkCoreConfigManager, err := configManager.NewManager(m.sysSigLoop.Conn(), configManagerPath) + if err != nil { + logger.Warning(err) + return + } + getDSettingsLoadServiceFromNM := func() bool { + v, err := ddeNetworkCoreConfigManager.Value(0, dsettingsLoadServiceFromNM) + if err != nil { + logger.Warning(err) + return false + } + return v.Value().(bool) + } + + ret = getDSettingsLoadServiceFromNM() + } else { + logger.Warning("[init] DConfig file not exist : /usr/share/dsg/configs/org.deepin.dde.network/org.deepin.dde.network.json") + } + + return +} + +func (m *Manager) destroy() { + logger.Info("destroy network") + m.multiVpn = nil + m.sessionSigLoop.Stop() + m.syncConfig.Destroy() + m.nmObjManager.RemoveHandler(proxy.RemoveAllHandlers) + m.sysNetwork.RemoveHandler(proxy.RemoveAllHandlers) + destroyDbusObjects() + destroyStateHandler(m.stateHandler) + m.clearDevices() + m.clearAccessPoints() + m.clearConnections() + m.clearActiveConnections() + + // reset dbus properties + m.setPropNetworkingEnabled(false) + m.updatePropState() + + if m.checkAPStrengthTimer != nil { + m.checkAPStrengthTimer.Stop() + m.checkAPStrengthTimer = nil + } +} + +func watchNetworkManagerRestart(m *Manager) { + _, err := dbusDaemon.ConnectNameOwnerChanged(func(name, oldOwner, newOwner string) { + if name == "org.freedesktop.NetworkManager" { + // if a new dbus session was installed, the name and newOwner + // will be no empty, if a dbus session was uninstalled, the + // name and oldOwner will be not empty + if len(newOwner) != 0 { + // network-manager is starting + logger.Info("network-manager is starting") + time.Sleep(1 * time.Second) + m.init() + } else { + // network-manager stopped + logger.Info("network-manager stopped") + m.destroy() + } + } + }) + if err != nil { + logger.Warning(err) + } +} + +func (m *Manager) initSysNetwork(sysBus *dbus.Conn) { + m.sysNetwork.InitSignalExt(m.sysSigLoop, true) + err := common.ActivateSysDaemonService(m.sysNetwork.ServiceName_()) + if err != nil { + logger.Warning(err) + } + + _, err = m.sysNetwork.ConnectDeviceEnabled(func(devPath dbus.ObjectPath, enabled bool) { + err := m.service.Emit(manager, "DeviceEnabled", string(devPath), enabled) + if err != nil { + logger.Warning(err) + } + }) + if err != nil { + logger.Warning(err) + } + + vpnEnabled, err := m.sysNetwork.VpnEnabled().Get(0) + if err != nil { + logger.Warning(err) + } else { + // set vpn enable + m.setVpnEnable(vpnEnabled) + } + err = m.sysNetwork.VpnEnabled().ConnectChanged(func(hasValue bool, value bool) { + if !hasValue { + return + } + + m.PropsMu.Lock() + m.setPropVpnEnabled(value) + m.PropsMu.Unlock() + }) + if err != nil { + logger.Warning(err) + } +} + +func (m *Manager) initNMObjManager(systemBus *dbus.Conn) { + objManager := nmdbus.NewObjectManager(systemBus) + m.nmObjManager = objManager + objManager.InitSignalExt(m.sysSigLoop, true) + _, err := objManager.ConnectInterfacesAdded(func(objectPath dbus.ObjectPath, + interfacesAndProperties map[string]map[string]dbus.Variant) { + _, ok := interfacesAndProperties["org.freedesktop.NetworkManager.Connection.Active"] + if ok { + // add active connection + m.activeConnectionsLock.Lock() + defer m.activeConnectionsLock.Unlock() + + logger.Debug("add active connection", objectPath) + aConn := m.newActiveConnection(objectPath) + m.activeConnections[objectPath] = aConn + m.updatePropActiveConnections() + } + }) + if err != nil { + logger.Warning(err) + } + _, err = objManager.ConnectInterfacesRemoved(func(objectPath dbus.ObjectPath, interfaces []string) { + if strv.Strv(interfaces).Contains("org.freedesktop.NetworkManager.Connection.Active") { + // remove active connection + m.activeConnectionsLock.Lock() + defer m.activeConnectionsLock.Unlock() + + logger.Debug("remove active connection", objectPath) + delete(m.activeConnections, objectPath) + m.updatePropActiveConnections() + } + }) + if err != nil { + logger.Warning(err) + } +} + +func (m *Manager) doPortalAuthentication() { + err := exec.Command("pgrep", "startdde").Run() + if err != nil { + return + } + + sincePortalDetection := time.Since(m.portalLastDetectionTime) + // 处于认证中状态无需再次打开认证窗口 + if sincePortalDetection < checkRepeatTime || m.protalAuthBrowserOpened { + return + } + + // http client to get url + client := &http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + // get url + detectUrl := "http://detectportal.deepin.com" + res, err := client.Get(detectUrl) + if err != nil { + logger.Warningf("get remote http failed ,err: %v", err) + return + } + // get portal addr from response + portal, err := getRedirectFromResponse(res, detectUrl) + if err != nil { + logger.Warningf("get redirect hosts failed, err: %v", err) + return + } + logger.Debugf("portal addr is %v", portal) + err = exec.Command(`xdg-open`, portal).Run() + if err != nil { + logger.Warningf("xdg open windows failed, err: %v", err) + return + } + m.portalLastDetectionTime = time.Now() + m.protalAuthBrowserOpened = true +} + +// auto connect vpn +func (m *Manager) autoConnectVpn() { + // get vpn list from NetworkManager/Settings + uuidList, err := getAutoConnectConnUuidListByConnType("vpn") + if err != nil { + logger.Warningf("get vpn conn uuid list failed, err: %v", err) + return + } + logger.Debugf("all auto connect vpn is %v", uuidList) + // auto connect vpn list + for _, uuid := range uuidList { + _, err := m.activateConnection(uuid, "/") + if err != nil { + logger.Warningf("activate connection vpn failed, err: %v", err) + } + } +} + +// set vpn enable +func (m *Manager) setVpnEnable(vpnEnabled bool) { + // if vpn enable is true, check if network is available. + if vpnEnabled { + // get network available state + avail, err := isNetworkAvailable() + if err != nil { + logger.Warning(err) + return + } + // check if network is available + if avail { + logger.Debug("network available is true") + // if network available is true and enable is true, + // set vpn enable and emit signal immediately. + m.setPropVpnEnabled(true) + // reset delay vpn enable + m.setDelayEnableVpn(false) + // auto connect vpn + m.autoConnectVpn() + } else { + logger.Debug("network available is false") + // mark delayEnableVpn as true + m.setDelayEnableVpn(true) + } + } else { + logger.Debug("set vpn enable false") + // reset delay enable vpn as false + m.setDelayEnableVpn(false) + } +} + +// load if vpn support multi connections +func (m *Manager) loadMultiVpn() { + // all vpn plugins dir + pathSl := []string{os.Getenv("NM_VPN_PLUGIN_DIR"), "/usr/lib/NetworkManager/VPN", "/etc/NetworkManager/VPN"} + + // read file + kf := keyfile.NewKeyFile() + for _, path := range pathSl { + // dont care about read error + if err := kf.LoadFromFile(path); err != nil { + continue + } + // get service name, service must exist + service, err := kf.GetString("VPN Connection", "service") + if err != nil { + logger.Warningf("cant read service from file %s, err: %v", path, err) + continue + } + // if service exist already, should ignore + if _, ok := m.multiVpn[service]; ok { + continue + } + // get if support vpn multi connections, key may not exist + exist, err := kf.GetBool("VPN Connection", "supports-multiple-connections") + if err != nil { + continue + } + // store + m.multiVpn[service] = exist + } +} + +// set delay enable vpn +func (m *Manager) setDelayEnableVpn(enable bool) { + m.delayVpnLock.Lock() + m.delayEnableVpn = enable + m.delayVpnLock.Unlock() +} + +// get delay enable vpn +func (m *Manager) getDelayEnableVpn() bool { + m.delayVpnLock.Lock() + enable := m.delayEnableVpn + m.delayVpnLock.Unlock() + return enable +} + +// checkConnectivity This function may block for a long time, +// is recommended for use in Goroutine +func (m *Manager) checkConnectivity() { + connectivity, err := nmManager.CheckConnectivity(0) + if err != nil { + logger.Warning(err) + return + } + if connectivity == nm.NM_CONNECTIVITY_PORTAL && m.protalAuthEnable && !m.enableLocalConnectivity { + m.doPortalAuthentication() + } +} diff --git a/network/manager_accesspoint.go b/network1/manager_accesspoint.go similarity index 98% rename from network/manager_accesspoint.go rename to network1/manager_accesspoint.go index 249c278fa..c207c8ecd 100644 --- a/network/manager_accesspoint.go +++ b/network1/manager_accesspoint.go @@ -9,9 +9,9 @@ import ( "fmt" "time" - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/network/nm" - nmdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.networkmanager" + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/network1/nm" + nmdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.networkmanager" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/utils" ) @@ -28,7 +28,7 @@ const ( const scanWifiDelayTime = 10 * time.Second const channelAutoChangeThreshold = 65 -//frequency range +// frequency range const ( frequency5GUpperlimit = 5825 frequency5GLowerlimit = 4915 @@ -540,7 +540,7 @@ func (m *Manager) activateAccessPoint(uuid string, apPath, devPath dbus.ObjectPa // need to set macAddress var hwAddr string hwAddr, err = nmGeneralGetDeviceHwAddr(devPath, true) - if (err != nil) { + if err != nil { logger.Warning("failed to get mac", err) } data := newWirelessConnectionData(decodeSsid(ssid), uuid, ssid, keymgmt, hwAddr) diff --git a/network/manager_active_conn.go b/network1/manager_active_conn.go similarity index 98% rename from network/manager_active_conn.go rename to network1/manager_active_conn.go index 0f95a5c75..132158941 100644 --- a/network/manager_active_conn.go +++ b/network1/manager_active_conn.go @@ -8,8 +8,8 @@ import ( "strconv" "strings" - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/network/nm" + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/network1/nm" "github.com/linuxdeepin/go-lib/dbusutil" . "github.com/linuxdeepin/go-lib/gettext" ) @@ -99,7 +99,7 @@ type hotspotConnectionInfo struct { } func (i ipv4Info) toDeprecatedStruct() ip4ConnectionInfoDeprecated { - ip4ConnectionInfoDeprecatedInfo := ip4ConnectionInfoDeprecated { + ip4ConnectionInfoDeprecatedInfo := ip4ConnectionInfoDeprecated{ Gateways: []string{i.Gateway}, Dnses: i.Nameservers, } @@ -111,7 +111,7 @@ func (i ipv4Info) toDeprecatedStruct() ip4ConnectionInfoDeprecated { } func (i ipv6Info) toDeprecatedStruct() ip6ConnectionInfoDeprecated { - ip6ConnectionInfoDeprecatedInfo := ip6ConnectionInfoDeprecated { + ip6ConnectionInfoDeprecatedInfo := ip6ConnectionInfoDeprecated{ Gateways: []string{i.Gateway}, Dnses: i.Nameservers, } diff --git a/network/manager_connection.go b/network1/manager_connection.go similarity index 99% rename from network/manager_connection.go rename to network1/manager_connection.go index 341f121ee..cc6016d48 100644 --- a/network/manager_connection.go +++ b/network1/manager_connection.go @@ -10,11 +10,11 @@ import ( "strconv" "strings" - dbus "github.com/godbus/dbus" - nmdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.networkmanager" + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/network1/nm" + nmdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.networkmanager" "github.com/linuxdeepin/go-lib/dbusutil" . "github.com/linuxdeepin/go-lib/gettext" - "github.com/linuxdeepin/dde-daemon/network/nm" ) type connectionSlice []*connection diff --git a/network/manager_dbusutil.go b/network1/manager_dbusutil.go similarity index 100% rename from network/manager_dbusutil.go rename to network1/manager_dbusutil.go diff --git a/network/manager_device.go b/network1/manager_device.go similarity index 95% rename from network/manager_device.go rename to network1/manager_device.go index 9d10ea1ec..144f8bd1f 100644 --- a/network/manager_device.go +++ b/network1/manager_device.go @@ -10,10 +10,10 @@ import ( "strings" "time" - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/network/nm" - mmdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.modemmanager1" - nmdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.networkmanager" + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/network1/nm" + mmdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.modemmanager1" + nmdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.networkmanager" "github.com/linuxdeepin/go-lib/dbusutil" ) @@ -189,31 +189,6 @@ func (m *Manager) newDevice(devPath dbus.ObjectPath) (dev *device, err error) { if err != nil { logger.Warningf("connect to ActivateConnection failed, err: %v", err) } - - if nmHasSystemSettingsModifyPermission() { - carrierChanged := func(hasValue, value bool) { - if !hasValue || !value { - return - } - - logger.Info("wired plugin", dev.Path) - logger.Debug("ensure wired connection exists", dev.Path) - _, _, err = m.ensureWiredConnectionExists(dev.Path, true) - if err != nil { - logger.Warning(err) - } - } - - err = nmDev.Wired().Carrier().ConnectChanged(carrierChanged) - if err != nil { - logger.Warning("failed to monitor Wired-Carrier's change:", err) - } - - carrier, _ := nmDev.Wired().Carrier().Get(0) - carrierChanged(true, carrier) - } else { - logger.Debug("do not have modify permission") - } case nm.NM_DEVICE_TYPE_WIFI: nmDevWireless := nmDev.Wireless() dev.ClonedAddress, _ = nmDevWireless.HwAddress().Get(0) diff --git a/network/manager_ip_conflict.go b/network1/manager_ip_conflict.go similarity index 80% rename from network/manager_ip_conflict.go rename to network1/manager_ip_conflict.go index 5dee68d3e..ecf736790 100644 --- a/network/manager_ip_conflict.go +++ b/network1/manager_ip_conflict.go @@ -8,9 +8,9 @@ import ( "context" "time" - dbus "github.com/godbus/dbus" - ipwatchd "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.ipwatchd" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" + dbus "github.com/godbus/dbus/v5" + ipwatchd "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.ipwatchd1" + ofdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.dbus" "github.com/linuxdeepin/go-lib/dbusutil" ) @@ -64,7 +64,7 @@ func (m *Manager) RequestIPConflictCheck(ip, ifc string) *dbus.Error { defer cancel() var mac string - err = conn.Object("com.deepin.system.IPWatchD", "/com/deepin/system/IPWatchD").CallWithContext(ctx, "com.deepin.system.IPWatchD.RequestIPConflictCheck", 0, ip, ifc).Store(&mac) + err = conn.Object("com.deepin.dde.IPWatchD1", "org/deepin/dde/IPWatchD1").CallWithContext(ctx, "org.deepin.dde.IPWatchD1.RequestIPConflictCheck", 0, ip, ifc).Store(&mac) if err != nil { logger.Warning(err) } diff --git a/network/manager_proxy.go b/network1/manager_proxy.go similarity index 99% rename from network/manager_proxy.go rename to network1/manager_proxy.go index 68ca2728a..85ea55492 100644 --- a/network/manager_proxy.go +++ b/network1/manager_proxy.go @@ -9,7 +9,7 @@ import ( "strconv" "strings" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-gir/gio-2.0" "github.com/linuxdeepin/go-lib/dbusutil" "golang.org/x/xerrors" diff --git a/network1/manager_stub.go b/network1/manager_stub.go new file mode 100644 index 000000000..33c83a40a --- /dev/null +++ b/network1/manager_stub.go @@ -0,0 +1,90 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package network + +import ( + "errors" + + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/network1/nm" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (m *Manager) networkingEnabledWriteCb(write *dbusutil.PropertyWrite) *dbus.Error { + // currently not need + return nil +} + +func (m *Manager) vpnEnabledWriteCb(write *dbusutil.PropertyWrite) *dbus.Error { + enabled, ok := write.Value.(bool) + if !ok { + err := errors.New("type of value is not bool") + logger.Warning(err) + return dbusutil.ToError(err) + } + + // FIXME: + // 由于断开是VPN是在system中完成,断开会触发VPN自动连接重试,这里提前先调整状态 + // 避免自动重连 + if !enabled { + m.setPropVpnEnabled(enabled) + } + + err := m.sysNetwork.VpnEnabled().Set(0, enabled) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + // if vpn enable state is set as true, try to auto connect vpn. + // when vpn enable state is set as false, close all vpn connections in system/network module. + if enabled { + err := enableNetworking() + if err != nil { + logger.Warning(err) + return nil + } + m.setVpnEnable(true) + } + + return nil +} + +func (m *Manager) updatePropActiveConnections() { + activeConnections, _ := marshalJSON(m.activeConnections) + m.setPropActiveConnections(activeConnections) +} + +func (m *Manager) updatePropState() { + state := nmGetManagerState() + m.setPropState(state) +} + +func (m *Manager) updatePropDevices() { + filteredDevices := make(map[string][]*device) + for key, devices := range m.devices { + filteredDevices[key] = make([]*device, 0) + for _, d := range devices { + ignoreIphoneUsbDevice := d.UsbDevice && + d.State <= nm.NM_DEVICE_STATE_UNAVAILABLE && + d.Driver == "ipheth" + if !ignoreIphoneUsbDevice { + filteredDevices[key] = append(filteredDevices[key], d) + } + } + } + devices, _ := marshalJSON(filteredDevices) + m.setPropDevices(devices) +} + +func (m *Manager) updatePropConnections() { + connections, _ := marshalJSON(m.connections) + m.setPropConnections(connections) +} + +func (m *Manager) updatePropWirelessAccessPoints() { + aps, _ := marshalJSON(m.accessPoints) + m.setPropWirelessAccessPoints(aps) +} diff --git a/network1/module.go b/network1/module.go new file mode 100644 index 000000000..e78044994 --- /dev/null +++ b/network1/module.go @@ -0,0 +1,150 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package network + +import ( + "time" + + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/dde-daemon/network1/proxychains" + "github.com/linuxdeepin/go-lib/log" + libnotify "github.com/linuxdeepin/go-lib/notify" +) + +var ( + logger = log.NewLogger("daemon/network") + manager *Manager +) + +func init() { + loader.Register(newModule(logger)) + proxychains.SetLogger(logger) +} + +func HandlePrepareForSleep(sleep bool) { + if manager == nil { + logger.Warning("Module 'network' has not start") + return + } + if sleep { + // suspend + disableNotify() + return + } + // wakeup + enableNotify() + //value decided the strategy of the wirelessScan + _ = manager.RequestWirelessScan() + time.AfterFunc(3*time.Second, func() { + manager.clearAccessPoints() + }) +} + +type Module struct { + *loader.ModuleBase +} + +func newModule(logger *log.Logger) *Module { + module := new(Module) + module.ModuleBase = loader.NewModuleBase("network", module, logger) + return module +} + +func (d *Module) GetDependencies() []string { + return []string{} +} + +func (d *Module) start() error { + service := loader.GetService() + manager = NewManager(service) + manager.init() + + managerServerObj, err := service.NewServerObject(dbusPath, manager, manager.syncConfig) + if err != nil { + return err + } + + err = managerServerObj.SetWriteCallback(manager, "NetworkingEnabled", manager.networkingEnabledWriteCb) + if err != nil { + return err + } + err = managerServerObj.SetWriteCallback(manager, "VpnEnabled", manager.vpnEnabledWriteCb) + if err != nil { + return err + } + + err = managerServerObj.Export() + if err != nil { + logger.Error("failed to export manager:", err) + manager = nil + return err + } + + manager.proxyChainsManager = proxychains.NewManager(service) + err = service.Export(proxychains.DBusPath, manager.proxyChainsManager) + if err != nil { + logger.Warning("failed to export proxyChainsManager:", err) + manager.proxyChainsManager = nil + return err + } + + err = service.RequestName(dbusServiceName) + if err != nil { + return err + } + + err = manager.syncConfig.Register() + if err != nil { + logger.Warning("Failed to register sync service:", err) + } + + initDBusDaemon() + watchNetworkManagerRestart(manager) + return nil +} + +func (d *Module) Start() error { + libnotify.Init("dde-session-daemon") + if manager != nil { + return nil + } + + initSlices() // initialize slice code + initSysSignalLoop() + initNotifyManager() + return d.start() +} + +func (d *Module) Stop() error { + if manager == nil { + return nil + } + + service := loader.GetService() + + err := service.ReleaseName(dbusServiceName) + if err != nil { + logger.Warning(err) + } + + manager.destroy() + destroyDBusDaemon() + sysSigLoop.Stop() + err = service.StopExport(manager) + if err != nil { + logger.Warning(err) + } + + if manager.proxyChainsManager != nil { + err = service.StopExport(manager.proxyChainsManager) + if err != nil { + logger.Warning(err) + } + manager.proxyChainsManager = nil + } + + manager = nil + return nil +} diff --git a/network/nm/README.md b/network1/nm/README.md similarity index 100% rename from network/nm/README.md rename to network1/nm/README.md diff --git a/network/nm/nm_consts_gen.go b/network1/nm/nm_consts_gen.go similarity index 100% rename from network/nm/nm_consts_gen.go rename to network1/nm/nm_consts_gen.go diff --git a/network/nm/nm_extends_consts.go b/network1/nm/nm_extends_consts.go similarity index 100% rename from network/nm/nm_extends_consts.go rename to network1/nm/nm_extends_consts.go diff --git a/network/nm_custom_type.go b/network1/nm_custom_type.go similarity index 98% rename from network/nm_custom_type.go rename to network1/nm_custom_type.go index dde1666ab..9b9f10e5f 100644 --- a/network/nm_custom_type.go +++ b/network1/nm_custom_type.go @@ -5,8 +5,8 @@ package network import ( + "github.com/linuxdeepin/dde-daemon/network1/nm" _ "github.com/linuxdeepin/go-lib/gettext" - "github.com/linuxdeepin/dde-daemon/network/nm" ) // Custom device types, use string instead of number, used by front-end diff --git a/network/nm_generator/Makefile b/network1/nm_generator/Makefile similarity index 100% rename from network/nm_generator/Makefile rename to network1/nm_generator/Makefile diff --git a/network/nm_generator/README.md b/network1/nm_generator/README.md similarity index 100% rename from network/nm_generator/README.md rename to network1/nm_generator/README.md diff --git a/network/nm_generator/gen_nm_consts.py b/network1/nm_generator/gen_nm_consts.py similarity index 100% rename from network/nm_generator/gen_nm_consts.py rename to network1/nm_generator/gen_nm_consts.py diff --git a/network/nm_generator/main.go b/network1/nm_generator/main.go similarity index 100% rename from network/nm_generator/main.go rename to network1/nm_generator/main.go diff --git a/network/nm_generator/nm_consts_gen.yml b/network1/nm_generator/nm_consts_gen.yml similarity index 100% rename from network/nm_generator/nm_consts_gen.yml rename to network1/nm_generator/nm_consts_gen.yml diff --git a/network/nm_generator/nm_consts_keys_override.yml b/network1/nm_generator/nm_consts_keys_override.yml similarity index 100% rename from network/nm_generator/nm_consts_keys_override.yml rename to network1/nm_generator/nm_consts_keys_override.yml diff --git a/network/nm_generator/nm_docs/NetworkManager.conf.html b/network1/nm_generator/nm_docs/NetworkManager.conf.html similarity index 100% rename from network/nm_generator/nm_docs/NetworkManager.conf.html rename to network1/nm_generator/nm_docs/NetworkManager.conf.html diff --git a/network/nm_generator/nm_docs/NetworkManager.devhelp2 b/network1/nm_generator/nm_docs/NetworkManager.devhelp2 similarity index 100% rename from network/nm_generator/nm_docs/NetworkManager.devhelp2 rename to network1/nm_generator/nm_docs/NetworkManager.devhelp2 diff --git a/network/nm_generator/nm_docs/NetworkManager.html b/network1/nm_generator/nm_docs/NetworkManager.html similarity index 100% rename from network/nm_generator/nm_docs/NetworkManager.html rename to network1/nm_generator/nm_docs/NetworkManager.html diff --git a/network/nm_generator/nm_docs/dbus-types.html b/network1/nm_generator/nm_docs/dbus-types.html similarity index 100% rename from network/nm_generator/nm_docs/dbus-types.html rename to network1/nm_generator/nm_docs/dbus-types.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.AccessPoint.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.AccessPoint.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.AccessPoint.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.AccessPoint.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.AgentManager.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.AgentManager.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.AgentManager.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.AgentManager.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Connection.Active.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Connection.Active.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Connection.Active.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Connection.Active.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.DHCP4Config.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.DHCP4Config.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.DHCP4Config.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.DHCP4Config.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.DHCP6Config.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.DHCP6Config.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.DHCP6Config.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.DHCP6Config.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Adsl.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Adsl.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Adsl.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Adsl.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Bluetooth.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Bluetooth.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Bluetooth.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Bluetooth.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Bond.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Bond.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Bond.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Bond.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Bridge.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Bridge.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Bridge.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Bridge.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Generic.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Generic.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Generic.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Generic.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.IPTunnel.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.IPTunnel.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.IPTunnel.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.IPTunnel.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Infiniband.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Infiniband.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Infiniband.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Infiniband.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Macvlan.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Macvlan.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Macvlan.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Macvlan.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Modem.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Modem.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Modem.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Modem.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.OlpcMesh.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.OlpcMesh.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.OlpcMesh.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.OlpcMesh.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Statistics.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Statistics.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Statistics.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Statistics.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Team.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Team.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Team.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Team.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Tun.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Tun.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Tun.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Tun.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Veth.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Veth.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Veth.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Veth.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Vlan.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Vlan.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Vlan.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Vlan.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Vxlan.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Vxlan.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Vxlan.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Vxlan.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.WiMax.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.WiMax.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.WiMax.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.WiMax.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Wired.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Wired.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Wired.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Wired.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Wireless.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Wireless.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Wireless.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.Wireless.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Device.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.IP4Config.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.IP4Config.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.IP4Config.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.IP4Config.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.IP6Config.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.IP6Config.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.IP6Config.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.IP6Config.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.PPP.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.PPP.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.PPP.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.PPP.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.SecretAgent.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.SecretAgent.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.SecretAgent.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.SecretAgent.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Settings.Connection.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Settings.Connection.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Settings.Connection.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Settings.Connection.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Settings.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Settings.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Settings.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.Settings.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.VPN.Connection.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.VPN.Connection.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.VPN.Connection.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.VPN.Connection.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.VPN.Plugin.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.VPN.Plugin.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.VPN.Plugin.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.VPN.Plugin.html diff --git a/network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.html b/network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.html similarity index 100% rename from network/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.html rename to network1/nm_generator/nm_docs/gdbus-org.freedesktop.NetworkManager.html diff --git a/network/nm_generator/nm_docs/home.png b/network1/nm_generator/nm_docs/home.png similarity index 100% rename from network/nm_generator/nm_docs/home.png rename to network1/nm_generator/nm_docs/home.png diff --git a/network/nm_generator/nm_docs/index.html b/network1/nm_generator/nm_docs/index.html similarity index 100% rename from network/nm_generator/nm_docs/index.html rename to network1/nm_generator/nm_docs/index.html diff --git a/network/nm_generator/nm_docs/ix01.html b/network1/nm_generator/nm_docs/ix01.html similarity index 100% rename from network/nm_generator/nm_docs/ix01.html rename to network1/nm_generator/nm_docs/ix01.html diff --git a/network/nm_generator/nm_docs/left-insensitive.png b/network1/nm_generator/nm_docs/left-insensitive.png similarity index 100% rename from network/nm_generator/nm_docs/left-insensitive.png rename to network1/nm_generator/nm_docs/left-insensitive.png diff --git a/network/nm_generator/nm_docs/left.png b/network1/nm_generator/nm_docs/left.png similarity index 100% rename from network/nm_generator/nm_docs/left.png rename to network1/nm_generator/nm_docs/left.png diff --git a/network/nm_generator/nm_docs/license.html b/network1/nm_generator/nm_docs/license.html similarity index 100% rename from network/nm_generator/nm_docs/license.html rename to network1/nm_generator/nm_docs/license.html diff --git a/network/nm_generator/nm_docs/manpages.html b/network1/nm_generator/nm_docs/manpages.html similarity index 100% rename from network/nm_generator/nm_docs/manpages.html rename to network1/nm_generator/nm_docs/manpages.html diff --git a/network/nm_generator/nm_docs/nm-dbus-types.html b/network1/nm_generator/nm_docs/nm-dbus-types.html similarity index 100% rename from network/nm_generator/nm_docs/nm-dbus-types.html rename to network1/nm_generator/nm_docs/nm-dbus-types.html diff --git a/network/nm_generator/nm_docs/nm-online.html b/network1/nm_generator/nm_docs/nm-online.html similarity index 100% rename from network/nm_generator/nm_docs/nm-online.html rename to network1/nm_generator/nm_docs/nm-online.html diff --git a/network/nm_generator/nm_docs/nm-settings-keyfile.html b/network1/nm_generator/nm_docs/nm-settings-keyfile.html similarity index 100% rename from network/nm_generator/nm_docs/nm-settings-keyfile.html rename to network1/nm_generator/nm_docs/nm-settings-keyfile.html diff --git a/network/nm_generator/nm_docs/nm-settings.html b/network1/nm_generator/nm_docs/nm-settings.html similarity index 100% rename from network/nm_generator/nm_docs/nm-settings.html rename to network1/nm_generator/nm_docs/nm-settings.html diff --git a/network/nm_generator/nm_docs/nm-vpn-dbus-types.html b/network1/nm_generator/nm_docs/nm-vpn-dbus-types.html similarity index 100% rename from network/nm_generator/nm_docs/nm-vpn-dbus-types.html rename to network1/nm_generator/nm_docs/nm-vpn-dbus-types.html diff --git a/network/nm_generator/nm_docs/nmcli-examples.html b/network1/nm_generator/nm_docs/nmcli-examples.html similarity index 100% rename from network/nm_generator/nm_docs/nmcli-examples.html rename to network1/nm_generator/nm_docs/nmcli-examples.html diff --git a/network/nm_generator/nm_docs/nmcli.html b/network1/nm_generator/nm_docs/nmcli.html similarity index 100% rename from network/nm_generator/nm_docs/nmcli.html rename to network1/nm_generator/nm_docs/nmcli.html diff --git a/network/nm_generator/nm_docs/nmtui.html b/network1/nm_generator/nm_docs/nmtui.html similarity index 100% rename from network/nm_generator/nm_docs/nmtui.html rename to network1/nm_generator/nm_docs/nmtui.html diff --git a/network/nm_generator/nm_docs/ref-settings.html b/network1/nm_generator/nm_docs/ref-settings.html similarity index 100% rename from network/nm_generator/nm_docs/ref-settings.html rename to network1/nm_generator/nm_docs/ref-settings.html diff --git a/network/nm_generator/nm_docs/right-insensitive.png b/network1/nm_generator/nm_docs/right-insensitive.png similarity index 100% rename from network/nm_generator/nm_docs/right-insensitive.png rename to network1/nm_generator/nm_docs/right-insensitive.png diff --git a/network/nm_generator/nm_docs/right.png b/network1/nm_generator/nm_docs/right.png similarity index 100% rename from network/nm_generator/nm_docs/right.png rename to network1/nm_generator/nm_docs/right.png diff --git a/network/nm_generator/nm_docs/secrets-flags.html b/network1/nm_generator/nm_docs/secrets-flags.html similarity index 100% rename from network/nm_generator/nm_docs/secrets-flags.html rename to network1/nm_generator/nm_docs/secrets-flags.html diff --git a/network/nm_generator/nm_docs/spec.html b/network1/nm_generator/nm_docs/spec.html similarity index 100% rename from network/nm_generator/nm_docs/spec.html rename to network1/nm_generator/nm_docs/spec.html diff --git a/network/nm_generator/nm_docs/style.css b/network1/nm_generator/nm_docs/style.css similarity index 100% rename from network/nm_generator/nm_docs/style.css rename to network1/nm_generator/nm_docs/style.css diff --git a/network/nm_generator/nm_docs/up-insensitive.png b/network1/nm_generator/nm_docs/up-insensitive.png similarity index 100% rename from network/nm_generator/nm_docs/up-insensitive.png rename to network1/nm_generator/nm_docs/up-insensitive.png diff --git a/network/nm_generator/nm_docs/up.png b/network1/nm_generator/nm_docs/up.png similarity index 100% rename from network/nm_generator/nm_docs/up.png rename to network1/nm_generator/nm_docs/up.png diff --git a/network/nm_generator/nm_girs/NM-1.0_1.10.0.gir b/network1/nm_generator/nm_girs/NM-1.0_1.10.0.gir similarity index 100% rename from network/nm_generator/nm_girs/NM-1.0_1.10.0.gir rename to network1/nm_generator/nm_girs/NM-1.0_1.10.0.gir diff --git a/network/nm_generator/nm_girs/NM-1.0_1.2.4.gir b/network1/nm_generator/nm_girs/NM-1.0_1.2.4.gir similarity index 100% rename from network/nm_generator/nm_girs/NM-1.0_1.2.4.gir rename to network1/nm_generator/nm_girs/NM-1.0_1.2.4.gir diff --git a/network/nm_generator/nm_girs/NM-1.0_1.4.2.gir b/network1/nm_generator/nm_girs/NM-1.0_1.4.2.gir similarity index 100% rename from network/nm_generator/nm_girs/NM-1.0_1.4.2.gir rename to network1/nm_generator/nm_girs/NM-1.0_1.4.2.gir diff --git a/network/nm_generator/nm_girs/NM-1.0_1.6.0.gir b/network1/nm_generator/nm_girs/NM-1.0_1.6.0.gir similarity index 100% rename from network/nm_generator/nm_girs/NM-1.0_1.6.0.gir rename to network1/nm_generator/nm_girs/NM-1.0_1.6.0.gir diff --git a/network/nm_generator/nm_girs/NM-1.0_1.8.2.gir b/network1/nm_generator/nm_girs/NM-1.0_1.8.2.gir similarity index 100% rename from network/nm_generator/nm_girs/NM-1.0_1.8.2.gir rename to network1/nm_generator/nm_girs/NM-1.0_1.8.2.gir diff --git a/network/nm_generator/nm_logicset_keys.yml b/network1/nm_generator/nm_logicset_keys.yml similarity index 100% rename from network/nm_generator/nm_logicset_keys.yml rename to network1/nm_generator/nm_logicset_keys.yml diff --git a/network/nm_generator/nm_virtual_sections.yml b/network1/nm_generator/nm_virtual_sections.yml similarity index 100% rename from network/nm_generator/nm_virtual_sections.yml rename to network1/nm_generator/nm_virtual_sections.yml diff --git a/network/nm_generator/nm_vpn_alias_settings.yml b/network1/nm_generator/nm_vpn_alias_settings.yml similarity index 100% rename from network/nm_generator/nm_vpn_alias_settings.yml rename to network1/nm_generator/nm_vpn_alias_settings.yml diff --git a/network/nm_generator/tpl.go b/network1/nm_generator/tpl.go similarity index 100% rename from network/nm_generator/tpl.go rename to network1/nm_generator/tpl.go diff --git a/network/nm_generator/utils.go b/network1/nm_generator/utils.go similarity index 100% rename from network/nm_generator/utils.go rename to network1/nm_generator/utils.go diff --git a/network/nm_key_converter.go b/network1/nm_key_converter.go similarity index 98% rename from network/nm_key_converter.go rename to network1/nm_key_converter.go index 89d303286..7495cec00 100644 --- a/network/nm_key_converter.go +++ b/network1/nm_key_converter.go @@ -18,7 +18,7 @@ func interfaceToString(v interface{}) (d string) { return } -//nolint +// nolint func interfaceToByte(v interface{}) (d byte) { if isInterfaceNil(v) { return @@ -55,7 +55,7 @@ func interfaceToUint32(v interface{}) (d uint32) { return } -//nolint +// nolint func interfaceToInt64(v interface{}) (d int64) { if isInterfaceNil(v) { return @@ -68,7 +68,7 @@ func interfaceToInt64(v interface{}) (d int64) { return } -//nolint +// nolint func interfaceToUint64(v interface{}) (d uint64) { if isInterfaceNil(v) { return @@ -117,7 +117,7 @@ func interfaceToArrayString(v interface{}) (d []string) { return } -//nolint +// nolint func interfaceToArrayUint32(v interface{}) (d []uint32) { if isInterfaceNil(v) { return @@ -130,7 +130,7 @@ func interfaceToArrayUint32(v interface{}) (d []uint32) { return } -//nolint +// nolint func interfaceToArrayArrayByte(v interface{}) (d [][]byte) { if isInterfaceNil(v) { return @@ -143,7 +143,7 @@ func interfaceToArrayArrayByte(v interface{}) (d [][]byte) { return } -//nolint +// nolint func interfaceToArrayArrayUint32(v interface{}) (d [][]uint32) { if isInterfaceNil(v) { return diff --git a/network/nm_key_converter_test.go b/network1/nm_key_converter_test.go similarity index 99% rename from network/nm_key_converter_test.go rename to network1/nm_key_converter_test.go index 20fa17c03..5a8d05517 100644 --- a/network/nm_key_converter_test.go +++ b/network1/nm_key_converter_test.go @@ -135,4 +135,4 @@ func (*testWrapper) TestInterfaceToArrayUint32(c *C.C) { for _, d := range data { c.Check(interfaceToArrayUint32(d.test), C.DeepEquals, d.result) } -} \ No newline at end of file +} diff --git a/network/nm_key_edit.go b/network1/nm_key_edit.go similarity index 98% rename from network/nm_key_edit.go rename to network1/nm_key_edit.go index 8c9dd04ef..1e7fdd4e4 100644 --- a/network/nm_key_edit.go +++ b/network1/nm_key_edit.go @@ -5,7 +5,7 @@ package network import ( - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" ) func getSettingKey(data connectionData, section, key string) (value interface{}) { diff --git a/network/nm_key_type.go b/network1/nm_key_type.go similarity index 100% rename from network/nm_key_type.go rename to network1/nm_key_type.go diff --git a/network/nm_setting_802_1x.go b/network1/nm_setting_802_1x.go similarity index 98% rename from network/nm_setting_802_1x.go rename to network1/nm_setting_802_1x.go index 758c49cfa..bce5f5cdf 100644 --- a/network/nm_setting_802_1x.go +++ b/network1/nm_setting_802_1x.go @@ -7,7 +7,7 @@ package network import ( "fmt" - "github.com/linuxdeepin/dde-daemon/network/nm" + "github.com/linuxdeepin/dde-daemon/network1/nm" ) // Logic setter diff --git a/network/nm_setting_beans_gen.go b/network1/nm_setting_beans_gen.go similarity index 99% rename from network/nm_setting_beans_gen.go rename to network1/nm_setting_beans_gen.go index ff34d6f1a..466ffdb77 100644 --- a/network/nm_setting_beans_gen.go +++ b/network1/nm_setting_beans_gen.go @@ -1,5 +1,5 @@ // Generated by nm-generator -//nolint +// nolint package network // General get setting key default value diff --git a/network/nm_setting_ip4_config.go b/network1/nm_setting_ip4_config.go similarity index 88% rename from network/nm_setting_ip4_config.go rename to network1/nm_setting_ip4_config.go index a88819504..c1afab54c 100644 --- a/network/nm_setting_ip4_config.go +++ b/network1/nm_setting_ip4_config.go @@ -5,7 +5,7 @@ package network import ( - "github.com/linuxdeepin/dde-daemon/network/nm" + "github.com/linuxdeepin/dde-daemon/network1/nm" ) func initSettingSectionIpv4(data connectionData) { diff --git a/network/nm_setting_ip6_config.go b/network1/nm_setting_ip6_config.go similarity index 87% rename from network/nm_setting_ip6_config.go rename to network1/nm_setting_ip6_config.go index 9787bfa1d..149ec4548 100644 --- a/network/nm_setting_ip6_config.go +++ b/network1/nm_setting_ip6_config.go @@ -5,7 +5,7 @@ package network import ( - "github.com/linuxdeepin/dde-daemon/network/nm" + "github.com/linuxdeepin/dde-daemon/network1/nm" ) func initSettingSectionIpv6(data connectionData) { diff --git a/network/nm_setting_vpn.go b/network1/nm_setting_vpn.go similarity index 100% rename from network/nm_setting_vpn.go rename to network1/nm_setting_vpn.go diff --git a/network/nm_setting_wired.go b/network1/nm_setting_wired.go similarity index 94% rename from network/nm_setting_wired.go rename to network1/nm_setting_wired.go index 70c77ecfe..8b59d9d61 100644 --- a/network/nm_setting_wired.go +++ b/network1/nm_setting_wired.go @@ -5,8 +5,8 @@ package network import ( - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/network/nm" + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/network1/nm" ) func newWiredConnectionForDevice(id, uuid string, devPath dbus.ObjectPath, active bool) (cpath dbus.ObjectPath, err error) { @@ -56,6 +56,6 @@ func initSettingSectionWired(data connectionData, devPath dbus.ObjectPath) { // need to set macAddress hwAddr, err := nmGeneralGetDeviceHwAddr(devPath, true) if err == nil { - setSettingWiredMacAddress(data, convertMacAddressToArrayByte(hwAddr)); + setSettingWiredMacAddress(data, convertMacAddressToArrayByte(hwAddr)) } } diff --git a/network/nm_setting_wireless.go b/network1/nm_setting_wireless.go similarity index 96% rename from network/nm_setting_wireless.go rename to network1/nm_setting_wireless.go index 6ea64453a..5aee0f8c2 100644 --- a/network/nm_setting_wireless.go +++ b/network1/nm_setting_wireless.go @@ -7,8 +7,8 @@ package network import ( "os" - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/network/nm" + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/network1/nm" ) func newWirelessHotspotConnectionForDevice(id, uuid string, devPath dbus.ObjectPath, active bool) (cpath dbus.ObjectPath, err error) { @@ -50,7 +50,7 @@ func newWirelessConnectionData(id, uuid string, ssid []byte, keymgmt, macAddress } if macAddress != "" { - setSettingWirelessMacAddress(data, convertMacAddressToArrayByte(macAddress)); + setSettingWirelessMacAddress(data, convertMacAddressToArrayByte(macAddress)) } initSettingSectionIpv4(data) diff --git a/network/nm_setting_wireless_security.go b/network1/nm_setting_wireless_security.go similarity index 98% rename from network/nm_setting_wireless_security.go rename to network1/nm_setting_wireless_security.go index faa024878..13f0b391c 100644 --- a/network/nm_setting_wireless_security.go +++ b/network1/nm_setting_wireless_security.go @@ -8,7 +8,7 @@ import ( "errors" "fmt" - "github.com/linuxdeepin/dde-daemon/network/nm" + "github.com/linuxdeepin/dde-daemon/network1/nm" ) // Virtual key getter and setter diff --git a/network/proxychains/check.go b/network1/proxychains/check.go similarity index 100% rename from network/proxychains/check.go rename to network1/proxychains/check.go diff --git a/network1/proxychains/config.go b/network1/proxychains/config.go new file mode 100644 index 000000000..8060a808a --- /dev/null +++ b/network1/proxychains/config.go @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package proxychains + +import ( + "encoding/json" + "io/ioutil" +) + +type Config struct { + Enable bool + Type string + IP string + Port uint32 + User string + Password string +} + +func loadConfig(file string) (*Config, error) { + data, err := ioutil.ReadFile(file) + if err != nil { + return nil, err + } + + var cfg Config + err = json.Unmarshal(data, &cfg) + if err != nil { + return nil, err + } + + return &cfg, nil +} + +func (cfg *Config) save(file string) error { + data, err := json.Marshal(cfg) + if err != nil { + return err + } + return ioutil.WriteFile(file, data, 0600) +} diff --git a/network/proxychains/exported_methods_auto.go b/network1/proxychains/exported_methods_auto.go similarity index 100% rename from network/proxychains/exported_methods_auto.go rename to network1/proxychains/exported_methods_auto.go diff --git a/network/proxychains/proxychains.go b/network1/proxychains/proxychains.go similarity index 97% rename from network/proxychains/proxychains.go rename to network1/proxychains/proxychains.go index a1ec58bb7..07414848c 100644 --- a/network/proxychains/proxychains.go +++ b/network1/proxychains/proxychains.go @@ -12,9 +12,9 @@ import ( "path/filepath" "sync" - proxy "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.proxy" + proxy "github.com/linuxdeepin/go-dbus-factory/system/com.deepin.system.proxy" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/log" "github.com/linuxdeepin/go-lib/xdg/basedir" @@ -62,8 +62,8 @@ func NewManager(service *dbusutil.Service) *Manager { } const ( - DBusPath = "/com/deepin/daemon/Network/ProxyChains" - dbusInterface = "com.deepin.daemon.Network.ProxyChains" + DBusPath = "/org/deepin/dde/Network/ProxyChains" + dbusInterface = "org.deepin.dde.Network.ProxyChains" ) func (*Manager) GetInterfaceName() string { diff --git a/network1/proxychains/utils_notify.go b/network1/proxychains/utils_notify.go new file mode 100644 index 000000000..b7327cce8 --- /dev/null +++ b/network1/proxychains/utils_notify.go @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package proxychains + +import ( + dbus "github.com/godbus/dbus/v5" + notifications "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.notifications" + . "github.com/linuxdeepin/go-lib/gettext" +) + +var ( + notification notifications.Notifications + notifyIconProxyEnabled = "notification-network-proxy-enabled" + notifyIconProxyDisabled = "notification-network-proxy-disabled" +) + +func init() { + sessionBus, err := dbus.SessionBus() + if err != nil { + notification = nil + return + } + notification = notifications.NewNotifications(sessionBus) +} + +func createNotify(appName string) func(string, string, string) { + var nid uint32 = 0 + return func(icon, summary, body string) { + if notification == nil { + logger.Warning("notification is nil") + logger.Debugf("%s %s %s", icon, summary, body) + return + } + var err error + nid, err = notification.Notify(0, appName, nid, + icon, summary, body, nil, nil, -1) + if err != nil { + logger.Warning(err) + return + } + } +} + +var notify = createNotify("dde-control-center") + +func notifyAppProxyEnabled() { + notify(notifyIconProxyEnabled, Tr("Network"), Tr("Application proxy is set successfully")) +} +func notifyAppProxyEnableFailed() { + notify(notifyIconProxyDisabled, Tr("Network"), Tr("Failed to set the application proxy")) +} diff --git a/network/secret_agent.go b/network1/secret_agent.go similarity index 99% rename from network/secret_agent.go rename to network1/secret_agent.go index 4ca65c0f6..5f6a75b11 100644 --- a/network/secret_agent.go +++ b/network1/secret_agent.go @@ -10,6 +10,7 @@ import ( "encoding/json" "errors" "fmt" + "os" "os/exec" "strconv" @@ -17,10 +18,10 @@ import ( "sync" "time" - "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/network/nm" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" - secrets "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.secrets" + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/network1/nm" + ofdbus "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.dbus" + secrets "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.secrets" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/strv" ) @@ -1254,5 +1255,5 @@ type SecretAgentSession struct { } func (*SecretAgentSession) GetInterfaceName() string { - return "com.deepin.daemon.Network.SecretAgent" + return "org.deepin.dde.Network1.SecretAgent" } diff --git a/network/state_handler.go b/network1/state_handler.go similarity index 99% rename from network/state_handler.go rename to network1/state_handler.go index f8d3891cc..51614d102 100644 --- a/network/state_handler.go +++ b/network1/state_handler.go @@ -8,9 +8,9 @@ import ( "fmt" "sync" - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/network/nm" - nmdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.networkmanager" + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/network1/nm" + nmdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.networkmanager" "github.com/linuxdeepin/go-lib/dbusutil" . "github.com/linuxdeepin/go-lib/gettext" ) @@ -283,7 +283,7 @@ func (sh *stateHandler) watch(path dbus.ObjectPath) { // 如果禁用了失败的消息,则不提示失败消息 return } - + // ignore device removed signals for that could not // query related information correct if reason == nm.NM_DEVICE_STATE_REASON_REMOVED { diff --git a/network1/sync_config.go b/network1/sync_config.go new file mode 100644 index 000000000..513d14f82 --- /dev/null +++ b/network1/sync_config.go @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package network + +import ( + "encoding/json" + + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/common/dsync" +) + +type syncConfig struct { + m *Manager +} + +const ( + daemonSysService = "org.deepin.dde.Daemon1" + daemonSysPath = "/org/deepin/dde/Daemon1" + daemonSysIFC = daemonSysService + + methodSysNetGetConnections = daemonSysIFC + ".NetworkGetConnections" + methodSysNetSetConnections = daemonSysIFC + ".NetworkSetConnections" +) + +func (sc *syncConfig) Get() (interface{}, error) { + obj, err := getDaemonSysBus() + if err != nil { + return nil, err + } + var data []byte + err = obj.Call(methodSysNetGetConnections, 0).Store(&data) + if err != nil { + return nil, err + } + var info dsync.NetworkData + err = json.Unmarshal(data, &info) + if err != nil { + return nil, err + } + return &info, nil +} + +func (sc *syncConfig) Set(data []byte) error { + obj, err := getDaemonSysBus() + if err != nil { + return err + } + return obj.Call(methodSysNetSetConnections, 0, data).Store() +} + +func getDaemonSysBus() (dbus.BusObject, error) { + conn, err := dbus.SystemBus() + if err != nil { + return nil, err + } + return conn.Object(daemonSysService, daemonSysPath), nil +} diff --git a/network/testdata/ca.crt b/network1/testdata/ca.crt similarity index 100% rename from network/testdata/ca.crt rename to network1/testdata/ca.crt diff --git a/network/testdata/ca.key b/network1/testdata/ca.key similarity index 100% rename from network/testdata/ca.key rename to network1/testdata/ca.key diff --git a/network/testdata/client.crt b/network1/testdata/client.crt similarity index 100% rename from network/testdata/client.crt rename to network1/testdata/client.crt diff --git a/network/testdata/client.key b/network1/testdata/client.key similarity index 100% rename from network/testdata/client.key rename to network1/testdata/client.key diff --git a/network1/utils.go b/network1/utils.go new file mode 100644 index 000000000..e1c6c64b0 --- /dev/null +++ b/network1/utils.go @@ -0,0 +1,312 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package network + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "os" + "os/exec" + "strings" + "time" + + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/iw" + "github.com/linuxdeepin/dde-daemon/network1/nm" + nmdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.networkmanager" + "github.com/linuxdeepin/go-gir/gio-2.0" + "github.com/linuxdeepin/go-lib/utils" +) + +func isStringInArray(s string, list []string) bool { + for _, i := range list { + if i == s { + return true + } + } + return false +} + +func isDBusPathInArray(path dbus.ObjectPath, pathList []dbus.ObjectPath) bool { + for _, i := range pathList { + if i == path { + return true + } + } + return false +} + +func isInterfaceNil(v interface{}) bool { + return utils.IsInterfaceNil(v) +} + +func marshalJSON(v interface{}) (jsonStr string, err error) { + b, err := json.Marshal(v) + if err != nil { + logger.Error(err) + return + } + jsonStr = string(b) + return +} + +// convert local path to uri, etc "/the/path" -> "file:///the/path" +func toUriPath(path string) (uriPath string) { + return utils.EncodeURI(path, utils.SCHEME_FILE) +} + +// convert uri to local path, etc "file:///the/path" -> "/the/path" +func toLocalPath(path string) (localPath string) { + return utils.DecodeURI(path) +} + +// convert local path to uri, etc "/the/path" -> "file:///the/path" +func toUriPathFor8021x(path string) (uriPath string) { + // the uri for 8021x cert files is specially, we just need append + // suffix "file://" for it + if !utils.IsURI(path) { + uriPath = "file://" + path + } else { + uriPath = path + } + return +} + +// convert uri to local path, etc "file:///the/path" -> "/the/path" +func toLocalPathFor8021x(path string) (uriPath string) { + // the uri for 8021x cert files is specially, we just need remove + // suffix "file://" from it + if utils.IsURI(path) { + uriPath = strings.TrimPrefix(path, "file://") + } else { + uriPath = path + } + return +} + +// byte array should end with null byte +func strToByteArrayPath(path string) (bytePath []byte) { + bytePath = []byte(path) + bytePath = append(bytePath, 0) + return +} +func byteArrayToStrPath(bytePath []byte) (path string) { + if len(bytePath) < 1 { + return + } + path = string(bytePath[:len(bytePath)-1]) + return +} + +// strToUuid convert any given string to md5, and then to uuid, for +// example, a device address string "00:12:34:56:ab:cd" will be +// converted to "086e214c-1f20-bca4-9816-c0a11c8c0e02" +func strToUuid(str string) (uuid string) { + md5, _ := utils.SumStrMd5(str) + return doStrToUuid(md5) +} +func doStrToUuid(str string) (uuid string) { + str = strings.ToLower(str) + for i := 0; i < len(str); i++ { + if (str[i] >= '0' && str[i] <= '9') || + (str[i] >= 'a' && str[i] <= 'f') { + uuid = uuid + string(str[i]) + } + } + if len(uuid) < 32 { + misslen := 32 - len(uuid) + uuid = strings.Repeat("0", misslen) + uuid + } + uuid = fmt.Sprintf("%s-%s-%s-%s-%s", uuid[0:8], uuid[8:12], uuid[12:16], uuid[16:20], uuid[20:32]) + return +} + +// execute program and read or write to it stdin/stdout pipe +func execWithIO(name string, arg ...string) (process *os.Process, stdin io.WriteCloser, stdout, stderr io.ReadCloser, err error) { + cmd := exec.Command(name, arg...) + stdin, _ = cmd.StdinPipe() + stdout, _ = cmd.StdoutPipe() + stderr, _ = cmd.StderrPipe() + + err = cmd.Start() + if err != nil { + return + } + go func() { + err = cmd.Wait() + if err != nil { + logger.Warning("failed to wait cmd:", err) + return + } + }() + process = cmd.Process + return +} + +func isWirelessDeviceSupportHotspot(macAddress string) bool { + devices, err := iw.ListWirelessInfo() + if err != nil { + logger.Warning("Failed to detect hotspot:", macAddress, err) + return false + } + dev := devices.Get(macAddress) + if dev == nil { + logger.Warning("Failed to find device:", macAddress) + return false + } + return dev.SupportedHotspot() +} + +func getAutoConnectConnUuidListByConnType(connType string) ([]string, error) { + var uuidSlice []string + // get connections slice from settings + connPaths, err := nmSettings.ListConnections(0) + if err != nil { + logger.Warningf("get network connections failed, err: %v", err) + return nil, err + } + // get system bus + systemBus, err := dbus.SystemBus() + if err != nil { + logger.Warning(err) + return nil, err + } + // get uuid list from list according to type + for _, connPath := range connPaths { + conn, err := nmdbus.NewConnectionSettings(systemBus, connPath) + if err != nil { + logger.Warning(err) + continue + } + settings, err := conn.GetSettings(0) + if err != nil { + logger.Warning(err) + continue + } + // check if type is wanted + if getSettingConnectionType(settings) != connType { + continue + } + // check if is auto connect + autoConnect := getSettingConnectionAutoconnect(settings) + if !autoConnect { + continue + } + // add uuid + uuid := getSettingConnectionUuid(settings) + if uuid != "" { + uuidSlice = append(uuidSlice, uuid) + } + } + return uuidSlice, nil +} + +func isNetworkAvailable() (bool, error) { + state, err := nmManager.PropState().Get(0) + if err != nil { + return false, err + } + return state >= nm.NM_STATE_CONNECTED_SITE, nil +} + +func enableNetworking() error { + enabled, err := nmManager.NetworkingEnabled().Get(0) + if err != nil { + return err + } + + if enabled { + return nil + } + + return nmManager.Enable(0, true) +} + +func (m *Manager) isSessionActive() bool { + if m.currentSession == nil { + logger.Error("currentSession is null") + return false + } + active, err := m.currentSession.Active().Get(dbus.FlagNoAutoStart) + if err != nil { + logger.Error("Failed to get self active:", err) + return false + } + return active +} + +// 解析重定向地址 +func getRedirectFromResponse(resp *http.Response, detectUrl string) (string, error) { + if resp == nil { + return "", errors.New("response is nil") + } + // 当前返回的是否为重定向 + if resp.StatusCode != 302 { + return "", errors.New("response is not redirect") + } + // 是否包含location + location := resp.Header.Get("Location") + if location == "" { + return "", errors.New("response has no location") + } + // 默认返回整个location + urlMsg, err := url.Parse(location) + if err != nil { + logger.Warningf("parse location failed, err: %v", err) + // 解析失败则返回原来的location,不对location做处理 + return location, nil + } + // 判断url参数 + if len(urlMsg.RawQuery) > 0 { + // 获取解析参数 + paramSl, err := url.ParseQuery(urlMsg.RawQuery) + if err != nil { + // 解析失败则返回原location + logger.Warningf("parse params failed, err: %v", err) + return location, nil + } + // 获取url信息 + redirectUrl := paramSl.Get("url") + // 认证后的跳转到地址如果为之前的请求地址,则删除该地址,否则不删除 + if strings.Contains(redirectUrl, detectUrl) { + paramSl.Del("url") + // 参数更新 + urlMsg.RawQuery = paramSl.Encode() + return urlMsg.String(), nil + } + } + return location, nil +} + +func (m *Manager) isConnectivityByHttp() bool { + client := &http.Client{ + Timeout: time.Duration(15 * time.Second), + } + gs := gio.NewSettings("com.deepin.dde.network-utils") + defer gs.Unref() + + urls := gs.GetStrv("network-checker-urls") + if len(urls) == 0 { + urls = append(urls, "http://detect.uniontech.com/") + } + for _, url := range urls { + if resp, err := client.Head(url); err == nil { + if resp.StatusCode >= 200 && resp.StatusCode <= 206 { + return true + } + } + } + return false +} + +func showOSD(signal string) { + logger.Debug("show OSD", signal) + sessionDBus, _ := dbus.SessionBus() + go sessionDBus.Object("com.deepin.dde.osd", "/").Call("com.deepin.dde.osd.ShowOSD", 0, signal) +} diff --git a/network/utils_dbus.go b/network1/utils_dbus.go similarity index 82% rename from network/utils_dbus.go rename to network1/utils_dbus.go index 652c53691..171ada4c5 100644 --- a/network/utils_dbus.go +++ b/network1/utils_dbus.go @@ -5,11 +5,11 @@ package network import ( - "github.com/godbus/dbus" - dbusmgr "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" - nmdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.networkmanager" - notifications "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.notifications" + "github.com/godbus/dbus/v5" + notifications "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.notifications" + dbusmgr "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.dbus" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" + nmdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.networkmanager" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/dbusutil/proxy" ) diff --git a/network/utils_dbus_mm.go b/network1/utils_dbus_mm.go similarity index 98% rename from network/utils_dbus_mm.go rename to network1/utils_dbus_mm.go index 8ce61f039..d355d6b40 100644 --- a/network/utils_dbus_mm.go +++ b/network1/utils_dbus_mm.go @@ -5,8 +5,8 @@ package network import ( - "github.com/godbus/dbus" - mmdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.modemmanager1" + "github.com/godbus/dbus/v5" + mmdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.modemmanager1" "github.com/linuxdeepin/go-lib/dbusutil/proxy" ) diff --git a/network/utils_dbus_nm.go b/network1/utils_dbus_nm.go similarity index 99% rename from network/utils_dbus_nm.go rename to network1/utils_dbus_nm.go index 10ae3bc96..c3d2b17bc 100644 --- a/network/utils_dbus_nm.go +++ b/network1/utils_dbus_nm.go @@ -12,9 +12,9 @@ import ( "strings" "time" - "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/network/nm" - nmdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.networkmanager" + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/network1/nm" + nmdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.networkmanager" "github.com/linuxdeepin/go-lib/dbusutil/proxy" . "github.com/linuxdeepin/go-lib/gettext" ) diff --git a/network/utils_ethtool.go b/network1/utils_ethtool.go similarity index 100% rename from network/utils_ethtool.go rename to network1/utils_ethtool.go diff --git a/network/utils_ip.go b/network1/utils_ip.go similarity index 100% rename from network/utils_ip.go rename to network1/utils_ip.go diff --git a/network/utils_ip_be_test.go b/network1/utils_ip_be_test.go similarity index 94% rename from network/utils_ip_be_test.go rename to network1/utils_ip_be_test.go index 04145d682..ec0e7d0f7 100644 --- a/network/utils_ip_be_test.go +++ b/network1/utils_ip_be_test.go @@ -1,4 +1,6 @@ +//go:build mips || mips64 || ppc64 || s390x // +build mips mips64 ppc64 s390x + // SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/network/utils_ip_le_test.go b/network1/utils_ip_le_test.go similarity index 90% rename from network/utils_ip_le_test.go rename to network1/utils_ip_le_test.go index 4d780d6ac..5cf186fda 100644 --- a/network/utils_ip_le_test.go +++ b/network1/utils_ip_le_test.go @@ -1,3 +1,4 @@ +//go:build i386 || amd64 || arm || arm64 || mipsle || mips64le || ppc64le || riscv64 || wasm // +build i386 amd64 arm arm64 mipsle mips64le ppc64le riscv64 wasm // SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. diff --git a/network/utils_ip_test.go b/network1/utils_ip_test.go similarity index 100% rename from network/utils_ip_test.go rename to network1/utils_ip_test.go diff --git a/network1/utils_notify.go b/network1/utils_notify.go new file mode 100644 index 000000000..7074c9520 --- /dev/null +++ b/network1/utils_notify.go @@ -0,0 +1,289 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package network + +import ( + "container/list" + "sync" + "time" + + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/network1/nm" + notifications "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.notifications" + . "github.com/linuxdeepin/go-lib/gettext" +) + +const ( + notifyIconNetworkOffline = "notification-network-offline" + notifyIconWiredConnected = "notification-network-wired-connected" + notifyIconWiredDisconnected = "notification-network-wired-disconnected" + notifyIconWiredError = notifyIconWiredDisconnected + notifyIconWirelessConnected = "notification-network-wireless-full" + notifyIconWirelessDisconnected = "notification-network-wireless-disconnected" + notifyIconWirelessDisabled = "notification-network-wireless-disabled" + notifyIconWirelessError = notifyIconWirelessDisconnected + notifyIconVpnConnected = "notification-network-vpn-connected" + notifyIconVpnDisconnected = "notification-network-vpn-disconnected" + notifyIconProxyEnabled = "notification-network-proxy-enabled" + notifyIconProxyDisabled = "notification-network-proxy-disabled" + notifyIconNetworkConnected = notifyIconWiredConnected + notifyIconNetworkDisconnected = notifyIconWiredDisconnected + notifyIconMobile2gConnected = "notification-network-mobile-2g-connected" + notifyIconMobile2gDisconnected = "notification-network-mobile-2g-disconnected" + notifyIconMobile3gConnected = "notification-network-mobile-3g-connected" + notifyIconMobile3gDisconnected = "notification-network-mobile-3g-disconnected" + notifyIconMobile4gConnected = "notification-network-mobile-4g-connected" + notifyIconMobile4gDisconnected = "notification-network-mobile-4g-disconnected" + notifyIconMobileUnknownConnected = "notification-network-mobile-unknown-connected" + notifyIconMobileUnknownDisconnected = "notification-network-mobile-unknown-disconnected" +) + +var ( + notifyEnabled = true + notification notifications.Notifications + notifyId uint32 + notifyIdMu sync.Mutex + globalNotifyManager *NotifyManager +) + +func initNotifyManager() { + globalNotifyManager = newNotifyManager() + go globalNotifyManager.loop() +} + +func enableNotify() { + go func() { + time.Sleep(5 * time.Second) + notifyEnabled = true + }() +} +func disableNotify() { + notifyEnabled = false +} + +type notifyMsgQueue list.List + +func newNotifyMsgQueue() *notifyMsgQueue { + l := list.New() + return (*notifyMsgQueue)(l) +} + +func (q *notifyMsgQueue) toList() *list.List { + return (*list.List)(q) +} + +type notifyMsg struct { + icon string + summary string + body string +} + +// 入队列 +func (q *notifyMsgQueue) enqueue(val *notifyMsg) { + q.toList().PushBack(val) +} + +// 出队列 +func (q *notifyMsgQueue) dequeue() *notifyMsg { + l := q.toList() + elem := l.Front() + if elem == nil { + return nil + } + val := l.Remove(elem) + return val.(*notifyMsg) +} + +type NotifyManager struct { + queue *notifyMsgQueue + mu sync.Mutex + cond *sync.Cond +} + +func newNotifyManager() *NotifyManager { + sm := &NotifyManager{} + sm.queue = newNotifyMsgQueue() + sm.cond = sync.NewCond(&sm.mu) + return sm +} + +func (nm *NotifyManager) addMsg(msg *notifyMsg) { + nm.mu.Lock() + nm.queue.enqueue(msg) + nm.cond.Signal() + nm.mu.Unlock() +} + +func (nm *NotifyManager) loop() { + for { + nm.mu.Lock() + msg := nm.queue.dequeue() + + if msg == nil { + nm.cond.Wait() + } else { + _notify(msg.icon, msg.summary, msg.body) + } + nm.mu.Unlock() + + if msg != nil { + time.Sleep(1500 * time.Millisecond) // sleep 1.5 seconds + } + } +} + +func notify(icon, summary, body string) { + if manager != nil && manager.isSessionActive() { + globalNotifyManager.addMsg(¬ifyMsg{ + icon: icon, + summary: summary, + body: body, + }) + } +} + +func _notify(icon, summary, body string) { + logger.Debugf("notify icon: %q, summary: %q, body: %q", icon, summary, body) + if !notifyEnabled { + logger.Debug("notify disabled") + return + } + notifyIdMu.Lock() + nid := notifyId + notifyIdMu.Unlock() + + nid, err := notification.Notify(0, "dde-control-center", nid, + icon, summary, body, nil, nil, -1) + if err != nil { + logger.Warning(err) + return + } + + notifyIdMu.Lock() + notifyId = nid + notifyIdMu.Unlock() +} + +func notifyAirplanModeEnabled() { + notify(notifyIconNetworkOffline, Tr("Disconnected"), Tr("Airplane mode enabled.")) +} + +func notifyWiredCableUnplugged() { + notify(notifyIconWiredError, Tr("Disconnected"), deviceErrorTable[CUSTOM_NM_DEVICE_STATE_REASON_CABLE_UNPLUGGED]) +} + +func notifyApModeNotSupport() { + notify(notifyIconWirelessError, Tr("Disconnected"), Tr("Access Point mode is not supported by this device.")) +} + +func notifyWirelessHardSwitchOff() { + notify(notifyIconWirelessDisabled, Tr("Network"), Tr("The hardware switch of WLAN Card is off, please switch on as necessary.")) +} + +func notifyProxyEnabled() { + notify(notifyIconProxyEnabled, Tr("Network"), Tr("System proxy is set successfully.")) +} +func notifyProxyDisabled() { + notify(notifyIconProxyDisabled, Tr("Network"), Tr("System proxy has been cancelled.")) +} + +func notifyVpnConnected(id string) { + notify(notifyIconVpnConnected, Tr("Connected"), id) +} +func notifyVpnDisconnected(id string) { + notify(notifyIconVpnDisconnected, Tr("Disconnected"), id) +} +func notifyVpnFailed(id string, reason uint32) { + notify(notifyIconVpnDisconnected, Tr("Disconnected"), vpnErrorTable[reason]) +} + +func getMobileConnectedNotifyIcon(mobileNetworkType string) (icon string) { + switch mobileNetworkType { + case moblieNetworkType4G: + icon = notifyIconMobile4gConnected + case moblieNetworkType3G: + icon = notifyIconMobile3gConnected + case moblieNetworkType2G: + icon = notifyIconMobile2gConnected + case moblieNetworkTypeUnknown: + icon = notifyIconMobileUnknownConnected + default: + icon = notifyIconMobileUnknownConnected + } + return +} +func getMobileDisconnectedNotifyIcon(mobileNetworkType string) (icon string) { + switch mobileNetworkType { + case moblieNetworkType4G: + icon = notifyIconMobile4gDisconnected + case moblieNetworkType3G: + icon = notifyIconMobile3gDisconnected + case moblieNetworkType2G: + icon = notifyIconMobile2gDisconnected + case moblieNetworkTypeUnknown: + icon = notifyIconMobileUnknownDisconnected + default: + icon = notifyIconMobileUnknownDisconnected + } + return +} + +func generalGetNotifyConnectedIcon(devType uint32, devPath dbus.ObjectPath) (icon string) { + switch devType { + case nm.NM_DEVICE_TYPE_ETHERNET: + icon = notifyIconWiredConnected + case nm.NM_DEVICE_TYPE_WIFI: + icon = notifyIconWirelessConnected + case nm.NM_DEVICE_TYPE_MODEM: + var mobileNetworkType string + dev := manager.getDevice(devPath) + if dev != nil { + manager.devicesLock.Lock() + defer manager.devicesLock.Unlock() + mobileNetworkType = dev.MobileNetworkType + } + icon = getMobileConnectedNotifyIcon(mobileNetworkType) + default: + icon = notifyIconNetworkConnected + } + return +} +func generalGetNotifyDisconnectedIcon(devType uint32, devPath dbus.ObjectPath) (icon string) { + switch devType { + case nm.NM_DEVICE_TYPE_ETHERNET: + icon = notifyIconWiredDisconnected + case nm.NM_DEVICE_TYPE_WIFI: + icon = notifyIconWirelessDisconnected + case nm.NM_DEVICE_TYPE_MODEM: + var mobileNetworkType string + dev := manager.getDevice(devPath) + if dev != nil { + manager.devicesLock.Lock() + mobileNetworkType = dev.MobileNetworkType + manager.devicesLock.Unlock() + } + icon = getMobileDisconnectedNotifyIcon(mobileNetworkType) + default: + logger.Warning("lost default notify icon for device", getCustomDeviceType(devType)) + icon = notifyIconNetworkDisconnected + } + return +} + +func notifyDeviceRemoved(devPath dbus.ObjectPath) { + var devType uint32 + dev := manager.getDevice(devPath) + if dev != nil { + manager.devicesLock.Lock() + devType = dev.nmDevType + manager.devicesLock.Unlock() + } + if !isDeviceTypeValid(devType) { + return + } + icon := generalGetNotifyDisconnectedIcon(devType, devPath) + msg := deviceErrorTable[nm.NM_DEVICE_STATE_REASON_REMOVED] + notify(icon, Tr("Disconnected"), msg) +} diff --git a/network1/utils_test.go b/network1/utils_test.go new file mode 100644 index 000000000..124b8dd8e --- /dev/null +++ b/network1/utils_test.go @@ -0,0 +1,391 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package network + +import ( + "testing" + + "github.com/linuxdeepin/dde-daemon/network1/nm" + C "gopkg.in/check.v1" +) + +func Test(t *testing.T) { C.TestingT(t) } + +type testWrapper struct{} + +func init() { + C.Suite(&testWrapper{}) +} + +func (*testWrapper) TestGetSetConnectionData(c *C.C) { + testConnectionId := "idname" + testConnectionUuid := "8e2f9aa2-42b8-47d5-b040-ae82c53fa1f2" + testConnectionType := "802-3-ethernet" + + data := make(connectionData) + + addSetting(data, nm.NM_SETTING_CONNECTION_SETTING_NAME) + setSettingConnectionId(data, testConnectionId) + setSettingConnectionUuid(data, testConnectionUuid) + setSettingConnectionType(data, testConnectionType) + + c.Check(getSettingConnectionId(data), C.Equals, testConnectionId) + c.Check(getSettingConnectionUuid(data), C.Equals, testConnectionUuid) + c.Check(getSettingConnectionType(data), C.Equals, testConnectionType) +} + +func (*testWrapper) TestConvertMacAddressToString(c *C.C) { + tests := []struct { + test []byte + result string + }{ + {[]byte{0, 0, 0, 0, 0, 0}, "00:00:00:00:00:00"}, + {[]byte{0, 18, 52, 86, 120, 171}, "00:12:34:56:78:AB"}, + } + for _, t := range tests { + c.Check(t.result, C.Equals, convertMacAddressToString(t.test)) + } +} + +func (*testWrapper) TestConvertMacAddressToArrayByte(c *C.C) { + tests := []struct { + test string + result []byte + }{ + {"00:00:00:00:00:00", []byte{0, 0, 0, 0, 0, 0}}, + {"00:12:34:56:78:AB", []byte{0, 18, 52, 86, 120, 171}}, + } + for _, t := range tests { + c.Check(t.result, C.DeepEquals, convertMacAddressToArrayByte(t.test)) + } +} + +func (*testWrapper) TestConvertIpv4PrefixToNetMask(c *C.C) { + tests := []struct { + test uint32 + result string + }{ + {0, "0.0.0.0"}, + {1, "128.0.0.0"}, + {2, "192.0.0.0"}, + {3, "224.0.0.0"}, + {4, "240.0.0.0"}, + {5, "248.0.0.0"}, + {6, "252.0.0.0"}, + {7, "254.0.0.0"}, + {8, "255.0.0.0"}, + {9, "255.128.0.0"}, + {10, "255.192.0.0"}, + {11, "255.224.0.0"}, + {12, "255.240.0.0"}, + {13, "255.248.0.0"}, + {14, "255.252.0.0"}, + {15, "255.254.0.0"}, + {16, "255.255.0.0"}, + {17, "255.255.128.0"}, + {18, "255.255.192.0"}, + {19, "255.255.224.0"}, + {20, "255.255.240.0"}, + {21, "255.255.248.0"}, + {22, "255.255.252.0"}, + {23, "255.255.254.0"}, + {24, "255.255.255.0"}, + {25, "255.255.255.128"}, + {26, "255.255.255.192"}, + {27, "255.255.255.224"}, + {28, "255.255.255.240"}, + {29, "255.255.255.248"}, + {30, "255.255.255.252"}, + {31, "255.255.255.254"}, + {32, "255.255.255.255"}, + } + for _, t := range tests { + c.Check(t.result, C.Equals, convertIpv4PrefixToNetMask(t.test)) + } +} + +func (*testWrapper) TestConvertIpv4NetMaskToPrefix(c *C.C) { + tests := []struct { + test string + result uint32 + }{ + {"0.0.0.0", 0}, + {"128.0.0.0", 1}, + {"192.0.0.0", 2}, + {"224.0.0.0", 3}, + {"240.0.0.0", 4}, + {"248.0.0.0", 5}, + {"252.0.0.0", 6}, + {"254.0.0.0", 7}, + {"255.0.0.0", 8}, + {"255.128.0.0", 9}, + {"255.192.0.0", 10}, + {"255.224.0.0", 11}, + {"255.240.0.0", 12}, + {"255.248.0.0", 13}, + {"255.252.0.0", 14}, + {"255.254.0.0", 15}, + {"255.255.0.0", 16}, + {"255.255.128.0", 17}, + {"255.255.192.0", 18}, + {"255.255.224.0", 19}, + {"255.255.240.0", 20}, + {"255.255.248.0", 21}, + {"255.255.252.0", 22}, + {"255.255.254.0", 23}, + {"255.255.255.0", 24}, + {"255.255.255.128", 25}, + {"255.255.255.192", 26}, + {"255.255.255.224", 27}, + {"255.255.255.240", 28}, + {"255.255.255.248", 29}, + {"255.255.255.252", 30}, + {"255.255.255.254", 31}, + {"255.255.255.255", 32}, + } + for _, t := range tests { + c.Check(t.result, C.Equals, convertIpv4NetMaskToPrefix(t.test)) + } + + // test error mask address + _, err := convertIpv4NetMaskToPrefixCheck("255.255.255.250") + c.Check(err, C.NotNil) + _, err = convertIpv4NetMaskToPrefixCheck("255.255.100.2") + c.Check(err, C.NotNil) + _, err = convertIpv4NetMaskToPrefixCheck("255.100.0.0") + c.Check(err, C.NotNil) + _, err = convertIpv4NetMaskToPrefixCheck("191.0.0.0") + c.Check(err, C.NotNil) +} + +func (*testWrapper) TestConvertIpv6AddressToString(c *C.C) { + tests := []struct { + test []byte + result string + }{ + {[]byte{0x12, 0x34, 0x23, 0x45, 0x34, 0x56, 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0xaa, 0xaa, 0xff, 0xff}, "1234:2345:3456:4444:5555:6666:AAAA:FFFF"}, + {[]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, "0000:0000:0000:0000:0000:0000:0000:0000"}, + } + for _, t := range tests { + c.Check(t.result, C.Equals, convertIpv6AddressToString(t.test)) + } +} + +func (*testWrapper) TestConvertIpv6AddressToArrayByte(c *C.C) { + tests := []struct { + test string + result []byte + }{ + {"1234:2345:3456:4444:5555:6666:AAAA:FFFF", []byte{0x12, 0x34, 0x23, 0x45, 0x34, 0x56, 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0xaa, 0xaa, 0xff, 0xff}}, + {"0000:0000:0000:0000:0000:0000:0000:0000", []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + } + for _, t := range tests { + c.Check(t.result, C.DeepEquals, convertIpv6AddressToArrayByte(t.test)) + } + + // check error ipv6 format + _, err := convertIpv6AddressToArrayByteCheck("-1234:2345:3456:4444:5555:6666:aaAA:ffFF") + c.Check(err, C.NotNil) + _, err = convertIpv6AddressToArrayByteCheck("1234:2345:3456:4444:5555:6666:aaAA:ffFh") + c.Check(err, C.NotNil) +} + +func (*testWrapper) TestExpandIpv6Address(c *C.C) { + tests := []struct { + test string + result string + }{ + {"1234:2345:3456:4444:5555:6666:AAAA:FFFF", "1234:2345:3456:4444:5555:6666:AAAA:FFFF"}, + {"0000:0000:0000:0000:0000:0000:0000:0000", "0000:0000:0000:0000:0000:0000:0000:0000"}, + {"0::0", "0000:0000:0000:0000:0000:0000:0000:0000"}, + {"2001:DB8:2de::e13", "2001:0DB8:02de:0000:0000:0000:0000:0e13"}, + {"::ffff:874B:2B34", "0000:0000:0000:0000:0000:ffff:874B:2B34"}, + } + for _, t := range tests { + r, _ := expandIpv6Address(t.test) + c.Check(t.result, C.Equals, r) + } + + // check error ipv6 format + _, err := expandIpv6Address("2001::25de::cade") + c.Check(err, C.NotNil) +} + +func (*testWrapper) TestGetterAndSetterForVirtualKey(c *C.C) { + data := newWirelessConnectionData("", "", nil, "none", "") + + err := logicSetSettingVkWirelessSecurityKeyMgmt(data, "none") + if err != nil { + logger.Warning("failed to set VkWirelessMgmt") + return + } + c.Check("none", C.Equals, getSettingVkWirelessSecurityKeyMgmt(data)) + + err = logicSetSettingVkWirelessSecurityKeyMgmt(data, "wep") + if err != nil { + logger.Warning("failed to set VkWirelessMgmt") + return + } + c.Check("wep", C.Equals, getSettingVkWirelessSecurityKeyMgmt(data)) + + err = logicSetSettingVkWirelessSecurityKeyMgmt(data, "wpa-psk") + if err != nil { + logger.Warning("failed to set VkWirelessMgmt") + return + } + c.Check("wpa-psk", C.Equals, getSettingVkWirelessSecurityKeyMgmt(data)) + + err = logicSetSettingVkWirelessSecurityKeyMgmt(data, "wpa-eap") + if err != nil { + logger.Warning("failed to set VkWirelessMgmt") + return + } + c.Check("wpa-eap", C.Equals, getSettingVkWirelessSecurityKeyMgmt(data)) +} + +func (*testWrapper) TestToUriPathFor8021x(c *C.C) { + tests := []struct { + test string + result string + }{ + {"/the/path", "file:///the/path"}, + {"file:///the/path", "file:///the/path"}, + {"/the/path/中文", "file:///the/path/中文"}, + {"file:///the/path/中文", "file:///the/path/中文"}, + {"/the/path/%E4%B8%AD%E6%96%87", "file:///the/path/%E4%B8%AD%E6%96%87"}, + } + for _, t := range tests { + c.Check(t.result, C.Equals, toUriPathFor8021x(t.test)) + } +} +func (*testWrapper) TestToLocalPathFor8021x(c *C.C) { + tests := []struct { + test string + result string + }{ + {"/the/path", "/the/path"}, + {"file:///the/path", "/the/path"}, + {"file:///the/path/%E4%B8%AD%E6%96%87", "/the/path/%E4%B8%AD%E6%96%87"}, + {"/the/path/中文", "/the/path/中文"}, + {"file:///the/path/中文", "/the/path/中文"}, + {"/the/path/%E4%B8%AD%E6%96%87", "/the/path/%E4%B8%AD%E6%96%87"}, + } + for _, t := range tests { + c.Check(t.result, C.Equals, toLocalPathFor8021x(t.test)) + } +} + +func (*testWrapper) TestToUriPath(c *C.C) { + tests := []struct { + test string + result string + }{ + {"/the/path", "file:///the/path"}, + {"file:///the/path", "file:///the/path"}, + {"/the/path/中文", "file:///the/path/%E4%B8%AD%E6%96%87"}, + {"file:///the/path/中文", "file:///the/path/%E4%B8%AD%E6%96%87"}, + } + for _, t := range tests { + c.Check(t.result, C.Equals, toUriPath(t.test)) + } +} +func (*testWrapper) TestToLocalPath(c *C.C) { + tests := []struct { + test string + result string + }{ + {"/the/path", "/the/path"}, + {"file:///the/path", "/the/path"}, + {"file:///the/path/%E4%B8%AD%E6%96%87", "/the/path/中文"}, + {"/the/path/中文", "/the/path/中文"}, + {"file:///the/path/中文", "/the/path/中文"}, + {"/the/path/%E4%B8%AD%E6%96%87", "/the/path/%E4%B8%AD%E6%96%87"}, + } + for _, t := range tests { + c.Check(t.result, C.Equals, toLocalPath(t.test)) + } +} + +func (*testWrapper) TestStrToByteArrayPath(c *C.C) { + tests := []struct { + test string + result []byte + }{ + {"/the/path", []byte{0x2f, 0x74, 0x68, 0x65, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x0}}, + {"/the/path/中文", []byte{0x2f, 0x74, 0x68, 0x65, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x2f, 0xe4, 0xb8, 0xad, 0xe6, 0x96, 0x87, 0x0}}, + } + for _, t := range tests { + c.Check(t.result, C.DeepEquals, strToByteArrayPath(t.test)) + } +} +func (*testWrapper) TestByteArrayToStrPath(c *C.C) { + tests := []struct { + test []byte + result string + }{ + {[]byte{}, ""}, + {[]byte{0x0}, ""}, + {[]byte{0x2f, 0x74, 0x68, 0x65, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x0}, "/the/path"}, + {[]byte{0x2f, 0x74, 0x68, 0x65, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x2f, 0xe4, 0xb8, 0xad, 0xe6, 0x96, 0x87, 0x0}, "/the/path/中文"}, + } + for _, t := range tests { + c.Check(t.result, C.Equals, byteArrayToStrPath(t.test)) + } +} + +func (*testWrapper) TestStrToUuid(c *C.C) { + data := []struct { + addr, uuid string + }{ + {"", "d41d8cd9-8f00-b204-e980-0998ecf8427e"}, + {"你好", "7eca689f-0d33-89d9-dea6-6ae112e5cfd7"}, + {"12:34:56:ab:cd:ef", "fdeaa9e5-b0a9-d05a-4c5a-624d6375bc0b"}, + {"fe:dc:ba:65:43:21", "9d9bc082-cc1b-ddbb-c502-46d7499954d8"}, + {"12:34:56:AB:CD:EF", "e2667717-e697-702d-7167-4bb2c5b9f58a"}, + {"123456abcdef", "6f3b8ded-65bd-7a4d-b116-25ac84e579bb"}, + {"12:34:56:ab:cd:xy", "c3701a18-6af4-aa02-7c54-53c09ea75e62"}, + {":34:56:ab:cd:ef", "2f2aab1d-d983-2df8-fe91-8598e79fc009"}, + {"123456abcdef1234abcd123456abcdef", "2fc8f109-cc40-de78-b0c4-1744b9ea62f0"}, + {"123456abcdef1234abcd123456abcdef1234", "18a1eaac-9a1e-3828-8191-511317dc2921"}, + } + for _, d := range data { + c.Check(d.uuid, C.Equals, strToUuid(d.addr)) + } +} + +func (*testWrapper) TestDoStrToUuid(c *C.C) { + data := []struct { + addr, uuid string + }{ + {"", "00000000-0000-0000-0000-000000000000"}, + {"你好", "00000000-0000-0000-0000-000000000000"}, + {"12:34:56:ab:cd:ef", "00000000-0000-0000-0000-123456abcdef"}, + {"fe:dc:ba:65:43:21", "00000000-0000-0000-0000-fedcba654321"}, + {"12:34:56:AB:CD:EF", "00000000-0000-0000-0000-123456abcdef"}, + {"123456abcdef", "00000000-0000-0000-0000-123456abcdef"}, + {"12:34:56:ab:cd:xy", "00000000-0000-0000-0000-00123456abcd"}, + {":34:56:ab:cd:ef", "00000000-0000-0000-0000-003456abcdef"}, + {"123456abcdef1234abcd123456abcdef", "123456ab-cdef-1234-abcd-123456abcdef"}, + {"123456abcdef1234abcd123456abcdef1234", "123456ab-cdef-1234-abcd-123456abcdef"}, + } + for _, d := range data { + c.Check(d.uuid, C.Equals, doStrToUuid(d.addr)) + } +} + +func (*testWrapper) TestFixupDeviceDesc(c *C.C) { + data := []struct { + desc, fixedDesc string + }{ + {"Intel Corporation 82567LM Gigabit Network Connection", "Intel 82567LM Gigabit"}, + {"Intel Corporation PRO/Wireless 5100 AGN [Shiloh] Network Connection", "Intel PRO/Wireless 5100 AGN [Shiloh]"}, + {"Ralink Technology, Corp. RT5370 Wireless Adapter", "Ralink RT5370"}, + {"Realtek RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (Motherboard)", "Realtek RTL8111/8168/8411 Gigabit"}, + {"Kontron (Industrial Computer Source / ICS Advent) DM9601 Fast Ethernet Adapter", "Kontron DM9601"}, + } + for _, d := range data { + c.Check(fixupDeviceDesc(d.desc), C.Equals, d.fixedDesc) + } +} diff --git a/network/utils_udev.c b/network1/utils_udev.c similarity index 100% rename from network/utils_udev.c rename to network1/utils_udev.c diff --git a/network/utils_udev.go b/network1/utils_udev.go similarity index 100% rename from network/utils_udev.go rename to network1/utils_udev.go diff --git a/network/utils_udev.h b/network1/utils_udev.h similarity index 100% rename from network/utils_udev.h rename to network1/utils_udev.h diff --git a/rpm/dde-daemon.spec b/rpm/dde-daemon.spec index fb6a80ada..de4d6653d 100644 --- a/rpm/dde-daemon.spec +++ b/rpm/dde-daemon.spec @@ -95,13 +95,13 @@ sed -i 's|boot/grub|boot/grub2|' grub2/{grub2,grub_params,theme}.go # Fix activate services failed (Permission denied) # dbus service pushd misc/system-services/ -sed -i '$aSystemdService=deepin-accounts-daemon.service' com.deepin.system.Power.service \ - com.deepin.daemon.{Accounts,Apps,Daemon}.service \ - com.deepin.daemon.{Gesture,SwapSchedHelper,Timedated}.service -sed -i '$aSystemdService=dbus-com.deepin.dde.lockservice.service' com.deepin.dde.LockService.service +sed -i '$aSystemdService=deepin-accounts-daemon.service' org.deepin.dde.Power1.service \ + org.deepin.dde.{Accounts,Apps,Daemon}1.service \ + org.deepin.dde.{Gesture,SwapSchedHelper,Timedated}1.service +sed -i '$aSystemdService=dbus-org.deepin.dde.Lockservice1.service' org.deepin.dde.LockService1.service popd # systemd service -cat > misc/systemd/services/dbus-com.deepin.dde.lockservice.service < misc/systemd/services/dbus-org.deepin.dde.Lockservice1.service <= suspendStatePrepare { - m.prepareSuspendLocker.Unlock() - continue - } - m.prepareSuspendLocker.Unlock() - - logger.Info("kwin handle idle off") - - if v := m.submodules[submodulePSP]; v != nil { - if psp := v.(*powerSavePlan); psp != nil { - psp.HandleIdleOff() - } - } - } - } - }() - } -} - -func (m *Manager) destroy() { - m.destroySubmodules() - m.releaseAmbientLight() - m.permitLogind() - - if m.helper != nil { - m.helper.Destroy() - m.helper = nil - } - - if m.inhibitor != nil { - err := m.inhibitor.unblock() - if err != nil { - logger.Warning(err) - } - m.inhibitor = nil - } - - m.systemSigLoop.Stop() - m.sessionSigLoop.Stop() - m.syncConfig.Destroy() -} - -func (*Manager) GetInterfaceName() string { - return dbusInterface -} - -func (m *Manager) Reset() *dbus.Error { - logger.Debug("Reset settings") - - var settingKeys = []string{ - settingKeyLinePowerScreenBlackDelay, - settingKeyLinePowerSleepDelay, - settingKeyLinePowerLockDelay, - settingKeyLinePowerLidClosedAction, - settingKeyLinePowerPressPowerBtnAction, - - settingKeyBatteryScreenBlackDelay, - settingKeyBatterySleepDelay, - settingKeyBatteryLockDelay, - settingKeyBatteryLidClosedAction, - settingKeyBatteryPressPowerBtnAction, - - settingKeyScreenBlackLock, - settingKeySleepLock, - settingKeyPowerButtonPressedExec, - - settingKeyLowPowerNotifyEnable, - settingKeyLowPowerNotifyThreshold, - settingKeyLowPowerAutoSleepThreshold, - settingKeyBrightnessDropPercent, - } - for _, key := range settingKeys { - logger.Debug("reset setting", key) - m.settings.Reset(key) - } - return nil -} - -func (m *Manager) initDsg() { - systemBus, err := dbus.SystemBus() - if err != nil { - return - } - - if !dutils.IsFileExist("/usr/share/dsg/configs/org.deepin.startdde/org.deepin.Display.json") { - logger.Warning(" [initDsg] dconfig file not exist : /usr/share/dsg/configs/org.deepin.startdde/org.deepin.Display.json.") - return - } - dsg := configManager.NewConfigManager(systemBus) - - // display - displayConfigManagerPath, err := dsg.AcquireManager(0, DSettingsAppID, DSettingsDisplayName, "") - if err != nil { - logger.Warning(err) - return - } - - m.dsDisplayConfigManager, err = configManager.NewManager(systemBus, displayConfigManagerPath) - if err != nil || displayConfigManagerPath == "" { - logger.Warning(err) - } - - // power - powerConfigManagerPath, err := dsg.AcquireManager(0, dsettingsAppID, dsettingsPowerName, "") - if err != nil { - logger.Warning(err) - return - } - m.dsPowerConfigManager, err = configManager.NewManager(systemBus, powerConfigManagerPath) - if err != nil { - logger.Warning(err) - return - } - getDsPowerConfig := func(key string, init bool) { - data, err := m.dsPowerConfigManager.Value(0, key) - if err != nil { - logger.Warning(err) - return - } - switch key { - case dsettingCustomShutdownWeekDays: - res := []byte{} - for _, v := range data.Value().([]dbus.Variant) { - res = append(res, byte(v.Value().(float64))) - } - if init { - m.CustomShutdownWeekDays = res - return - } - if m.setPropCustomShutdownWeekDays(res) { - logger.Info("Set CustomShutdownWeekDays property", m.CustomShutdownWeekDays) - } - case dsettingShutdownCountdown: - m.shutdownCountdown = int(data.Value().(float64)) - case dsettingNextShutdownTime: - m.nextShutdownTime = int64(data.Value().(float64)) - case dsettingShutdownRepetition: - if init { - m.ShutdownRepetition = int(data.Value().(float64)) - return - } - if m.setPropShutdownRepetition(int(data.Value().(float64))) { - logger.Info("Set ShutdownRepetition property", m.ShutdownRepetition) - } - case dsettingShutdownTime: - if init { - m.ShutdownTime = data.Value().(string) - return - } - if m.setPropShutdownTime(data.Value().(string)) { - logger.Info("Set ShutdownTime property", m.ShutdownTime) - } - case dsettingScheduledShutdownState: - if init { - m.ScheduledShutdownState = data.Value().(bool) - } else { - if m.setPropScheduledShutdownState(data.Value().(bool)) { - logger.Info("Set ScheduledShutdownState property", m.ScheduledShutdownState) - } - } - } - // m.scheduledShutdownSwitch(false, false) - // m.scheduledShutdownSwitch(m.ScheduledShutdownState, false) - - } - - getDsPowerConfig(dsettingCustomShutdownWeekDays, true) - getDsPowerConfig(dsettingShutdownCountdown, true) - getDsPowerConfig(dsettingShutdownRepetition, true) - getDsPowerConfig(dsettingShutdownTime, true) - getDsPowerConfig(dsettingScheduledShutdownState, true) - getDsPowerConfig(dsettingNextShutdownTime, true) - m.dsPowerConfigManager.InitSignalExt(m.systemSigLoop, true) - m.dsPowerConfigManager.ConnectValueChanged(func(key string) { - if key == dsettingNextShutdownTime { - return - } - logger.Info("DSG org.deepin.dde.daemon.power valueChanged, key : ", key) - getDsPowerConfig(key, false) - // 如果重复一次,重置nextShutdownTime - if m.ScheduledShutdownState { - m.setNextShutdownTime(0) - } - m.scheduledShutdown(Init) - }) - - if m.nextShutdownTime == 0 { - m.setNextShutdownTime(0) - } - m.scheduledShutdown(Init) -} - -func (m *Manager) setNextShutdownTime(bt int64) { - m.nextShutdownTime = m.getNextShutdownTime(bt) - m.savePowerDsgConfig(dsettingNextShutdownTime) -} - -func (m *Manager) savePowerDsgConfig(key string) (err error) { - var value interface{} - switch key { - case dsettingCustomShutdownWeekDays: - var tmp []dbus.Variant - for _, v := range m.CustomShutdownWeekDays { - tmp = append(tmp, dbus.MakeVariant(float64(v))) - } - value = tmp - case dsettingShutdownCountdown: - value = m.shutdownCountdown - case dsettingNextShutdownTime: - value = m.nextShutdownTime - case dsettingShutdownRepetition: - value = m.ShutdownRepetition - case dsettingShutdownTime: - value = m.ShutdownTime - case dsettingScheduledShutdownState: - value = m.ScheduledShutdownState - } - err = m.setDsgData(key, value, m.dsPowerConfigManager) - if err != nil { - logger.Warning(err) - return err - } - return nil -} - -func (m *Manager) setDsgData(key string, value interface{}, dsg configManager.Manager) error { - if dsg == nil { - return errors.New("setDsgData dsg is nil") - } - err := dsg.SetValue(0, key, dbus.MakeVariant(value)) - if err != nil { - logger.Warningf("setDsgData key : %s. err : %v", key, err) - return err - } - logger.Infof("setDsgData key : %s , value : %v", key, value) - return nil -} - -const ( - Init = iota // 初始阶段 - WaitingToNotify // 等待发送通知 - Countdowning // 倒计时中 - // 下面是执行结果 - Shutdown // 倒计时结束,准备关机 - Cancle // 执行关机取消,可能需要重置定时器 - TimeOut // 检测到超时,可能需要重置定时器 -) - -func (m *Manager) scheduledShutdown(state int) { - logger.Debugf("scheduledShutdown,pre-stat:%v next-stat:%v nextShutDownTime:%v", m.shutdownStatus, state, time.Unix(m.nextShutdownTime, 0).Format("2006-01-02 15:04:05")) - if m.shutdownTimer != nil { - m.shutdownTimer.Stop() - m.shutdownTimer = nil - } - - // 用户非活跃状态或者低电量屏保状态,停止定时关机流程 - isSessionActive, _ := m.helper.SessionWatcher.IsActive().Get(0) - if !isSessionActive || m.WarnLevel == WarnLevelAction { - m.notify.CloseNotification(0, m.notifyId) - logger.Warning("Stop scheduledShutdown") - return - } - - if state != Init && state == m.shutdownStatus { - return - } - - // 下次关机时间为0,则退出调度 - if m.nextShutdownTime == 0 { - logger.Warning("next shutdown time is illegal, please check the config") - return - } - - next := time.Unix(m.nextShutdownTime, 0) - currentTime := time.Now() - switch state { - case Init: - // 定时关闭的情况下,关闭定时器 - if m.shutdownStatus >= Countdowning { - m.notify.CloseNotification(0, m.notifyId) - } - if !m.ScheduledShutdownState { - return - } - m.shutdownStatus = Init - var nextStatus int - logger.Debugf("shutdown sub:%v s, %v min, countDown:%v", int(next.Sub(currentTime).Seconds()), int(next.Sub(currentTime).Minutes()), m.shutdownCountdown) - if int(next.Sub(currentTime).Minutes()) < 0 { - // 超时太久,则进行超时处理 - nextStatus = TimeOut - } else if int(next.Sub(currentTime).Minutes()) == 0 { - // 超时太久,则进行超时处理 - nextStatus = Countdowning - } else if int(next.Sub(currentTime).Seconds()) <= m.shutdownCountdown { - // 如果在倒计时的时区内 - nextStatus = Countdowning - } else { - // 时间远远未到,等待发送通知 - nextStatus = WaitingToNotify - } - m.scheduledShutdown(nextStatus) - case WaitingToNotify: - m.shutdownStatus = WaitingToNotify - // 提前通知,设置通知的定时器 - t := time.Duration(m.shutdownCountdown) * time.Second * -1 - next = next.Add(t) - m.shutdownTimer = time.AfterFunc(time.Until(next), func() { - m.scheduledShutdown(Countdowning) - }) - case Countdowning: - m.shutdownStatus = Countdowning - // 已经发送通知,正在进行关机倒计时 - counter := func() func() int { - count := m.shutdownCountdown + 1 - return func() int { - count-- - return count - } - }() - go func() { - count := counter() - m.shutdownCountdownNotify(count, true) - m.shutdownTimer = time.NewTimer(time.Second) - for range m.shutdownTimer.C { - count := counter() - if count == 0 { - m.scheduledShutdown(Shutdown) - } else { - // TODO: 每秒通知一次?有没有更好的办法? - m.shutdownCountdownNotify(count, false) - m.shutdownTimer.Reset(time.Second) - } - } - }() - case Shutdown, Cancle, TimeOut: - // 如果是超时,则关闭通知 - if state == TimeOut { - m.notify.CloseNotification(0, m.notifyId) - } - m.shutdownStatus = state - if m.ShutdownRepetition == Once { - // 如果是重复一次,则停止定时器 - m.setPropScheduledShutdownState(false) - m.nextShutdownTime = 0 - m.savePowerDsgConfig(dsettingNextShutdownTime) - m.savePowerDsgConfig(dsettingScheduledShutdownState) - } else { - // 重新生成下一次定时关机时间,并保存 - m.setNextShutdownTime(m.nextShutdownTime) - // 当前与设定的时间超过1分钟 - t := time.Until(next).Minutes() - if t > 0 { - // 超时,重新开始调度 - m.shutdownTimer = time.AfterFunc(10*time.Second, func() { - m.scheduledShutdown(Init) - }) - } else { - // 提前取消,则等待count时间后在重新调度 - m.shutdownTimer = time.AfterFunc(time.Duration(m.shutdownCountdown)*time.Second, func() { - m.scheduledShutdown(Init) - }) - } - } - if state == Shutdown { - // 执行关机,整个状态机应该结束了 - m.notify.CloseNotification(0, m.notifyId) - m.doAutoShutdown() - } - } -} - -func (m *Manager) shutdownCountdownNotify(count int, playSound bool) { - body := fmt.Sprintf(gettext.Tr("The system will shut down automatically after %d s"), count) - title := gettext.Tr("Scheduled Shutdown") - actions := []string{"Cancle", gettext.Tr("Cancle"), "Shutdown", gettext.Tr("Shut down")} - hints := map[string]dbus.Variant{"x-deepin-PlaySound": dbus.MakeVariant(playSound), - "x-deepin-ShowInNotifyCenter": dbus.MakeVariant(false), - "x-deepin-ClickToDisappear": dbus.MakeVariant(false), - "x-deepin-DisappearAfterLock": dbus.MakeVariant(false)} - m.notifyIdMu.Lock() - nid := m.notifyId - m.notifyIdMu.Unlock() - nid, err := m.notify.Notify(0, "dde-control-center", nid, "preferences-system", title, body, actions, hints, -1) - if err != nil { - logger.Warningf("failed to send notify: %s", err) - } - m.notifyIdMu.Lock() - m.notifyId = nid - m.notifyIdMu.Unlock() - m.notify.ConnectActionInvoked(func(id uint32, actionKey string) { - - var nextStatus int - if actionKey == "Cancle" { - // m.actionShutdown(true) - nextStatus = Cancle - } else if actionKey == "Shutdown" { - // m.actionShutdown(false) - // 执行关机 - nextStatus = Shutdown - } else { - logger.Warningf("unknown actionKey %v", actionKey) - nextStatus = Cancle - } - logger.Warning("notify Invoked:", actionKey) - m.scheduledShutdown(nextStatus) - }) -} - -func (m *Manager) isWorkday(date time.Time) (res bool) { - year, month, _ := date.Date() - val, err := m.calendar.GetFestivalMonth(0, uint32(year), uint32(month)) - if err == nil { - var rootCfg []FestivalRootConfig - err = json.Unmarshal([]byte(val), &rootCfg) - if err != nil { - logger.Warning(err) - return false - } - // 如果list不包含,则按正常周末处理,如果包含,则判断status状态 - if len(rootCfg) <= 0 { - return date.Weekday() != time.Sunday && date.Weekday() != time.Saturday - } - for _, holidayInfo := range rootCfg[0].List { - if holidayInfo.Date == date.Format("2006-1-2") { - return holidayInfo.Status == 2 - } - } - return date.Weekday() != time.Sunday && date.Weekday() != time.Saturday - } else { - logger.Warning(err) - } - return -} - -func (m *Manager) isCustomday(date time.Time) (res bool) { - for _, v := range m.CustomShutdownWeekDays { - if byte(date.Weekday()) == v { - logger.Debug("Today is included in custom shutdown weekdays") - return true - } - } - return false -} - -const ( - daysOfWeek = 7 //一周天数 - daysOfYear = 366 // 一年天数 -) - -func (m *Manager) getNextShutdownTime(bt int64) int64 { - getNextTime := func() time.Time { - bastTime := time.Unix(bt, 0) - currentTime := time.Now() - // 构建目标时间 - targetTimeLayout := "15:04" - targetTime, _ := time.Parse(targetTimeLayout, m.ShutdownTime) - targetTime = time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), targetTime.Hour(), targetTime.Minute(), 0, 0, currentTime.Location()) - // 如果比当前时间小,则跳过今天 - if int(targetTime.Sub(currentTime).Minutes()) < 0 { - // 如果在同一分鐘內,應該立发送通知 - t, _ := time.ParseDuration("24h") - targetTime = targetTime.Add(t) - } - // 如果比base时间小,则target时间加1天 - if int(targetTime.Sub(bastTime).Minutes()) <= 0 { - // 如果在同一分鐘內,應該立发送通知 - t, _ := time.ParseDuration("24h") - targetTime = targetTime.Add(t) - } - return targetTime - } - - var targetTime time.Time - switch m.ShutdownRepetition { - case Once, Everyday: - targetTime = getNextTime() - case Workdays: - targetTime = getNextTime() - // 获取下一个工作日,也可能是今天 - // isWorkday依赖第三方接口,防止调用一直报错导致死循环 - for i := 0; i <= daysOfYear; i++ { - if i == daysOfYear { - return 0 - } - if m.isWorkday(targetTime) { - break - } else { - t, _ := time.ParseDuration("24h") - targetTime = targetTime.Add(t) - } - } - case Custom: - targetTime = getNextTime() - // 一周7天,获取下一个自定义工作日,也可能是今天 - for i := 0; i <= daysOfWeek; i++ { - // 循环一周都获取不到工作日,则返回无效日期 - if i == daysOfWeek { - return 0 - } - if m.isCustomday(targetTime) { - break - } else { - t, _ := time.ParseDuration("24h") - targetTime = targetTime.Add(t) - } - } - } - logger.Debug("gen next shutdown time:", targetTime.Format("2006-01-02 15:04:05")) - return targetTime.Unix() -} - -func (m *Manager) getAutoChangeDeepinWm() bool { - if m.dsDisplayConfigManager == nil { - logger.Warning("getAutoChangeDeepinWm, dsgConfig org.deepin.startdde auto-change-deepin-wm not exist") - return false - } - v, err := m.dsDisplayConfigManager.Value(0, DSettingsAutoChangeWm) - if err != nil { - logger.Warning(err) - return false - } - dsAutoChangeDeepinWm := v.Value().(bool) - logger.Info("Auto Change Deepin Wm:", dsAutoChangeDeepinWm) - - return dsAutoChangeDeepinWm -} - -func (m *Manager) setAutoChangeDeepinWm(value bool) error { - if m.dsDisplayConfigManager == nil { - return errors.New("setAutoChangeDeepinWm, dsgConfig org.deepin.startdde auto-change-deepin-wm not exist") - } - err := m.dsDisplayConfigManager.SetValue(0, DSettingsAutoChangeWm, dbus.MakeVariant(value)) - if err != nil { - return err - } - return nil -} - -func (m *Manager) inhibitLogind() { - inhibit := func() { - fd, err := m.helper.LoginManager.Inhibit(0, - "handle-power-key:handle-lid-switch:handle-suspend-key", dbusServiceName, - "handling key press and lid switch close", "block") - logger.Debug("inhibitLogind fd:", fd) - if err != nil { - logger.Warning(err) - return - } - m.inhibitFd = fd - } - inhibit() - // handle login1 restart - dbusObj := ofdbus.NewDBus(m.systemSigLoop.Conn()) - sysLoop := dbusutil.NewSignalLoop(m.systemSigLoop.Conn(), 10) - sysLoop.Start() - dbusObj.InitSignalExt(sysLoop, true) - _, _ = dbusObj.ConnectNameOwnerChanged(func(name string, oldOwner string, newOwner string) { - if name == "org.freedesktop.login1" && newOwner != "" && oldOwner == "" { - if m.inhibitFd != -1 { // 如果之前存在inhibit时,login1重启需要重新inhibit - err := syscall.Close(int(m.inhibitFd)) - m.inhibitFd = -1 - if err != nil { - logger.Warning("failed to close fd:", err) - return - } - inhibit() - } - } - }) - // end handle login1 restart -} - -func (m *Manager) permitLogind() { - if m.inhibitFd != -1 { - err := syscall.Close(int(m.inhibitFd)) - if err != nil { - logger.Warning("failed to close inhibitFd:", err) - } - m.inhibitFd = -1 - } -} - -func (m *Manager) SetPrepareSuspend(suspendState int) *dbus.Error { - m.setPrepareSuspend(suspendState) - return nil -} - -func (m *Manager) isSessionActive() bool { - active, err := m.currentSession.Active().Get(dbus.FlagNoAutoStart) - if err != nil { - logger.Error("failed to get session active status:", err) - return false - } - return active -} - -// wayland下在收到键盘或者鼠标事件后,需要进行系统空闲处理(主要是唤醒屏幕) -func (m *Manager) listenEventToHandleIdleOff() error { - // + 监控按键事件 - err := m.systemSigLoop.Conn().Object("com.deepin.daemon.Gesture", - "/com/deepin/daemon/Gesture").AddMatchSignal("com.deepin.daemon.Gesture", "KeyboardEvent").Err - if err != nil { - logger.Warning(err) - return err - } - - m.systemSigLoop.AddHandler(&dbusutil.SignalRule{ - Name: "com.deepin.daemon.Gesture.KeyboardEvent", - }, func(sig *dbus.Signal) { - if len(sig.Body) > 1 { - value := sig.Body[1].(uint32) - if m.getDPMSMode() != dpmsStateOn && value == 1 { - logger.Debug("receive keyboard event to handle idle off") - m.kwinHanleIdleOffCh <- true - } - } - }) - - // + 监控鼠标移动事件 - err = m.sessionSigLoop.Conn().Object("com.deepin.daemon.KWayland", - "/com/deepin/daemon/KWayland/Output").AddMatchSignal("com.deepin.daemon.KWayland.Output", "CursorMove").Err - if err != nil { - logger.Warning(err) - return err - } - m.sessionSigLoop.AddHandler(&dbusutil.SignalRule{ - Name: "com.deepin.daemon.KWayland.Output.CursorMove", - }, func(sig *dbus.Signal) { - if len(sig.Body) > 1 { - if m.getDPMSMode() != dpmsStateOn { - logger.Debug("receive cursor move event to handle idle off") - m.kwinHanleIdleOffCh <- true - } - } - }) - - // + 监控鼠标按下事件 - err = m.sessionSigLoop.Conn().Object("com.deepin.daemon.KWayland", - "/com/deepin/daemon/KWayland/Output").AddMatchSignal("com.deepin.daemon.KWayland.Output", "ButtonPress").Err - if err != nil { - logger.Warning(err) - return err - } - m.sessionSigLoop.AddHandler(&dbusutil.SignalRule{ - Name: "com.deepin.daemon.KWayland.Output.ButtonPress", - }, func(sig *dbus.Signal) { - if len(sig.Body) > 1 { - if m.getDPMSMode() != dpmsStateOn { - logger.Debug("acquire button press to handle idle off") - m.kwinHanleIdleOffCh <- true - } - } - }) - - return nil -} diff --git a/session/power/manager_stub.go b/session/power/manager_stub.go deleted file mode 100644 index a3b94da36..000000000 --- a/session/power/manager_stub.go +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package power - -import ( - "github.com/linuxdeepin/dde-api/powersupply/battery" -) - -const ( - dbusServiceName = "com.deepin.daemon.Power" - dbusPath = "/com/deepin/daemon/Power" - dbusInterface = dbusServiceName -) - -func (m *Manager) setPropBatteryIsPresent(val bool) { - old, exist := m.BatteryIsPresent[batteryDisplay] - if old != val || !exist { - m.BatteryIsPresent[batteryDisplay] = val - m.emitPropChangedBatteryIsPresent() - } -} - -func (m *Manager) emitPropChangedBatteryIsPresent() { - err := m.service.EmitPropertyChanged(m, "BatteryIsPresent", m.BatteryIsPresent) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) setPropBatteryPercentage(val float64) { - logger.Debugf("set batteryDisplay percentage %.1f%%", val) - old, exist := m.BatteryPercentage[batteryDisplay] - if old != val || !exist { - m.BatteryPercentage[batteryDisplay] = val - m.emitPropChangedBatteryPercentage() - } -} - -func (m *Manager) emitPropChangedBatteryPercentage() { - err := m.service.EmitPropertyChanged(m, "BatteryPercentage", m.BatteryPercentage) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) setPropBatteryState(val uint32) { - logger.Debug("set BatteryDisplay status", battery.Status(val), val) - old, exist := m.BatteryState[batteryDisplay] - if old != val || !exist { - m.BatteryState[batteryDisplay] = val - m.emitPropChangedBatteryState() - } -} - -func (m *Manager) emitPropChangedBatteryState() { - err := m.service.EmitPropertyChanged(m, "BatteryState", m.BatteryState) - if err != nil { - logger.Warning(err) - } -} diff --git a/session/power/utils.go b/session/power/utils.go deleted file mode 100644 index bc2cbe5dc..000000000 --- a/session/power/utils.go +++ /dev/null @@ -1,711 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package power - -import ( - "io/ioutil" - "math" - "os/exec" - "strings" - "time" - - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-api/soundutils" - . "github.com/linuxdeepin/go-lib/gettext" - "github.com/linuxdeepin/go-lib/gsettings" - "github.com/linuxdeepin/go-lib/pulse" - "github.com/linuxdeepin/go-x11-client/ext/dpms" -) - -const ( - dpmsStateOn int32 = iota - dpmsStateStandBy - dpmsStateSuspend - dpmsStateOff -) - -func (m *Manager) waitLockShowing(timeout time.Duration) { - ticker := time.NewTicker(time.Millisecond * 300) - timer := time.NewTimer(timeout) - for { - select { - case _, ok := <-ticker.C: - if !ok { - logger.Error("Invalid ticker event") - return - } - - logger.Debug("waitLockShowing tick") - locked, err := m.helper.SessionManager.Locked().Get(0) - if err != nil { - logger.Warning(err) - continue - } - if locked { - logger.Debug("waitLockShowing found") - ticker.Stop() - return - } - - case <-timer.C: - logger.Debug("waitLockShowing failed timeout!") - ticker.Stop() - return - } - } -} - -func (m *Manager) lockWaitShow(timeout time.Duration, autoStartAuth bool) { - m.doLock(autoStartAuth) - if m.UseWayland { - logger.Debug("In wayland environment, unsupported check lock whether showin") - return - } - m.waitLockShowing(timeout) -} - -func (m *Manager) isWmBlackScreenActive() bool { - bus, err := dbus.SessionBus() - if err == nil { - kwinInter := bus.Object("org.kde.KWin", "/BlackScreen") - var active bool - err = kwinInter.Call("org.kde.kwin.BlackScreen.getActive", - dbus.FlagNoAutoStart).Store(&active) - if err != nil { - logger.Warning("failed to get kwin blackscreen effect active:", err) - return false - } - return active - } else { - return false - } -} - -func (m *Manager) setWmBlackScreenActive(active bool) { - if m.delayInActive { - return - } - - logger.Info("set blackScreen effect active: ", active) - bus, err := dbus.SessionBus() - if err == nil { - kwinInter := bus.Object("org.kde.KWin", "/BlackScreen") - err = kwinInter.Call("org.kde.kwin.BlackScreen.setActive", 0, active).Err - if err != nil { - logger.Warning("set blackScreen active failed:", err) - } - } -} - -func (m *Manager) setDDEBlackScreenActive(active bool) { - if m.delayInActive { - return - } - - if !m.SleepLock.Get() { - logger.Info("setDDEBlackScreenActive GSettings of sleep-lock is false, Not use dde black widget") - return - } - - logger.Info("set blackScreen effect active: ", active) - bus, err := dbus.SessionBus() - if err == nil { - dbusObject := bus.Object("com.deepin.dde.BlackScreen", "/com/deepin/dde/BlackScreen") - err = dbusObject.Call("com.deepin.dde.BlackScreen.setActive", 0, active).Err - if err != nil { - logger.Warning("set blackScreen active failed:", err) - } - } - - blackscreenCmd := "dbus-send --print-reply --dest=org.kde.KWin /BlackScreen org.kde.kwin.BlackScreen.setActive boolean:" - if active { - blackscreenCmd = blackscreenCmd + "true" - } else { - blackscreenCmd = blackscreenCmd + "false" - } - cmd := exec.Command("/bin/bash", "-c", blackscreenCmd) - err = cmd.Run() - if err != nil { - logger.Warning("Set wm blackscreen failed", err) - } -} - -func (m *Manager) getDPMSMode() int32 { - logger.Debug("get DPMS Mode") - - var err error - var mode int32 - - if m.UseWayland { - mode, err = m.getDpmsModeByKwin() - } else { - var dpmsInfo *dpms.InfoReply - c := m.helper.xConn - dpmsInfo, err = dpms.Info(c).Reply(c) - if err != nil { - mode = int32(dpmsInfo.PowerLevel) - } - } - - if err != nil { - logger.Warning("get DPMS mode error:", err) - } - - return mode -} - -var prevTimestamp int64 - -func (m *Manager) setDPMSModeOn() { - if m.delayHandleIdleOffIntervalWhenScreenBlack == 0 { - timestamp := time.Now().UnixNano() - tmp := timestamp - prevTimestamp - logger.Debug("[setDPMSModeOn] timestamp:", prevTimestamp, timestamp, tmp) - prevTimestamp = timestamp - if tmp < 300000000 { - logger.Debug("[setDPMSModeOn] div < 300ms ignored.") - return - } - } - - logger.Info("DPMS On") - - autoWm := m.getAutoChangeDeepinWm() - if autoWm { - m.tryChangeDeepinWM() - } - - var err error - if m.UseWayland { - err = m.setDpmsModeByKwin(dpmsStateOn) - } else { - c := m.helper.xConn - err = dpms.ForceLevelChecked(c, dpms.DPMSModeOn).Check(c) - } - - if err != nil { - logger.Warning("set DPMS on error:", err) - } - - if autoWm { - m.setAutoChangeDeepinWm(false) - } -} - -func (m *Manager) setDPMSModeOff() { - logger.Info("DPMS Off") - - var err error - if m.UseWayland { - err = m.setDpmsModeByKwin(dpmsStateOff) - } else { - c := m.helper.xConn - err = dpms.ForceLevelChecked(c, dpms.DPMSModeOff).Check(c) - } - if err != nil { - logger.Warning("set DPMS off error:", err) - } - ioutil.WriteFile("/tmp/dpms-state", []byte("1"), 0644) -} - -const ( - lockFrontServiceName = "com.deepin.dde.lockFront" - lockFrontIfc = lockFrontServiceName - lockFrontObjPath = "/com/deepin/dde/lockFront" -) - -func (m *Manager) tryChangeDeepinWM() bool { - ret := false - count := 0 - for { - if count > 2 { - break - } - count++ - - enabled, err := m.wmDBus.CompositingEnabled().Get(0) - if err != nil { - logger.Warning("tryChangeDeepinWM get CompositingEnabled err : ", err) - continue - } - if !enabled { - err := m.wmDBus.CompositingEnabled().Set(0, true) - if err != nil { - logger.Warning("tryChangeDeepinWM set CompositingEnabled true, err :", err) - continue - } - - // dde-osd需要使用该dconfig值,true不弹该特效osd - ret = true - break - } - } - - logger.Info(" tryChangeDeepinWM ret : ", ret) - return ret -} - -func (m *Manager) doLock(autoStartAuth bool) { - locked, err := m.sessionManager.Locked().Get(0) - if err != nil { - logger.Warning(err) - } - if locked { - logger.Info("Current is locked. ignore this doLock.") - return - } - - logger.Info("Lock Screen") - bus, err := dbus.SessionBus() - if err != nil { - logger.Warning(err) - return - } - lockFrontObj := bus.Object(lockFrontServiceName, lockFrontObjPath) - err = lockFrontObj.Call(lockFrontIfc+".ShowAuth", 0, autoStartAuth).Err - if err != nil { - logger.Warning("failed to call lockFront ShowAuth:", err) - } -} - -func (m *Manager) canSuspend() bool { - can, err := m.helper.SessionManager.CanSuspend(0) - if err != nil { - logger.Warning(err) - return false - } - return can -} - -func (m *Manager) doSuspend() { - if !m.canSuspend() { - logger.Info("can not suspend") - return - } - - logger.Debug("suspend") - err := m.helper.SessionManager.RequestSuspend(0) - if err != nil { - logger.Warning("failed to suspend:", err) - } -} - -// 为了处理待机闪屏的问题,通过前端进行待机,前端会在待机前显示一个纯黑的界面 -func (m *Manager) doSuspendByFront() { - if !m.canSuspend() { - logger.Info("can not suspend") - return - } - - logger.Debug("suspend") - err := m.helper.ShutdownFront.Suspend(0) - if err != nil { - logger.Warning("failed to suspend:", err) - } -} - -func (m *Manager) canShutdown() bool { - can, err := m.helper.SessionManager.CanShutdown(0) - if err != nil { - logger.Warning(err) - return false - } - return can -} - -// 正常关机流程,存在 block or delay shutdown 或多用户时,显示shutdown界面,其他情况,直接关机 -func (m *Manager) doShutdown() { - if m.hasShutdownInhibit() || m.hasMultipleDisplaySession() { - logger.Info("exist shutdown inhibit(delay or block) or multiple display session") - err := m.ddeShutdown.Shutdown(0) - if err != nil { - logger.Warning(err) - } - } else { - logger.Debug("Shutdown") - err := m.helper.SessionManager.RequestShutdown(0) - if err != nil { - logger.Warning("failed to Shutdown:", err) - } - } -} - -func (m *Manager) hasShutdownInhibit() bool { - // 先检查是否有delay 或 block shutdown的inhibitor - inhibitors, err := m.objLogin.ListInhibitors(0) - if err != nil { - logger.Warning("failed to call login ListInhibitors:", err) - } else { - for _, inhibit := range inhibitors { - logger.Infof("inhibit is: %+v", inhibit) - if strings.Contains(inhibit.What, "shutdown") { - return true - } - } - } - return false -} - -// 定时关机流程: 存在block关机项时,显示shutdown界面,无block时,直接关机,delay情况进行延迟关机 -func (m *Manager) doAutoShutdown() { - if m.hasShutdownBlock() { - logger.Warning("Shutdown") - err := m.ddeShutdown.Shutdown(0) - if err != nil { - logger.Warning(err) - } - } else { - logger.Warning("Shutdown") - err := m.helper.SessionManager.RequestShutdown(0) - // m.lastShutdownTime = time.Now().Unix() - // m.savePowerDsgConfig(dsettingLastShutdownTime) - if err != nil { - logger.Warning("failed to Shutdown:", err) - } - } -} - -func (m *Manager) hasShutdownBlock() bool { - // 检查是否有block shutdown的inhibitor - inhibitors, err := m.objLogin.ListInhibitors(0) - if err != nil { - logger.Warning("failed to call login ListInhibitors:", err) - } else { - for _, inhibit := range inhibitors { - logger.Infof("inhibit is: %+v", inhibit) - if strings.Contains(inhibit.What, "shutdown") && inhibit.Mode == "block" { - logger.Info("exist shutdown block") - return true - } - } - } - return false -} - -func (m *Manager) hasMultipleDisplaySession() bool { - // 检查是否有多个图形session,有多个图形session就需要显示阻塞界面 - sessions, err := m.displayManager.Sessions().Get(0) - if err != nil { - logger.Warning(err) - return false - } - return len(sessions) >= 2 -} - -func (m *Manager) canHibernate() bool { - can, err := m.helper.SessionManager.CanHibernate(0) - if err != nil { - logger.Warning(err) - return false - } - return can -} - -func (m *Manager) doHibernate() { - if !m.canHibernate() { - logger.Info("can not hibernate") - return - } - logger.Debug("hibernate") - err := m.helper.SessionManager.RequestHibernate(0) - if err != nil { - logger.Warning("failed to hibernate:", err) - } -} - -func (m *Manager) doHibernateByFront() { - if !m.canHibernate() { - logger.Info("can not hibernate") - return - } - - logger.Debug("hibernate") - err := m.helper.ShutdownFront.Hibernate(0) - if err != nil { - logger.Warning("failed to hibernate:", err) - } -} - -func (m *Manager) doTurnOffScreen() { - if m.ScreenBlackLock.Get() { - logger.Info("Show lock") - m.doLock(true) - time.Sleep(1 * time.Second) - } - - logger.Info("Turn off screen") - m.setDPMSModeOff() -} - -func (m *Manager) setDisplayBrightness(brightnessTable map[string]float64) { - display := m.helper.Display - for output, brightness := range brightnessTable { - logger.Infof("Change output %q brightness to %.2f", output, brightness) - err := display.SetBrightness(0, output, brightness) - if err != nil { - logger.Warningf("Change output %q brightness to %.2f failed: %v", output, brightness, err) - } else { - logger.Infof("Change output %q brightness to %.2f done!", output, brightness) - } - } -} - -func (m *Manager) setAndSaveDisplayBrightness(brightnessTable map[string]float64) { - display := m.helper.Display - for output, brightness := range brightnessTable { - logger.Infof("Change output %q brightness to %.2f", output, brightness) - err := display.SetAndSaveBrightness(0, output, brightness) - if err != nil { - logger.Warningf("Change output %q brightness to %.2f failed: %v", output, brightness, err) - } else { - logger.Infof("Change output %q brightness to %.2f done!", output, brightness) - } - } -} - -func doShowDDELowPower() { - logger.Info("Show dde low power") - go func() { - err := exec.Command(cmdDDELowPower, "--raise").Run() - if err != nil { - logger.Warning(err) - } - }() -} - -func doCloseDDELowPower() { - logger.Info("Close low power") - go func() { - err := exec.Command(cmdDDELowPower, "--quit").Run() - if err != nil { - logger.Warning(err) - } - }() -} - -func (m *Manager) sendNotify(icon, summary, body string) { - if !m.LowPowerNotifyEnable.Get() { - logger.Info("notify switch is off ") - return - } - n := m.helper.Notifications - _, err := n.Notify(0, "dde-control-center", 0, icon, summary, body, nil, nil, -1) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) sendChangeNotify(icon, summary, body string) { - n := m.helper.Notifications - _, err := n.Notify(0, "dde-control-center", 0, icon, summary, body, nil, nil, -1) - if err != nil { - logger.Warning(err) - } -} - -const iconBatteryLow = "notification-battery-low" - -func playSound(name string) { - logger.Debug("play system sound", name) - go func() { - err := soundutils.PlaySystemSound(name, "") - if err != nil { - logger.Warning(err) - } - }() -} - -const ( - deepinScreensaverDBusServiceName = "com.deepin.ScreenSaver" - deepinScreensaverDBusPath = "/com/deepin/ScreenSaver" - deepinScreensaverDBusInterface = deepinScreensaverDBusServiceName -) - -func startScreensaver() { - logger.Info("start screensaver") - bus, err := dbus.SessionBus() - if err != nil { - logger.Warning(err) - return - } - - obj := bus.Object(deepinScreensaverDBusServiceName, deepinScreensaverDBusPath) - err = obj.Call(deepinScreensaverDBusInterface+".Start", 0).Err - if err != nil { - logger.Warning(err) - } -} - -func stopScreensaver() { - logger.Info("stop screensaver") - bus, err := dbus.SessionBus() - if err != nil { - logger.Warning(err) - return - } - - obj := bus.Object(deepinScreensaverDBusServiceName, deepinScreensaverDBusPath) - err = obj.Call(deepinScreensaverDBusInterface+".Stop", 0).Err - if err != nil { - logger.Warning(err) - } -} - -// TODO(jouyouyun): move to common library -func suspendPulseSinks(suspend int) { - var ctx = pulse.GetContext() - if ctx == nil { - logger.Error("Failed to connect pulseaudio server") - return - } - for _, sink := range ctx.GetSinkList() { - ctx.SuspendSinkById(sink.Index, suspend) - } -} - -// TODO(jouyouyun): move to common library -func suspendPulseSources(suspend int) { - var ctx = pulse.GetContext() - if ctx == nil { - logger.Error("Failed to connect pulseaudio server") - return - } - for _, source := range ctx.GetSourceList() { - ctx.SuspendSourceById(source.Index, suspend) - } -} - -func (m *Manager) initGSettingsConnectChanged() { - const powerSettingsIcon = "preferences-system" - - isIllegalAction := func(action int32) bool { - return (action == powerActionHibernate && !m.canHibernate()) || - (action == powerActionSuspend && !m.canSuspend()) - } - - // 监听 session power 的属性的改变,并发送通知 - gsettings.ConnectChanged(gsSchemaPower, "*", func(key string) { - logger.Debug("Power Settings Changed :", key) - switch key { - case settingKeyLinePowerLidClosedAction: - value := m.LinePowerLidClosedAction.Get() - if isIllegalAction(value) { - break - } - case settingKeyLinePowerPressPowerBtnAction: - value := m.LinePowerPressPowerBtnAction.Get() - if isIllegalAction(value) { - break - } - case settingKeyBatteryLidClosedAction: - value := m.BatteryLidClosedAction.Get() - if isIllegalAction(value) { - break - } - case settingKeyBatteryPressPowerBtnAction: - value := m.BatteryPressPowerBtnAction.Get() - if isIllegalAction(value) { - break - } - case settingKeyHighPerformanceEnabled: - // 根据systemPower::IsHighPerformanceEnabled GSetting::settingKeyHighPerformanceEnabled - bSettingKeyHighPerformanceEnabled := m.settings.GetBoolean(settingKeyHighPerformanceEnabled) - if bSettingKeyHighPerformanceEnabled == m.gsHighPerformanceEnabled { - return - } - m.gsHighPerformanceEnabled = bSettingKeyHighPerformanceEnabled - isHighPerformanceSupported, _ := m.systemPower.IsHighPerformanceSupported().Get(0) - m.setPropIsHighPerformanceSupported(isHighPerformanceSupported && bSettingKeyHighPerformanceEnabled) - } - }) -} - -func getPowerActionString(action int32) string { - switch action { - case powerActionShutdown: - return Tr("your computer will shut down") - case powerActionSuspend: - return Tr("your computer will suspend") - case powerActionHibernate: - return Tr("your computer will hibernate") - case powerActionTurnOffScreen: - return Tr("your monitor will turn off") - case powerActionShowShutdownInterface: - return Tr("your monitor will show the shutdown interface") - case powerActionDoNothing: - return Tr("it will do nothing to your computer") - } - return "" -} - -func isFloatEqual(f1, f2 float64) bool { - return math.Abs(f1-f2) < 1e-6 -} - -func (m *Manager) getDpmsList() ([]dbus.Variant, error) { - sessionBus := m.sessionSigLoop.Conn() - sessionObj := sessionBus.Object("com.deepin.daemon.KWayland", "/com/deepin/daemon/KWayland/DpmsManager") - var ret []dbus.Variant - err := sessionObj.Call("com.deepin.daemon.KWayland.DpmsManager.dpmsList", 0).Store(&ret) - if err != nil { - logger.Warning(err) - return nil, err - } - - return ret, nil -} - -func (m *Manager) getDpmsModeByKwin() (int32, error) { - list, err := m.getDpmsList() - if err != nil { - logger.Warning(err) - return dpmsStateOn, err - } - - var dpmsMode int32 - for i := 0; i < len(list); i++ { - v := list[i].Value().(string) - sessionObj := m.sessionSigLoop.Conn().Object("com.deepin.daemon.KWayland", dbus.ObjectPath(v)) - err = sessionObj.Call("com.deepin.daemon.KWayland.Dpms.getDpmsMode", 0).Store(&dpmsMode) - if err != nil { - logger.Warning(err) - return dpmsStateOn, err - } - } - - return dpmsMode, nil -} - -func (m *Manager) setDpmsModeByKwin(mode int32) error { - list, err := m.getDpmsList() - if err != nil { - logger.Warning(err) - return err - } - - for i := 0; i < len(list); i++ { - v := list[i].Value().(string) - sessionObj := m.sessionSigLoop.Conn().Object("com.deepin.daemon.KWayland", dbus.ObjectPath(v)) - err = sessionObj.Call("com.deepin.daemon.KWayland.Dpms.setDpmsMode", 0, int32(mode)).Err - if err != nil { - logger.Warning(err) - return err - } - } - - return nil -} - -func byteSliceEqual(v1, v2 []byte) bool { - if len(v1) != len(v2) { - return false - } - for i, e1 := range v1 { - if e1 != v2[i] { - return false - } - } - return true -} diff --git a/session/power/ambient_light_test.go b/session/power1/ambient_light_test.go similarity index 100% rename from session/power/ambient_light_test.go rename to session/power1/ambient_light_test.go diff --git a/session/power/constant.go b/session/power1/constant.go similarity index 100% rename from session/power/constant.go rename to session/power1/constant.go diff --git a/session/power/count_ticker.go b/session/power1/count_ticker.go similarity index 100% rename from session/power/count_ticker.go rename to session/power1/count_ticker.go diff --git a/session/power1/daemon.go b/session/power1/daemon.go new file mode 100644 index 000000000..c604f4b41 --- /dev/null +++ b/session/power1/daemon.go @@ -0,0 +1,83 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package power + +import ( + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" +) + +var logger = log.NewLogger("daemon/session/power") + +func init() { + loader.Register(NewDaemon(logger)) +} + +type Daemon struct { + *loader.ModuleBase + manager *Manager +} + +func NewDaemon(logger *log.Logger) *Daemon { + daemon := new(Daemon) + daemon.ModuleBase = loader.NewModuleBase("power", daemon, logger) + return daemon +} + +func (d *Daemon) GetDependencies() []string { + return []string{"screensaver", "sessionwatcher"} +} + +func (d *Daemon) Start() error { + service := loader.GetService() + var err error + d.manager, err = newManager(service) + if err != nil { + return err + } + + err = service.Export(dbusPath, d.manager, + d.manager.warnLevelConfig, d.manager.syncConfig) + if err != nil { + return err + } + + err = service.RequestName(dbusServiceName) + if err != nil { + return err + } + + err = d.manager.syncConfig.Register() + if err != nil { + logger.Warning("failed to register for deepin sync:", err) + } + + go d.manager.init() + _manager = d.manager + return nil +} + +func (d *Daemon) Stop() error { + if d.manager == nil { + return nil + } + service := loader.GetService() + err := service.ReleaseName(dbusServiceName) + if err != nil { + logger.Warning(err) + } + err = service.StopExport(d.manager) + if err != nil { + logger.Warning(err) + } + err = service.StopExport(d.manager.syncConfig) + if err != nil { + logger.Warning(err) + } + + d.manager.destroy() + d.manager = nil + return nil +} diff --git a/session/power/delayed_task.go b/session/power1/delayed_task.go similarity index 100% rename from session/power/delayed_task.go rename to session/power1/delayed_task.go diff --git a/session/power/exported_methods_auto.go b/session/power1/exported_methods_auto.go similarity index 100% rename from session/power/exported_methods_auto.go rename to session/power1/exported_methods_auto.go diff --git a/session/power1/helper.go b/session/power1/helper.go new file mode 100644 index 000000000..b3dbd6836 --- /dev/null +++ b/session/power1/helper.go @@ -0,0 +1,107 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package power + +import ( + "github.com/godbus/dbus/v5" + notifications "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.notifications" + "github.com/linuxdeepin/go-lib/dbusutil/proxy" + + // system bus + shutdownfront "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.dde.shutdownfront" + sensorproxy "github.com/linuxdeepin/go-dbus-factory/system/net.hadess.sensorproxy" + daemon "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.daemon1" + libpower "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.power1" + ofdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.dbus" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" + + // session bus + display "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.display1" + sessionmanager "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.sessionmanager1" + sessionwatcher "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.sessionwatcher1" + screensaver "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.screensaver" + "github.com/linuxdeepin/go-lib/dbusutil" + x "github.com/linuxdeepin/go-x11-client" +) + +type Helper struct { + Notifications notifications.Notifications + + Power libpower.Power // sig + LoginManager login1.Manager // sig + SensorProxy sensorproxy.SensorProxy + SysDBusDaemon ofdbus.DBus + Daemon daemon.Daemon + + SessionManager sessionmanager.SessionManager + SessionWatcher sessionwatcher.SessionWatcher + ShutdownFront shutdownfront.ShutdownFront + ScreenSaver screensaver.ScreenSaver // sig + Display display.Display + + xConn *x.Conn +} + +func newHelper(systemBus, sessionBus *dbus.Conn) (*Helper, error) { + h := &Helper{} + err := h.init(systemBus, sessionBus) + if err != nil { + return nil, err + } + return h, nil +} + +func (h *Helper) init(sysBus, sessionBus *dbus.Conn) error { + var err error + + h.Notifications = notifications.NewNotifications(sessionBus) + + h.Power = libpower.NewPower(sysBus) + h.LoginManager = login1.NewManager(sysBus) + h.SensorProxy = sensorproxy.NewSensorProxy(sysBus) + h.SysDBusDaemon = ofdbus.NewDBus(sysBus) + h.Daemon = daemon.NewDaemon(sysBus) + h.SessionManager = sessionmanager.NewSessionManager(sessionBus) + h.ScreenSaver = screensaver.NewScreenSaver(sessionBus) + h.Display = display.NewDisplay(sessionBus) + h.SessionWatcher = sessionwatcher.NewSessionWatcher(sessionBus) + h.ShutdownFront = shutdownfront.NewShutdownFront(sessionBus) + + // init X conn + h.xConn, err = x.NewConn() + if err != nil { + return err + } + return nil +} + +func (h *Helper) initSignalExt(systemSigLoop, sessionSigLoop *dbusutil.SignalLoop) { + // sys + h.SysDBusDaemon.InitSignalExt(systemSigLoop, true) + h.LoginManager.InitSignalExt(systemSigLoop, true) + h.Power.InitSignalExt(systemSigLoop, true) + h.SensorProxy.InitSignalExt(systemSigLoop, true) + h.Daemon.InitSignalExt(systemSigLoop, true) + // session + h.ScreenSaver.InitSignalExt(sessionSigLoop, true) + h.SessionWatcher.InitSignalExt(sessionSigLoop, true) + h.Display.InitSignalExt(sessionSigLoop, true) +} + +func (h *Helper) Destroy() { + h.SysDBusDaemon.RemoveHandler(proxy.RemoveAllHandlers) + h.LoginManager.RemoveHandler(proxy.RemoveAllHandlers) + h.Power.RemoveHandler(proxy.RemoveAllHandlers) + h.SensorProxy.RemoveHandler(proxy.RemoveAllHandlers) + h.Daemon.RemoveHandler(proxy.RemoveAllHandlers) + + h.ScreenSaver.RemoveHandler(proxy.RemoveAllHandlers) + h.SessionWatcher.RemoveHandler(proxy.RemoveAllHandlers) + + if h.xConn != nil { + h.xConn.Close() + h.xConn = nil + } +} diff --git a/session/power/lid_switch.go b/session/power1/lid_switch.go similarity index 97% rename from session/power/lid_switch.go rename to session/power1/lid_switch.go index 86c8faa93..bad3b37f9 100644 --- a/session/power/lid_switch.go +++ b/session/power1/lid_switch.go @@ -22,14 +22,14 @@ const ( ) type LidSwitchHandler struct { - manager *Manager - cmd *exec.Cmd - cookie chan struct{} + manager *Manager + cmd *exec.Cmd + cookie chan struct{} } func newLidSwitchHandler(m *Manager) (string, submodule, error) { h := &LidSwitchHandler{ - manager: m, + manager: m, } return "LidSwitchHandler", h, nil } diff --git a/session/power1/manager.go b/session/power1/manager.go new file mode 100644 index 000000000..5e06c1513 --- /dev/null +++ b/session/power1/manager.go @@ -0,0 +1,1197 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package power + +import ( + "encoding/json" + "errors" + "fmt" + + "os" + "sync" + "syscall" + "time" + + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/common/dsync" + "github.com/linuxdeepin/dde-daemon/session/common" + configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" + calendar "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.api.lunarcalendar" + shutdownfront "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.dde.shutdownfront" + wm "github.com/linuxdeepin/go-dbus-factory/session/com.deepin.wm" + display "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.display1" + sessionmanager "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.sessionmanager1" + sessiontimedate "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.timedate1" + ofdbus "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.dbus" + notifications "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.notifications" + systemPower "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.power1" + DisplayManager "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.DisplayManager" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" + timedate "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.timedate1" + gio "github.com/linuxdeepin/go-gir/gio-2.0" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/dbusutil/gsprop" + "github.com/linuxdeepin/go-lib/gettext" + dutils "github.com/linuxdeepin/go-lib/utils" +) + +//go:generate dbusutil-gen -type Manager manager.go +//go:generate dbusutil-gen em -type Manager,WarnLevelConfigManager + +const ( + DSettingsAppID = "org.deepin.startdde" + DSettingsDisplayName = "org.deepin.Display" + DSettingsAutoChangeWm = "auto-change-deepin-wm" + + // 定时关机 + dsettingScheduledShutdownState = "scheduledShutdownState" + dsettingShutdownTime = "shutdownTime" + dsettingShutdownRepetition = "shutdownRepetition" + dsettingCustomShutdownWeekDays = "customShutdownWeekDays" + dsettingShutdownCountdown = "shutdownCountdown" + dsettingNextShutdownTime = "nextShutdownTime" +) + +const ( + Once int = iota + Everyday + Workdays + Custom +) + +type FestivalRootConfig struct { + Description string `json:"description"` + Id string `json:"id"` + List []HolidayDate `json:"list"` + Month byte `json:"month"` + NewDaemoname string `json:"name"` + Rest string `json:"rest"` +} + +type HolidayDate struct { + Date string `json:"date"` + Status byte `json:"status"` +} + +type Manager struct { + service *dbusutil.Service + sessionSigLoop *dbusutil.SignalLoop + systemSigLoop *dbusutil.SignalLoop + syncConfig *dsync.Config + helper *Helper + settings *gio.Settings + warnLevelCountTicker *countTicker + warnLevelConfig *WarnLevelConfigManager + submodules map[string]submodule + inhibitor *sleepInhibitor + inhibitFd dbus.UnixFD + systemPower systemPower.Power + display display.Display + calendar calendar.LunarCalendar + objLogin login1.Manager + ddeShutdown shutdownfront.ShutdownFront + displayManager DisplayManager.DisplayManager + lightSensorEnabled bool + + sessionManager sessionmanager.SessionManager + currentSessionPath dbus.ObjectPath + currentSession login1.Session + + // 定时关机 + ScheduledShutdownState bool `prop:"access:rw"` + ShutdownTime string `prop:"access:rw"` + ShutdownRepetition int `prop:"access:rw"` + // dbusutil-gen: equal=byteSliceEqual + CustomShutdownWeekDays []byte `prop:"access:rw"` + shutdownTimer *time.Timer + shutdownCountdown int + notifyId uint32 + notifyIdMu sync.Mutex + notify notifications.Notifications + + nextShutdownTime int64 // 下一次关机时间,只有关机配置、系统时间/时区等手动更改时,触发变更. 0则为无效日期 + shutdownStatus int + + sessionTimeDate sessiontimedate.Timedate + timeDate timedate.Timedate + + PropsMu sync.RWMutex + // 是否有盖子,一般笔记本电脑才有 + LidIsPresent bool + // 是否使用电池, 接通电源时为 false, 使用电池时为 true + OnBattery bool + // 是否使用Wayland + UseWayland bool + // 警告级别 + WarnLevel WarnLevel + + // 是否有环境光传感器 + HasAmbientLightSensor bool + + // dbusutil-gen: ignore-below + // 电池是否可用,是否存在 + BatteryIsPresent map[string]bool + // 电池电量百分比 + BatteryPercentage map[string]float64 + // 电池状态 + BatteryState map[string]uint32 + + // 接通电源时,不做任何操作,到显示屏保的时间 + LinePowerScreensaverDelay gsprop.Int `prop:"access:rw"` + // 接通电源时,不做任何操作,到关闭屏幕的时间 + LinePowerScreenBlackDelay gsprop.Int `prop:"access:rw"` + // 接通电源时,不做任何操作,到睡眠的时间 + LinePowerSleepDelay gsprop.Int `prop:"access:rw"` + + // 使用电池时,不做任何操作,到显示屏保的时间 + BatteryScreensaverDelay gsprop.Int `prop:"access:rw"` + // 使用电池时,不做任何操作,到关闭屏幕的时间 + BatteryScreenBlackDelay gsprop.Int `prop:"access:rw"` + // 使用电池时,不做任何操作,到睡眠的时间 + BatterySleepDelay gsprop.Int `prop:"access:rw"` + + // 关闭屏幕前是否锁定 + ScreenBlackLock gsprop.Bool `prop:"access:rw"` + // 睡眠前是否锁定 + SleepLock gsprop.Bool `prop:"access:rw"` + + // 废弃 + LidClosedSleep gsprop.Bool `prop:"access:rw"` + + // 接通电源时,笔记本电脑盖上盖子 待机(默认选择)、睡眠、关闭显示器、无任何操作 + LinePowerLidClosedAction gsprop.Enum `prop:"access:rw"` + + // 接通电源时,按下电源按钮 关机(默认选择)、待机、睡眠、关闭显示器、无任何操作 + LinePowerPressPowerBtnAction gsprop.Enum `prop:"access:rw"` // keybinding中监听power按键事件,获取gsettings的值 + + // 使用电池时,笔记本电脑盖上盖子 待机(默认选择)、睡眠、关闭显示器、无任何操作 + BatteryLidClosedAction gsprop.Enum `prop:"access:rw"` + + // 使用电池时,按下电源按钮 关机(默认选择)、待机、睡眠、关闭显示器、无任何操作 + BatteryPressPowerBtnAction gsprop.Enum `prop:"access:rw"` // keybinding中监听power按键事件,获取gsettings的值 + + // 接通电源时,不做任何操作,到自动锁屏的时间 + LinePowerLockDelay gsprop.Int `prop:"access:rw"` + // 使用电池时,不做任何操作,到自动锁屏的时间 + BatteryLockDelay gsprop.Int `prop:"access:rw"` + + // 打开电量通知 + LowPowerNotifyEnable gsprop.Bool `prop:"access:rw"` // 开启后默认当电池仅剩余达到电量水平低时(默认15%)发出系统通知“电池电量低,请连接电源”; + // 当电池仅剩余为设置低电量时(默认5%),发出系统通知“电池电量耗尽”,进入待机模式; + + // 电池低电量通知百分比 + LowPowerNotifyThreshold gsprop.Int `prop:"access:rw"` // 设置电量低提醒的阈值,可设置范围10%-25%,默认为20% + + // 自动待机电量百分比 + LowPowerAutoSleepThreshold gsprop.Int `prop:"access:rw"` // 设置电池电量进入待机模式(s3)的阈值,可设置范围为1%-9%,默认为5%(范围待确定) + + savingModeBrightnessDropPercent gsprop.Int // 用来接收和保存来自system power中降低的屏幕亮度值 + + AmbientLightAdjustBrightness gsprop.Bool `prop:"access:rw"` + + ambientLightClaimed bool + lightLevelUnit string + lidSwitchState uint + sessionActive bool + sessionActiveTime time.Time + + // if prepare suspend, ignore idle off + prepareSuspend int + prepareSuspendLocker sync.Mutex + + // 是否支持高性能模式 + IsHighPerformanceSupported bool + gsHighPerformanceEnabled bool + + // 是否支持节能模式 + isPowerSaveSupported bool + kwinHanleIdleOffCh chan bool + + dsDisplayConfigManager configManager.Manager + dsPowerConfigManager configManager.Manager + wmDBus wm.Wm + + delayInActive bool + delayWakeupInterval uint32 + delayHandleIdleOffIntervalWhenScreenBlack uint32 +} + +var _manager *Manager + +func newManager(service *dbusutil.Service) (*Manager, error) { + systemBus, err := dbus.SystemBus() + if err != nil { + return nil, err + } + m := new(Manager) + m.service = service + sessionBus := service.Conn() + m.sessionSigLoop = dbusutil.NewSignalLoop(sessionBus, 10) + m.systemSigLoop = dbusutil.NewSignalLoop(systemBus, 10) + m.objLogin = login1.NewManager(systemBus) + m.ddeShutdown = shutdownfront.NewShutdownFront(sessionBus) + m.displayManager = DisplayManager.NewDisplayManager(systemBus) + m.inhibitFd = -1 + m.prepareSuspend = suspendStateUnknown + + m.syncConfig = dsync.NewConfig("power", &syncConfig{m: m}, m.sessionSigLoop, dbusPath, logger) + + helper, err := newHelper(systemBus, sessionBus) + if err != nil { + return nil, err + } + m.helper = helper + + m.sessionManager = sessionmanager.NewSessionManager(sessionBus) + m.currentSessionPath, err = m.sessionManager.CurrentSessionPath().Get(0) + if err != nil || m.currentSessionPath == "" { + logger.Warning("get sessionManager CurrentSessionPath failed:", err) + return nil, err + } + m.currentSession, err = login1.NewSession(systemBus, m.currentSessionPath) + if err != nil || m.currentSession == nil { + logger.Error("Failed to connect self session:", err) + return nil, err + } + + m.settings = gio.NewSettings(gsSchemaPower) + m.warnLevelConfig = NewWarnLevelConfigManager(m.settings) + + m.LinePowerScreensaverDelay.Bind(m.settings, settingKeyLinePowerScreensaverDelay) + m.LinePowerScreenBlackDelay.Bind(m.settings, settingKeyLinePowerScreenBlackDelay) + m.LinePowerSleepDelay.Bind(m.settings, settingKeyLinePowerSleepDelay) + m.LinePowerLockDelay.Bind(m.settings, settingKeyLinePowerLockDelay) + m.BatteryScreensaverDelay.Bind(m.settings, settingKeyBatteryScreensaverDelay) + m.BatteryScreenBlackDelay.Bind(m.settings, settingKeyBatteryScreenBlackDelay) + m.BatterySleepDelay.Bind(m.settings, settingKeyBatterySleepDelay) + m.BatteryLockDelay.Bind(m.settings, settingKeyBatteryLockDelay) + m.ScreenBlackLock.Bind(m.settings, settingKeyScreenBlackLock) + m.SleepLock.Bind(m.settings, settingKeySleepLock) + + m.LinePowerLidClosedAction.Bind(m.settings, settingKeyLinePowerLidClosedAction) + m.LinePowerPressPowerBtnAction.Bind(m.settings, settingKeyLinePowerPressPowerBtnAction) + m.BatteryLidClosedAction.Bind(m.settings, settingKeyBatteryLidClosedAction) + m.BatteryPressPowerBtnAction.Bind(m.settings, settingKeyBatteryPressPowerBtnAction) + m.LowPowerNotifyEnable.Bind(m.settings, settingKeyLowPowerNotifyEnable) + m.LowPowerNotifyThreshold.Bind(m.settings, settingKeyLowPowerNotifyThreshold) + m.LowPowerAutoSleepThreshold.Bind(m.settings, settingKeyLowPowerAutoSleepThreshold) + m.savingModeBrightnessDropPercent.Bind(m.settings, settingKeyBrightnessDropPercent) + m.initGSettingsConnectChanged() + m.AmbientLightAdjustBrightness.Bind(m.settings, + settingKeyAmbientLightAdjuestBrightness) + m.lightSensorEnabled = m.settings.GetBoolean(settingLightSensorEnabled) + m.gsHighPerformanceEnabled = m.settings.GetBoolean(settingKeyHighPerformanceEnabled) + + power := m.helper.Power + err = common.ActivateSysDaemonService(power.ServiceName_()) + if err != nil { + logger.Warning(err) + } + + m.LidIsPresent, err = power.HasLidSwitch().Get(0) + if err != nil { + logger.Warning(err) + } + + m.OnBattery, err = power.OnBattery().Get(0) + if err != nil { + logger.Warning(err) + } + + logger.Info("LidIsPresent", m.LidIsPresent) + + if m.lightSensorEnabled { + m.HasAmbientLightSensor, _ = helper.SensorProxy.HasAmbientLight().Get(0) + logger.Debug("HasAmbientLightSensor:", m.HasAmbientLightSensor) + if m.HasAmbientLightSensor { + m.lightLevelUnit, _ = helper.SensorProxy.LightLevelUnit().Get(0) + } + } + + m.sessionActive, _ = helper.SessionWatcher.IsActive().Get(0) + + // init battery display + m.BatteryIsPresent = make(map[string]bool) + m.BatteryPercentage = make(map[string]float64) + m.BatteryState = make(map[string]uint32) + + // 初始化电源模式 + m.systemPower = systemPower.NewPower(systemBus) + isHighPerformanceSupported, err := m.systemPower.IsHighPerformanceSupported().Get(0) + if err != nil { + logger.Warning("Get systemPower.IsHighPerformanceSupported err :", err) + } + m.setPropIsHighPerformanceSupported(isHighPerformanceSupported && m.settings.GetBoolean(settingKeyHighPerformanceEnabled)) + m.isPowerSaveSupported, err = m.systemPower.IsPowerSaveSupported().Get(0) + if err != nil { + logger.Warning("Get systemPower.IsPowerSaveSupported err :", err) + } + + // 绑定org.deepin.dde.Display1的DBus + m.display = display.NewDisplay(sessionBus) + m.wmDBus = wm.NewWm(sessionBus) + + m.calendar = calendar.NewLunarCalendar(sessionBus) + m.notify = notifications.NewNotifications(sessionBus) + m.notify.InitSignalExt(m.sessionSigLoop, true) + + m.sessionTimeDate = sessiontimedate.NewTimedate(sessionBus) + m.sessionTimeDate.InitSignalExt(m.sessionSigLoop, true) + + m.timeDate = timedate.NewTimedate(systemBus) + m.timeDate.InitSignalExt(m.systemSigLoop, true) + return m, nil +} + +func (m *Manager) init() { + m.claimOrReleaseAmbientLight() + m.sessionSigLoop.Start() + m.systemSigLoop.Start() + + if len(os.Getenv("WAYLAND_DISPLAY")) != 0 { + m.UseWayland = true + } else { + m.UseWayland = false + } + + logger.Info("init Getenv(WAYLAND_DISPLAY) UseWayland : ", m.UseWayland) + m.helper.initSignalExt(m.systemSigLoop, m.sessionSigLoop) + + // init sleep inhibitor + m.inhibitor = newSleepInhibitor(m.helper.LoginManager, m.helper.Daemon) + m.inhibitor.OnBeforeSuspend = m.handleBeforeSuspend + m.inhibitor.OnWakeup = m.handleWakeup + err := m.inhibitor.block() + if err != nil { + logger.Warning(err) + } + + m.handleBatteryDisplayUpdate() + power := m.helper.Power + _, err = power.ConnectBatteryDisplayUpdate(func(timestamp int64) { + logger.Debug("BatteryDisplayUpdate", timestamp) + m.handleBatteryDisplayUpdate() + }) + if err != nil { + logger.Warning(err) + } + + if m.lightSensorEnabled { + err = m.helper.SensorProxy.LightLevel().ConnectChanged(func(hasValue bool, value float64) { + if !hasValue { + return + } + m.handleLightLevelChanged(value) + }) + if err != nil { + logger.Warning(err) + } + } + + _, err = m.helper.SysDBusDaemon.ConnectNameOwnerChanged( + func(name string, oldOwner string, newOwner string) { + if m.lightSensorEnabled { + serviceName := m.helper.SensorProxy.ServiceName_() + if name == serviceName && newOwner != "" { + logger.Debug("sensorProxy restarted") + hasSensor, _ := m.helper.SensorProxy.HasAmbientLight().Get(0) + var lightLevelUnit string + if hasSensor { + lightLevelUnit, _ = m.helper.SensorProxy.LightLevelUnit().Get(0) + } + + m.PropsMu.Lock() + m.setPropHasAmbientLightSensor(hasSensor) + m.ambientLightClaimed = false + m.lightLevelUnit = lightLevelUnit + m.PropsMu.Unlock() + + m.claimOrReleaseAmbientLight() + } + } + if name == m.helper.LoginManager.ServiceName_() && oldOwner != "" && newOwner == "" { + if m.prepareSuspend == suspendStatePrepare { + logger.Info("auto handleWakeup if systemd-logind coredump") + m.handleWakeup() + } + } + }) + if err != nil { + logger.Warning(err) + } + + // 修改时间后通过信号通知更新关机定时器 + _, err = m.sessionTimeDate.ConnectTimeUpdate(func() { + if m.ScheduledShutdownState { + m.setNextShutdownTime(0) + m.scheduledShutdown(Init) + } + }) + if err != nil { + logger.Warning("connect signal TimeUpdate failed:", err) + } + + err = m.timeDate.Timezone().ConnectChanged(func(hasValue bool, value string) { + time.AfterFunc(time.Second*2, func() { + if m.ScheduledShutdownState { + m.setNextShutdownTime(0) + m.scheduledShutdown(Init) + } + }) + }) + if err != nil { + logger.Warning(err) + } + + err = m.timeDate.NTP().ConnectChanged(func(hasValue bool, value bool) { + time.AfterFunc(time.Second*2, func() { + if m.ScheduledShutdownState { + m.setNextShutdownTime(0) + m.scheduledShutdown(Init) + } + }) + }) + if err != nil { + logger.Warning("connect NTP failed:", err) + } + + err = m.helper.SessionWatcher.IsActive().ConnectChanged(func(hasValue bool, value bool) { + if !hasValue { + return + } + + m.PropsMu.Lock() + m.sessionActive = value + m.sessionActiveTime = time.Now() + m.PropsMu.Unlock() + + logger.Debug("session active changed to:", value) + m.claimOrReleaseAmbientLight() + // 出发关机定时器 + m.scheduledShutdown(Init) + }) + if err != nil { + logger.Warning(err) + } + + m.warnLevelConfig.setChangeCallback(m.handleBatteryDisplayUpdate) + + m.initOnBatteryChangedHandler() + m.initSubmodules() + m.startSubmodules() + m.inhibitLogind() + m.initDsg() + + so := m.service.GetServerObject(m) + if so != nil { + err = so.SetWriteCallback(m, "ScheduledShutdownState", func(write *dbusutil.PropertyWrite) *dbus.Error { + value, ok := write.Value.(bool) + if !ok { + logger.Warning("Type is not bool") + } else { + logger.Info("ScheduledShutdownState change to", value) + } + m.setPropScheduledShutdownState(value) + err = m.savePowerDsgConfig(dsettingScheduledShutdownState) + return dbusutil.ToError(err) + }) + err = so.SetWriteCallback(m, "ShutdownTime", func(write *dbusutil.PropertyWrite) *dbus.Error { + value, ok := write.Value.(string) + if !ok { + logger.Warning("Type is not string") + } else { + logger.Info("ShutdownTime change to", value) + } + m.setPropShutdownTime(value) + err = m.savePowerDsgConfig(dsettingShutdownTime) + return dbusutil.ToError(err) + }) + err = so.SetWriteCallback(m, "ShutdownRepetition", func(write *dbusutil.PropertyWrite) *dbus.Error { + value, ok := write.Value.(int32) + if !ok { + logger.Warning("Type is not int") + } else { + logger.Info("ShutdownRepetition change to", value) + } + m.setPropShutdownRepetition(int(value)) + err = m.savePowerDsgConfig(dsettingShutdownRepetition) + return dbusutil.ToError(err) + }) + err = so.SetWriteCallback(m, "CustomShutdownWeekDays", func(write *dbusutil.PropertyWrite) *dbus.Error { + days := []byte{} + for _, v := range write.Value.([]uint8) { + days = append(days, byte(v)) + } + m.setPropCustomShutdownWeekDays(days) + err = m.savePowerDsgConfig(dsettingCustomShutdownWeekDays) + return dbusutil.ToError(err) + }) + } + + if m.UseWayland { + m.kwinHanleIdleOffCh = make(chan bool, 10) + go m.listenEventToHandleIdleOff() + + go func() { + for ch := range m.kwinHanleIdleOffCh { + if ch { + m.prepareSuspendLocker.Lock() + // 如果系统处于suspend状态,不需要在上层通过鼠标键盘事件唤醒系统 + if m.prepareSuspend >= suspendStatePrepare { + m.prepareSuspendLocker.Unlock() + continue + } + m.prepareSuspendLocker.Unlock() + + logger.Info("kwin handle idle off") + + if v := m.submodules[submodulePSP]; v != nil { + if psp := v.(*powerSavePlan); psp != nil { + psp.HandleIdleOff() + } + } + } + } + }() + } +} + +func (m *Manager) destroy() { + m.destroySubmodules() + m.releaseAmbientLight() + m.permitLogind() + + if m.helper != nil { + m.helper.Destroy() + m.helper = nil + } + + if m.inhibitor != nil { + err := m.inhibitor.unblock() + if err != nil { + logger.Warning(err) + } + m.inhibitor = nil + } + + m.systemSigLoop.Stop() + m.sessionSigLoop.Stop() + m.syncConfig.Destroy() +} + +func (*Manager) GetInterfaceName() string { + return dbusInterface +} + +func (m *Manager) Reset() *dbus.Error { + logger.Debug("Reset settings") + + var settingKeys = []string{ + settingKeyLinePowerScreenBlackDelay, + settingKeyLinePowerSleepDelay, + settingKeyLinePowerLockDelay, + settingKeyLinePowerLidClosedAction, + settingKeyLinePowerPressPowerBtnAction, + + settingKeyBatteryScreenBlackDelay, + settingKeyBatterySleepDelay, + settingKeyBatteryLockDelay, + settingKeyBatteryLidClosedAction, + settingKeyBatteryPressPowerBtnAction, + + settingKeyScreenBlackLock, + settingKeySleepLock, + settingKeyPowerButtonPressedExec, + + settingKeyLowPowerNotifyEnable, + settingKeyLowPowerNotifyThreshold, + settingKeyLowPowerAutoSleepThreshold, + settingKeyBrightnessDropPercent, + } + for _, key := range settingKeys { + logger.Debug("reset setting", key) + m.settings.Reset(key) + } + return nil +} + +func (m *Manager) initDsg() { + systemBus, err := dbus.SystemBus() + if err != nil { + return + } + + if !dutils.IsFileExist("/usr/share/dsg/configs/org.deepin.startdde/org.deepin.Display.json") { + logger.Warning(" [initDsg] dconfig file not exist : /usr/share/dsg/configs/org.deepin.startdde/org.deepin.Display.json.") + return + } + dsg := configManager.NewConfigManager(systemBus) + + // display + displayConfigManagerPath, err := dsg.AcquireManager(0, DSettingsAppID, DSettingsDisplayName, "") + if err != nil { + logger.Warning(err) + return + } + + m.dsDisplayConfigManager, err = configManager.NewManager(systemBus, displayConfigManagerPath) + if err != nil || displayConfigManagerPath == "" { + logger.Warning(err) + } + + // power + powerConfigManagerPath, err := dsg.AcquireManager(0, dsettingsAppID, dsettingsPowerName, "") + if err != nil { + logger.Warning(err) + return + } + m.dsPowerConfigManager, err = configManager.NewManager(systemBus, powerConfigManagerPath) + if err != nil { + logger.Warning(err) + return + } + getDsPowerConfig := func(key string, init bool) { + data, err := m.dsPowerConfigManager.Value(0, key) + if err != nil { + logger.Warning(err) + return + } + switch key { + case dsettingCustomShutdownWeekDays: + res := []byte{} + for _, v := range data.Value().([]dbus.Variant) { + res = append(res, byte(v.Value().(float64))) + } + if init { + m.CustomShutdownWeekDays = res + return + } + if m.setPropCustomShutdownWeekDays(res) { + logger.Info("Set CustomShutdownWeekDays property", m.CustomShutdownWeekDays) + } + case dsettingShutdownCountdown: + m.shutdownCountdown = int(data.Value().(float64)) + case dsettingNextShutdownTime: + m.nextShutdownTime = int64(data.Value().(float64)) + case dsettingShutdownRepetition: + if init { + m.ShutdownRepetition = int(data.Value().(float64)) + return + } + if m.setPropShutdownRepetition(int(data.Value().(float64))) { + logger.Info("Set ShutdownRepetition property", m.ShutdownRepetition) + } + case dsettingShutdownTime: + if init { + m.ShutdownTime = data.Value().(string) + return + } + if m.setPropShutdownTime(data.Value().(string)) { + logger.Info("Set ShutdownTime property", m.ShutdownTime) + } + case dsettingScheduledShutdownState: + if init { + m.ScheduledShutdownState = data.Value().(bool) + } else { + if m.setPropScheduledShutdownState(data.Value().(bool)) { + logger.Info("Set ScheduledShutdownState property", m.ScheduledShutdownState) + } + } + } + // m.scheduledShutdownSwitch(false, false) + // m.scheduledShutdownSwitch(m.ScheduledShutdownState, false) + + } + + getDsPowerConfig(dsettingCustomShutdownWeekDays, true) + getDsPowerConfig(dsettingShutdownCountdown, true) + getDsPowerConfig(dsettingShutdownRepetition, true) + getDsPowerConfig(dsettingShutdownTime, true) + getDsPowerConfig(dsettingScheduledShutdownState, true) + getDsPowerConfig(dsettingNextShutdownTime, true) + m.dsPowerConfigManager.InitSignalExt(m.systemSigLoop, true) + m.dsPowerConfigManager.ConnectValueChanged(func(key string) { + if key == dsettingNextShutdownTime { + return + } + logger.Info("DSG org.deepin.dde.daemon.power valueChanged, key : ", key) + getDsPowerConfig(key, false) + // 如果重复一次,重置nextShutdownTime + if m.ScheduledShutdownState { + m.setNextShutdownTime(0) + } + m.scheduledShutdown(Init) + }) + + if m.nextShutdownTime == 0 { + m.setNextShutdownTime(0) + } + m.scheduledShutdown(Init) +} + +func (m *Manager) setNextShutdownTime(bt int64) { + m.nextShutdownTime = m.getNextShutdownTime(bt) + m.savePowerDsgConfig(dsettingNextShutdownTime) +} + +func (m *Manager) savePowerDsgConfig(key string) (err error) { + var value interface{} + switch key { + case dsettingCustomShutdownWeekDays: + var tmp []dbus.Variant + for _, v := range m.CustomShutdownWeekDays { + tmp = append(tmp, dbus.MakeVariant(float64(v))) + } + value = tmp + case dsettingShutdownCountdown: + value = m.shutdownCountdown + case dsettingNextShutdownTime: + value = m.nextShutdownTime + case dsettingShutdownRepetition: + value = m.ShutdownRepetition + case dsettingShutdownTime: + value = m.ShutdownTime + case dsettingScheduledShutdownState: + value = m.ScheduledShutdownState + } + err = m.setDsgData(key, value, m.dsPowerConfigManager) + if err != nil { + logger.Warning(err) + return err + } + return nil +} + +func (m *Manager) setDsgData(key string, value interface{}, dsg configManager.Manager) error { + if dsg == nil { + return errors.New("setDsgData dsg is nil") + } + err := dsg.SetValue(0, key, dbus.MakeVariant(value)) + if err != nil { + logger.Warningf("setDsgData key : %s. err : %v", key, err) + return err + } + logger.Infof("setDsgData key : %s , value : %v", key, value) + return nil +} + +const ( + Init = iota // 初始阶段 + WaitingToNotify // 等待发送通知 + Countdowning // 倒计时中 + // 下面是执行结果 + Shutdown // 倒计时结束,准备关机 + Cancle // 执行关机取消,可能需要重置定时器 + TimeOut // 检测到超时,可能需要重置定时器 +) + +func (m *Manager) scheduledShutdown(state int) { + logger.Debugf("scheduledShutdown,pre-stat:%v next-stat:%v nextShutDownTime:%v", m.shutdownStatus, state, time.Unix(m.nextShutdownTime, 0).Format("2006-01-02 15:04:05")) + if m.shutdownTimer != nil { + m.shutdownTimer.Stop() + m.shutdownTimer = nil + } + + // 用户非活跃状态或者低电量屏保状态,停止定时关机流程 + isSessionActive, _ := m.helper.SessionWatcher.IsActive().Get(0) + if !isSessionActive || m.WarnLevel == WarnLevelAction { + m.notify.CloseNotification(0, m.notifyId) + logger.Warning("Stop scheduledShutdown") + return + } + + if state != Init && state == m.shutdownStatus { + return + } + + // 下次关机时间为0,则退出调度 + if m.nextShutdownTime == 0 { + logger.Warning("next shutdown time is illegal, please check the config") + return + } + + next := time.Unix(m.nextShutdownTime, 0) + currentTime := time.Now() + switch state { + case Init: + // 定时关闭的情况下,关闭定时器 + if m.shutdownStatus >= Countdowning { + m.notify.CloseNotification(0, m.notifyId) + } + if !m.ScheduledShutdownState { + return + } + m.shutdownStatus = Init + var nextStatus int + logger.Debugf("shutdown sub:%v s, %v min, countDown:%v", int(next.Sub(currentTime).Seconds()), int(next.Sub(currentTime).Minutes()), m.shutdownCountdown) + if int(next.Sub(currentTime).Minutes()) < 0 { + // 超时太久,则进行超时处理 + nextStatus = TimeOut + } else if int(next.Sub(currentTime).Minutes()) == 0 { + // 超时太久,则进行超时处理 + nextStatus = Countdowning + } else if int(next.Sub(currentTime).Seconds()) <= m.shutdownCountdown { + // 如果在倒计时的时区内 + nextStatus = Countdowning + } else { + // 时间远远未到,等待发送通知 + nextStatus = WaitingToNotify + } + m.scheduledShutdown(nextStatus) + case WaitingToNotify: + m.shutdownStatus = WaitingToNotify + // 提前通知,设置通知的定时器 + t := time.Duration(m.shutdownCountdown) * time.Second * -1 + next = next.Add(t) + m.shutdownTimer = time.AfterFunc(time.Until(next), func() { + m.scheduledShutdown(Countdowning) + }) + case Countdowning: + m.shutdownStatus = Countdowning + // 已经发送通知,正在进行关机倒计时 + counter := func() func() int { + count := m.shutdownCountdown + 1 + return func() int { + count-- + return count + } + }() + go func() { + count := counter() + m.shutdownCountdownNotify(count, true) + m.shutdownTimer = time.NewTimer(time.Second) + for range m.shutdownTimer.C { + count := counter() + if count == 0 { + m.scheduledShutdown(Shutdown) + } else { + // TODO: 每秒通知一次?有没有更好的办法? + m.shutdownCountdownNotify(count, false) + m.shutdownTimer.Reset(time.Second) + } + } + }() + case Shutdown, Cancle, TimeOut: + // 如果是超时,则关闭通知 + if state == TimeOut { + m.notify.CloseNotification(0, m.notifyId) + } + m.shutdownStatus = state + if m.ShutdownRepetition == Once { + // 如果是重复一次,则停止定时器 + m.setPropScheduledShutdownState(false) + m.nextShutdownTime = 0 + m.savePowerDsgConfig(dsettingNextShutdownTime) + m.savePowerDsgConfig(dsettingScheduledShutdownState) + } else { + // 重新生成下一次定时关机时间,并保存 + m.setNextShutdownTime(m.nextShutdownTime) + // 当前与设定的时间超过1分钟 + t := time.Until(next).Minutes() + if t > 0 { + // 超时,重新开始调度 + m.shutdownTimer = time.AfterFunc(10*time.Second, func() { + m.scheduledShutdown(Init) + }) + } else { + // 提前取消,则等待count时间后在重新调度 + m.shutdownTimer = time.AfterFunc(time.Duration(m.shutdownCountdown)*time.Second, func() { + m.scheduledShutdown(Init) + }) + } + } + if state == Shutdown { + // 执行关机,整个状态机应该结束了 + m.notify.CloseNotification(0, m.notifyId) + m.doAutoShutdown() + } + } +} + +func (m *Manager) shutdownCountdownNotify(count int, playSound bool) { + body := fmt.Sprintf(gettext.Tr("The system will shut down automatically after %d s"), count) + title := gettext.Tr("Scheduled Shutdown") + actions := []string{"Cancle", gettext.Tr("Cancle"), "Shutdown", gettext.Tr("Shut down")} + hints := map[string]dbus.Variant{"x-deepin-PlaySound": dbus.MakeVariant(playSound), + "x-deepin-ShowInNotifyCenter": dbus.MakeVariant(false), + "x-deepin-ClickToDisappear": dbus.MakeVariant(false), + "x-deepin-DisappearAfterLock": dbus.MakeVariant(false)} + m.notifyIdMu.Lock() + nid := m.notifyId + m.notifyIdMu.Unlock() + nid, err := m.notify.Notify(0, "dde-control-center", nid, "preferences-system", title, body, actions, hints, -1) + if err != nil { + logger.Warningf("failed to send notify: %s", err) + } + m.notifyIdMu.Lock() + m.notifyId = nid + m.notifyIdMu.Unlock() + m.notify.ConnectActionInvoked(func(id uint32, actionKey string) { + + var nextStatus int + if actionKey == "Cancle" { + // m.actionShutdown(true) + nextStatus = Cancle + } else if actionKey == "Shutdown" { + // m.actionShutdown(false) + // 执行关机 + nextStatus = Shutdown + } else { + logger.Warningf("unknown actionKey %v", actionKey) + nextStatus = Cancle + } + logger.Warning("notify Invoked:", actionKey) + m.scheduledShutdown(nextStatus) + }) +} + +func (m *Manager) isWorkday(date time.Time) (res bool) { + year, month, _ := date.Date() + val, err := m.calendar.GetFestivalMonth(0, int32(year), int32(month)) + if err == nil { + var rootCfg []FestivalRootConfig + err = json.Unmarshal([]byte(val), &rootCfg) + if err != nil { + logger.Warning(err) + return false + } + // 如果list不包含,则按正常周末处理,如果包含,则判断status状态 + if len(rootCfg) <= 0 { + return date.Weekday() != time.Sunday && date.Weekday() != time.Saturday + } + for _, holidayInfo := range rootCfg[0].List { + if holidayInfo.Date == date.Format("2006-1-2") { + return holidayInfo.Status == 2 + } + } + return date.Weekday() != time.Sunday && date.Weekday() != time.Saturday + } else { + logger.Warning(err) + } + return +} + +func (m *Manager) isCustomday(date time.Time) (res bool) { + for _, v := range m.CustomShutdownWeekDays { + if byte(date.Weekday()) == v { + logger.Debug("Today is included in custom shutdown weekdays") + return true + } + } + return false +} + +const ( + daysOfWeek = 7 //一周天数 + daysOfYear = 366 // 一年天数 +) + +func (m *Manager) getNextShutdownTime(bt int64) int64 { + getNextTime := func() time.Time { + bastTime := time.Unix(bt, 0) + currentTime := time.Now() + // 构建目标时间 + targetTimeLayout := "15:04" + targetTime, _ := time.Parse(targetTimeLayout, m.ShutdownTime) + targetTime = time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), targetTime.Hour(), targetTime.Minute(), 0, 0, currentTime.Location()) + // 如果比当前时间小,则跳过今天 + if int(targetTime.Sub(currentTime).Minutes()) < 0 { + // 如果在同一分鐘內,應該立发送通知 + t, _ := time.ParseDuration("24h") + targetTime = targetTime.Add(t) + } + // 如果比base时间小,则target时间加1天 + if int(targetTime.Sub(bastTime).Minutes()) <= 0 { + // 如果在同一分鐘內,應該立发送通知 + t, _ := time.ParseDuration("24h") + targetTime = targetTime.Add(t) + } + return targetTime + } + + var targetTime time.Time + switch m.ShutdownRepetition { + case Once, Everyday: + targetTime = getNextTime() + case Workdays: + targetTime = getNextTime() + // 获取下一个工作日,也可能是今天 + // isWorkday依赖第三方接口,防止调用一直报错导致死循环 + for i := 0; i <= daysOfYear; i++ { + if i == daysOfYear { + return 0 + } + if m.isWorkday(targetTime) { + break + } else { + t, _ := time.ParseDuration("24h") + targetTime = targetTime.Add(t) + } + } + case Custom: + targetTime = getNextTime() + // 一周7天,获取下一个自定义工作日,也可能是今天 + for i := 0; i <= daysOfWeek; i++ { + // 循环一周都获取不到工作日,则返回无效日期 + if i == daysOfWeek { + return 0 + } + if m.isCustomday(targetTime) { + break + } else { + t, _ := time.ParseDuration("24h") + targetTime = targetTime.Add(t) + } + } + } + logger.Debug("gen next shutdown time:", targetTime.Format("2006-01-02 15:04:05")) + return targetTime.Unix() +} + +func (m *Manager) getAutoChangeDeepinWm() bool { + if m.dsDisplayConfigManager == nil { + logger.Warning("getAutoChangeDeepinWm, dsgConfig org.deepin.startdde auto-change-deepin-wm not exist") + return false + } + v, err := m.dsDisplayConfigManager.Value(0, DSettingsAutoChangeWm) + if err != nil { + logger.Warning(err) + return false + } + dsAutoChangeDeepinWm := v.Value().(bool) + logger.Info("Auto Change Deepin Wm:", dsAutoChangeDeepinWm) + + return dsAutoChangeDeepinWm +} + +func (m *Manager) setAutoChangeDeepinWm(value bool) error { + if m.dsDisplayConfigManager == nil { + return errors.New("setAutoChangeDeepinWm, dsgConfig org.deepin.startdde auto-change-deepin-wm not exist") + } + err := m.dsDisplayConfigManager.SetValue(0, DSettingsAutoChangeWm, dbus.MakeVariant(value)) + if err != nil { + return err + } + return nil +} + +func (m *Manager) inhibitLogind() { + inhibit := func() { + fd, err := m.helper.LoginManager.Inhibit(0, + "handle-power-key:handle-lid-switch:handle-suspend-key", dbusServiceName, + "handling key press and lid switch close", "block") + logger.Debug("inhibitLogind fd:", fd) + if err != nil { + logger.Warning(err) + return + } + m.inhibitFd = fd + } + inhibit() + // handle login1 restart + dbusObj := ofdbus.NewDBus(m.systemSigLoop.Conn()) + sysLoop := dbusutil.NewSignalLoop(m.systemSigLoop.Conn(), 10) + sysLoop.Start() + dbusObj.InitSignalExt(sysLoop, true) + _, _ = dbusObj.ConnectNameOwnerChanged(func(name string, oldOwner string, newOwner string) { + if name == "org.freedesktop.login1" && newOwner != "" && oldOwner == "" { + if m.inhibitFd != -1 { // 如果之前存在inhibit时,login1重启需要重新inhibit + err := syscall.Close(int(m.inhibitFd)) + m.inhibitFd = -1 + if err != nil { + logger.Warning("failed to close fd:", err) + return + } + inhibit() + } + } + }) + // end handle login1 restart +} + +func (m *Manager) permitLogind() { + if m.inhibitFd != -1 { + err := syscall.Close(int(m.inhibitFd)) + if err != nil { + logger.Warning("failed to close inhibitFd:", err) + } + m.inhibitFd = -1 + } +} + +func (m *Manager) SetPrepareSuspend(suspendState int) *dbus.Error { + m.setPrepareSuspend(suspendState) + return nil +} + +func (m *Manager) isSessionActive() bool { + active, err := m.currentSession.Active().Get(dbus.FlagNoAutoStart) + if err != nil { + logger.Error("failed to get session active status:", err) + return false + } + return active +} + +// wayland下在收到键盘或者鼠标事件后,需要进行系统空闲处理(主要是唤醒屏幕) +func (m *Manager) listenEventToHandleIdleOff() error { + // + 监控按键事件 + err := m.systemSigLoop.Conn().Object("org.deepin.dde.Gesture1", + "/org/deepin/dde/Gesture1").AddMatchSignal("org.deepin.dde.Gesture1", "KeyboardEvent").Err + if err != nil { + logger.Warning(err) + return err + } + + m.systemSigLoop.AddHandler(&dbusutil.SignalRule{ + Name: "org.deepin.dde.Gesture1.KeyboardEvent", + }, func(sig *dbus.Signal) { + if len(sig.Body) > 1 { + value := sig.Body[1].(uint32) + if m.getDPMSMode() != dpmsStateOn && value == 1 { + logger.Debug("receive keyboard event to handle idle off") + m.kwinHanleIdleOffCh <- true + } + } + }) + + // + 监控鼠标移动事件 + err = m.sessionSigLoop.Conn().Object("org.deepin.dde.KWayland1", + "/org/deepin/dde/KWayland1/Output").AddMatchSignal("org.deepin.dde.KWayland1.Output", "CursorMove").Err + if err != nil { + logger.Warning(err) + return err + } + m.sessionSigLoop.AddHandler(&dbusutil.SignalRule{ + Name: "org.deepin.dde.KWayland1.Output.CursorMove", + }, func(sig *dbus.Signal) { + if len(sig.Body) > 1 { + if m.getDPMSMode() != dpmsStateOn { + logger.Debug("receive cursor move event to handle idle off") + m.kwinHanleIdleOffCh <- true + } + } + }) + + // + 监控鼠标按下事件 + err = m.sessionSigLoop.Conn().Object("org.deepin.dde.KWayland1", + "/org/deepin/dde/KWayland1/Output").AddMatchSignal("org.deepin.dde.KWayland1.Output", "ButtonPress").Err + if err != nil { + logger.Warning(err) + return err + } + m.sessionSigLoop.AddHandler(&dbusutil.SignalRule{ + Name: "org.deepin.dde.KWayland1.Output.ButtonPress", + }, func(sig *dbus.Signal) { + if len(sig.Body) > 1 { + if m.getDPMSMode() != dpmsStateOn { + logger.Debug("acquire button press to handle idle off") + m.kwinHanleIdleOffCh <- true + } + } + }) + + return nil +} diff --git a/session/power/manager_ambient_light.go b/session/power1/manager_ambient_light.go similarity index 100% rename from session/power/manager_ambient_light.go rename to session/power1/manager_ambient_light.go diff --git a/session/power/manager_events.go b/session/power1/manager_events.go similarity index 97% rename from session/power/manager_events.go rename to session/power1/manager_events.go index 4c888425d..713c106d7 100644 --- a/session/power/manager_events.go +++ b/session/power1/manager_events.go @@ -7,7 +7,7 @@ package power import ( "time" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-api/soundutils" . "github.com/linuxdeepin/go-lib/gettext" ) @@ -81,8 +81,8 @@ func (m *Manager) handleWakeup() { // Fix wayland sometimes no dpms event after wakeup if m.UseWayland { - err := m.service.Conn().Object("com.deepin.daemon.KWayland", - "/com/deepin/daemon/KWayland/Output").Call("com.deepin.daemon.KWayland.Idle.simulateUserActivity", 0).Err + err := m.service.Conn().Object("org.deepin.dde.KWayland1", + "/org/deepin/dde/KWayland1/Output").Call("org.deepin.dde.KWayland1.Idle.simulateUserActivity", 0).Err if err != nil { logger.Warning(err) diff --git a/session/power1/manager_stub.go b/session/power1/manager_stub.go new file mode 100644 index 000000000..332bd804b --- /dev/null +++ b/session/power1/manager_stub.go @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package power + +import ( + "github.com/linuxdeepin/dde-api/powersupply/battery" +) + +const ( + dbusServiceName = "org.deepin.dde.Power1" + dbusPath = "/org/deepin/dde/Power1" + dbusInterface = dbusServiceName +) + +func (m *Manager) setPropBatteryIsPresent(val bool) { + old, exist := m.BatteryIsPresent[batteryDisplay] + if old != val || !exist { + m.BatteryIsPresent[batteryDisplay] = val + m.emitPropChangedBatteryIsPresent() + } +} + +func (m *Manager) emitPropChangedBatteryIsPresent() { + err := m.service.EmitPropertyChanged(m, "BatteryIsPresent", m.BatteryIsPresent) + if err != nil { + logger.Warning(err) + } +} + +func (m *Manager) setPropBatteryPercentage(val float64) { + logger.Debugf("set batteryDisplay percentage %.1f%%", val) + old, exist := m.BatteryPercentage[batteryDisplay] + if old != val || !exist { + m.BatteryPercentage[batteryDisplay] = val + m.emitPropChangedBatteryPercentage() + } +} + +func (m *Manager) emitPropChangedBatteryPercentage() { + err := m.service.EmitPropertyChanged(m, "BatteryPercentage", m.BatteryPercentage) + if err != nil { + logger.Warning(err) + } +} + +func (m *Manager) setPropBatteryState(val uint32) { + logger.Debug("set BatteryDisplay status", battery.Status(val), val) + old, exist := m.BatteryState[batteryDisplay] + if old != val || !exist { + m.BatteryState[batteryDisplay] = val + m.emitPropChangedBatteryState() + } +} + +func (m *Manager) emitPropChangedBatteryState() { + err := m.service.EmitPropertyChanged(m, "BatteryState", m.BatteryState) + if err != nil { + logger.Warning(err) + } +} diff --git a/session/power/power_dbusutil.go b/session/power1/power_dbusutil.go similarity index 100% rename from session/power/power_dbusutil.go rename to session/power1/power_dbusutil.go diff --git a/session/power/power_save_plan.go b/session/power1/power_save_plan.go similarity index 99% rename from session/power/power_save_plan.go rename to session/power1/power_save_plan.go index b89effe2f..b1013d54b 100644 --- a/session/power/power_save_plan.go +++ b/session/power1/power_save_plan.go @@ -7,17 +7,17 @@ package power import ( "encoding/json" "errors" + "io/ioutil" "math" "os" "strings" "sync" "time" - "io/ioutil" gio "github.com/linuxdeepin/go-gir/gio-2.0" "github.com/linuxdeepin/go-lib/dbusutil/gsprop" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" ConfigManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/gsettings" @@ -1007,18 +1007,18 @@ func (psp *powerSavePlan) ConnectIdle() error { logger.Warning(err) return err } - err = sessionBus.Object("com.deepin.daemon.KWayland", - "/com/deepin/daemon/KWayland/Output").AddMatchSignal("com.deepin.daemon.KWayland.Idle", "IdleTimeout").Err + err = sessionBus.Object("org.deepin.dde.KWayland1", + "/org/deepin/dde/KWayland1/Output").AddMatchSignal("org.deepin.dde.KWayland1.Idle", "IdleTimeout").Err if err != nil { logger.Warning(err) return err } sessionSigLoop := dbusutil.NewSignalLoop(sessionBus, 10) sessionSigLoop.AddHandler(&dbusutil.SignalRule{ - Name: "com.deepin.daemon.KWayland.Idle.IdleTimeout", + Name: "org.deepin.dde.KWayland1.Idle.IdleTimeout", }, func(sig *dbus.Signal) { if strings.HasPrefix(string(sig.Path), - "/com/deepin/daemon/KWayland/") && + "/org/deepin/dde/KWayland1/") && len(sig.Body) == 1 { bIdle, ok := sig.Body[0].(bool) if !ok { diff --git a/session/power/power_test.go b/session/power1/power_test.go similarity index 100% rename from session/power/power_test.go rename to session/power1/power_test.go diff --git a/session/power/sleep_inhibit.go b/session/power1/sleep_inhibit.go similarity index 89% rename from session/power/sleep_inhibit.go rename to session/power1/sleep_inhibit.go index b6e6d611c..108c4fc39 100644 --- a/session/power/sleep_inhibit.go +++ b/session/power1/sleep_inhibit.go @@ -5,14 +5,13 @@ package power import ( - "github.com/linuxdeepin/dde-daemon/appearance" - "github.com/linuxdeepin/dde-daemon/network" + "github.com/linuxdeepin/dde-daemon/network1" "syscall" - "github.com/godbus/dbus" - daemon "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.daemon" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" + "github.com/godbus/dbus/v5" + daemon "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.daemon1" + ofdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.dbus" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" "github.com/linuxdeepin/go-lib/dbusutil" ) @@ -56,7 +55,7 @@ func newSleepInhibitor(login1Manager login1.Manager, daemon daemon.Daemon) *slee inhibitor.hasRunBeforeSleep = true // TODO(jouyouyun): implement 'HandleForSleep' register - appearance.HandlePrepareForSleep(true) + //appearance.HandlePrepareForSleep(true) network.HandlePrepareForSleep(true) if inhibitor.OnBeforeSuspend != nil { inhibitor.OnBeforeSuspend() @@ -83,7 +82,7 @@ func newSleepInhibitor(login1Manager login1.Manager, daemon daemon.Daemon) *slee _manager.handleWakeupDDELowPowerCheck() } network.HandlePrepareForSleep(false) - appearance.HandlePrepareForSleep(false) + //appearance.HandlePrepareForSleep(false) err := inhibitor.block() if err != nil { logger.Warning(err) diff --git a/session/power/submodule.go b/session/power1/submodule.go similarity index 100% rename from session/power/submodule.go rename to session/power1/submodule.go diff --git a/session/power/sync_config.go b/session/power1/sync_config.go similarity index 100% rename from session/power/sync_config.go rename to session/power1/sync_config.go diff --git a/session/power1/utils.go b/session/power1/utils.go new file mode 100644 index 000000000..7b998b94b --- /dev/null +++ b/session/power1/utils.go @@ -0,0 +1,711 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package power + +import ( + "io/ioutil" + "math" + "os/exec" + "strings" + "time" + + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-api/soundutils" + . "github.com/linuxdeepin/go-lib/gettext" + "github.com/linuxdeepin/go-lib/gsettings" + "github.com/linuxdeepin/go-lib/pulse" + "github.com/linuxdeepin/go-x11-client/ext/dpms" +) + +const ( + dpmsStateOn int32 = iota + dpmsStateStandBy + dpmsStateSuspend + dpmsStateOff +) + +func (m *Manager) waitLockShowing(timeout time.Duration) { + ticker := time.NewTicker(time.Millisecond * 300) + timer := time.NewTimer(timeout) + for { + select { + case _, ok := <-ticker.C: + if !ok { + logger.Error("Invalid ticker event") + return + } + + logger.Debug("waitLockShowing tick") + locked, err := m.helper.SessionManager.Locked().Get(0) + if err != nil { + logger.Warning(err) + continue + } + if locked { + logger.Debug("waitLockShowing found") + ticker.Stop() + return + } + + case <-timer.C: + logger.Debug("waitLockShowing failed timeout!") + ticker.Stop() + return + } + } +} + +func (m *Manager) lockWaitShow(timeout time.Duration, autoStartAuth bool) { + m.doLock(autoStartAuth) + if m.UseWayland { + logger.Debug("In wayland environment, unsupported check lock whether showin") + return + } + m.waitLockShowing(timeout) +} + +func (m *Manager) isWmBlackScreenActive() bool { + bus, err := dbus.SessionBus() + if err == nil { + kwinInter := bus.Object("org.kde.KWin", "/BlackScreen") + var active bool + err = kwinInter.Call("org.kde.kwin.BlackScreen.getActive", + dbus.FlagNoAutoStart).Store(&active) + if err != nil { + logger.Warning("failed to get kwin blackscreen effect active:", err) + return false + } + return active + } else { + return false + } +} + +func (m *Manager) setWmBlackScreenActive(active bool) { + if m.delayInActive { + return + } + + logger.Info("set blackScreen effect active: ", active) + bus, err := dbus.SessionBus() + if err == nil { + kwinInter := bus.Object("org.kde.KWin", "/BlackScreen") + err = kwinInter.Call("org.kde.kwin.BlackScreen.setActive", 0, active).Err + if err != nil { + logger.Warning("set blackScreen active failed:", err) + } + } +} + +func (m *Manager) setDDEBlackScreenActive(active bool) { + if m.delayInActive { + return + } + + if !m.SleepLock.Get() { + logger.Info("setDDEBlackScreenActive GSettings of sleep-lock is false, Not use dde black widget") + return + } + + logger.Info("set blackScreen effect active: ", active) + bus, err := dbus.SessionBus() + if err == nil { + dbusObject := bus.Object("com.deepin.dde.BlackScreen", "/com/deepin/dde/BlackScreen") + err = dbusObject.Call("com.deepin.dde.BlackScreen.setActive", 0, active).Err + if err != nil { + logger.Warning("set blackScreen active failed:", err) + } + } + + blackscreenCmd := "dbus-send --print-reply --dest=org.kde.KWin /BlackScreen org.kde.kwin.BlackScreen.setActive boolean:" + if active { + blackscreenCmd = blackscreenCmd + "true" + } else { + blackscreenCmd = blackscreenCmd + "false" + } + cmd := exec.Command("/bin/bash", "-c", blackscreenCmd) + err = cmd.Run() + if err != nil { + logger.Warning("Set wm blackscreen failed", err) + } +} + +func (m *Manager) getDPMSMode() int32 { + logger.Debug("get DPMS Mode") + + var err error + var mode int32 + + if m.UseWayland { + mode, err = m.getDpmsModeByKwin() + } else { + var dpmsInfo *dpms.InfoReply + c := m.helper.xConn + dpmsInfo, err = dpms.Info(c).Reply(c) + if err != nil { + mode = int32(dpmsInfo.PowerLevel) + } + } + + if err != nil { + logger.Warning("get DPMS mode error:", err) + } + + return mode +} + +var prevTimestamp int64 + +func (m *Manager) setDPMSModeOn() { + if m.delayHandleIdleOffIntervalWhenScreenBlack == 0 { + timestamp := time.Now().UnixNano() + tmp := timestamp - prevTimestamp + logger.Debug("[setDPMSModeOn] timestamp:", prevTimestamp, timestamp, tmp) + prevTimestamp = timestamp + if tmp < 300000000 { + logger.Debug("[setDPMSModeOn] div < 300ms ignored.") + return + } + } + + logger.Info("DPMS On") + + autoWm := m.getAutoChangeDeepinWm() + if autoWm { + m.tryChangeDeepinWM() + } + + var err error + if m.UseWayland { + err = m.setDpmsModeByKwin(dpmsStateOn) + } else { + c := m.helper.xConn + err = dpms.ForceLevelChecked(c, dpms.DPMSModeOn).Check(c) + } + + if err != nil { + logger.Warning("set DPMS on error:", err) + } + + if autoWm { + m.setAutoChangeDeepinWm(false) + } +} + +func (m *Manager) setDPMSModeOff() { + logger.Info("DPMS Off") + + var err error + if m.UseWayland { + err = m.setDpmsModeByKwin(dpmsStateOff) + } else { + c := m.helper.xConn + err = dpms.ForceLevelChecked(c, dpms.DPMSModeOff).Check(c) + } + if err != nil { + logger.Warning("set DPMS off error:", err) + } + ioutil.WriteFile("/tmp/dpms-state", []byte("1"), 0644) +} + +const ( + lockFrontServiceName = "org.deepin.dde.LockFront1" + lockFrontIfc = lockFrontServiceName + lockFrontObjPath = "/org/deepin/dde/LockFront1" +) + +func (m *Manager) tryChangeDeepinWM() bool { + ret := false + count := 0 + for { + if count > 2 { + break + } + count++ + + enabled, err := m.wmDBus.CompositingEnabled().Get(0) + if err != nil { + logger.Warning("tryChangeDeepinWM get CompositingEnabled err : ", err) + continue + } + if !enabled { + err := m.wmDBus.CompositingEnabled().Set(0, true) + if err != nil { + logger.Warning("tryChangeDeepinWM set CompositingEnabled true, err :", err) + continue + } + + // dde-osd需要使用该dconfig值,true不弹该特效osd + ret = true + break + } + } + + logger.Info(" tryChangeDeepinWM ret : ", ret) + return ret +} + +func (m *Manager) doLock(autoStartAuth bool) { + locked, err := m.sessionManager.Locked().Get(0) + if err != nil { + logger.Warning(err) + } + if locked { + logger.Info("Current is locked. ignore this doLock.") + return + } + + logger.Info("Lock Screen") + bus, err := dbus.SessionBus() + if err != nil { + logger.Warning(err) + return + } + lockFrontObj := bus.Object(lockFrontServiceName, lockFrontObjPath) + err = lockFrontObj.Call(lockFrontIfc+".ShowAuth", 0, autoStartAuth).Err + if err != nil { + logger.Warning("failed to call lockFront ShowAuth:", err) + } +} + +func (m *Manager) canSuspend() bool { + can, err := m.helper.SessionManager.CanSuspend(0) + if err != nil { + logger.Warning(err) + return false + } + return can +} + +func (m *Manager) doSuspend() { + if !m.canSuspend() { + logger.Info("can not suspend") + return + } + + logger.Debug("suspend") + err := m.helper.SessionManager.RequestSuspend(0) + if err != nil { + logger.Warning("failed to suspend:", err) + } +} + +// 为了处理待机闪屏的问题,通过前端进行待机,前端会在待机前显示一个纯黑的界面 +func (m *Manager) doSuspendByFront() { + if !m.canSuspend() { + logger.Info("can not suspend") + return + } + + logger.Debug("suspend") + err := m.helper.ShutdownFront.Suspend(0) + if err != nil { + logger.Warning("failed to suspend:", err) + } +} + +func (m *Manager) canShutdown() bool { + can, err := m.helper.SessionManager.CanShutdown(0) + if err != nil { + logger.Warning(err) + return false + } + return can +} + +// 正常关机流程,存在 block or delay shutdown 或多用户时,显示shutdown界面,其他情况,直接关机 +func (m *Manager) doShutdown() { + if m.hasShutdownInhibit() || m.hasMultipleDisplaySession() { + logger.Info("exist shutdown inhibit(delay or block) or multiple display session") + err := m.ddeShutdown.Shutdown(0) + if err != nil { + logger.Warning(err) + } + } else { + logger.Debug("Shutdown") + err := m.helper.SessionManager.RequestShutdown(0) + if err != nil { + logger.Warning("failed to Shutdown:", err) + } + } +} + +func (m *Manager) hasShutdownInhibit() bool { + // 先检查是否有delay 或 block shutdown的inhibitor + inhibitors, err := m.objLogin.ListInhibitors(0) + if err != nil { + logger.Warning("failed to call login ListInhibitors:", err) + } else { + for _, inhibit := range inhibitors { + logger.Infof("inhibit is: %+v", inhibit) + if strings.Contains(inhibit.What, "shutdown") { + return true + } + } + } + return false +} + +// 定时关机流程: 存在block关机项时,显示shutdown界面,无block时,直接关机,delay情况进行延迟关机 +func (m *Manager) doAutoShutdown() { + if m.hasShutdownBlock() { + logger.Warning("Shutdown") + err := m.ddeShutdown.Shutdown(0) + if err != nil { + logger.Warning(err) + } + } else { + logger.Warning("Shutdown") + err := m.helper.SessionManager.RequestShutdown(0) + // m.lastShutdownTime = time.Now().Unix() + // m.savePowerDsgConfig(dsettingLastShutdownTime) + if err != nil { + logger.Warning("failed to Shutdown:", err) + } + } +} + +func (m *Manager) hasShutdownBlock() bool { + // 检查是否有block shutdown的inhibitor + inhibitors, err := m.objLogin.ListInhibitors(0) + if err != nil { + logger.Warning("failed to call login ListInhibitors:", err) + } else { + for _, inhibit := range inhibitors { + logger.Infof("inhibit is: %+v", inhibit) + if strings.Contains(inhibit.What, "shutdown") && inhibit.Mode == "block" { + logger.Info("exist shutdown block") + return true + } + } + } + return false +} + +func (m *Manager) hasMultipleDisplaySession() bool { + // 检查是否有多个图形session,有多个图形session就需要显示阻塞界面 + sessions, err := m.displayManager.Sessions().Get(0) + if err != nil { + logger.Warning(err) + return false + } + return len(sessions) >= 2 +} + +func (m *Manager) canHibernate() bool { + can, err := m.helper.SessionManager.CanHibernate(0) + if err != nil { + logger.Warning(err) + return false + } + return can +} + +func (m *Manager) doHibernate() { + if !m.canHibernate() { + logger.Info("can not hibernate") + return + } + logger.Debug("hibernate") + err := m.helper.SessionManager.RequestHibernate(0) + if err != nil { + logger.Warning("failed to hibernate:", err) + } +} + +func (m *Manager) doHibernateByFront() { + if !m.canHibernate() { + logger.Info("can not hibernate") + return + } + + logger.Debug("hibernate") + err := m.helper.ShutdownFront.Hibernate(0) + if err != nil { + logger.Warning("failed to hibernate:", err) + } +} + +func (m *Manager) doTurnOffScreen() { + if m.ScreenBlackLock.Get() { + logger.Info("Show lock") + m.doLock(true) + time.Sleep(1 * time.Second) + } + + logger.Info("Turn off screen") + m.setDPMSModeOff() +} + +func (m *Manager) setDisplayBrightness(brightnessTable map[string]float64) { + display := m.helper.Display + for output, brightness := range brightnessTable { + logger.Infof("Change output %q brightness to %.2f", output, brightness) + err := display.SetBrightness(0, output, brightness) + if err != nil { + logger.Warningf("Change output %q brightness to %.2f failed: %v", output, brightness, err) + } else { + logger.Infof("Change output %q brightness to %.2f done!", output, brightness) + } + } +} + +func (m *Manager) setAndSaveDisplayBrightness(brightnessTable map[string]float64) { + display := m.helper.Display + for output, brightness := range brightnessTable { + logger.Infof("Change output %q brightness to %.2f", output, brightness) + err := display.SetAndSaveBrightness(0, output, brightness) + if err != nil { + logger.Warningf("Change output %q brightness to %.2f failed: %v", output, brightness, err) + } else { + logger.Infof("Change output %q brightness to %.2f done!", output, brightness) + } + } +} + +func doShowDDELowPower() { + logger.Info("Show dde low power") + go func() { + err := exec.Command(cmdDDELowPower, "--raise").Run() + if err != nil { + logger.Warning(err) + } + }() +} + +func doCloseDDELowPower() { + logger.Info("Close low power") + go func() { + err := exec.Command(cmdDDELowPower, "--quit").Run() + if err != nil { + logger.Warning(err) + } + }() +} + +func (m *Manager) sendNotify(icon, summary, body string) { + if !m.LowPowerNotifyEnable.Get() { + logger.Info("notify switch is off ") + return + } + n := m.helper.Notifications + _, err := n.Notify(0, "dde-control-center", 0, icon, summary, body, nil, nil, -1) + if err != nil { + logger.Warning(err) + } +} + +func (m *Manager) sendChangeNotify(icon, summary, body string) { + n := m.helper.Notifications + _, err := n.Notify(0, "dde-control-center", 0, icon, summary, body, nil, nil, -1) + if err != nil { + logger.Warning(err) + } +} + +const iconBatteryLow = "notification-battery-low" + +func playSound(name string) { + logger.Debug("play system sound", name) + go func() { + err := soundutils.PlaySystemSound(name, "") + if err != nil { + logger.Warning(err) + } + }() +} + +const ( + deepinScreensaverDBusServiceName = "com.deepin.ScreenSaver" + deepinScreensaverDBusPath = "/com/deepin/ScreenSaver" + deepinScreensaverDBusInterface = deepinScreensaverDBusServiceName +) + +func startScreensaver() { + logger.Info("start screensaver") + bus, err := dbus.SessionBus() + if err != nil { + logger.Warning(err) + return + } + + obj := bus.Object(deepinScreensaverDBusServiceName, deepinScreensaverDBusPath) + err = obj.Call(deepinScreensaverDBusInterface+".Start", 0).Err + if err != nil { + logger.Warning(err) + } +} + +func stopScreensaver() { + logger.Info("stop screensaver") + bus, err := dbus.SessionBus() + if err != nil { + logger.Warning(err) + return + } + + obj := bus.Object(deepinScreensaverDBusServiceName, deepinScreensaverDBusPath) + err = obj.Call(deepinScreensaverDBusInterface+".Stop", 0).Err + if err != nil { + logger.Warning(err) + } +} + +// TODO(jouyouyun): move to common library +func suspendPulseSinks(suspend int) { + var ctx = pulse.GetContext() + if ctx == nil { + logger.Error("Failed to connect pulseaudio server") + return + } + for _, sink := range ctx.GetSinkList() { + ctx.SuspendSinkById(sink.Index, suspend) + } +} + +// TODO(jouyouyun): move to common library +func suspendPulseSources(suspend int) { + var ctx = pulse.GetContext() + if ctx == nil { + logger.Error("Failed to connect pulseaudio server") + return + } + for _, source := range ctx.GetSourceList() { + ctx.SuspendSourceById(source.Index, suspend) + } +} + +func (m *Manager) initGSettingsConnectChanged() { + const powerSettingsIcon = "preferences-system" + + isIllegalAction := func(action int32) bool { + return (action == powerActionHibernate && !m.canHibernate()) || + (action == powerActionSuspend && !m.canSuspend()) + } + + // 监听 session power 的属性的改变,并发送通知 + gsettings.ConnectChanged(gsSchemaPower, "*", func(key string) { + logger.Debug("Power Settings Changed :", key) + switch key { + case settingKeyLinePowerLidClosedAction: + value := m.LinePowerLidClosedAction.Get() + if isIllegalAction(value) { + break + } + case settingKeyLinePowerPressPowerBtnAction: + value := m.LinePowerPressPowerBtnAction.Get() + if isIllegalAction(value) { + break + } + case settingKeyBatteryLidClosedAction: + value := m.BatteryLidClosedAction.Get() + if isIllegalAction(value) { + break + } + case settingKeyBatteryPressPowerBtnAction: + value := m.BatteryPressPowerBtnAction.Get() + if isIllegalAction(value) { + break + } + case settingKeyHighPerformanceEnabled: + // 根据systemPower::IsHighPerformanceEnabled GSetting::settingKeyHighPerformanceEnabled + bSettingKeyHighPerformanceEnabled := m.settings.GetBoolean(settingKeyHighPerformanceEnabled) + if bSettingKeyHighPerformanceEnabled == m.gsHighPerformanceEnabled { + return + } + m.gsHighPerformanceEnabled = bSettingKeyHighPerformanceEnabled + isHighPerformanceSupported, _ := m.systemPower.IsHighPerformanceSupported().Get(0) + m.setPropIsHighPerformanceSupported(isHighPerformanceSupported && bSettingKeyHighPerformanceEnabled) + } + }) +} + +func getPowerActionString(action int32) string { + switch action { + case powerActionShutdown: + return Tr("your computer will shut down") + case powerActionSuspend: + return Tr("your computer will suspend") + case powerActionHibernate: + return Tr("your computer will hibernate") + case powerActionTurnOffScreen: + return Tr("your monitor will turn off") + case powerActionShowShutdownInterface: + return Tr("your monitor will show the shutdown interface") + case powerActionDoNothing: + return Tr("it will do nothing to your computer") + } + return "" +} + +func isFloatEqual(f1, f2 float64) bool { + return math.Abs(f1-f2) < 1e-6 +} + +func (m *Manager) getDpmsList() ([]dbus.Variant, error) { + sessionBus := m.sessionSigLoop.Conn() + sessionObj := sessionBus.Object("org.deepin.dde.KWayland1", "/org/deepin/dde/KWayland1/DpmsManager") + var ret []dbus.Variant + err := sessionObj.Call("org.deepin.dde.KWayland1.DpmsManager.dpmsList", 0).Store(&ret) + if err != nil { + logger.Warning(err) + return nil, err + } + + return ret, nil +} + +func (m *Manager) getDpmsModeByKwin() (int32, error) { + list, err := m.getDpmsList() + if err != nil { + logger.Warning(err) + return dpmsStateOn, err + } + + var dpmsMode int32 + for i := 0; i < len(list); i++ { + v := list[i].Value().(string) + sessionObj := m.sessionSigLoop.Conn().Object("org.deepin.dde.KWayland1", dbus.ObjectPath(v)) + err = sessionObj.Call("org.deepin.dde.KWayland1.Dpms.getDpmsMode", 0).Store(&dpmsMode) + if err != nil { + logger.Warning(err) + return dpmsStateOn, err + } + } + + return dpmsMode, nil +} + +func (m *Manager) setDpmsModeByKwin(mode int32) error { + list, err := m.getDpmsList() + if err != nil { + logger.Warning(err) + return err + } + + for i := 0; i < len(list); i++ { + v := list[i].Value().(string) + sessionObj := m.sessionSigLoop.Conn().Object("org.deepin.dde.KWayland1", dbus.ObjectPath(v)) + err = sessionObj.Call("org.deepin.dde.KWayland1.Dpms.setDpmsMode", 0, int32(mode)).Err + if err != nil { + logger.Warning(err) + return err + } + } + + return nil +} + +func byteSliceEqual(v1, v2 []byte) bool { + if len(v1) != len(v2) { + return false + } + for i, e1 := range v1 { + if e1 != v2[i] { + return false + } + } + return true +} diff --git a/session/power/warn_level.go b/session/power1/warn_level.go similarity index 100% rename from session/power/warn_level.go rename to session/power1/warn_level.go diff --git a/session/power/warn_level_config.go b/session/power1/warn_level_config.go similarity index 99% rename from session/power/warn_level_config.go rename to session/power1/warn_level_config.go index c0178d6ef..78ab1396f 100644 --- a/session/power/warn_level_config.go +++ b/session/power1/warn_level_config.go @@ -7,7 +7,7 @@ package power import ( "time" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" gio "github.com/linuxdeepin/go-gir/gio-2.0" "github.com/linuxdeepin/go-lib/dbusutil/gsprop" "github.com/linuxdeepin/go-lib/gsettings" @@ -31,7 +31,6 @@ func (c *warnLevelConfig) isValid() bool { if c.LowTime > c.DangerTime && c.DangerTime > c.CriticalTime && c.CriticalTime > c.ActionTime && - c.remindPercentage > c.LowPercentage && c.LowPercentage > c.DangerPercentage && c.DangerPercentage > c.CriticalPercentage && diff --git a/session/uadpagent/module.go b/session/uadpagent/module.go deleted file mode 100644 index ba69bc3ca..000000000 --- a/session/uadpagent/module.go +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package uadpagent - -import ( - "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/dde-daemon/loader" -) - -func init() { - loader.Register(NewModule(logger)) -} - -type Module struct { - uAgent *UadpAgent - *loader.ModuleBase -} - -func NewModule(logger *log.Logger) *Module { - m := new(Module) - m.ModuleBase = loader.NewModuleBase("uadpagent", m, logger) - return m -} - -func (m *Module) GetDependencies() []string { - return []string{} -} - -func (m *Module) Start() error { - // service := loader.GetService() - - // if m.uAgent != nil { - // return nil - // } - - // var err error - // m.uAgent, err = newUadpAgent(service) - // if err != nil { - // logger.Warning("failed to newUadpAgent:", err) - // return err - // } - - // err = service.Export(dbusPath, m.uAgent) - // if err != nil { - // logger.Warning("failed to Export uAgent:", err) - // return err - // } - - // err = service.RequestName(dbusServiceName) - // if err != nil { - // logger.Warning("failed to RequestName:", err) - // return err - // } - - return nil -} - -func (m *Module) Stop() error { - if m.uAgent == nil { - return nil - } - - service := loader.GetService() - err := service.ReleaseName(dbusServiceName) - if err != nil { - logger.Warning("failed to releaseName:", err) - } - - err = service.StopExport(m.uAgent) - if err != nil { - logger.Warning("failed to stopExport:", err) - } - m.uAgent = nil - - return nil -} diff --git a/session/uadpagent/exported_methods_auto.go b/session/uadpagent1/exported_methods_auto.go similarity index 100% rename from session/uadpagent/exported_methods_auto.go rename to session/uadpagent1/exported_methods_auto.go diff --git a/session/uadpagent1/module.go b/session/uadpagent1/module.go new file mode 100644 index 000000000..2b525910e --- /dev/null +++ b/session/uadpagent1/module.go @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package uadpagent + +import ( + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" +) + +func init() { + loader.Register(NewModule(logger)) +} + +type Module struct { + uAgent *UadpAgent + *loader.ModuleBase +} + +func NewModule(logger *log.Logger) *Module { + m := new(Module) + m.ModuleBase = loader.NewModuleBase("uadpagent", m, logger) + return m +} + +func (m *Module) GetDependencies() []string { + return []string{} +} + +func (m *Module) Start() error { + // service := loader.GetService() + + // if m.uAgent != nil { + // return nil + // } + + // var err error + // m.uAgent, err = newUadpAgent(service) + // if err != nil { + // logger.Warning("failed to newUadpAgent:", err) + // return err + // } + + // err = service.Export(dbusPath, m.uAgent) + // if err != nil { + // logger.Warning("failed to Export uAgent:", err) + // return err + // } + + // err = service.RequestName(dbusServiceName) + // if err != nil { + // logger.Warning("failed to RequestName:", err) + // return err + // } + + return nil +} + +func (m *Module) Stop() error { + if m.uAgent == nil { + return nil + } + + service := loader.GetService() + err := service.ReleaseName(dbusServiceName) + if err != nil { + logger.Warning("failed to releaseName:", err) + } + + err = service.StopExport(m.uAgent) + if err != nil { + logger.Warning("failed to stopExport:", err) + } + m.uAgent = nil + + return nil +} diff --git a/session/uadpagent/uadpagent.go b/session/uadpagent1/uadpagent.go similarity index 96% rename from session/uadpagent/uadpagent.go rename to session/uadpagent1/uadpagent.go index 06a831b3f..997eaf3d3 100644 --- a/session/uadpagent/uadpagent.go +++ b/session/uadpagent1/uadpagent.go @@ -12,13 +12,13 @@ import ( "os" "sync" - dbus "github.com/godbus/dbus" - uadp "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.uadp" - secrets "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.secrets" + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/session/common" + secrets "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.secrets" + uadp "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.uadp1" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/log" "github.com/linuxdeepin/go-lib/procfs" - "github.com/linuxdeepin/dde-daemon/session/common" ) //go:generate dbusutil-gen em -type UadpAgent @@ -26,8 +26,8 @@ import ( var logger = log.NewLogger("daemon/session/UadpAgent") const ( - dbusServiceName = "com.deepin.daemon.UadpAgent" - dbusPath = "/com/deepin/daemon/UadpAgent" + dbusServiceName = "org.deepin.dde.UadpAgent1" + dbusPath = "/org/deepin/dde/UadpAgent1" dbusInterface = dbusServiceName ) diff --git a/sessionwatcher/manager.go b/sessionwatcher/manager.go deleted file mode 100644 index 5e4e340bb..000000000 --- a/sessionwatcher/manager.go +++ /dev/null @@ -1,311 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package sessionwatcher - -import ( - "sync" - - "github.com/godbus/dbus" - libdisplay "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.display" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/dbusutil/proxy" -) - -//go:generate dbusutil-gen em -type Manager - -const ( - dbusServiceName = "com.deepin.daemon.SessionWatcher" - dbusPath = "/com/deepin/daemon/SessionWatcher" - dbusInterface = dbusServiceName -) - -type Manager struct { - service *dbusutil.Service - display libdisplay.Display - loginManager login1.Manager - systemSigLoop *dbusutil.SignalLoop - mu sync.Mutex - sessions map[string]login1.Session - activeSessionType string - - PropsMu sync.RWMutex - IsActive bool -} - -var ( - _validSessionList = []string{ - "x11", - "wayland", - } -) - -func newManager(service *dbusutil.Service) (*Manager, error) { - manager := &Manager{ - service: service, - sessions: make(map[string]login1.Session), - } - systemConn, err := dbus.SystemBus() - if err != nil { - return nil, err - } - sessionConn := service.Conn() - manager.loginManager = login1.NewManager(systemConn) - manager.display = libdisplay.NewDisplay(sessionConn) - - manager.systemSigLoop = dbusutil.NewSignalLoop(systemConn, 10) - manager.systemSigLoop.Start() - manager.loginManager.InitSignalExt(manager.systemSigLoop, true) - - // default as active - manager.IsActive = true - return manager, nil -} - -func (m *Manager) destroy() { - m.mu.Lock() - for _, session := range m.sessions { - session.RemoveHandler(proxy.RemoveAllHandlers) - } - m.mu.Unlock() - - m.loginManager.RemoveHandler(proxy.RemoveAllHandlers) - m.systemSigLoop.Stop() -} - -func (*Manager) GetInterfaceName() string { - return dbusInterface -} - -func (m *Manager) initUserSessions() { - sessions, err := m.loginManager.ListSessions(0) - if err != nil { - logger.Warning("List sessions failed:", err) - return - } - - for _, session := range sessions { - m.addSession(session.SessionId, session.Path) - } - m.handleSessionChanged() - _, err = m.loginManager.ConnectSessionNew(func(id string, path dbus.ObjectPath) { - logger.Debug("Session added:", id, path) - m.addSession(id, path) - m.handleSessionChanged() - }) - if err != nil { - logger.Warning("ConnectSessionNew error:", err) - } - - _, err = m.loginManager.ConnectSessionRemoved(func(id string, path dbus.ObjectPath) { - logger.Debug("Session removed:", id, path) - m.deleteSession(id, path) - m.handleSessionChanged() - }) - if err != nil { - logger.Warning("ConnectSessionRemoved error:", err) - } -} - -func (m *Manager) addSession(id string, path dbus.ObjectPath) { - systemConn := m.systemSigLoop.Conn() - session, err := login1.NewSession(systemConn, path) - if err != nil { - logger.Warning(err) - return - } - - userInfo, err := session.User().Get(0) - if err != nil { - logger.Warning(err) - return - } - - uid := userInfo.UID - logger.Debug("Add session:", id, path, uid) - if !isCurrentUser(uid) { - logger.Debug("Not the current user session:", id, path, uid) - return - } - remote, err := session.Remote().Get(0) - if err != nil { - logger.Warning(err) - return - } - if remote { - logger.Debugf("session %v is remote", id) - return - } - - m.mu.Lock() - m.sessions[id] = session - m.mu.Unlock() - - session.InitSignalExt(m.systemSigLoop, true) - err = session.Active().ConnectChanged(func(hasValue bool, value bool) { - m.handleSessionChanged() - }) - if err != nil { - logger.Warning("ConnectChanged error:", err) - } -} - -func (m *Manager) deleteSession(id string, path dbus.ObjectPath) { - m.mu.Lock() - session, ok := m.sessions[id] - if !ok { - m.mu.Unlock() - return - } - - session.RemoveHandler(proxy.RemoveAllHandlers) - logger.Debug("Delete session:", id, path) - delete(m.sessions, id) - m.mu.Unlock() -} - -func (m *Manager) handleSessionChanged() { - m.mu.Lock() - defer m.mu.Unlock() - if len(m.sessions) == 0 { - return - } - - session := m.getActiveSession() - var isActive bool - var sessionType string - if session != nil { - isActive = true - var err error - sessionType, err = session.Type().Get(0) - if err != nil { - logger.Warning(err) - } - } - - m.activeSessionType = sessionType - m.PropsMu.Lock() - changed := m.setIsActive(isActive) - m.PropsMu.Unlock() - if !changed { - return - } - - if isActive { - logger.Debug("[handleSessionChanged] Resume pulse") - // fixed block when unused pulse-audio - go suspendPulseSinks(0) - go suspendPulseSources(0) - - logger.Debug("[handleSessionChanged] Refresh Brightness") - go func() { - _ = m.display.RefreshBrightness(0) - }() - } else { - logger.Debug("[handleSessionChanged] Suspend pulse") - go suspendPulseSinks(1) - go suspendPulseSources(1) - } -} - -// return is changed? -func (m *Manager) setIsActive(val bool) bool { - if m.IsActive != val { - m.IsActive = val - logger.Debug("[setIsActive] IsActive changed:", val) - err := m.service.EmitPropertyChanged(m, "IsActive", val) - if err != nil { - logger.Warning("EmitPropertyChanged error:", err) - } - return true - } - return false -} - -func (m *Manager) getActiveSession() login1.Session { - for _, session := range m.sessions { - seatInfo, err := session.Seat().Get(0) - if err != nil { - logger.Warning(err) - continue - } - - if seatInfo.Id != "" && seatInfo.Path != "/" { - active, err := session.Active().Get(0) - if err != nil { - logger.Warning(err) - continue - } - if active { - return session - } - } - } - return nil -} - -func (m *Manager) IsX11SessionActive(sender dbus.Sender) (active bool, busErr *dbus.Error) { - // 从login1获取当前登录的用户是否激活 - pid, err := m.service.GetConnPID(string(sender)) - if err != nil { - logger.Warning(err) - return false, dbusutil.ToError(err) - } - - service, err := dbusutil.NewSystemService() - if err != nil { - logger.Warning(err) - return false, dbusutil.ToError(err) - } - - login1Manager := login1.NewManager(service.Conn()) - userObjectPath, err := login1Manager.GetUserByPID(0, pid) - if err != nil { - logger.Warning(err) - return false, dbusutil.ToError(err) - } - - userDbus, err := login1.NewUser(service.Conn(), userObjectPath) - if err != nil { - logger.Warning(err) - return false, dbusutil.ToError(err) - } - - sessionInfo, err := userDbus.Display().Get(0) - if err != nil { - logger.Warning(err) - return false, dbusutil.ToError(err) - } - - session, err := login1.NewSession(service.Conn(), sessionInfo.Path) - if err != nil { - logger.Warning(err) - return false, dbusutil.ToError(err) - } - - isActive, err := session.Active().Get(0) - if err != nil { - logger.Warning(err) - return false, dbusutil.ToError(err) - } - - if isActive { - return true, nil - } - - return false, nil -} - -func (m *Manager) GetSessions() (sessions []dbus.ObjectPath, err *dbus.Error) { - m.mu.Lock() - sessions = make([]dbus.ObjectPath, len(m.sessions)) - i := 0 - for _, session := range m.sessions { - sessions[i] = session.Path_() - i++ - } - m.mu.Unlock() - return -} diff --git a/sessionwatcher/exported_methods_auto.go b/sessionwatcher1/exported_methods_auto.go similarity index 100% rename from sessionwatcher/exported_methods_auto.go rename to sessionwatcher1/exported_methods_auto.go diff --git a/sessionwatcher1/manager.go b/sessionwatcher1/manager.go new file mode 100644 index 000000000..485e6496b --- /dev/null +++ b/sessionwatcher1/manager.go @@ -0,0 +1,311 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package sessionwatcher + +import ( + "sync" + + "github.com/godbus/dbus/v5" + libdisplay "github.com/linuxdeepin/go-dbus-factory/session/org.deepin.dde.display1" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/dbusutil/proxy" +) + +//go:generate dbusutil-gen em -type Manager + +const ( + dbusServiceName = "org.deepin.dde.SessionWatcher1" + dbusPath = "/org/deepin/dde/SessionWatcher1" + dbusInterface = dbusServiceName +) + +type Manager struct { + service *dbusutil.Service + display libdisplay.Display + loginManager login1.Manager + systemSigLoop *dbusutil.SignalLoop + mu sync.Mutex + sessions map[string]login1.Session + activeSessionType string + + PropsMu sync.RWMutex + IsActive bool +} + +var ( + _validSessionList = []string{ + "x11", + "wayland", + } +) + +func newManager(service *dbusutil.Service) (*Manager, error) { + manager := &Manager{ + service: service, + sessions: make(map[string]login1.Session), + } + systemConn, err := dbus.SystemBus() + if err != nil { + return nil, err + } + sessionConn := service.Conn() + manager.loginManager = login1.NewManager(systemConn) + manager.display = libdisplay.NewDisplay(sessionConn) + + manager.systemSigLoop = dbusutil.NewSignalLoop(systemConn, 10) + manager.systemSigLoop.Start() + manager.loginManager.InitSignalExt(manager.systemSigLoop, true) + + // default as active + manager.IsActive = true + return manager, nil +} + +func (m *Manager) destroy() { + m.mu.Lock() + for _, session := range m.sessions { + session.RemoveHandler(proxy.RemoveAllHandlers) + } + m.mu.Unlock() + + m.loginManager.RemoveHandler(proxy.RemoveAllHandlers) + m.systemSigLoop.Stop() +} + +func (*Manager) GetInterfaceName() string { + return dbusInterface +} + +func (m *Manager) initUserSessions() { + sessions, err := m.loginManager.ListSessions(0) + if err != nil { + logger.Warning("List sessions failed:", err) + return + } + + for _, session := range sessions { + m.addSession(session.SessionId, session.Path) + } + m.handleSessionChanged() + _, err = m.loginManager.ConnectSessionNew(func(id string, path dbus.ObjectPath) { + logger.Debug("Session added:", id, path) + m.addSession(id, path) + m.handleSessionChanged() + }) + if err != nil { + logger.Warning("ConnectSessionNew error:", err) + } + + _, err = m.loginManager.ConnectSessionRemoved(func(id string, path dbus.ObjectPath) { + logger.Debug("Session removed:", id, path) + m.deleteSession(id, path) + m.handleSessionChanged() + }) + if err != nil { + logger.Warning("ConnectSessionRemoved error:", err) + } +} + +func (m *Manager) addSession(id string, path dbus.ObjectPath) { + systemConn := m.systemSigLoop.Conn() + session, err := login1.NewSession(systemConn, path) + if err != nil { + logger.Warning(err) + return + } + + userInfo, err := session.User().Get(0) + if err != nil { + logger.Warning(err) + return + } + + uid := userInfo.UID + logger.Debug("Add session:", id, path, uid) + if !isCurrentUser(uid) { + logger.Debug("Not the current user session:", id, path, uid) + return + } + remote, err := session.Remote().Get(0) + if err != nil { + logger.Warning(err) + return + } + if remote { + logger.Debugf("session %v is remote", id) + return + } + + m.mu.Lock() + m.sessions[id] = session + m.mu.Unlock() + + session.InitSignalExt(m.systemSigLoop, true) + err = session.Active().ConnectChanged(func(hasValue bool, value bool) { + m.handleSessionChanged() + }) + if err != nil { + logger.Warning("ConnectChanged error:", err) + } +} + +func (m *Manager) deleteSession(id string, path dbus.ObjectPath) { + m.mu.Lock() + session, ok := m.sessions[id] + if !ok { + m.mu.Unlock() + return + } + + session.RemoveHandler(proxy.RemoveAllHandlers) + logger.Debug("Delete session:", id, path) + delete(m.sessions, id) + m.mu.Unlock() +} + +func (m *Manager) handleSessionChanged() { + m.mu.Lock() + defer m.mu.Unlock() + if len(m.sessions) == 0 { + return + } + + session := m.getActiveSession() + var isActive bool + var sessionType string + if session != nil { + isActive = true + var err error + sessionType, err = session.Type().Get(0) + if err != nil { + logger.Warning(err) + } + } + + m.activeSessionType = sessionType + m.PropsMu.Lock() + changed := m.setIsActive(isActive) + m.PropsMu.Unlock() + if !changed { + return + } + + if isActive { + logger.Debug("[handleSessionChanged] Resume pulse") + // fixed block when unused pulse-audio + go suspendPulseSinks(0) + go suspendPulseSources(0) + + logger.Debug("[handleSessionChanged] Refresh Brightness") + go func() { + _ = m.display.RefreshBrightness(0) + }() + } else { + logger.Debug("[handleSessionChanged] Suspend pulse") + go suspendPulseSinks(1) + go suspendPulseSources(1) + } +} + +// return is changed? +func (m *Manager) setIsActive(val bool) bool { + if m.IsActive != val { + m.IsActive = val + logger.Debug("[setIsActive] IsActive changed:", val) + err := m.service.EmitPropertyChanged(m, "IsActive", val) + if err != nil { + logger.Warning("EmitPropertyChanged error:", err) + } + return true + } + return false +} + +func (m *Manager) getActiveSession() login1.Session { + for _, session := range m.sessions { + seatInfo, err := session.Seat().Get(0) + if err != nil { + logger.Warning(err) + continue + } + + if seatInfo.Id != "" && seatInfo.Path != "/" { + active, err := session.Active().Get(0) + if err != nil { + logger.Warning(err) + continue + } + if active { + return session + } + } + } + return nil +} + +func (m *Manager) IsX11SessionActive(sender dbus.Sender) (active bool, busErr *dbus.Error) { + // 从login1获取当前登录的用户是否激活 + pid, err := m.service.GetConnPID(string(sender)) + if err != nil { + logger.Warning(err) + return false, dbusutil.ToError(err) + } + + service, err := dbusutil.NewSystemService() + if err != nil { + logger.Warning(err) + return false, dbusutil.ToError(err) + } + + login1Manager := login1.NewManager(service.Conn()) + userObjectPath, err := login1Manager.GetUserByPID(0, pid) + if err != nil { + logger.Warning(err) + return false, dbusutil.ToError(err) + } + + userDbus, err := login1.NewUser(service.Conn(), userObjectPath) + if err != nil { + logger.Warning(err) + return false, dbusutil.ToError(err) + } + + sessionInfo, err := userDbus.Display().Get(0) + if err != nil { + logger.Warning(err) + return false, dbusutil.ToError(err) + } + + session, err := login1.NewSession(service.Conn(), sessionInfo.Path) + if err != nil { + logger.Warning(err) + return false, dbusutil.ToError(err) + } + + isActive, err := session.Active().Get(0) + if err != nil { + logger.Warning(err) + return false, dbusutil.ToError(err) + } + + if isActive { + return true, nil + } + + return false, nil +} + +func (m *Manager) GetSessions() (sessions []dbus.ObjectPath, err *dbus.Error) { + m.mu.Lock() + sessions = make([]dbus.ObjectPath, len(m.sessions)) + i := 0 + for _, session := range m.sessions { + sessions[i] = session.Path_() + i++ + } + m.mu.Unlock() + return +} diff --git a/sessionwatcher/sessionwatcher.go b/sessionwatcher1/sessionwatcher.go similarity index 100% rename from sessionwatcher/sessionwatcher.go rename to sessionwatcher1/sessionwatcher.go index 2f5f4fc1d..aa491d57f 100644 --- a/sessionwatcher/sessionwatcher.go +++ b/sessionwatcher1/sessionwatcher.go @@ -5,8 +5,8 @@ package sessionwatcher import ( - "github.com/linuxdeepin/go-lib/log" "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" ) var ( diff --git a/sessionwatcher/utils.go b/sessionwatcher1/utils.go similarity index 100% rename from sessionwatcher/utils.go rename to sessionwatcher1/utils.go diff --git a/soundeffect/manager.go b/soundeffect/manager.go deleted file mode 100644 index 9fcc39cf3..000000000 --- a/soundeffect/manager.go +++ /dev/null @@ -1,216 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package soundeffect - -import ( - "bufio" - "bytes" - "errors" - "os/exec" - "sync" - - "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-api/soundutils" - soundthemeplayer "github.com/linuxdeepin/go-dbus-factory/com.deepin.api.soundthemeplayer" - "github.com/linuxdeepin/go-gir/gio-2.0" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/dbusutil/gsprop" - "github.com/linuxdeepin/go-lib/strv" -) - -//go:generate dbusutil-gen em -type Manager - -const ( - gsSchemaSoundEffect = "com.deepin.dde.sound-effect" - gsSchemaAppearance = "com.deepin.dde.appearance" - gsKeyEnabled = "enabled" - gsKeySoundTheme = "sound-theme" - - DBusServiceName = "com.deepin.daemon.SoundEffect" - dbusPath = "/com/deepin/daemon/SoundEffect" - dbusInterface = DBusServiceName - allowPlaySoundMaxCount = 3 -) - -type Manager struct { - service *dbusutil.Service - soundEffectGs *gio.Settings - appearanceGs *gio.Settings - count int - countMu sync.Mutex - names strv.Strv - - Enabled gsprop.Bool `prop:"access:rw"` -} - -func NewManager(service *dbusutil.Service) *Manager { - var m = new(Manager) - - m.service = service - m.soundEffectGs = gio.NewSettings(gsSchemaSoundEffect) - m.appearanceGs = gio.NewSettings(gsSchemaAppearance) - return m -} - -func (m *Manager) init() error { - m.Enabled.Bind(m.soundEffectGs, gsKeyEnabled) - var err error - m.names, err = getSoundNames() - if err != nil { - return err - } - logger.Debug(m.names) - return nil -} - -func getSoundNames() ([]string, error) { - var result []string - out, err := exec.Command("gsettings", "list-recursively", gsSchemaSoundEffect).Output() - if err != nil { - return nil, err - } - scanner := bufio.NewScanner(bytes.NewReader(out)) - for scanner.Scan() { - parts := bytes.Fields(scanner.Bytes()) - if len(parts) == 3 { - if bytes.Equal(parts[1], []byte("enabled")) { - // skip key enabled - continue - } - key := string(parts[1]) - value := parts[2] - if bytes.Equal(value, []byte("true")) || bytes.Equal(value, []byte("false")) { - result = append(result, key) - } - } - } - if scanner.Err() != nil { - return nil, scanner.Err() - } - - return result, nil -} - -func (*Manager) GetInterfaceName() string { - return dbusInterface -} - -// deprecated -func (m *Manager) PlaySystemSound(name string) *dbus.Error { - return m.PlaySound(name) -} - -func (m *Manager) PlaySound(name string) *dbus.Error { - m.service.DelayAutoQuit() - - if name == "" { - return nil - } - - go func() { - m.countMu.Lock() - m.count++ - logger.Debug("start", m.count) - m.countMu.Unlock() - - if m.count <= allowPlaySoundMaxCount { - err := soundutils.PlaySystemSound(name, "") - if err != nil { - logger.Error(err) - } - } else { - logger.Warning("PlaySystemSound thread more than 3") - } - - m.countMu.Lock() - logger.Debug("end", m.count) - m.count-- - m.countMu.Unlock() - }() - return nil -} - -// deprecated -func (m *Manager) GetSystemSoundFile(name string) (file string, busErr *dbus.Error) { - return m.GetSoundFile(name) -} - -func (m *Manager) GetSoundFile(name string) (file string, busErr *dbus.Error) { - m.service.DelayAutoQuit() - - file = soundutils.GetSystemSoundFile(name) - if file == "" { - return "", dbusutil.ToError(errors.New("sound file not found")) - } - - return file, nil -} - -func (m *Manager) canQuit() bool { - m.countMu.Lock() - count := m.count - m.countMu.Unlock() - return count == 0 -} - -func (m *Manager) syncConfigToSoundThemePlayer(name string, enabled bool) error { - logger.Debug("sync config to sound-theme-player") - sysBus, err := dbus.SystemBus() - if err != nil { - return err - } - player := soundthemeplayer.NewSoundThemePlayer(sysBus) - err = player.EnableSound(0, name, enabled) - if err != nil { - return err - } - theme := m.appearanceGs.GetString(gsKeySoundTheme) - err = player.SetSoundTheme(0, theme) - return err -} - -func (m *Manager) EnableSound(name string, enabled bool) *dbus.Error { - if !m.names.Contains(name) { - return dbusutil.ToError(errors.New("invalid sound event")) - } - - if name == soundutils.EventDesktopLogin || - name == soundutils.EventSystemShutdown { - err := m.syncConfigToSoundThemePlayer(name, enabled) - if err != nil { - return dbusutil.ToError(err) - } - } - - m.soundEffectGs.SetBoolean(name, enabled) - return nil -} - -func (m *Manager) IsSoundEnabled(name string) (enabled bool, busErr *dbus.Error) { - if !m.names.Contains(name) { - return false, dbusutil.ToError(errors.New("invalid sound event")) - } - - return m.soundEffectGs.GetBoolean(name), nil -} - -func (m *Manager) GetSoundEnabledMap() (result map[string]bool, busErr *dbus.Error) { - result = make(map[string]bool, len(m.names)) - for _, name := range m.names { - result[name] = m.soundEffectGs.GetBoolean(name) - } - return result, nil -} - -func (m *Manager) enabledWriteCb(write *dbusutil.PropertyWrite) *dbus.Error { - enabled := write.Value.(bool) - - // NOTE: 已经约定 name 为空表示控制总开关 - err := m.syncConfigToSoundThemePlayer("", enabled) - if err != nil { - logger.Warning(err) - } - return nil -} diff --git a/soundeffect/exported_methods_auto.go b/soundeffect1/exported_methods_auto.go similarity index 100% rename from soundeffect/exported_methods_auto.go rename to soundeffect1/exported_methods_auto.go diff --git a/soundeffect1/manager.go b/soundeffect1/manager.go new file mode 100644 index 000000000..a256d6176 --- /dev/null +++ b/soundeffect1/manager.go @@ -0,0 +1,216 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package soundeffect + +import ( + "bufio" + "bytes" + "errors" + "os/exec" + "sync" + + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-api/soundutils" + soundthemeplayer "github.com/linuxdeepin/go-dbus-factory/system/com.deepin.api.soundthemeplayer" + "github.com/linuxdeepin/go-gir/gio-2.0" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/dbusutil/gsprop" + "github.com/linuxdeepin/go-lib/strv" +) + +//go:generate dbusutil-gen em -type Manager + +const ( + gsSchemaSoundEffect = "com.deepin.dde.sound-effect" + gsSchemaAppearance = "com.deepin.dde.appearance" + gsKeyEnabled = "enabled" + gsKeySoundTheme = "sound-theme" + + DBusServiceName = "org.deepin.dde.SoundEffect1" + dbusPath = "/org/deepin/dde/SoundEffect1" + dbusInterface = DBusServiceName + allowPlaySoundMaxCount = 3 +) + +type Manager struct { + service *dbusutil.Service + soundEffectGs *gio.Settings + appearanceGs *gio.Settings + count int + countMu sync.Mutex + names strv.Strv + + Enabled gsprop.Bool `prop:"access:rw"` +} + +func NewManager(service *dbusutil.Service) *Manager { + var m = new(Manager) + + m.service = service + m.soundEffectGs = gio.NewSettings(gsSchemaSoundEffect) + m.appearanceGs = gio.NewSettings(gsSchemaAppearance) + return m +} + +func (m *Manager) init() error { + m.Enabled.Bind(m.soundEffectGs, gsKeyEnabled) + var err error + m.names, err = getSoundNames() + if err != nil { + return err + } + logger.Debug(m.names) + return nil +} + +func getSoundNames() ([]string, error) { + var result []string + out, err := exec.Command("gsettings", "list-recursively", gsSchemaSoundEffect).Output() + if err != nil { + return nil, err + } + scanner := bufio.NewScanner(bytes.NewReader(out)) + for scanner.Scan() { + parts := bytes.Fields(scanner.Bytes()) + if len(parts) == 3 { + if bytes.Equal(parts[1], []byte("enabled")) { + // skip key enabled + continue + } + key := string(parts[1]) + value := parts[2] + if bytes.Equal(value, []byte("true")) || bytes.Equal(value, []byte("false")) { + result = append(result, key) + } + } + } + if scanner.Err() != nil { + return nil, scanner.Err() + } + + return result, nil +} + +func (*Manager) GetInterfaceName() string { + return dbusInterface +} + +// deprecated +func (m *Manager) PlaySystemSound(name string) *dbus.Error { + return m.PlaySound(name) +} + +func (m *Manager) PlaySound(name string) *dbus.Error { + m.service.DelayAutoQuit() + + if name == "" { + return nil + } + + go func() { + m.countMu.Lock() + m.count++ + logger.Debug("start", m.count) + m.countMu.Unlock() + + if m.count <= allowPlaySoundMaxCount { + err := soundutils.PlaySystemSound(name, "") + if err != nil { + logger.Error(err) + } + } else { + logger.Warning("PlaySystemSound thread more than 3") + } + + m.countMu.Lock() + logger.Debug("end", m.count) + m.count-- + m.countMu.Unlock() + }() + return nil +} + +// deprecated +func (m *Manager) GetSystemSoundFile(name string) (file string, busErr *dbus.Error) { + return m.GetSoundFile(name) +} + +func (m *Manager) GetSoundFile(name string) (file string, busErr *dbus.Error) { + m.service.DelayAutoQuit() + + file = soundutils.GetSystemSoundFile(name) + if file == "" { + return "", dbusutil.ToError(errors.New("sound file not found")) + } + + return file, nil +} + +func (m *Manager) canQuit() bool { + m.countMu.Lock() + count := m.count + m.countMu.Unlock() + return count == 0 +} + +func (m *Manager) syncConfigToSoundThemePlayer(name string, enabled bool) error { + logger.Debug("sync config to sound-theme-player") + sysBus, err := dbus.SystemBus() + if err != nil { + return err + } + player := soundthemeplayer.NewSoundThemePlayer(sysBus) + err = player.EnableSound(0, name, enabled) + if err != nil { + return err + } + theme := m.appearanceGs.GetString(gsKeySoundTheme) + err = player.SetSoundTheme(0, theme) + return err +} + +func (m *Manager) EnableSound(name string, enabled bool) *dbus.Error { + if !m.names.Contains(name) { + return dbusutil.ToError(errors.New("invalid sound event")) + } + + if name == soundutils.EventDesktopLogin || + name == soundutils.EventSystemShutdown { + err := m.syncConfigToSoundThemePlayer(name, enabled) + if err != nil { + return dbusutil.ToError(err) + } + } + + m.soundEffectGs.SetBoolean(name, enabled) + return nil +} + +func (m *Manager) IsSoundEnabled(name string) (enabled bool, busErr *dbus.Error) { + if !m.names.Contains(name) { + return false, dbusutil.ToError(errors.New("invalid sound event")) + } + + return m.soundEffectGs.GetBoolean(name), nil +} + +func (m *Manager) GetSoundEnabledMap() (result map[string]bool, busErr *dbus.Error) { + result = make(map[string]bool, len(m.names)) + for _, name := range m.names { + result[name] = m.soundEffectGs.GetBoolean(name) + } + return result, nil +} + +func (m *Manager) enabledWriteCb(write *dbusutil.PropertyWrite) *dbus.Error { + enabled := write.Value.(bool) + + // NOTE: 已经约定 name 为空表示控制总开关 + err := m.syncConfigToSoundThemePlayer("", enabled) + if err != nil { + logger.Warning(err) + } + return nil +} diff --git a/soundeffect/soundeffect.go b/soundeffect1/soundeffect.go similarity index 100% rename from soundeffect/soundeffect.go rename to soundeffect1/soundeffect.go diff --git a/system/airplane_mode/manager.go b/system/airplane_mode/manager.go deleted file mode 100644 index cb1110c73..000000000 --- a/system/airplane_mode/manager.go +++ /dev/null @@ -1,295 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package airplane_mode - -import ( - "errors" - "sync" - "time" - - "github.com/godbus/dbus" - networkmanager "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.networkmanager" - polkit "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.policykit1" - "github.com/linuxdeepin/go-lib/dbusutil" -) - -const ( - dbusServiceName = "com.deepin.daemon.AirplaneMode" - dbusPath = "/com/deepin/daemon/AirplaneMode" - dbusInterface = dbusServiceName - - actionId = "com.deepin.daemon.airplane-mode.enable-disable-any" -) - -type device struct { - typ rfkillType - soft rfkillState - hard rfkillState -} - -//go:generate dbusutil-gen -type Manager manager.go -//go:generate dbusutil-gen em -type Manager - -type Manager struct { - service *dbusutil.Service - btRfkillDevices map[uint32]device - btDevicesMu sync.RWMutex - // Airplane Mode status - Enabled bool - HasAirplaneMode bool - WifiEnabled bool - BluetoothEnabled bool - - nmManager networkmanager.Manager - hasNmWirelessDevices bool - - sigLoop *dbusutil.SignalLoop - // all rfkill module config - config *Config -} - -// NewManager create manager -func newManager(service *dbusutil.Service) *Manager { - mgr := &Manager{ - service: service, - btRfkillDevices: make(map[uint32]device), - config: NewConfig(), - } - err := mgr.init() - if err != nil { - logger.Warningf("init manager failed, err: %v", err) - } - - return mgr -} - -func (mgr *Manager) GetInterfaceName() string { - return dbusInterface -} - -func (mgr *Manager) DumpState() *dbus.Error { - return nil -} - -// Enable enable or disable *Airplane Mode*, isn't enable the devices -func (mgr *Manager) Enable(sender dbus.Sender, enableAirplaneMode bool) *dbus.Error { - // check auth - err := checkAuthorization(actionId, string(sender)) - if err != nil { - return dbusutil.ToError(err) - } - - // try to block - err = mgr.block(rfkillTypeAll, enableAirplaneMode) - if err != nil { - logger.Warningf("block all radio failed, err: %v", err) - return dbusutil.ToError(err) - } - - return nil -} - -// EnableWifi enable or disable *Airplane Mode* for wlan, isn't enable the wlan devices -func (mgr *Manager) EnableWifi(sender dbus.Sender, enableAirplaneMode bool) *dbus.Error { - err := checkAuthorization(actionId, string(sender)) - if err != nil { - return dbusutil.ToError(err) - } - - // try to block - err = mgr.block(rfkillTypeWifi, enableAirplaneMode) - if err != nil { - logger.Warningf("block wifi radio failed, err: %v", err) - return dbusutil.ToError(err) - } - - return nil -} - -// EnableBluetooth enable or disable *Airplane Mode* for bluetooth, isn't enable the bluetooth devices -func (mgr *Manager) EnableBluetooth(sender dbus.Sender, enableAirplaneMode bool) *dbus.Error { - err := checkAuthorization(actionId, string(sender)) - if err != nil { - return dbusutil.ToError(err) - } - - // try to block - err = mgr.block(rfkillTypeBT, enableAirplaneMode) - if err != nil { - logger.Warningf("block bluetooth radio failed, err: %v", err) - return dbusutil.ToError(err) - } - - return nil -} - -// init use to init manager -func (mgr *Manager) init() error { - // load config file - err := mgr.config.LoadConfig() - if err != nil { - logger.Debugf("load airplane module config failed, err: %v", err) - } - mgr.nmManager = networkmanager.NewManager(mgr.service.Conn()) - mgr.sigLoop = dbusutil.NewSignalLoop(mgr.service.Conn(), 10) - mgr.sigLoop.Start() - mgr.nmManager.InitSignalExt(mgr.sigLoop, true) - mgr.hasNmWirelessDevices = mgr.hasWirelessDevicesWithRetry() - mgr.initBTRfkillDevice() - // recover - mgr.recover() - // use goroutine to monitor rfkill event - go mgr.listenRfkill() - mgr.listenWirelessEnabled() - mgr.listenNMDevicesChanged() - - return nil -} - -// recover recover origin state from config -func (mgr *Manager) recover() { - logger.Debug("recover last state") - // bluetooth - mgr.BluetoothEnabled = mgr.config.GetBlocked(rfkillTypeBT) - // bluetooth enabled, means bluetooth soft/hard block is enabled last time - // should recover block state here - err := mgr.block(rfkillTypeBT, mgr.BluetoothEnabled) - if err != nil { - logger.Warningf("recover bluetooth failed, state: %v, err: %v", mgr.BluetoothEnabled, err) - } - - // wlan - mgr.WifiEnabled = mgr.config.GetBlocked(rfkillTypeWifi) - // wifi enabled, means wlan soft/hard block is enabled last time - // should recover block state here - err = mgr.block(rfkillTypeWifi, mgr.WifiEnabled) - if err != nil { - logger.Warningf("recover wifi failed, state: %v, err: %v", mgr.WifiEnabled, err) - } - - // all - mgr.Enabled = mgr.config.GetBlocked(rfkillTypeAll) - // enabled, means all soft/hard block is enabled last time - // should recover block state here - err = mgr.block(rfkillTypeAll, mgr.Enabled) - if err != nil { - logger.Warningf("recover all failed, state: %v, err: %v", mgr.Enabled, err) - } - - mgr.btDevicesMu.RLock() - defer mgr.btDevicesMu.RUnlock() - mgr.setPropHasAirplaneMode(len(mgr.btRfkillDevices) > 0 || mgr.hasNmWirelessDevices) -} - -// block use rfkill to block wifi -func (mgr *Manager) block(typ rfkillType, enableAirplaneMode bool) error { - state := rfkillStateUnblock - if enableAirplaneMode { - state = rfkillStateBlock - } - if typ < 2 { // 无线网卡飞行模式通过NM管控 - if mgr.hasNmWirelessDevices { - err := mgr.nmManager.WirelessEnabled().Set(0, !enableAirplaneMode) - if err != nil { - logger.Warning(err) - } - } - } - return rfkillAction(typ, state) -} - -func checkAuthorization(actionId string, sysBusName string) error { - systemBus, err := dbus.SystemBus() - if err != nil { - return err - } - authority := polkit.NewAuthority(systemBus) - subject := polkit.MakeSubject(polkit.SubjectKindSystemBusName) - subject.SetDetail("name", sysBusName) - - ret, err := authority.CheckAuthorization(0, subject, actionId, - nil, polkit.CheckAuthorizationFlagsAllowUserInteraction, "") - if err != nil { - return err - } - if !ret.IsAuthorized { - return errors.New("not authorized") - } - return nil -} - -func (mgr *Manager) listenWirelessEnabled() { - _ = mgr.nmManager.WirelessEnabled().ConnectChanged(func(hasValue bool, wifiEnable bool) { - if !hasValue { - return - } - // 硬件关闭时,开启wifi会先收到enable变为true 然后变为false - hardEnable, err := mgr.nmManager.WirelessHardwareEnabled().Get(0) - if err != nil { - logger.Warning(err) - } - wifiAirplaneMode := !wifiEnable || !hardEnable - mgr.setPropWifiEnabled(wifiAirplaneMode) - mgr.config.SetBlocked(rfkillTypeWifi, !wifiEnable) // 无法判断wifi是否为soft block - mgr.btDevicesMu.RLock() - defer mgr.btDevicesMu.RUnlock() - - mgr.updateAllState() - err = mgr.config.SaveConfig() - if err != nil { - logger.Warningf("save rfkill config file failed, err: %v", err) - } - logger.Debugf("rfkill state, bluetooth: %v, wifi: %v, airplane: %v", mgr.BluetoothEnabled, mgr.WifiEnabled, mgr.Enabled) - }) -} - -func (mgr *Manager) listenNMDevicesChanged() { - _ = mgr.nmManager.Devices().ConnectChanged(func(hasValue bool, value []dbus.ObjectPath) { - if !hasValue { - return - } - mgr.hasNmWirelessDevices = mgr.hasWirelessDevices(value) - mgr.btDevicesMu.RLock() - defer mgr.btDevicesMu.RUnlock() - mgr.setPropHasAirplaneMode(len(mgr.btRfkillDevices) > 0 || mgr.hasNmWirelessDevices) - }) -} - -func (mgr *Manager) hasWirelessDevicesWithRetry() bool { - // try get all devices 5 times - for i := 0; i < 5; i++ { - devicePaths, err := mgr.nmManager.GetDevices(0) - if err != nil { - logger.Warning(err) - // sleep for 1 seconds, and retry get devices - time.Sleep(1 * time.Second) - } else { - return mgr.hasWirelessDevices(devicePaths) - } - } - return false -} - -const NM_DEVICE_TYPE_WIFI = 2 - -// add and check devices -func (mgr *Manager) hasWirelessDevices(devicePaths []dbus.ObjectPath) bool { - for _, devPath := range devicePaths { - nmDev, err := networkmanager.NewDevice(mgr.service.Conn(), devPath) - if err != nil { - logger.Warning(err) - continue - } - d := nmDev.Device() - deviceType, err := d.DeviceType().Get(0) - if err != nil { - logger.Warningf("get device %s type failed: %v", nmDev.Path_(), err) - } - if deviceType == NM_DEVICE_TYPE_WIFI { - return true - } - } - return false -} diff --git a/system/airplane_mode/airplane_mode.go b/system/airplane_mode1/airplane_mode.go similarity index 100% rename from system/airplane_mode/airplane_mode.go rename to system/airplane_mode1/airplane_mode.go diff --git a/system/airplane_mode/airplane_mode_dbusutil.go b/system/airplane_mode1/airplane_mode_dbusutil.go similarity index 100% rename from system/airplane_mode/airplane_mode_dbusutil.go rename to system/airplane_mode1/airplane_mode_dbusutil.go diff --git a/system/airplane_mode/config.go b/system/airplane_mode1/config.go similarity index 100% rename from system/airplane_mode/config.go rename to system/airplane_mode1/config.go diff --git a/system/airplane_mode/define.go b/system/airplane_mode1/define.go similarity index 100% rename from system/airplane_mode/define.go rename to system/airplane_mode1/define.go diff --git a/system/airplane_mode/exported_methods_auto.go b/system/airplane_mode1/exported_methods_auto.go similarity index 100% rename from system/airplane_mode/exported_methods_auto.go rename to system/airplane_mode1/exported_methods_auto.go diff --git a/system/airplane_mode1/manager.go b/system/airplane_mode1/manager.go new file mode 100644 index 000000000..1d31d1968 --- /dev/null +++ b/system/airplane_mode1/manager.go @@ -0,0 +1,296 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package airplane_mode + +import ( + "errors" + "sync" + "time" + + "github.com/godbus/dbus/v5" + networkmanager "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.networkmanager" + polkit "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.policykit1" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +const ( + dbusServiceName = "org.deepin.dde.AirplaneMode1" + dbusPath = "/org/deepin/dde/AirplaneMode1" + dbusInterface = dbusServiceName + + actionId = "org.deepin.dde.airplane-mode.enable-disable-any" +) + +type device struct { + typ rfkillType + soft rfkillState + hard rfkillState +} + +//go:generate dbusutil-gen -type Manager manager.go +//go:generate dbusutil-gen em -type Manager + +type Manager struct { + service *dbusutil.Service + btRfkillDevices map[uint32]device + btDevicesMu sync.RWMutex + // Airplane Mode status + Enabled bool + HasAirplaneMode bool + WifiEnabled bool + BluetoothEnabled bool + + nmManager networkmanager.Manager + hasNmWirelessDevices bool + + sigLoop *dbusutil.SignalLoop + // all rfkill module config + config *Config +} + +// NewManager create manager +func newManager(service *dbusutil.Service) *Manager { + mgr := &Manager{ + service: service, + btRfkillDevices: make(map[uint32]device), + config: NewConfig(), + } + err := mgr.init() + if err != nil { + logger.Warningf("init manager failed, err: %v", err) + } + + return mgr +} + +func (mgr *Manager) GetInterfaceName() string { + return dbusInterface +} + +func (mgr *Manager) DumpState() *dbus.Error { + return nil +} + +// Enable enable or disable *Airplane Mode*, isn't enable the devices +func (mgr *Manager) Enable(sender dbus.Sender, enableAirplaneMode bool) *dbus.Error { + // check auth + err := checkAuthorization(actionId, string(sender)) + if err != nil { + logger.Warningf("checkAuthorization failed, err: %v, actionId=%v", err, actionId) + return dbusutil.ToError(err) + } + + // try to block + err = mgr.block(rfkillTypeAll, enableAirplaneMode) + if err != nil { + logger.Warningf("block all radio failed, err: %v", err) + return dbusutil.ToError(err) + } + + return nil +} + +// EnableWifi enable or disable *Airplane Mode* for wlan, isn't enable the wlan devices +func (mgr *Manager) EnableWifi(sender dbus.Sender, enableAirplaneMode bool) *dbus.Error { + err := checkAuthorization(actionId, string(sender)) + if err != nil { + return dbusutil.ToError(err) + } + + // try to block + err = mgr.block(rfkillTypeWifi, enableAirplaneMode) + if err != nil { + logger.Warningf("block wifi radio failed, err: %v", err) + return dbusutil.ToError(err) + } + + return nil +} + +// EnableBluetooth enable or disable *Airplane Mode* for bluetooth, isn't enable the bluetooth devices +func (mgr *Manager) EnableBluetooth(sender dbus.Sender, enableAirplaneMode bool) *dbus.Error { + err := checkAuthorization(actionId, string(sender)) + if err != nil { + return dbusutil.ToError(err) + } + + // try to block + err = mgr.block(rfkillTypeBT, enableAirplaneMode) + if err != nil { + logger.Warningf("block bluetooth radio failed, err: %v", err) + return dbusutil.ToError(err) + } + + return nil +} + +// init use to init manager +func (mgr *Manager) init() error { + // load config file + err := mgr.config.LoadConfig() + if err != nil { + logger.Debugf("load airplane module config failed, err: %v", err) + } + mgr.nmManager = networkmanager.NewManager(mgr.service.Conn()) + mgr.sigLoop = dbusutil.NewSignalLoop(mgr.service.Conn(), 10) + mgr.sigLoop.Start() + mgr.nmManager.InitSignalExt(mgr.sigLoop, true) + mgr.hasNmWirelessDevices = mgr.hasWirelessDevicesWithRetry() + mgr.initBTRfkillDevice() + // recover + mgr.recover() + // use goroutine to monitor rfkill event + go mgr.listenRfkill() + mgr.listenWirelessEnabled() + mgr.listenNMDevicesChanged() + + return nil +} + +// recover recover origin state from config +func (mgr *Manager) recover() { + logger.Debug("recover last state") + // bluetooth + mgr.BluetoothEnabled = mgr.config.GetBlocked(rfkillTypeBT) + // bluetooth enabled, means bluetooth soft/hard block is enabled last time + // should recover block state here + err := mgr.block(rfkillTypeBT, mgr.BluetoothEnabled) + if err != nil { + logger.Warningf("recover bluetooth failed, state: %v, err: %v", mgr.BluetoothEnabled, err) + } + + // wlan + mgr.WifiEnabled = mgr.config.GetBlocked(rfkillTypeWifi) + // wifi enabled, means wlan soft/hard block is enabled last time + // should recover block state here + err = mgr.block(rfkillTypeWifi, mgr.WifiEnabled) + if err != nil { + logger.Warningf("recover wifi failed, state: %v, err: %v", mgr.WifiEnabled, err) + } + + // all + mgr.Enabled = mgr.config.GetBlocked(rfkillTypeAll) + // enabled, means all soft/hard block is enabled last time + // should recover block state here + err = mgr.block(rfkillTypeAll, mgr.Enabled) + if err != nil { + logger.Warningf("recover all failed, state: %v, err: %v", mgr.Enabled, err) + } + + mgr.btDevicesMu.RLock() + defer mgr.btDevicesMu.RUnlock() + mgr.setPropHasAirplaneMode(len(mgr.btRfkillDevices) > 0 || mgr.hasNmWirelessDevices) +} + +// block use rfkill to block wifi +func (mgr *Manager) block(typ rfkillType, enableAirplaneMode bool) error { + state := rfkillStateUnblock + if enableAirplaneMode { + state = rfkillStateBlock + } + if typ < 2 { // 无线网卡飞行模式通过NM管控 + if mgr.hasNmWirelessDevices { + err := mgr.nmManager.WirelessEnabled().Set(0, !enableAirplaneMode) + if err != nil { + logger.Warning(err) + } + } + } + return rfkillAction(typ, state) +} + +func checkAuthorization(actionId string, sysBusName string) error { + systemBus, err := dbus.SystemBus() + if err != nil { + return err + } + authority := polkit.NewAuthority(systemBus) + subject := polkit.MakeSubject(polkit.SubjectKindSystemBusName) + subject.SetDetail("name", sysBusName) + + ret, err := authority.CheckAuthorization(0, subject, actionId, + nil, polkit.CheckAuthorizationFlagsAllowUserInteraction, "") + if err != nil { + return err + } + if !ret.IsAuthorized { + return errors.New("not authorized") + } + return nil +} + +func (mgr *Manager) listenWirelessEnabled() { + _ = mgr.nmManager.WirelessEnabled().ConnectChanged(func(hasValue bool, wifiEnable bool) { + if !hasValue { + return + } + // 硬件关闭时,开启wifi会先收到enable变为true 然后变为false + hardEnable, err := mgr.nmManager.WirelessHardwareEnabled().Get(0) + if err != nil { + logger.Warning(err) + } + wifiAirplaneMode := !wifiEnable || !hardEnable + mgr.setPropWifiEnabled(wifiAirplaneMode) + mgr.config.SetBlocked(rfkillTypeWifi, !wifiEnable) // 无法判断wifi是否为soft block + mgr.btDevicesMu.RLock() + defer mgr.btDevicesMu.RUnlock() + + mgr.updateAllState() + err = mgr.config.SaveConfig() + if err != nil { + logger.Warningf("save rfkill config file failed, err: %v", err) + } + logger.Debugf("rfkill state, bluetooth: %v, wifi: %v, airplane: %v", mgr.BluetoothEnabled, mgr.WifiEnabled, mgr.Enabled) + }) +} + +func (mgr *Manager) listenNMDevicesChanged() { + _ = mgr.nmManager.Devices().ConnectChanged(func(hasValue bool, value []dbus.ObjectPath) { + if !hasValue { + return + } + mgr.hasNmWirelessDevices = mgr.hasWirelessDevices(value) + mgr.btDevicesMu.RLock() + defer mgr.btDevicesMu.RUnlock() + mgr.setPropHasAirplaneMode(len(mgr.btRfkillDevices) > 0 || mgr.hasNmWirelessDevices) + }) +} + +func (mgr *Manager) hasWirelessDevicesWithRetry() bool { + // try get all devices 5 times + for i := 0; i < 5; i++ { + devicePaths, err := mgr.nmManager.GetDevices(0) + if err != nil { + logger.Warning(err) + // sleep for 1 seconds, and retry get devices + time.Sleep(1 * time.Second) + } else { + return mgr.hasWirelessDevices(devicePaths) + } + } + return false +} + +const NM_DEVICE_TYPE_WIFI = 2 + +// add and check devices +func (mgr *Manager) hasWirelessDevices(devicePaths []dbus.ObjectPath) bool { + for _, devPath := range devicePaths { + nmDev, err := networkmanager.NewDevice(mgr.service.Conn(), devPath) + if err != nil { + logger.Warning(err) + continue + } + d := nmDev.Device() + deviceType, err := d.DeviceType().Get(0) + if err != nil { + logger.Warningf("get device %s type failed: %v", nmDev.Path_(), err) + } + if deviceType == NM_DEVICE_TYPE_WIFI { + return true + } + } + return false +} diff --git a/system/airplane_mode/rfkill.go b/system/airplane_mode1/rfkill.go similarity index 87% rename from system/airplane_mode/rfkill.go rename to system/airplane_mode1/rfkill.go index 89a7f4b89..cd2e3f590 100644 --- a/system/airplane_mode/rfkill.go +++ b/system/airplane_mode1/rfkill.go @@ -51,10 +51,27 @@ type RfkillEvent struct { } func (mgr *Manager) listenRfkill() { - fd, err := syscall.Open("/dev/rfkill", syscall.O_RDWR, 0777) + getRfkill := func() (fd int, err error) { + return syscall.Open("/dev/rfkill", syscall.O_RDWR, 0777) + } + fd, err := getRfkill() if err != nil { - logger.Warning("failed to open /dev/rfkill:", err) - return + // 个别机器文件创建较晚,尝试多读几次 + var checkTimer = time.NewTimer(time.Second) + count := 0 + for range checkTimer.C { + if count == 5 { + logger.Warning("failed to open /dev/rfkill:", err) + return + } else { + fd, err = getRfkill() + if err == nil { + break + } + count++ + checkTimer.Reset(time.Second) + } + } } defer syscall.Close(fd) @@ -155,20 +172,29 @@ func (mgr *Manager) updateAllState() { // 仅保存 soft block 的状态 allSoftBlocked := false + wifiBlocked := false states, err := getRfkillState(rfkillTypeWifi) - if err != nil { - logger.Warning(err) - allSoftBlocked = mgr.BluetoothEnabled && mgr.WifiEnabled - } else if mgr.WifiEnabled { - allSoftBlocked = mgr.BluetoothEnabled - } else { + if err == nil { // nm 无线控制关闭,可能是hard关闭,dde只控制soft。 + allWifiSoftBlocked := true for _, v := range states { - if v.Soft != 0 { - allSoftBlocked = true - + if v.Soft == 0 { + allWifiSoftBlocked = false + break } } + wifiBlocked = allWifiSoftBlocked + } else { + logger.Warning(err) + wifiBlocked = mgr.hasNmWirelessDevices && mgr.WifiEnabled + } + + if mgr.hasNmWirelessDevices && len(mgr.btRfkillDevices) > 0 { + allSoftBlocked = wifiBlocked && mgr.BluetoothEnabled + } else if mgr.hasNmWirelessDevices { + allSoftBlocked = wifiBlocked + } else if len(mgr.btRfkillDevices) > 0 { + allSoftBlocked = mgr.BluetoothEnabled } mgr.config.SetBlocked(rfkillTypeAll, allSoftBlocked) @@ -177,6 +203,7 @@ func (mgr *Manager) updateAllState() { // 只处理bluetooth设备 func (mgr *Manager) handleBTRfkillEvent(event *RfkillEvent) { + logger.Warning("handleBTRfkillEvent=======>", event.Typ, event.Op, event.Op == rfkillOpDel) if event.Typ != rfkillTypeBT { return } diff --git a/system/airplane_mode/utils.go b/system/airplane_mode1/utils.go similarity index 100% rename from system/airplane_mode/utils.go rename to system/airplane_mode1/utils.go diff --git a/system/bluetooth/adapter.go b/system/bluetooth/adapter.go deleted file mode 100644 index 48e3efaf3..000000000 --- a/system/bluetooth/adapter.go +++ /dev/null @@ -1,253 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package bluetooth - -import ( - "fmt" - "os" - "time" - - "github.com/godbus/dbus" - bluez "github.com/linuxdeepin/go-dbus-factory/org.bluez" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/dbusutil/proxy" -) - -type adapter struct { - bt *SysBluetooth - core bluez.HCI - Address string - - Path dbus.ObjectPath - Name string - Alias string - Powered bool - Discovering bool - Discoverable bool - DiscoverableTimeout uint32 - // discovering timer, when time is up, stop discovering until start button is clicked next time - discoveringTimer *time.Timer - // 扫描完成 - discoveringFinished bool - scanReadyToConnectDeviceTimeoutFlag bool - // 自动回连完成标志位 - autoConnectFinished bool - // waitDiscovery未使用 - // waitDiscovery bool - poweredActionTime time.Time -} - -var defaultDiscoveringTimeout = 1 * time.Minute - -func newAdapter(systemSigLoop *dbusutil.SignalLoop, objPath dbus.ObjectPath) (a *adapter) { - a = &adapter{Path: objPath, autoConnectFinished: false} - systemConn := systemSigLoop.Conn() - a.core, _ = bluez.NewHCI(systemConn, objPath) - a.core.InitSignalExt(systemSigLoop, true) - a.connectProperties() - a.Address, _ = a.core.Adapter().Address().Get(0) - // a.waitDiscovery = true - // 用于定时停止扫描 - a.discoveringTimer = time.AfterFunc(defaultDiscoveringTimeout, func() { - logger.Debug("discovery time out, stop discovering") - // NOTE: 扫描结束后不用备份设备,因为处理设备添加时就会同时备份设备。 - //Scan timeout - a.discoveringFinished = true - if err := a.core.Adapter().StopDiscovery(0); err != nil { - logger.Warningf("stop discovery failed, err:%v", err) - } - _bt.prepareToConnectedDevice = "" - }) - // stop timer at first - a.discoveringTimer.Stop() - // fix alias - alias, _ := a.core.Adapter().Alias().Get(0) - if alias == "first-boot-hostname" { - hostname, err := os.Hostname() - if err == nil { - if hostname != "first-boot-hostname" { - // reset alias - err = a.core.Adapter().Alias().Set(0, "") - if err != nil { - logger.Warning(err) - } - } - } else { - logger.Warning("failed to get hostname:", err) - } - } - - a.Alias, _ = a.core.Adapter().Alias().Get(0) - a.Name, _ = a.core.Adapter().Name().Get(0) - a.Powered, _ = a.core.Adapter().Powered().Get(0) - a.Discovering, _ = a.core.Adapter().Discovering().Get(0) - a.Discoverable, _ = a.core.Adapter().Discoverable().Get(0) - a.DiscoverableTimeout, _ = a.core.Adapter().DiscoverableTimeout().Get(0) - return -} - -func (a *adapter) destroy() { - a.core.RemoveHandler(proxy.RemoveAllHandlers) -} - -func (a *adapter) String() string { - return fmt.Sprintf("adapter %s [%s]", a.Alias, a.Address) -} - -func (a *adapter) notifyAdapterAdded() { - logger.Info("AdapterAdded", a) - err := _bt.service.Emit(_bt, "AdapterAdded", marshalJSON(a)) - if err != nil { - logger.Warning(err) - } - _bt.updateState() -} - -func (a *adapter) notifyAdapterRemoved() { - logger.Info("AdapterRemoved", a) - err := _bt.service.Emit(_bt, "AdapterRemoved", marshalJSON(a)) - if err != nil { - logger.Warning(err) - } - _bt.updateState() -} - -func (a *adapter) notifyPropertiesChanged() { - err := _bt.service.Emit(_bt, "AdapterPropertiesChanged", marshalJSON(a)) - if err != nil { - logger.Warning(err) - } - _bt.updateState() -} - -func (a *adapter) connectProperties() { - err := a.core.Adapter().Name().ConnectChanged(func(hasValue bool, value string) { - if !hasValue { - return - } - a.Name = value - logger.Debugf("%s Name: %v", a, value) - a.notifyPropertiesChanged() - }) - if err != nil { - logger.Warning(err) - } - - err = a.core.Adapter().Alias().ConnectChanged(func(hasValue bool, value string) { - if !hasValue { - return - } - a.Alias = value - logger.Debugf("%s Alias: %v", a, value) - a.notifyPropertiesChanged() - }) - if err != nil { - logger.Warning(err) - } - - err = a.core.Adapter().Powered().ConnectChanged(func(hasValue bool, value bool) { - if !hasValue { - return - } - // 接口操作时效内,按接口配置状态配置蓝牙状态。 - if a.Powered != value && time.Since(a.poweredActionTime) < time.Second { - logger.Debug("sync power status because dde power status opt is working") - go a.core.Adapter().Powered().Set(0, a.Powered) - return - } - a.Powered = value - logger.Debugf("%s Powered: %v", a, value) - if a.Powered { - //err := a.core.Adapter().Discoverable().Set(0, _bt.config.Discoverable) - //if err != nil { - // logger.Warningf("failed to set discoverable for %s: %v", a, err) - //} - go func() { - err = a.core.Adapter().StopDiscovery(0) - if err != nil { - logger.Warningf("failed to stop discovery for %s: %v", a, err) - } - // a.waitDiscovery = true - // in case auto connect to device failed, only when signal power on is received, try to auto connect device - _bt.tryConnectPairedDevices(a.Path) - }() - } else { - // if power off, stop discovering time out - a.discoveringTimer.Stop() - a.bt.syncCommonToBackupDevices(a.Path) - } - // Sleep for 1s and wait for bluez to set the attributes before sending the attribute change signal - time.Sleep(1 * time.Second) - a.notifyPropertiesChanged() - }) - if err != nil { - logger.Warning(err) - } - - err = a.core.Adapter().Discovering().ConnectChanged(func(hasValue bool, value bool) { - if !hasValue { - return - } - if a.Discovering != value { - a.Discovering = value - logger.Debugf("%s Discovering: %v", a, value) - - if value { - a.bt.syncCommonToBackupDevices(a.Path) - a.discoveringTimer.Reset(defaultDiscoveringTimeout) - } else { - // 停止扫描了,设备属性不会再更新了,于是更新设备到备份设备 - a.bt.updateBackupDevices(a.Path) - } - a.notifyPropertiesChanged() - } - }) - if err != nil { - logger.Warning(err) - } - - err = a.core.Adapter().Discoverable().ConnectChanged(func(hasValue bool, value bool) { - if !hasValue { - return - } - a.Discoverable = value - logger.Debugf("%s Discoverable: %v", a, value) - a.notifyPropertiesChanged() - }) - if err != nil { - logger.Warning(err) - } - - err = a.core.Adapter().DiscoverableTimeout().ConnectChanged(func(hasValue bool, value uint32) { - if !hasValue { - return - } - a.DiscoverableTimeout = value - logger.Debugf("%s DiscoverableTimeout: %v", a, value) - a.notifyPropertiesChanged() - }) - if err != nil { - logger.Warning(err) - } -} - -func (a *adapter) startDiscovery() { - a.discoveringFinished = false - // 已经开始扫描 或 回连未结束 禁止开始扫描 - if a.Discovering || !a.autoConnectFinished { - return - } - - logger.Debugf("start discovery") - err := a.core.Adapter().StartDiscovery(0) - if err != nil { - logger.Warningf("failed to start discovery for %s: %v", a, err) - } else { - logger.Debug("reset timer for stop scan") - // a.waitDiscovery = false - // start discovering success, reset discovering timer - a.discoveringTimer.Reset(defaultDiscoveringTimeout) - } -} diff --git a/system/bluetooth/agent.go b/system/bluetooth/agent.go deleted file mode 100644 index 7d4b004a5..000000000 --- a/system/bluetooth/agent.go +++ /dev/null @@ -1,482 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package bluetooth - -import ( - "errors" - "fmt" - "strings" - "sync" - - "github.com/godbus/dbus" - btcommon "github.com/linuxdeepin/dde-daemon/common/bluetooth" - sysbtagent "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.bluetooth.agent" - bluez "github.com/linuxdeepin/go-dbus-factory/org.bluez" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" - "github.com/linuxdeepin/go-lib/dbusutil" -) - -const ( - agentDBusPath = dbusPath + "/Agent" - agentDBusInterface = "org.bluez.Agent1" -) - -type userAgentMap struct { - mu sync.Mutex - m map[string]*sessionAgentMapItem // key 是 uid - activeUid string -} - -type sessionAgentMapItem struct { - sessions map[dbus.ObjectPath]login1.Session // key 是 session 的路径 - agents map[dbus.ObjectPath]sysbtagent.Agent // key 是 agent 的路径 -} - -func (m *userAgentMap) setActiveUid(uid string) { - m.mu.Lock() - m.activeUid = uid - m.mu.Unlock() -} - -func newUserAgentMap() *userAgentMap { - return &userAgentMap{ - m: make(map[string]*sessionAgentMapItem, 1), - } -} - -func (m *userAgentMap) addAgent(uid string, agent sysbtagent.Agent) { - m.mu.Lock() - defer m.mu.Unlock() - - item, ok := m.m[uid] - if ok { - if item.agents == nil { - item.agents = make(map[dbus.ObjectPath]sysbtagent.Agent, 1) - } - if len(item.agents) > 10 { - // 限制数量 - return - } - item.agents[agent.Path_()] = agent - } else { - m.m[uid] = &sessionAgentMapItem{ - agents: map[dbus.ObjectPath]sysbtagent.Agent{ - agent.Path_(): agent, - }, - } - } -} - -func (m *userAgentMap) handleNameLost(name string) { - m.mu.Lock() - defer m.mu.Unlock() - - for _, item := range m.m { - for path, agent := range item.agents { - if agent.ServiceName_() == name { - logger.Debug("remove agent", name, path) - delete(item.agents, path) - } - } - } -} - -func (m *userAgentMap) removeAgent(uid string, agentPath dbus.ObjectPath) error { - m.mu.Lock() - defer m.mu.Unlock() - - item, ok := m.m[uid] - if !ok { - return errors.New("invalid uid") - } - - if _, ok := item.agents[agentPath]; !ok { - return errors.New("invalid agent path") - } - delete(item.agents, agentPath) - return nil -} - -func (m *userAgentMap) addUser(uid string) { - m.mu.Lock() - defer m.mu.Unlock() - - _, ok := m.m[uid] - if !ok { - m.m[uid] = &sessionAgentMapItem{ - sessions: make(map[dbus.ObjectPath]login1.Session), - agents: make(map[dbus.ObjectPath]sysbtagent.Agent), - } - } -} - -func (m *userAgentMap) removeUser(uid string) { - m.mu.Lock() - defer m.mu.Unlock() - - item, ok := m.m[uid] - if !ok { - return - } - - for sessionPath, session := range item.sessions { - session.RemoveAllHandlers() - delete(item.sessions, sessionPath) - } - delete(m.m, uid) -} - -func (m *userAgentMap) hasUser(uid string) bool { - m.mu.Lock() - defer m.mu.Unlock() - _, ok := m.m[uid] - return ok -} - -func (m *userAgentMap) addSession(uid string, session login1.Session) bool { - m.mu.Lock() - defer m.mu.Unlock() - - item, ok := m.m[uid] - if !ok { - return false - } - - _, ok = item.sessions[session.Path_()] - if ok { - return false - } - item.sessions[session.Path_()] = session - return true -} - -func (m *userAgentMap) removeSession(sessionPath dbus.ObjectPath) { - m.mu.Lock() - defer m.mu.Unlock() - - for _, item := range m.m { - for sPath, session := range item.sessions { - if sPath == sessionPath { - session.RemoveAllHandlers() - delete(item.sessions, sPath) - } - } - } -} - -func (m *userAgentMap) getActiveAgent() sysbtagent.Agent { - m.mu.Lock() - defer m.mu.Unlock() - - if m.activeUid == "" { - return nil - } - - item := m.m[m.activeUid] - if item == nil { - return nil - } - // 目前只使用标准的 - return item.agents[btcommon.SessionAgentPath] -} - -func (m *userAgentMap) GetActiveAgentName() string { - agent := m.getActiveAgent() - if agent != nil { - return agent.ServiceName_() - } - return "" -} - -func (m *userAgentMap) GetAllAgentNames() (result []string) { - m.mu.Lock() - defer m.mu.Unlock() - - for _, item := range m.m { - // 目前只使用标准的 - agent := item.agents[btcommon.SessionAgentPath] - if agent != nil { - result = append(result, agent.ServiceName_()) - } - } - return result -} - -type authorize struct { - path dbus.ObjectPath - key string - accept bool -} - -type agent struct { - service *dbusutil.Service - bluezManager bluez.Manager - - b *SysBluetooth - rspChan chan authorize - - mu sync.Mutex - requestDevice dbus.ObjectPath -} - -func (*agent) GetInterfaceName() string { - return agentDBusInterface -} - -func toErrFromAgent(err error) *dbus.Error { - if err == nil { - return nil - } - busErr, ok := err.(dbus.Error) - if !ok { - // 强制转换为 Rejected - return &dbus.Error{ - Name: btcommon.ErrNameRejected, - Body: []interface{}{err.Error()}, - } - } - - if busErr.Name == btcommon.ErrNameRejected || busErr.Name == btcommon.ErrNameCanceled { - return &busErr - } - - // 强制转换为 Rejected - return &dbus.Error{ - Name: btcommon.ErrNameRejected, - Body: []interface{}{fmt.Sprintf("[%s] %s", busErr.Name, busErr.Error())}, - } -} - -/*****************************************************************************/ - -//Release method gets called when the service daemon unregisters the agent. -//An agent can use it to do cleanup tasks. There is no need to unregister the -//agent, because when this method gets called it has already been unregistered. -func (a *agent) Release() *dbus.Error { - logger.Info("Release()") - return nil -} - -//RequestPinCode method gets called when the service daemon needs to get the passkey for an authentication. -//The return value should be a string of 1-16 characters length. The string can be alphanumeric. -//Possible errors: org.bluez.Error.Rejected -// org.bluez.Error.Canceled -func (a *agent) RequestPinCode(device dbus.ObjectPath) (pinCode string, busErr *dbus.Error) { - logger.Info("RequestPinCode()") - - ua := a.b.getActiveUserAgent() - if ua == nil { - logger.Warning("ua is nil") - return "", btcommon.ErrRejected - } - - d, err := a.b.getDevice(device) - if err != nil { - logger.Warning(err) - return "", btcommon.ErrRejected - } - d.agentWorkStart() - defer d.agentWorkEnd() - - pinCode, err = ua.RequestPinCode(0, device) - return pinCode, toErrFromAgent(err) -} - -//DisplayPinCode method gets called when the service daemon needs to display a pincode for an authentication. -//An empty reply should be returned. When the pincode needs no longer to be displayed, the Cancel method -//of the agent will be called. This is used during the pairing process of keyboards that don't support -//Bluetooth 2.1 Secure Simple Pairing, in contrast to DisplayPasskey which is used for those that do. -//This method will only ever be called once since older keyboards do not support typing notification. -//Note that the PIN will always be a 6-digit number, zero-padded to 6 digits. This is for harmony with -//the later specification. -//Possible errors: org.bluez.Error.Rejected -// org.bluez.Error.Canceled -func (a *agent) DisplayPinCode(device dbus.ObjectPath, pinCode string) (busErr *dbus.Error) { - logger.Info("DisplayPinCode()", pinCode) - ua := a.b.getActiveUserAgent() - if ua == nil { - logger.Warning("ua is nil") - return btcommon.ErrRejected - } - err := ua.DisplayPinCode(0, device, pinCode) - return toErrFromAgent(err) -} - -//RequestPasskey method gets called when the service daemon needs to get the passkey for an authentication. -//The return value should be a numeric value between 0-999999. -//Possible errors: org.bluez.Error.Rejected -// org.bluez.Error.Canceled -func (a *agent) RequestPasskey(device dbus.ObjectPath) (passkey uint32, busErr *dbus.Error) { - logger.Info("RequestPasskey()") - ua := a.b.getActiveUserAgent() - if ua == nil { - logger.Warning("ua is nil") - return 0, btcommon.ErrRejected - } - - d, err := a.b.getDevice(device) - if err != nil { - logger.Warning(err) - return 0, btcommon.ErrRejected - } - d.agentWorkStart() - defer d.agentWorkEnd() - - passkey, err = ua.RequestPasskey(0, device) - return passkey, toErrFromAgent(err) -} - -//DisplayPasskey method gets called when the service daemon needs to display a passkey for an authentication. -//The entered parameter indicates the number of already typed keys on the remote side. -//An empty reply should be returned. When the passkey needs no longer to be displayed, the Cancel method -//of the agent will be called. -//During the pairing process this method might be called multiple times to update the entered value. -//Note that the passkey will always be a 6-digit number, so the display should be zero-padded at the start if -//the value contains less than 6 digits. -func (a *agent) DisplayPasskey(device dbus.ObjectPath, passkey uint32, entered uint16) *dbus.Error { - logger.Info("DisplayPasskey()", passkey, entered) - ua := a.b.getActiveUserAgent() - if ua == nil { - logger.Warning("ua is nil") - return btcommon.ErrRejected - } - err := ua.DisplayPasskey(0, device, passkey, entered) - return toErrFromAgent(err) -} - -//RequestConfirmation This method gets called when the service daemon needs to confirm a passkey for an authentication. -//To confirm the value it should return an empty reply or an error in case the passkey is invalid. -//Note that the passkey will always be a 6-digit number, so the display should be zero-padded at the start if -//the value contains less than 6 digits. -//Possible errors: org.bluez.Error.Rejected -// org.bluez.Error.Canceled -func (a *agent) RequestConfirmation(device dbus.ObjectPath, passkey uint32) *dbus.Error { - logger.Info("RequestConfirmation", device, passkey) - ua := a.b.getActiveUserAgent() - if ua == nil { - logger.Warning("ua is nil") - return btcommon.ErrRejected - } - - d, err := a.b.getDevice(device) - if err != nil { - logger.Warning(err) - return btcommon.ErrRejected - } - d.agentWorkStart() - defer d.agentWorkEnd() - - if d.Icon == "audio-card" && strings.Contains(strings.ToLower(d.Name), "huawei") { - logger.Warning("audio-card device don't need confirm") - return nil - } - - err = ua.RequestConfirmation(0, device, passkey) - return toErrFromAgent(err) -} - -//RequestAuthorization method gets called to request the user to authorize an incoming pairing attempt which -//would in other circumstances trigger the just-works model. -//Possible errors: org.bluez.Error.Rejected -// org.bluez.Error.Canceled -func (a *agent) RequestAuthorization(device dbus.ObjectPath) *dbus.Error { - logger.Info("RequestAuthorization()") - ua := a.b.getActiveUserAgent() - if ua == nil { - logger.Warning("ua is nil") - return btcommon.ErrRejected - } - - d, err := a.b.getDevice(device) - if err != nil { - logger.Warning(err) - return btcommon.ErrRejected - } - d.agentWorkStart() - defer d.agentWorkEnd() - - err = ua.RequestAuthorization(0, device) - return toErrFromAgent(err) -} - -//AuthorizeService method gets called when the service daemon needs to authorize a connection/service request. -//Possible errors: org.bluez.Error.Rejected -// org.bluez.Error.Canceled -func (a *agent) AuthorizeService(device dbus.ObjectPath, uuid string) *dbus.Error { - logger.Infof("AuthorizeService %q %q", device, uuid) - _, err := a.b.getDevice(device) - if err != nil { - logger.Warning(err) - return btcommon.ErrRejected - } - - ua := a.b.getActiveUserAgent() - if ua == nil { - logger.Warning("ua is nil") - return btcommon.ErrRejected - } - err = ua.AuthorizeService(0, device, uuid) - return toErrFromAgent(err) -} - -//Cancel method gets called to indicate that the agent request failed before a reply was returned. -func (a *agent) Cancel() *dbus.Error { - logger.Info("Cancel()") - ua := a.b.getActiveUserAgent() - if ua == nil { - logger.Warning("ua is nil") - return nil - } - err := ua.Cancel(0) - return toErrFromAgent(err) -} - -/*****************************************************************************/ - -func newAgent(service *dbusutil.Service) (a *agent) { - a = &agent{ - service: service, - rspChan: make(chan authorize), - } - return -} - -func (a *agent) init() { - sysBus := a.service.Conn() - a.bluezManager = bluez.NewManager(sysBus) - a.registerDefaultAgent() -} - -func (a *agent) registerDefaultAgent() { - // register agent - err := a.bluezManager.AgentManager().RegisterAgent(0, agentDBusPath, "DisplayYesNo") - if err != nil { - logger.Warning("failed to register agent:", err) - return - } - - // request default agent - err = a.bluezManager.AgentManager().RequestDefaultAgent(0, agentDBusPath) - if err != nil { - logger.Warning("failed to become the default agent:", err) - err = a.bluezManager.AgentManager().UnregisterAgent(0, agentDBusPath) - if err != nil { - logger.Warning(err) - } - return - } -} - -func (a *agent) destroy() { - err := a.bluezManager.AgentManager().UnregisterAgent(0, agentDBusPath) - if err != nil { - logger.Warning(err) - } - - err = a.service.StopExport(a) - if err != nil { - logger.Warning(err) - } -} diff --git a/system/bluetooth/bluetooth.go b/system/bluetooth/bluetooth.go deleted file mode 100644 index 0ee3d064c..000000000 --- a/system/bluetooth/bluetooth.go +++ /dev/null @@ -1,1072 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package bluetooth - -import ( - "fmt" - "os" - "strconv" - "strings" - "sync" - "time" - - "github.com/godbus/dbus" - bluez "github.com/linuxdeepin/go-dbus-factory/org.bluez" - ConfigManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" - "github.com/linuxdeepin/go-lib/dbusutil" -) - -const ( - bluezDBusServiceName = "org.bluez" - bluezAdapterDBusInterface = "org.bluez.Adapter1" - bluezDeviceDBusInterface = "org.bluez.Device1" - - dbusServiceName = "com.deepin.system.Bluetooth" - dbusPath = "/com/deepin/system/Bluetooth" - dbusInterface = dbusServiceName -) - -const ( - StateUnavailable = 0 - StateAvailable = 1 - StateConnected = 2 -) - -const ( - devIconComputer = "computer" - devIconPhone = "phone" - devIconModem = "modem" - devIconNetworkWireless = "network-wireless" - devIconAudioCard = "audio-card" - devIconCameraVideo = "camera-video" - devIconCameraPhoto = "camera-photo" - devIconPrinter = "printer" - devIconInputGaming = "input-gaming" - devIconInputKeyboard = "input-keyboard" - devIconInputTablet = "input-tablet" - devIconInputMouse = "input-mouse" -) - -const ( - dsettingsAppID = "org.deepin.dde.daemon" - dsettingsBluetoothName = "org.deepin.dde.daemon.bluetooth" - dsettingsAutoPairEnableKey = "autoPairEnable" - dsettingsAdapterPowerd = "adapterPowerd" - dsettingsAdapterDiscoverable = "adapterDiscoverable" -) - -//go:generate dbusutil-gen -type SysBluetooth bluetooth.go -//go:generate dbusutil-gen em -type SysBluetooth,agent - -type SysBluetooth struct { - service *dbusutil.Service - sigLoop *dbusutil.SignalLoop - config *config - objectManager bluez.ObjectManager - sysDBusDaemon ofdbus.DBus - loginManager login1.Manager - agent *agent - userAgents *userAgentMap - - // adapter - adaptersMu sync.Mutex - adapters map[dbus.ObjectPath]*adapter - - // device - devicesMu sync.Mutex - devices map[dbus.ObjectPath][]*device - - // backup device - backupDevicesMu sync.Mutex - backupDevices map[dbus.ObjectPath][]*backupDevice - - acm *autoConnectManager - - PropsMu sync.RWMutex - State uint32 // StateUnavailable/StateAvailable/StateConnected - CanSendFile bool - - // 当发起设备连接成功后,应该把连接的设备添加进设备列表 - connectedDevices map[dbus.ObjectPath][]*device - connectedMu sync.RWMutex - // 设备被清空后需要连接的设备路径 - prepareToConnectedDevice dbus.ObjectPath - prepareToConnectedMu sync.Mutex - // 升级后第一次进系统,此时需要根据之前有蓝牙连接时,打开蓝牙开关 - needFixBtPoweredStatus bool - canAutoPair func() bool - - // nolint - signals *struct { - // adapter/device properties changed signals - AdapterAdded, AdapterRemoved, AdapterPropertiesChanged struct { - adapterJSON string - } - - DeviceAdded, DeviceRemoved, DevicePropertiesChanged struct { - devJSON string - } - } -} - -func newSysBluetooth(service *dbusutil.Service) (b *SysBluetooth) { - sysBus := service.Conn() - b = &SysBluetooth{ - service: service, - sigLoop: dbusutil.NewSignalLoop(sysBus, 100), - userAgents: newUserAgentMap(), - needFixBtPoweredStatus: false, - } - - b.config = newConfig() - b.loginManager = login1.NewManager(sysBus) - b.sysDBusDaemon = ofdbus.NewDBus(sysBus) - b.objectManager = bluez.NewObjectManager(sysBus) - b.adapters = make(map[dbus.ObjectPath]*adapter) - b.devices = make(map[dbus.ObjectPath][]*device) - b.backupDevices = make(map[dbus.ObjectPath][]*backupDevice) - b.connectedDevices = make(map[dbus.ObjectPath][]*device) - b.acm = newAutoConnectManager() - b.acm.connectCb = func(adapterPath, devicePath dbus.ObjectPath, wId int) error { - adapter, err := b.getAdapter(adapterPath) - if err != nil { - // 可能是适配器被移除了,停止连接 - return nil - } - if !adapter.Powered { - // 适配器电源关闭了,停止连接 - return nil - } - - adapter.autoConnectFinished = false - return b.autoConnectPairedDevice(devicePath, adapterPath) - } - - b.acm.startDiscoveryCb = func(adapterPath dbus.ObjectPath) { - adapter, err := b.getAdapter(adapterPath) - if err != nil { - // 可能是适配器被移除了,不需要开始扫描 - logger.Warningf("call getAdapter failed; adapterPath:[%s] err:[%s]", adapterPath, err) - return - } - - if !adapter.Powered { - // 适配器电源关闭了,不需要开始扫描 - logger.Warningf("adapter: [%s] is power off", adapterPath) - return - } - - adapter.autoConnectFinished = true - adapter.startDiscovery() - } - - return -} - -func (b *SysBluetooth) destroy() { - b.agent.destroy() - - b.objectManager.RemoveAllHandlers() - b.sysDBusDaemon.RemoveAllHandlers() - b.loginManager.RemoveAllHandlers() - - b.devicesMu.Lock() - for _, devices := range b.devices { - for _, device := range devices { - device.destroy() - } - } - b.devicesMu.Unlock() - - b.adaptersMu.Lock() - for _, adapter := range b.adapters { - adapter.destroy() - } - b.adaptersMu.Unlock() - - err := b.service.StopExport(b) - if err != nil { - logger.Warning(err) - } - b.sigLoop.Stop() -} - -func (*SysBluetooth) GetInterfaceName() string { - return dbusInterface -} - -func (b *SysBluetooth) init() { - var err error - b.CanSendFile, err = canSendFile() - if err != nil { - logger.Warning("canSendFile err:", err) - } - - // 需要在Load加载之前判断系统级蓝牙配置文件是否存在 - b.needFixBtPoweredStatus = !b.config.core.IsConfigFileExists() - b.sigLoop.Start() - b.config.load() - b.sysDBusDaemon.InitSignalExt(b.sigLoop, true) - _, err = b.sysDBusDaemon.ConnectNameOwnerChanged(b.handleDBusNameOwnerChanged) - if err != nil { - logger.Warning(err) - } - - ds := ConfigManager.NewConfigManager(b.sigLoop.Conn()) - - dsBluetoothPath, err := ds.AcquireManager(0, dsettingsAppID, dsettingsBluetoothName, "") - if err != nil { - logger.Warning(err) - return - } - - dsBluetooth, err := ConfigManager.NewManager(b.sigLoop.Conn(), dsBluetoothPath) - if err != nil { - logger.Warning(err) - return - } - - b.canAutoPair = func() bool { - v, err := dsBluetooth.Value(0, dsettingsAutoPairEnableKey) - if err != nil { - logger.Warning(err) - return true - } - return v.Value().(bool) - } - - logger.Info("====== dsg autoPairEnable is ======", b.canAutoPair()) - - adapterDefaultPowered = func() bool { - v, err := dsBluetooth.Value(0, dsettingsAdapterPowerd) - if err != nil { - logger.Warning(err) - return false - } - return v.Value().(bool) - }() - - adapterDefaultDiscoverable = func() bool { - v, err := dsBluetooth.Value(0, dsettingsAdapterDiscoverable) - if err != nil { - logger.Warning(err) - return true - } - return v.Value().(bool) - }() - - b.loginManager.InitSignalExt(b.sigLoop, true) - _, err = b.loginManager.ConnectSessionNew(b.handleSessionNew) - - _, err = b.loginManager.ConnectSessionRemoved(func(sessionId string, sessionPath dbus.ObjectPath) { - logger.Info("session removed", sessionId, sessionPath) - b.userAgents.removeSession(sessionPath) - }) - if err != nil { - logger.Warning(err) - } - - _, err = b.loginManager.ConnectUserRemoved(func(uid uint32, userPath dbus.ObjectPath) { - uidStr := strconv.Itoa(int(uid)) - b.userAgents.removeUser(uidStr) - }) - - _, err = b.loginManager.ConnectPrepareForSleep(b.handlePrepareForSleep) - if err != nil { - logger.Warning(err) - } - - b.objectManager.InitSignalExt(b.sigLoop, true) - _, err = b.objectManager.ConnectInterfacesAdded(b.handleInterfacesAdded) - if err != nil { - logger.Warning(err) - } - - _, err = b.objectManager.ConnectInterfacesRemoved(b.handleInterfacesRemoved) - if err != nil { - logger.Warning(err) - } - - b.agent.init() - b.loadObjects() - - b.config.clearSpareConfig(b) - go b.tryConnectPairedDevices("") -} - -const btAvailableFile = "/sys/kernel/security/bluetooth/available" - -func canSendFile() (can bool, err error) { - _, err = os.Stat(btAvailableFile) - if err != nil { - if os.IsNotExist(err) { - // 表示没有加载限制性的内核模块 - return true, nil - } - return false, err - } - - can, err = readBoolFile(btAvailableFile) - return -} - -func (b *SysBluetooth) handleSessionNew(sessionId string, sessionPath dbus.ObjectPath) { - logger.Info("session added", sessionId, sessionPath) - sysBus := b.sigLoop.Conn() - session, err := login1.NewSession(sysBus, sessionPath) - if err != nil { - logger.Warning(err) - return - } - - userInfo, err := session.User().Get(0) - if err != nil { - logger.Warning(err) - return - } - - uidStr := strconv.Itoa(int(userInfo.UID)) - if !b.userAgents.hasUser(uidStr) { - // 不关心这个用户的新 session - return - } - - newlyAdded := b.userAgents.addSession(uidStr, session) - if newlyAdded { - b.watchSession(uidStr, session) - } -} - -func (b *SysBluetooth) handlePrepareForSleep(beforeSleep bool) { - if beforeSleep { - logger.Debug("prepare to sleep") - return - } - logger.Debug("Wakeup from sleep, will set adapter and try connect device") - time.AfterFunc(time.Second*3, func() { - // for _, adapter := range b.adapters { - // if !adapter.Powered { - // continue - // } - // //_ = adapter.core.Adapter().Discoverable().Set(0, b.config.Discoverable) - // } - b.tryConnectPairedDevices("") - }) -} - -func (b *SysBluetooth) watchSession(uid string, session login1.Session) { - session.InitSignalExt(b.sigLoop, true) - err := session.Active().ConnectChanged(func(hasValue bool, active bool) { - if !hasValue { - return - } - if active { - b.userAgents.setActiveUid(uid) - } - }) - - if err != nil { - logger.Warning(err) - } - - active, err := session.Active().Get(0) - if err != nil { - logger.Warning(err) - } - if active { - b.userAgents.setActiveUid(uid) - } -} - -func (b *SysBluetooth) loadObjects() { - // add exists adapters and devices - objects, err := b.objectManager.GetManagedObjects(0) - if err != nil { - logger.Error(err) - return - } - - // add adapters - for path, obj := range objects { - if _, ok := obj[bluezAdapterDBusInterface]; ok { - b.addAdapter(path) - } - } - - // then add devices - for path, obj := range objects { - if _, ok := obj[bluezDeviceDBusInterface]; ok { - b.addDevice(path) - } - } -} - -func (b *SysBluetooth) removeAllObjects() { - b.devicesMu.Lock() - for _, devices := range b.devices { - for _, device := range devices { - device.notifyDeviceRemoved() - device.destroy() - } - } - b.devices = make(map[dbus.ObjectPath][]*device) - b.devicesMu.Unlock() - - b.adaptersMu.Lock() - for _, adapter := range b.adapters { - adapter.notifyAdapterRemoved() - adapter.destroy() - } - b.adapters = make(map[dbus.ObjectPath]*adapter) - b.adaptersMu.Unlock() -} - -func (b *SysBluetooth) handleInterfacesAdded(path dbus.ObjectPath, data map[string]map[string]dbus.Variant) { - if _, ok := data[bluezAdapterDBusInterface]; ok { - b.addAdapter(path) - } - if _, ok := data[bluezDeviceDBusInterface]; ok { - b.addDeviceWithCount(path, 3) - } -} - -func (b *SysBluetooth) handleInterfacesRemoved(path dbus.ObjectPath, interfaces []string) { - if isStringInArray(bluezAdapterDBusInterface, interfaces) { - b.removeAdapter(path) - } - if isStringInArray(bluezDeviceDBusInterface, interfaces) { - b.removeDevice(path) - } -} - -func (b *SysBluetooth) handleDBusNameOwnerChanged(name, oldOwner, newOwner string) { - // if a new dbus session was installed, the name and newOwner - // will be not empty, if a dbus session was uninstalled, the - // name and oldOwner will be not empty - if name == bluezDBusServiceName { - if newOwner != "" { - logger.Info("bluetooth is starting") - time.AfterFunc(1*time.Second, func() { - b.loadObjects() - b.agent.registerDefaultAgent() - b.tryConnectPairedDevices("") - }) - } else { - logger.Info("bluetooth stopped") - b.removeAllObjects() - } - } else { - if strings.HasPrefix(name, ":") && oldOwner != "" && newOwner == "" { - b.userAgents.handleNameLost(name) - } - } -} - -func (b *SysBluetooth) addDeviceWithCount(devPath dbus.ObjectPath, count int) { - logger.Debug("receive signal device added", devPath) - if b.isDeviceExists(devPath) { - return - } - - d := newDevice(b.sigLoop, devPath) - b.adaptersMu.Lock() - d.adapter = b.adapters[d.AdapterPath] - b.adaptersMu.Unlock() - - if d.adapter == nil { - logger.Warningf("failed to add device %s, not found adapter", devPath) - if count > 0 { - logger.Debugf("retry add device %s after 100ms", devPath) - time.AfterFunc(100*time.Millisecond, func() { - b.addDeviceWithCount(devPath, count-1) - }) - } - return - } - - // device detail info is needed to write into config file - b.config.addDeviceConfig(d) - - b.devicesMu.Lock() - b.devices[d.AdapterPath] = append(b.devices[d.AdapterPath], d) - b.devicesMu.Unlock() - - // 设备加入的同时进行备份 - b.backupDevicesMu.Lock() - idx := b.indexBackupDeviceNoLock(d.AdapterPath, devPath) - if idx == -1 { - b.backupDevices[d.AdapterPath] = append(b.backupDevices[d.AdapterPath], newBackupDevice(d)) - } - b.backupDevicesMu.Unlock() - - d.notifyDeviceAdded() - - // 若扫描到需要连接的设备,直接连接 - if b.prepareToConnectedDevice == d.Path { - b.prepareToConnectedDevice = "" - go func() { - err := d.Connect() - if err != nil { - logger.Warning(err) - } - }() - } -} - -func (b *SysBluetooth) addDevice(devPath dbus.ObjectPath) { - b.addDeviceWithCount(devPath, 0) -} - -func (b *SysBluetooth) removeDevice(devPath dbus.ObjectPath) { - logger.Debug("receive signal device removed", devPath) - adapterPath, idx := b.getDeviceIndex(devPath) - if idx == -1 { - logger.Warning("repeat remove device", devPath) - return - } - - var removedDev *device - b.devicesMu.Lock() - b.devices[adapterPath], removedDev = b.doRemoveDevice(b.devices[adapterPath], idx) - b.devicesMu.Unlock() - - b.acm.handleDeviceEvent(removedDev) - - idx = b.indexBackupDevice(adapterPath, devPath) - if idx == -1 { - // 未找到备份设备,需要发送设备移除信号 - removedDev.notifyDeviceRemoved() - } else { - // 找得到备份设备,但是是已经配对的设备,一般是通过 bluetoothctl remove 命令删除已经配对的设备。 - // 备份设备也删除,并发送信号。 - adapter := b.adapters[adapterPath] - if removedDev.Paired || (adapter != nil && adapter.Discovering) { - b.removeBackupDevice(devPath) - removedDev.notifyDeviceRemoved() - } - } -} - -func (b *SysBluetooth) doRemoveDevice(devices []*device, i int) ([]*device, *device) { - // NOTE: do not remove device from config - d := devices[i] - d.destroy() - copy(devices[i:], devices[i+1:]) - devices[len(devices)-1] = nil - devices = devices[:len(devices)-1] - return devices, d -} - -func (b *SysBluetooth) removeBackupDevice(devPath dbus.ObjectPath) { - b.backupDevicesMu.Lock() - defer b.backupDevicesMu.Unlock() - - adapterPath, i := b.findBackupDeviceNoLock(devPath) - if i < 0 { - logger.Debug("repeat remove device", devPath) - return - } - - b.backupDevices[adapterPath] = b.doRemoveBackupDevice(b.backupDevices[adapterPath], i) -} - -func (b *SysBluetooth) doRemoveBackupDevice(devices []*backupDevice, i int) []*backupDevice { - copy(devices[i:], devices[i+1:]) - devices[len(devices)-1] = nil - devices = devices[:len(devices)-1] - return devices -} - -func (b *SysBluetooth) syncCommonToBackupDevices(adapterPath dbus.ObjectPath) { - logger.Debug("syncCommonToBackupDevices", adapterPath) - devices := b.getDevices(adapterPath) - - // 转换为 map - deviceMap := make(map[dbus.ObjectPath]*device) - for _, d := range devices { - deviceMap[d.Path] = d - } - - // 应该只需要关注备份的设备比普通设备多的情况。 - var removedBackupDevices []*backupDevice - var newBackupDevices []*backupDevice - - b.backupDevicesMu.Lock() - for _, backupDevice := range b.backupDevices[adapterPath] { - // 从 devices 能找到,保留,不能找到,则删除 - _, ok := deviceMap[backupDevice.Path] - if !ok { - removedBackupDevices = append(removedBackupDevices, backupDevice) - } - } - - for _, d := range devices { - newBackupDevices = append(newBackupDevices, newBackupDevice(d)) - } - b.backupDevices[adapterPath] = newBackupDevices - b.backupDevicesMu.Unlock() - - for _, d := range removedBackupDevices { - d.notifyDeviceRemoved() - } -} - -func (b *SysBluetooth) isDeviceExists(devPath dbus.ObjectPath) bool { - _, i := b.getDeviceIndex(devPath) - return i >= 0 -} - -func (b *SysBluetooth) findDevice(devPath dbus.ObjectPath) (adapterPath dbus.ObjectPath, index int) { - for p, devices := range b.devices { - for i, d := range devices { - if d.Path == devPath { - return p, i - } - } - } - return "", -1 -} - -func (b *SysBluetooth) findBackupDevice(devPath dbus.ObjectPath) (adapterPath dbus.ObjectPath, index int) { - b.backupDevicesMu.Lock() - defer b.backupDevicesMu.Unlock() - return b.findBackupDeviceNoLock(devPath) -} - -func (b *SysBluetooth) findBackupDeviceNoLock(devPath dbus.ObjectPath) (adapterPath dbus.ObjectPath, index int) { - for p, devices := range b.backupDevices { - for i, d := range devices { - if d.Path == devPath { - return p, i - } - } - } - return "", -1 -} - -func (b *SysBluetooth) indexBackupDevice(adapterPath, devPath dbus.ObjectPath) (index int) { - b.backupDevicesMu.Lock() - defer b.backupDevicesMu.Unlock() - return b.indexBackupDeviceNoLock(adapterPath, devPath) -} - -func (b *SysBluetooth) indexBackupDeviceNoLock(adapterPath, devPath dbus.ObjectPath) (index int) { - devices, ok := b.backupDevices[adapterPath] - if !ok { - return -1 - } - for idx, d := range devices { - if d.Path == devPath { - return idx - } - } - return -1 -} - -func (b *SysBluetooth) getDeviceIndex(devPath dbus.ObjectPath) (adapterPath dbus.ObjectPath, index int) { - b.devicesMu.Lock() - defer b.devicesMu.Unlock() - return b.findDevice(devPath) -} - -func (b *SysBluetooth) getDevice(devPath dbus.ObjectPath) (*device, error) { - b.devicesMu.Lock() - defer b.devicesMu.Unlock() - adapterPath, index := b.findDevice(devPath) - if index < 0 { - return nil, errInvalidDevicePath - } - return b.devices[adapterPath][index], nil -} - -func (b *SysBluetooth) getBackupDevice(devPath dbus.ObjectPath) (*backupDevice, error) { - b.backupDevicesMu.Lock() - defer b.backupDevicesMu.Unlock() - adapterPath, index := b.findBackupDeviceNoLock(devPath) - if index < 0 { - return nil, errInvalidDevicePath - } - return b.backupDevices[adapterPath][index], nil -} - -// 更新 backupDevices -func (b *SysBluetooth) updateBackupDevices(adapterPath dbus.ObjectPath) { - logger.Debug("updateBackupDevices", adapterPath) - devices := b.getDevices(adapterPath) - b.backupDevicesMu.Lock() - defer b.backupDevicesMu.Unlock() - for _, device := range devices { - index := b.indexBackupDeviceNoLock(adapterPath, device.Path) - if index < 0 { - logger.Warning("[updateBackupDevices] invalid device path: ", device.Path) - } else { - b.backupDevices[adapterPath][index] = newBackupDevice(device) - } - } -} - -func (b *SysBluetooth) getAdapterDevices(adapterAddress string) []*device { - var aPath dbus.ObjectPath - b.adaptersMu.Lock() - for adapterPath, adapter := range b.adapters { - if adapter.Address == adapterAddress { - aPath = adapterPath - break - } - } - b.adaptersMu.Unlock() - - if aPath == "" { - return nil - } - - b.devicesMu.Lock() - defer b.devicesMu.Unlock() - - devices := b.devices[aPath] - if devices == nil { - return nil - } - - result := make([]*device, 0, len(devices)) - result = append(result, devices...) - return result -} - -func (b *SysBluetooth) addAdapter(adapterPath dbus.ObjectPath) { - logger.Debug("receive signal adapter added", adapterPath) - if b.isAdapterExists(adapterPath) { - return - } - - a := newAdapter(b.sigLoop, adapterPath) - a.bt = b - // initialize adapter power state - b.config.addAdapterConfig(a.Address) - cfgPowered := b.config.getAdapterConfigPowered(a.Address) - - err := a.core.Adapter().Powered().Set(0, cfgPowered) - if err != nil { - logger.Warning(err) - } - - err = a.core.Adapter().DiscoverableTimeout().Set(0, 0) - if err != nil { - logger.Warning(err) - } - - // 读取配置文件中可被发现状态值,并修改Discoverable属性值,默认为true - discoverable := b.config.getAdapterConfigDiscoverable(a.Address) - err = a.core.Adapter().Discoverable().Set(0, discoverable) - if err != nil { - logger.Warning(err) - } - - b.adaptersMu.Lock() - b.adapters[adapterPath] = a - b.adaptersMu.Unlock() - - a.notifyAdapterAdded() - b.acm.addAdapter(adapterPath) - logger.Debug("addAdapter", adapterPath) -} - -func (b *SysBluetooth) removeAdapter(adapterPath dbus.ObjectPath) { - logger.Debug("receive signal adapter removed", adapterPath) - b.adaptersMu.Lock() - - if b.adapters[adapterPath] == nil { - b.adaptersMu.Unlock() - logger.Warning("repeat remove adapter", adapterPath) - return - } - - b.doRemoveAdapter(adapterPath) - b.adaptersMu.Unlock() - - b.devicesMu.Lock() - b.devices[adapterPath] = nil - b.devicesMu.Unlock() - b.syncCommonToBackupDevices(adapterPath) -} - -func (b *SysBluetooth) doRemoveAdapter(adapterPath dbus.ObjectPath) { - // NOTE: do not remove adapter from config file - removeAdapter := b.adapters[adapterPath] - delete(b.adapters, adapterPath) - removeAdapter.notifyAdapterRemoved() - removeAdapter.destroy() - b.acm.removeAdapter(adapterPath) -} - -func (b *SysBluetooth) getAdapter(adapterPath dbus.ObjectPath) (adapter *adapter, err error) { - b.adaptersMu.Lock() - defer b.adaptersMu.Unlock() - - adapter = b.adapters[adapterPath] - if adapter == nil { - err = fmt.Errorf("adapter not exists %s", adapterPath) - logger.Error(err) - return - } - return -} - -func (b *SysBluetooth) isAdapterExists(adapterPath dbus.ObjectPath) bool { - b.adaptersMu.Lock() - defer b.adaptersMu.Unlock() - return b.adapters[adapterPath] != nil -} - -func (b *SysBluetooth) updateState() { - newState := StateUnavailable - if len(b.adapters) > 0 { - newState = StateAvailable - } - - for _, devices := range b.devices { - for _, d := range devices { - if d.adapter != nil && d.adapter.Powered && d.connected && d.Paired { - newState = StateConnected - break - } - } - } - - b.PropsMu.Lock() - b.setPropState(uint32(newState)) - b.PropsMu.Unlock() -} - -func (b *SysBluetooth) getAdapters() []*adapter { - b.adaptersMu.Lock() - defer b.adaptersMu.Unlock() - - result := make([]*adapter, 0, len(b.adapters)) - for _, adapter := range b.adapters { - result = append(result, adapter) - } - return result -} - -func (b *SysBluetooth) getDevices(adapterPath dbus.ObjectPath) []*device { - b.devicesMu.Lock() - defer b.devicesMu.Unlock() - - devices := b.devices[adapterPath] - result := make([]*device, len(devices)) - copy(result, devices) - return result -} - -func (b *SysBluetooth) tryConnectPairedDevices(adapterPath dbus.ObjectPath) { - if b.canAutoPair != nil { - if !b.canAutoPair() { - logger.Info("can't auto pair beacuse autoPairEnable key is unable") - return - } - } else { - return - } - - inputOnly := true - // 自动连接时长 - defaultConnectDuration := 2 * time.Minute - if b.getActiveUserAgent() != nil { - // 表示用户已经登录 - inputOnly = false - // 可能有用户控制,为便于用户控制,缩短自动连接时长。 - defaultConnectDuration = 20 * time.Second - } - logger.Debugf("tryConnectPairedDevices adapterPath: %q, inputOnly: %v", adapterPath, inputOnly) - adapterDevicesMap := b.getPairedDevicesForAutoConnect(adapterPath) - - for adapterPath, devices := range adapterDevicesMap { - if inputOnly { - // 登录界面,只需要输入设备 - devices = filterOutDevices(devices, func(device *device) bool { - return strings.HasPrefix(device.Icon, "input") - }) - } - logger.Debug("before soft devices:", devices) - b.config.softDevices(devices) - logger.Debug("after soft devices:", devices) - var deviceInfos []autoDeviceInfo - priority := 0 - // 可能由设备主动连接的设备 - var activeReconnectDevices []*device - for _, d := range devices { - if d.maybeReconnectByDevice() { - activeReconnectDevices = append(activeReconnectDevices, d) - } - connectDuration := defaultConnectDuration - if d.shouldReconnectByHost() { - logger.Debug("try auto connect", d) - } else { - logger.Debugf("do not auto connect %v, but try connect once", d) - connectDuration = 1 * time.Second - if !d.Trusted { - err := d.core.Trusted().Set(0, true) - if err != nil { - logger.Warning(err) - } - } - err := d.cancelBlock() - if err != nil { - logger.Warning(err) - } - } - deviceInfos = append(deviceInfos, autoDeviceInfo{ - adapter: adapterPath, - device: d.Path, - alias: d.Alias, - priority: priority, - connectDurationMax: connectDuration, - }) - priority++ - } - b.acm.addDevices(adapterPath, deviceInfos, activeReconnectDevices) - } -} - -func (b *SysBluetooth) autoConnectPairedDevice(devPath dbus.ObjectPath, adapterPath dbus.ObjectPath) error { - device, err := b.getDevice(devPath) - if err != nil { - return err - } - - if device.connected { - logger.Debugf("%v is already connected", device) - return nil - } - - switch device.Icon { - // 只自动连接一个这些图标的设备 - case devIconAudioCard, devIconInputKeyboard, devIconInputMouse, devIconInputTablet: - connectedDevice := b.findFirstConnectedDeviceByIcon(device.Icon) - if connectedDevice != nil { - logger.Debugf("there is already a connected %v, icon: %v, do not auto connect it: %v", - connectedDevice, device.Icon, device) - return nil - } - } - - logger.Debug("auto connect paired", device) - err = device.doConnect(false) - if err != nil { - logger.Debugf("failed to auto connect %v: %v", device, err) - // 设置 connect phase 可以造成界面上一直在连接,而不中断的情况。 - device.setConnectPhase(connectPhaseConnectFailedSleep) - time.Sleep(3 * time.Second) - device.setConnectPhase(connectPhaseNone) - } - return err -} - -// 当 adapterPath 为空时,获取所有适配器的配对,但未连接的设备。 -// 当 adapterPath 不为空时,或者获取指定适配器的配对,但未连接的设备。 -func (b *SysBluetooth) getPairedDevicesForAutoConnect(adapterPath dbus.ObjectPath) map[dbus.ObjectPath][]*device { - adapters := b.getAdapters() - if adapterPath != "" { - var theAdapter *adapter - for _, adapter := range adapters { - if adapter.Path == adapterPath { - theAdapter = adapter - break - } - } - if theAdapter == nil { - return nil - } - adapters = []*adapter{theAdapter} - } - result := make(map[dbus.ObjectPath][]*device) - for _, adapter := range adapters { - // 当适配器打开电源时才自动连接 - if !adapter.Powered { - continue - } - devices := b.getDevices(adapter.Path) - var tmpDevices []*device - for _, d := range devices { - if d != nil && d.Paired && !d.connected { - tmpDevices = append(tmpDevices, d) - } - } - - result[adapter.Path] = tmpDevices - } - - return result -} - -// 判断设备是否为经典蓝牙设备 -func (d *device) isBREDRDevice() bool { - technologies, err := d.getTechnologies() - if err != nil { - logger.Warningf("failed to get %v technologies: %v", - d, err) - return false - } - for _, tech := range technologies { - if tech == "BR/EDR" { - return true - } - } - return false -} - -func (b *SysBluetooth) addConnectedDevice(connectedDev *device) { - b.connectedMu.Lock() - b.connectedDevices[connectedDev.AdapterPath] = append(b.connectedDevices[connectedDev.AdapterPath], connectedDev) - b.connectedMu.Unlock() -} - -func (b *SysBluetooth) removeConnectedDevice(disconnectedDev *device) { - b.connectedMu.Lock() - // check if dev exist in connectedDevices map, if exist, remove device - if connectedDevices, ok := _bt.connectedDevices[disconnectedDev.AdapterPath]; ok { - var tempDevices []*device - for _, dev := range connectedDevices { - // check if disconnected device exist in connected devices, if exist, abandon this - if dev.Address != disconnectedDev.Address { - tempDevices = append(tempDevices, dev) - } - } - _bt.connectedDevices[disconnectedDev.AdapterPath] = tempDevices - } - b.connectedMu.Unlock() -} - -func (b *SysBluetooth) getConnectedDeviceByAddress(address string) *device { - b.connectedMu.Lock() - defer b.connectedMu.Unlock() - - for _, devices := range b.connectedDevices { - for _, dev := range devices { - if dev.Address == address { - return dev - } - } - } - - return nil -} - -func (b *SysBluetooth) findFirstConnectedDeviceByIcon(icon string) *device { - b.connectedMu.Lock() - defer b.connectedMu.Unlock() - - for _, devices := range b.connectedDevices { - for _, dev := range devices { - if dev.Icon == icon { - return dev - } - } - } - return nil -} diff --git a/system/bluetooth/bluetooth_ifc.go b/system/bluetooth/bluetooth_ifc.go deleted file mode 100644 index dcbb58fec..000000000 --- a/system/bluetooth/bluetooth_ifc.go +++ /dev/null @@ -1,429 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package bluetooth - -import ( - "fmt" - "strconv" - "time" - - "github.com/godbus/dbus" - sysbtagent "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.bluetooth.agent" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (b *SysBluetooth) ConnectDevice(devPath dbus.ObjectPath, adapterPath dbus.ObjectPath) *dbus.Error { - device, err := b.getDevice(devPath) - if err != nil { - logger.Debug("getDevice failed:", err) - adapter, err := b.getAdapter(adapterPath) - if err != nil { - logger.Debug("getAdapter failed:", err) - return dbusutil.ToError(err) - } - - // 当蓝牙在扫描中,打开蓝牙设备,扫描到蓝牙设备后,关闭蓝牙设备,此时bluez该设备已被移除,但backup中依旧存在蓝牙设备 - // 导致了控制中心第一次手动连接此蓝牙时报错,第二次连接时无响应,因此在第二次连接时直接将此蓝牙设备移除,并弹出横幅 - // Note Bug 107601 - bakDevice, err := b.getBackupDevice(devPath) - if err != nil { - logger.Warning("call getBackupDevice err:", err) - } else { - b.removeBackupDevice(devPath) - bakDevice.notifyDeviceRemoved() - notifyConnectFailedHostDown(bakDevice.Alias) - } - - // 当处于扫描状态时且无法得到device,将准备连接设备置空,防止自动连接 - if adapter.Discovering { - b.prepareToConnectedDevice = "" - return nil - } - - // 当扫描一分钟后停止,此时连接设备,会先开始扫描,然后将连接的此设备设为准备连接状态,发现此设备后,直接连接 - adapter.startDiscovery() - adapter.scanReadyToConnectDeviceTimeoutFlag = true - b.prepareToConnectedMu.Lock() - b.prepareToConnectedDevice = devPath - b.prepareToConnectedMu.Unlock() - } else { - go func() { - err := device.Connect() - if err != nil { - logger.Warning(err) - } - }() - } - return nil -} - -func (b *SysBluetooth) DisconnectDevice(devPath dbus.ObjectPath) *dbus.Error { - device, err := b.getDevice(devPath) - if err != nil { - return dbusutil.ToError(err) - } - go device.Disconnect() - return nil -} - -func (b *SysBluetooth) RemoveDevice(adapterPath, devPath dbus.ObjectPath) *dbus.Error { - adapter, err := b.getAdapter(adapterPath) - if err != nil { - return dbusutil.ToError(err) - } - // find remove device from map - removeDev, err := b.getDevice(devPath) - if err != nil { - logger.Warningf("failed to get device, err: %v", err) - return dbusutil.ToError(err) - } - - // 删除之前先取消配对,无论是否配对状态都应取消,防止配对过程中,关闭蓝牙异常 - err = removeDev.cancelPairing() - if err != nil { - logger.Warning("call cancelPairing err: ", err) - } - - // check if device connect state is connecting, if is, mark remove state as true - deviceState := removeDev.getState() - if deviceState == deviceStateConnecting { - removeDev.markNeedRemove(true) - } else { - // connection finish, allow removing device directly - b.removeBackupDevice(devPath) - err = adapter.core.Adapter().RemoveDevice(0, devPath) - if err != nil { - logger.Warningf("failed to remove device %q from adapter %q: %v", - devPath, adapterPath, err) - return dbusutil.ToError(err) - } - } - return nil -} - -func (b *SysBluetooth) SetDeviceAlias(device dbus.ObjectPath, alias string) *dbus.Error { - d, err := b.getDevice(device) - if err != nil { - return dbusutil.ToError(err) - } - err = d.core.Alias().Set(0, alias) - if err != nil { - return dbusutil.ToError(err) - } - return nil -} - -func (b *SysBluetooth) SetDeviceTrusted(device dbus.ObjectPath, trusted bool) *dbus.Error { - d, err := b.getDevice(device) - if err != nil { - return dbusutil.ToError(err) - } - err = d.core.Trusted().Set(0, trusted) - if err != nil { - return dbusutil.ToError(err) - } - return nil -} - -// GetDevices return all device objects that marshaled by json. -func (b *SysBluetooth) GetDevices(adapterPath dbus.ObjectPath) (devicesJSON string, busErr *dbus.Error) { - _, err := b.getAdapter(adapterPath) - if err != nil { - return "", dbusutil.ToError(err) - } - - var deviceMap = make(map[dbus.ObjectPath]*backupDevice) - b.backupDevicesMu.Lock() - for _, d := range b.backupDevices[adapterPath] { - deviceMap[d.Path] = d - } - b.backupDevicesMu.Unlock() - - b.devicesMu.Lock() - for _, d := range b.devices[adapterPath] { - deviceMap[d.Path] = newBackupDevice(d) - } - b.devicesMu.Unlock() - - var devices []*backupDevice - for _, d := range deviceMap { - devices = append(devices, d) - } - devicesJSON = marshalJSON(devices) - return -} - -// GetAdapters return all adapter objects that marshaled by json. -func (b *SysBluetooth) GetAdapters() (adaptersJSON string, err *dbus.Error) { - adapters := make([]*adapter, 0, len(b.adapters)) - b.adaptersMu.Lock() - for _, a := range b.adapters { - adapters = append(adapters, a) - } - b.adaptersMu.Unlock() - adaptersJSON = marshalJSON(adapters) - return -} - -func (b *SysBluetooth) RequestDiscovery(adapterPath dbus.ObjectPath) *dbus.Error { - adapter, err := b.getAdapter(adapterPath) - if err != nil { - return dbusutil.ToError(err) - } - - if !adapter.Powered { - err = fmt.Errorf("'%s' power off", adapter) - return dbusutil.ToError(err) - } - - discovering, err := adapter.core.Adapter().Discovering().Get(0) - if err != nil { - return dbusutil.ToError(err) - } - - if discovering { - // if adapter is discovering now, just return - return nil - } - - adapter.startDiscovery() - - return nil -} - -func (b *SysBluetooth) SetAdapterPowered(adapterPath dbus.ObjectPath, - powered bool) *dbus.Error { - - logger.Debug("SetAdapterPowered", adapterPath, powered) - - adapter, err := b.getAdapter(adapterPath) - if err != nil { - return dbusutil.ToError(err) - } - // 将DDE和前端的蓝牙 power 状态在设置时,立马保持同步 - // 为了避免,在下发power off给bluez后 bluez返回属性值中携带,power、discovering、class值,DDE在监听时, - // 当先收到 discovering,后收到power时 - // 在discovering改变时,此时power状态依旧为true,当时此时power是false状态,导致闪开后关闭 - // Note: BUG102434 - adapter.poweredActionTime = time.Now() - adapter.Powered = powered - adapter.discoveringFinished = false - - err = adapter.core.Adapter().Powered().Set(0, powered) - if err != nil { - logger.Warningf("failed to set %s powered: %v", adapter, err) - return dbusutil.ToError(err) - } - _bt.config.setAdapterConfigPowered(adapter.Address, powered) - - return nil -} - -func (b *SysBluetooth) SetAdapterAlias(adapterPath dbus.ObjectPath, alias string) *dbus.Error { - adapter, err := b.getAdapter(adapterPath) - if err != nil { - return dbusutil.ToError(err) - } - - err = adapter.core.Adapter().Alias().Set(0, alias) - if err != nil { - logger.Warningf("failed to set %s alias: %v", adapter, err) - return dbusutil.ToError(err) - } - - return nil -} - -func (b *SysBluetooth) SetAdapterDiscoverable(adapterPath dbus.ObjectPath, - discoverable bool) *dbus.Error { - logger.Debug("SetAdapterDiscoverable", adapterPath, discoverable) - - adapter, err := b.getAdapter(adapterPath) - if err != nil { - return dbusutil.ToError(err) - } - - if !adapter.Powered { - err = fmt.Errorf("'%s' power off", adapter) - return dbusutil.ToError(err) - } - - err = adapter.core.Adapter().Discoverable().Set(0, discoverable) - if err != nil { - logger.Warningf("failed to set %s discoverable: %v", adapter, err) - return dbusutil.ToError(err) - } - _bt.config.setAdapterConfigDiscoverable(adapter.Address, discoverable) - - return nil -} - -func (b *SysBluetooth) SetAdapterDiscovering(adapterPath dbus.ObjectPath, - discovering bool) *dbus.Error { - logger.Debug("SetAdapterDiscovering", adapterPath, discovering) - - adapter, err := b.getAdapter(adapterPath) - if err != nil { - return dbusutil.ToError(err) - } - - if !adapter.Powered { - err = fmt.Errorf("'%s' power off", adapter) - return dbusutil.ToError(err) - } - - if discovering { - adapter.startDiscovery() - } else { - err = adapter.core.Adapter().StopDiscovery(0) - if err != nil { - logger.Warningf("failed to stop discovery for %s: %v", adapter, err) - return dbusutil.ToError(err) - } - } - - return nil -} - -func (b *SysBluetooth) SetAdapterDiscoverableTimeout(adapterPath dbus.ObjectPath, - discoverableTimeout uint32) *dbus.Error { - logger.Debug("SetAdapterDiscoverableTimeout", adapterPath, discoverableTimeout) - - adapter, err := b.getAdapter(adapterPath) - if err != nil { - return dbusutil.ToError(err) - } - - err = adapter.core.Adapter().DiscoverableTimeout().Set(0, discoverableTimeout) - if err != nil { - logger.Warningf("failed to set %s discoverableTimeout: %v", adapter, err) - return dbusutil.ToError(err) - } - - return nil -} - -func (b *SysBluetooth) getActiveUserAgent() sysbtagent.Agent { - return b.userAgents.getActiveAgent() -} - -func (b *SysBluetooth) RegisterAgent(sender dbus.Sender, agentPath dbus.ObjectPath) *dbus.Error { - uid, err := b.service.GetConnUID(string(sender)) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - uidStr := strconv.Itoa(int(uid)) - b.userAgents.addUser(uidStr) - - sessionDetails, err := b.loginManager.ListSessions(0) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - sysBus := b.service.Conn() - for _, detail := range sessionDetails { - if detail.UID == uid { - session, err := login1.NewSession(sysBus, detail.Path) - if err != nil { - logger.Warning(err) - continue - } - newlyAdded := b.userAgents.addSession(uidStr, session) - if newlyAdded { - b.watchSession(uidStr, session) - } - } - } - - agent, err := sysbtagent.NewAgent(sysBus, string(sender), agentPath) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - b.userAgents.addAgent(uidStr, agent) - // 防止第一次进入系统,此时无设备连接,但是 needFixBtPoweredStatus 为true,此时打开蓝牙添加设备后paired为true - // 此时在调用addDevice接口后,会走不必要的逻辑,因此将此标志位置为false规避 - b.needFixBtPoweredStatus = false - go b.tryConnectPairedDevices("") - - logger.Debugf("agent registered, sender: %q, agentPath: %q", sender, agentPath) - return nil -} - -func (b *SysBluetooth) UnregisterAgent(sender dbus.Sender, agentPath dbus.ObjectPath) *dbus.Error { - uid, err := b.service.GetConnUID(string(sender)) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - uidStr := strconv.Itoa(int(uid)) - err = b.userAgents.removeAgent(uidStr, agentPath) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - logger.Debugf("agent unregistered, sender: %q, agentPath: %q", sender, agentPath) - return nil -} - -func (b *SysBluetooth) DebugInfo() (info string, busErr *dbus.Error) { - info = fmt.Sprintf("adapters: %s\ndevices: %s", marshalJSON(b.adapters), marshalJSON(b.devices)) - return info, nil -} - -//ClearUnpairedDevice will remove all device in unpaired list -func (b *SysBluetooth) ClearUnpairedDevice() *dbus.Error { - logger.Debug("ClearUnpairedDevice") - var removeDevices []*device - b.devicesMu.Lock() - for _, devices := range b.devices { - for _, d := range devices { - if !d.Paired { - logger.Info("remove unpaired device", d) - removeDevices = append(removeDevices, d) - } - } - } - b.devicesMu.Unlock() - - for _, d := range removeDevices { - err := b.RemoveDevice(d.AdapterPath, d.Path) - if err != nil { - logger.Warning(err) - } - } - return nil -} - -// 断开所有音频设备 -func (b *SysBluetooth) DisconnectAudioDevices() *dbus.Error { - logger.Debug("call DisconnectAudioDevices") - b.adaptersMu.Lock() - devices := make([]*device, 0, len(b.adapters)) - for aPath, _ := range b.adapters { - b.connectedMu.Lock() - for _, d := range b.connectedDevices[aPath] { - for _, uuid := range d.UUIDs { - if uuid == A2DP_SINK_UUID && d.connected { - logger.Infof("disconnect A2DP %s", d) - devices = append(devices, d) - } - } - } - b.connectedMu.Unlock() - } - b.adaptersMu.Unlock() - - for _, device := range devices { - device.Disconnect() - } - - return nil -} diff --git a/system/bluetooth/config_test.go b/system/bluetooth/config_test.go deleted file mode 100644 index 39b8ac091..000000000 --- a/system/bluetooth/config_test.go +++ /dev/null @@ -1,119 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package bluetooth - -import ( - "os" - "testing" - - "github.com/stretchr/testify/assert" -) - -const adapteraddress = "00:1A:7D:DA:71:13" -const deviceaddress = "00:1A:7D:DA:71:13/00:1A:7D:DA:71:11" -const testfile = "testfile" - -var _deviceConfig = &deviceConfig{ - Icon: "computer", - Connected: false, - LatestTime: 0, -} - -func Test_config(t *testing.T) { - configAdapters := map[string]*adapterConfig{ - "00:1A:7D:DA:71:13": { - Powered: false, - Discoverable: true, - }, - } - - configDevices := map[string]*deviceConfig{ - "00:1A:7D:DA:71:13/00:1A:7D:DA:71:11": { - Icon: "computer", - Connected: false, - LatestTime: 0, - }, - "00:1A:7D:DA:71:13/00:1A:7D:DA:71:13": { - Icon: "computer", - Connected: false, - LatestTime: 0, - }, - "00:1A:7D:DA:71:13/0B:4C:03:C8:EA:7C": { - Icon: "", - Connected: false, - LatestTime: 0, - }, - "00:1A:7D:DA:71:13/10:D0:7A:B1:D3:2F": { - Icon: "", - Connected: false, - LatestTime: 0, - }, - "00:1A:7D:DA:71:13/10:E9:53:E9:EA:3C": { - Icon: "phone", - Connected: false, - LatestTime: 0, - }, - } - - c := &config{} - c.core.SetConfigFile(testfile) - logger.Info("load bluetooth config file:", c.core.GetConfigFile()) - c.Adapters = make(map[string]*adapterConfig) - c.Devices = make(map[string]*deviceConfig) - //c.Discoverable = true - - c.addAdapterConfig(adapteraddress) - - for address, configDevice := range configDevices { - c.addConfigDevice(address, configDevice) - } - - c.load() - - assert.Equal(t, c.Adapters, configAdapters) - assert.Equal(t, c.Devices, configDevices) - //assert.True(t, c.Discoverable) - - c.setAdapterConfigPowered(adapteraddress, false) - assert.False(t, c.getAdapterConfigPowered(adapteraddress)) - - c.setAdapterConfigPowered(adapteraddress, true) - assert.True(t, c.getAdapterConfigPowered(adapteraddress)) - - c.setConfigDeviceConnected(deviceaddress, _deviceConfig, true) - assert.True(t, c.getDeviceConfigConnected(deviceaddress)) - - c.setConfigDeviceConnected(deviceaddress, _deviceConfig, false) - assert.False(t, c.getDeviceConfigConnected(deviceaddress)) - - err := os.Remove(testfile) - logger.Warning("Remove failed:", err) -} - -func (c *config) addConfigDevice(address string, addDeviceconfig *deviceConfig) { - if c.isDeviceConfigExist(address) { - return - } - - deviceInfo := newDeviceConfig() - deviceInfo.Icon = addDeviceconfig.Icon - deviceInfo.LatestTime = 0 - deviceInfo.Connected = addDeviceconfig.Connected - - c.Devices[address] = deviceInfo - c.save() -} - -func (c *config) setConfigDeviceConnected(address string, Deviceconfig *deviceConfig, connected bool) { - dc, ok := c.getDeviceConfig(address) - if !ok { - return - } - - dc.Connected = connected - dc.Icon = Deviceconfig.Icon - - c.save() -} diff --git a/system/bluetooth/device.go b/system/bluetooth/device.go deleted file mode 100644 index e3931576d..000000000 --- a/system/bluetooth/device.go +++ /dev/null @@ -1,908 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package bluetooth - -import ( - "errors" - "fmt" - "path/filepath" - "strings" - "sync" - "time" - - "github.com/godbus/dbus" - bluez "github.com/linuxdeepin/go-dbus-factory/org.bluez" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/dbusutil/proxy" -) - -const ( - deviceStateDisconnected = 0 - // device state is connecting or disconnecting, mark them as device state doing - deviceStateConnecting = 1 - deviceStateConnected = 2 - deviceStateDisconnecting = 3 -) - -const ( - resourceUnavailable = "Resource temporarily unavailable" -) - -type deviceState uint32 - -func (s deviceState) String() string { - switch s { - case deviceStateDisconnected: - return "Disconnected" - case deviceStateConnecting: - return "Connecting" - case deviceStateConnected: - return "Connected" - case deviceStateDisconnecting: - return "Disconnecting" - default: - return fmt.Sprintf("Unknown(%d)", s) - } -} - -var ( - errInvalidDevicePath = fmt.Errorf("invalid device path") -) - -type device struct { - core bluez.Device - adapter *adapter - - Path dbus.ObjectPath - AdapterPath dbus.ObjectPath - - Alias string - Trusted bool - Paired bool - State deviceState - ServicesResolved bool - ConnectState bool - - // optional - UUIDs []string - Name string - Icon string - RSSI int16 - Address string - - connected bool - connectedTime time.Time - retryConnectCount int - agentWorking bool - needNotify bool - - connectPhase connectPhase - disconnectPhase disconnectPhase - disconnectChan chan struct{} - mu sync.Mutex - pairingFailedTime time.Time - - // mark if pc or mobile request a connection - // if is pc, then do not need to show notification window - // else show notification window - isInitiativeConnect bool - // remove device when device state is connecting or disconnecting may cause blueZ crash - // to avoid this situation, remove device only allowed when connected or disconnected finished - needRemove bool - removeLock sync.Mutex - inputReconnectMode string - blocked bool -} - -//设备的备份,扫描结束3分钟后保存设备 -type backupDevice struct { - Path dbus.ObjectPath - AdapterPath dbus.ObjectPath - - Alias string - Trusted bool - Paired bool - State deviceState - ServicesResolved bool - ConnectState bool - - // optional - UUIDs []string - Name string - Icon string - RSSI int16 - Address string -} - -type connectPhase uint32 - -const ( - connectPhaseNone = iota - connectPhaseStart - connectPhasePairStart - connectPhasePairEnd - connectPhaseConnectProfilesStart - connectPhaseConnectProfilesEnd - connectPhaseConnectFailedSleep // 反复连接过程中,失败后的短暂延时 -) - -type disconnectPhase uint32 - -const ( - disconnectPhaseNone = iota - disconnectPhaseStart - disconnectPhaseDisconnectStart - disconnectPhaseDisconnectEnd -) - -func (d *device) setDisconnectPhase(value disconnectPhase) { - d.mu.Lock() - d.disconnectPhase = value - d.mu.Unlock() - - switch value { - case disconnectPhaseDisconnectStart: - logger.Debugf("%s disconnect start", d) - case disconnectPhaseDisconnectEnd: - logger.Debugf("%s disconnect end", d) - } - d.updateState() - d.notifyDevicePropertiesChanged() -} - -func (d *device) getDisconnectPhase() disconnectPhase { - d.mu.Lock() - value := d.disconnectPhase - d.mu.Unlock() - return value -} - -func (d *device) setConnectPhase(value connectPhase) { - d.mu.Lock() - d.connectPhase = value - d.mu.Unlock() - - switch value { - case connectPhasePairStart: - logger.Debugf("%s pair start", d) - case connectPhasePairEnd: - logger.Debugf("%s pair end", d) - - case connectPhaseConnectProfilesStart: - logger.Debugf("%s connect profiles start", d) - case connectPhaseConnectProfilesEnd: - logger.Debugf("%s connect profiles end", d) - } - - d.updateState() - d.notifyDevicePropertiesChanged() - if d.Paired && d.State == deviceStateConnected && d.ConnectState && d.needNotify { - d.needNotify = false - notifyConnected(d.Alias) - } -} - -func (d *device) getConnectPhase() connectPhase { - d.mu.Lock() - value := d.connectPhase - d.mu.Unlock() - return value -} - -func (d *device) agentWorkStart() { - logger.Debugf("%s agent work start", d) - d.mu.Lock() - d.agentWorking = true - d.mu.Unlock() - d.updateState() - d.notifyDevicePropertiesChanged() -} - -func (d *device) agentWorkEnd() { - logger.Debugf("%s agent work end", d) - d.mu.Lock() - d.agentWorking = false - d.mu.Unlock() - d.updateState() - d.notifyDevicePropertiesChanged() -} - -func (d *device) String() string { - return fmt.Sprintf("device [%s] %s", d.Address, d.Alias) -} - -func newDevice(systemSigLoop *dbusutil.SignalLoop, dpath dbus.ObjectPath) (d *device) { - d = &device{Path: dpath} - systemConn := systemSigLoop.Conn() - d.core, _ = bluez.NewDevice(systemConn, dpath) - d.AdapterPath, _ = d.core.Adapter().Get(0) - d.Name, _ = d.core.Name().Get(0) - d.Alias, _ = d.core.Alias().Get(0) - d.Address, _ = d.core.Address().Get(0) - d.Trusted, _ = d.core.Trusted().Get(0) - d.Paired, _ = d.core.Paired().Get(0) - d.connected, _ = d.core.Connected().Get(0) - d.UUIDs, _ = d.core.UUIDs().Get(0) - d.ServicesResolved, _ = d.core.ServicesResolved().Get(0) - d.Icon, _ = d.core.Icon().Get(0) - d.RSSI, _ = d.core.RSSI().Get(0) - d.blocked, _ = d.core.Blocked().Get(0) - d.needNotify = true - var err error - d.inputReconnectMode, err = d.getInputReconnectModeRaw() - if err != nil { - logger.Warning(err) - } - d.updateState() - - // 升级后第一次进入系统,登录界面时,当之前有蓝牙连接时,打开蓝牙开关(蓝牙可被发现状态 为默认状态),否则关闭 - if d.Paired && _bt.needFixBtPoweredStatus { - // 防止多个设备反复打开蓝牙 - adapter, err := _bt.getAdapter(d.AdapterPath) - if err != nil { - return - } - - if !adapter.Powered { - _bt.SetAdapterPowered(d.AdapterPath, true) - _bt.needFixBtPoweredStatus = false - } - } - - if d.Paired && d.connected { - d.ConnectState = true - //切換用户时添加设备到connectedDevices列表中 - _bt.addConnectedDevice(d) - } - d.disconnectChan = make(chan struct{}) - d.core.InitSignalExt(systemSigLoop, true) - d.connectProperties() - return -} - -func (d *device) destroy() { - d.core.RemoveHandler(proxy.RemoveAllHandlers) -} - -func (d *device) notifyDeviceAdded() { - logger.Debug("notifyDeviceAdded", d.Alias, d.Path) - err := _bt.service.Emit(_bt, "DeviceAdded", marshalJSON(d)) - if err != nil { - logger.Warning(err) - } - _bt.updateState() -} - -func (d *device) notifyDeviceRemoved() { - logger.Debug("notifyDeviceRemoved", d.Alias, d.Path) - err := _bt.service.Emit(_bt, "DeviceRemoved", marshalJSON(d)) - if err != nil { - logger.Warning(err) - } - _bt.updateState() -} - -func (d *device) notifyDevicePropertiesChanged() { - err := _bt.service.Emit(_bt, "DevicePropertiesChanged", marshalJSON(d)) - if err != nil { - logger.Warning(err) - } - _bt.updateState() -} - -func (d *device) connectProperties() { - err := d.core.Connected().ConnectChanged(func(hasValue bool, connected bool) { - if !hasValue { - return - } - logger.Debugf("%s Connected: %v", d, connected) - d.connected = connected - - //音频设备主动发起连接时也断开之前的音频连接 - if d.connected && d.Paired { - go d.audioA2DPWorkaround() - } - - // check if device need to be removed, if is, remove device - needRemove := d.getAndResetNeedRemove() - if needRemove { - // start remove device - d.adapter.bt.removeBackupDevice(d.Path) - err := d.adapter.core.Adapter().RemoveDevice(0, d.Path) - if err != nil { - logger.Warningf("failed to remove device %q from adapter %q: %v", - d.adapter.Path, d.Path, err) - return - } - return - } - - if connected { - d.ConnectState = true - d.connectedTime = time.Now() - _bt.config.setDeviceConfigConnected(d, true) - _bt.acm.handleDeviceEvent(d) - dev := _bt.getConnectedDeviceByAddress(d.Address) - if dev == nil { - _bt.addConnectedDevice(d) - logger.Debug("connectedDevices", _bt.connectedDevices) - } - } else { - //If the pairing is successful and connected, the signal will be sent when the device is disconnected - if d.Paired && d.ConnectState { - notifyDisconnected(d.Alias) - } - d.needNotify = true - d.ConnectState = false - - // if disconnect success, remove device from map - _bt.removeConnectedDevice(d) - // when disconnected quickly after connecting, automatically try to connect - sinceConnected := time.Since(d.connectedTime) - logger.Debug("sinceConnected:", sinceConnected) - logger.Debug("retryConnectCount:", d.retryConnectCount) - - if sinceConnected < 300*time.Millisecond { - if d.retryConnectCount == 0 { - go func() { - err := d.Connect() - if err != nil { - logger.Warning(err) - } - }() - } - d.retryConnectCount++ - } else if sinceConnected > 2*time.Second { - d.retryConnectCount = 0 - } - - select { - case d.disconnectChan <- struct{}{}: - logger.Debugf("%s disconnectChan send done", d) - default: - } - } - d.updateState() - d.notifyDevicePropertiesChanged() - - if d.needNotify && d.Paired && d.State == deviceStateConnected && d.ConnectState { - d.notifyConnectedChanged() - } - }) - if err != nil { - logger.Warning(err) - } - - _ = d.core.Name().ConnectChanged(func(hasValue bool, value string) { - if !hasValue { - return - } - logger.Debugf("%s Name: %v", d, value) - d.Name = value - d.notifyDevicePropertiesChanged() - }) - - _ = d.core.Alias().ConnectChanged(func(hasValue bool, value string) { - if !hasValue { - return - } - d.Alias = value - logger.Debugf("%s Alias: %v", d, value) - d.notifyDevicePropertiesChanged() - }) - - _ = d.core.Address().ConnectChanged(func(hasValue bool, value string) { - if !hasValue { - return - } - d.Address = value - logger.Debugf("%s Address: %v", d, value) - d.notifyDevicePropertiesChanged() - }) - - _ = d.core.Trusted().ConnectChanged(func(hasValue bool, value bool) { - if !hasValue { - return - } - d.Trusted = value - logger.Debugf("%s Trusted: %v", d, value) - d.notifyDevicePropertiesChanged() - }) - - _ = d.core.Paired().ConnectChanged(func(hasValue bool, value bool) { - if !hasValue { - return - } - d.Paired = value - d.updateState() // Paired属性被修改,影响到下面使用的State和ConnectState - logger.Debugf("%s Paired: %v State: %v", d, value, d.State) - - if d.Paired && d.connected && d.State == deviceStateConnected { - d.ConnectState = true - dev := _bt.getConnectedDeviceByAddress(d.Address) - if dev == nil { - _bt.addConnectedDevice(d) - } - } - - if d.needNotify && d.Paired && d.State == deviceStateConnected && d.ConnectState { - notifyConnected(d.Alias) - d.needNotify = false - } - d.notifyDevicePropertiesChanged() - }) - - _ = d.core.ServicesResolved().ConnectChanged(func(hasValue bool, value bool) { - if !hasValue { - return - } - d.ServicesResolved = value - logger.Debugf("%s ServicesResolved: %v", d, value) - d.notifyDevicePropertiesChanged() - }) - - _ = d.core.Icon().ConnectChanged(func(hasValue bool, value string) { - if !hasValue { - return - } - d.Icon = value - logger.Debugf("%s Icon: %v", d, value) - d.notifyDevicePropertiesChanged() - var err error - d.inputReconnectMode, err = d.getInputReconnectModeRaw() - if err != nil { - logger.Warning(err) - } - }) - - _ = d.core.UUIDs().ConnectChanged(func(hasValue bool, value []string) { - if !hasValue { - return - } - d.UUIDs = value - logger.Debugf("%s UUIDs: %v", d, value) - d.notifyDevicePropertiesChanged() - }) - - _ = d.core.RSSI().ConnectChanged(func(hasValue bool, value int16) { - if !hasValue { - d.RSSI = 0 - logger.Debugf("%s RSSI invalidated", d) - } else { - d.RSSI = value - logger.Debugf("%s RSSI: %v", d, value) - } - d.notifyDevicePropertiesChanged() - }) - - _ = d.core.LegacyPairing().ConnectChanged(func(hasValue bool, value bool) { - if !hasValue { - return - } - logger.Debugf("%s LegacyPairing: %v", d, value) - }) - - _ = d.core.Blocked().ConnectChanged(func(hasValue bool, value bool) { - if !hasValue { - return - } - logger.Debugf("%s Blocked: %v", d, value) - d.blocked = value - }) -} - -func (d *device) notifyConnectedChanged() { - connectPhase := d.getConnectPhase() - if connectPhase != connectPhaseNone { - // connect is in progress - logger.Debugf("%s handleNotifySend: connect is in progress", d) - return - } - - disconnectPhase := d.getDisconnectPhase() - if disconnectPhase != disconnectPhaseNone { - // disconnect is in progress - logger.Debugf("%s handleNotifySend: disconnect is in progress", d) - return - } - - if d.connected { - notifyConnected(d.Alias) - d.needNotify = false - //} else { - // if time.Since(d.pairingFailedTime) < 2*time.Second { - // return - // } - // notifyDisconnected(d.Alias) - } -} - -func (d *device) updateState() { - newState := d.getState() - if d.State != newState { - d.State = newState - logger.Debugf("%s State: %s", d, d.State) - } -} - -func (d *device) getState() deviceState { - d.mu.Lock() - defer d.mu.Unlock() - if d.agentWorking { - return deviceStateConnecting - } - - if d.connectPhase != connectPhaseNone { - return deviceStateConnecting - - } else if d.disconnectPhase != connectPhaseNone { - return deviceStateDisconnecting - - } else { - if d.connected && d.Paired { - return deviceStateConnected - } else { - return deviceStateDisconnected - } - } -} - -func (d *device) getAddress() string { - if d.adapter != nil { - return d.adapter.Address + "/" + d.Address - } - return "/" -} - -func (d *device) doConnect(hasNotify bool) error { - connectPhase := d.getConnectPhase() - disconnectPhase := d.getDisconnectPhase() - if connectPhase != connectPhaseNone { - logger.Warningf("%s connect is in progress", d) - return nil - } else if disconnectPhase != disconnectPhaseNone { - logger.Debugf("%s disconnect is in progress", d) - return nil - } - - d.setConnectPhase(connectPhaseStart) - defer d.setConnectPhase(connectPhaseNone) - - err := d.cancelBlock() - if err != nil { - // if hasNotify { - // // TODO(jouyouyun): notify device blocked - // } - return err - } - - err = d.doPair() - if err != nil { - d.ConnectState = false - if hasNotify { - notifyConnectFailedHostDown(d.Alias) - } - return err - } - - d.audioA2DPWorkaround() - - err = d.doRealConnect() - if err != nil { - if hasNotify { - if resourceUnavailable == err.Error() { - notifyConnectFailedResourceUnavailable(d.Alias, d.adapter.Alias) - } else { - notifyConnectFailedHostDown(d.Alias) - } - } - d.ConnectState = false - return err - } - - d.ConnectState = true - d.notifyDevicePropertiesChanged() - if d.needNotify && d.Paired && d.State == deviceStateConnected && d.ConnectState { - notifyConnected(d.Alias) - d.needNotify = false - } - return nil -} - -func (d *device) doRealConnect() error { - d.setConnectPhase(connectPhaseConnectProfilesStart) - err := d.core.Connect(0) - d.setConnectPhase(connectPhaseConnectProfilesEnd) - if err != nil { - if strings.Contains(err.Error(), "Input/output error") { - logger.Info("Input/output error -> ignore profile fail.") - } else { - // connect failed - logger.Warningf("%s connect failed: %v", d, err) - _bt.config.setDeviceConfigConnected(d, false) - return err - } - } - - // connect succeeded - logger.Infof("%s connect succeeded", d) - _bt.config.setDeviceConfigConnected(d, true) - - // auto trust device when connecting success - err = d.doTrust() - if err != nil { - logger.Warning(err) - } - - return nil -} - -func (d *device) doTrust() error { - trusted, _ := d.core.Trusted().Get(0) - if trusted { - return nil - } - err := d.core.Trusted().Set(0, true) - if err != nil { - logger.Warning(err) - } - return err -} - -func (d *device) cancelBlock() error { - blocked, err := d.core.Blocked().Get(0) - if err != nil { - logger.Warning(err) - return err - } - if !blocked { - return nil - } - err = d.core.Blocked().Set(0, false) - if err != nil { - logger.Warning(err) - } - return err -} - -func (d *device) cancelPairing() error { - err := d.core.CancelPairing(0) - - return err -} - -func (d *device) doPair() error { - paired, err := d.core.Paired().Get(0) - if err != nil { - logger.Warning(err) - return err - } - if paired { - logger.Debugf("%s already paired", d) - return nil - } - - d.setConnectPhase(connectPhasePairStart) - err = d.core.Pair(0) - d.setConnectPhase(connectPhasePairEnd) - if err != nil { - logger.Warningf("%s pair failed: %v", d, err) - d.pairingFailedTime = time.Now() - d.setConnectPhase(connectPhaseNone) - return err - } - - logger.Warningf("%s pair succeeded", d) - return nil -} - -func (d *device) markNeedRemove(need bool) { - d.removeLock.Lock() - d.needRemove = need - d.removeLock.Unlock() -} - -// get and reset needRemove -func (d *device) getAndResetNeedRemove() bool { - d.removeLock.Lock() - defer d.removeLock.Unlock() - needRemove := d.needRemove - // if needRemove is true, reset needRemove - if needRemove { - d.needRemove = false - } - return needRemove -} - -func (d *device) audioA2DPWorkaround() { - // TODO: remove work code if bluez a2dp is ok - // bluez do not support muti a2dp devices - // disconnect a2dp device before connect - for _, uuid := range d.UUIDs { - if uuid == A2DP_SINK_UUID { - _bt.disconnectA2DPDeviceExcept(d) - } - } -} - -func (d *device) Connect() error { - logger.Debug(d, "call Connect()") - err := d.doConnect(true) - return err -} - -func (d *device) Disconnect() { - logger.Debugf("%s call Disconnect()", d) - - disconnectPhase := d.getDisconnectPhase() - if disconnectPhase != disconnectPhaseNone { - logger.Debugf("%s disconnect is in progress", d) - return - } - - d.setDisconnectPhase(disconnectPhaseStart) - defer d.setDisconnectPhase(disconnectPhaseNone) - - connected, err := d.core.Connected().Get(0) - if err != nil { - logger.Warning(err) - return - } - if !connected { - logger.Debugf("%s not connected", d) - return - } - - // 如果是 LE 或由设备主动重连接的设备, 则先设置 Trusted 为 false, 防止很快地重连接。 - if d.maybeReconnectByDevice() { - err = d.core.Trusted().Set(0, false) - if err != nil { - logger.Warning("set trusted failed:", err) - } - } - - _bt.config.setDeviceConfigConnected(d, false) - - ch := d.goWaitDisconnect() - - d.setDisconnectPhase(disconnectPhaseDisconnectStart) - err = d.core.Disconnect(0) - if err != nil { - logger.Warningf("failed to disconnect %s: %v", d, err) - } - d.setDisconnectPhase(disconnectPhaseDisconnectEnd) - d.ConnectState = false - d.notifyDevicePropertiesChanged() - - <-ch - notifyDisconnected(d.Alias) - d.needNotify = true -} - -func (d *device) maybeReconnectByDevice() bool { - reconnectMode, err := d.getInputReconnectMode() - if err != nil { - logger.Warning(err) - } - if (reconnectMode == inputReconnectModeDevice || reconnectMode == inputReconnectModeAny) || - !d.isBREDRDevice() { - return true - } - return false -} - -func (d *device) shouldReconnectByHost() bool { - reconnectMode, err := d.getInputReconnectMode() - if err != nil { - logger.Warning(err) - } - if reconnectMode == inputReconnectModeDevice { - return false - } - if (reconnectMode == inputReconnectModeHost || reconnectMode == inputReconnectModeAny) || - d.isBREDRDevice() { - return true - } - return false -} - -//nolint -const ( - inputReconnectModeNone = "none" - inputReconnectModeHost = "host" - inputReconnectModeDevice = "device" - inputReconnectModeAny = "any" -) - -func (d *device) getInputReconnectMode() (string, error) { - if d.inputReconnectMode != "" { - return d.inputReconnectMode, nil - } - return d.getInputReconnectModeRaw() -} - -func (d *device) getInputReconnectModeRaw() (string, error) { - sysBus, err := dbus.SystemBus() - if err != nil { - return "", err - } - obj := sysBus.Object(d.core.ServiceName_(), d.core.Path_()) - if strings.HasPrefix(d.Icon, "input") { - propVar, err := obj.GetProperty("org.bluez.Input1.ReconnectMode") - if err != nil { - busErr, ok := err.(dbus.Error) - if ok && strings.Contains(strings.ToLower(busErr.Error()), "no such interface") { - // 这个接口不是一定存在的,所以忽略这种错误。 - return "", nil - } - return "", err - } - mode, ok := propVar.Value().(string) - if !ok { - return "", errors.New("type of the property value is not string") - } - return mode, nil - } - return "", nil -} - -func (d *device) goWaitDisconnect() chan struct{} { - ch := make(chan struct{}) - go func() { - select { - case <-d.disconnectChan: - logger.Debugf("%s disconnectChan receive ok", d) - case <-time.After(60 * time.Second): - logger.Debugf("%s disconnectChan receive timed out", d) - } - ch <- struct{}{} - }() - return ch -} - -func (d *device) getTechnologies() ([]string, error) { - if d.adapter == nil { - return nil, errors.New("d.adapter is nil") - } - var filename = filepath.Join(bluetoothPrefixDir, d.adapter.Address, d.Address, "info") - techs, err := doGetDeviceTechnologies(filename) - return techs, err -} - -// 按条件过滤出期望的设备,fn 返回 true 表示需要。 -func filterOutDevices(devices []*device, fn func(d *device) bool) (result []*device) { - for _, d := range devices { - if fn(d) { - result = append(result, d) - } - } - return -} - -func newBackupDevice(d *device) (bd *backupDevice) { - bd = &backupDevice{} - bd.AdapterPath = d.AdapterPath - bd.Path = d.Path - bd.Alias = d.Alias - bd.Paired = d.Paired - bd.Address = d.Address - bd.State = d.State - bd.Name = d.Name - bd.ConnectState = d.ConnectState - bd.Icon = d.Icon - bd.RSSI = d.RSSI - bd.ServicesResolved = d.ServicesResolved - bd.Trusted = d.Trusted - bd.UUIDs = d.UUIDs - return bd -} - -func (d *backupDevice) notifyDeviceRemoved() { - logger.Debug("backupDevice notifyDeviceRemoved", d.Alias, d.Path) - err := _bt.service.Emit(_bt, "DeviceRemoved", marshalJSON(d)) - if err != nil { - logger.Warning(err) - } -} diff --git a/system/bluetooth/a2dp_workaround.go b/system/bluetooth1/a2dp_workaround.go similarity index 91% rename from system/bluetooth/a2dp_workaround.go rename to system/bluetooth1/a2dp_workaround.go index 81b59ce7b..d17cf3bd4 100644 --- a/system/bluetooth/a2dp_workaround.go +++ b/system/bluetooth1/a2dp_workaround.go @@ -7,7 +7,7 @@ package bluetooth func (b *SysBluetooth) disconnectA2DPDeviceExcept(d *device) { for _, devices := range b.devices { for _, device := range devices { - if device.Path == d.Path { + if device == nil || device.Path == d.Path { continue } for _, uuid := range device.UUIDs { diff --git a/system/bluetooth1/adapter.go b/system/bluetooth1/adapter.go new file mode 100644 index 000000000..9a4cb5fc0 --- /dev/null +++ b/system/bluetooth1/adapter.go @@ -0,0 +1,253 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package bluetooth + +import ( + "fmt" + "os" + "time" + + "github.com/godbus/dbus/v5" + bluez "github.com/linuxdeepin/go-dbus-factory/system/org.bluez" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/dbusutil/proxy" +) + +type adapter struct { + bt *SysBluetooth + core bluez.HCI + Address string + + Path dbus.ObjectPath + Name string + Alias string + Powered bool + Discovering bool + Discoverable bool + DiscoverableTimeout uint32 + // discovering timer, when time is up, stop discovering until start button is clicked next time + discoveringTimer *time.Timer + // 扫描完成 + discoveringFinished bool + scanReadyToConnectDeviceTimeoutFlag bool + // 自动回连完成标志位 + autoConnectFinished bool + // waitDiscovery未使用 + // waitDiscovery bool + poweredActionTime time.Time +} + +var defaultDiscoveringTimeout = 30 * time.Second + +func newAdapter(systemSigLoop *dbusutil.SignalLoop, objPath dbus.ObjectPath) (a *adapter) { + a = &adapter{Path: objPath, autoConnectFinished: false} + systemConn := systemSigLoop.Conn() + a.core, _ = bluez.NewHCI(systemConn, objPath) + a.core.InitSignalExt(systemSigLoop, true) + a.connectProperties() + a.Address, _ = a.core.Adapter().Address().Get(0) + // a.waitDiscovery = true + // 用于定时停止扫描 + a.discoveringTimer = time.AfterFunc(defaultDiscoveringTimeout, func() { + logger.Debug("discovery time out, stop discovering") + // NOTE: 扫描结束后不用备份设备,因为处理设备添加时就会同时备份设备。 + //Scan timeout + a.discoveringFinished = true + if err := a.core.Adapter().StopDiscovery(0); err != nil { + logger.Warningf("stop discovery failed, err:%v", err) + } + _bt.prepareToConnectedDevice = "" + }) + // stop timer at first + a.discoveringTimer.Stop() + // fix alias + alias, _ := a.core.Adapter().Alias().Get(0) + if alias == "first-boot-hostname" { + hostname, err := os.Hostname() + if err == nil { + if hostname != "first-boot-hostname" { + // reset alias + err = a.core.Adapter().Alias().Set(0, "") + if err != nil { + logger.Warning(err) + } + } + } else { + logger.Warning("failed to get hostname:", err) + } + } + + a.Alias, _ = a.core.Adapter().Alias().Get(0) + a.Name, _ = a.core.Adapter().Name().Get(0) + a.Powered, _ = a.core.Adapter().Powered().Get(0) + a.Discovering, _ = a.core.Adapter().Discovering().Get(0) + a.Discoverable, _ = a.core.Adapter().Discoverable().Get(0) + a.DiscoverableTimeout, _ = a.core.Adapter().DiscoverableTimeout().Get(0) + return +} + +func (a *adapter) destroy() { + a.core.RemoveHandler(proxy.RemoveAllHandlers) +} + +func (a *adapter) String() string { + return fmt.Sprintf("adapter %s [%s]", a.Alias, a.Address) +} + +func (a *adapter) notifyAdapterAdded() { + logger.Info("AdapterAdded", a) + err := _bt.service.Emit(_bt, "AdapterAdded", marshalJSON(a)) + if err != nil { + logger.Warning(err) + } + _bt.updateState() +} + +func (a *adapter) notifyAdapterRemoved() { + logger.Info("AdapterRemoved", a) + err := _bt.service.Emit(_bt, "AdapterRemoved", marshalJSON(a)) + if err != nil { + logger.Warning(err) + } + _bt.updateState() +} + +func (a *adapter) notifyPropertiesChanged() { + err := _bt.service.Emit(_bt, "AdapterPropertiesChanged", marshalJSON(a)) + if err != nil { + logger.Warning(err) + } + _bt.updateState() +} + +func (a *adapter) connectProperties() { + err := a.core.Adapter().Name().ConnectChanged(func(hasValue bool, value string) { + if !hasValue { + return + } + a.Name = value + logger.Debugf("%s Name: %v", a, value) + a.notifyPropertiesChanged() + }) + if err != nil { + logger.Warning(err) + } + + err = a.core.Adapter().Alias().ConnectChanged(func(hasValue bool, value string) { + if !hasValue { + return + } + a.Alias = value + logger.Debugf("%s Alias: %v", a, value) + a.notifyPropertiesChanged() + }) + if err != nil { + logger.Warning(err) + } + + err = a.core.Adapter().Powered().ConnectChanged(func(hasValue bool, value bool) { + if !hasValue { + return + } + // 接口操作时效内,按接口配置状态配置蓝牙状态。 + if a.Powered != value && time.Since(a.poweredActionTime) < time.Second { + logger.Debug("sync power status because dde power status opt is working") + go a.core.Adapter().Powered().Set(0, a.Powered) + return + } + a.Powered = value + logger.Debugf("%s Powered: %v", a, value) + if a.Powered { + //err := a.core.Adapter().Discoverable().Set(0, _bt.config.Discoverable) + //if err != nil { + // logger.Warningf("failed to set discoverable for %s: %v", a, err) + //} + go func() { + err = a.core.Adapter().StopDiscovery(0) + if err != nil { + logger.Warningf("failed to stop discovery for %s: %v", a, err) + } + // a.waitDiscovery = true + // in case auto connect to device failed, only when signal power on is received, try to auto connect device + _bt.tryConnectPairedDevices(a.Path) + }() + } else { + // if power off, stop discovering time out + a.discoveringTimer.Stop() + a.bt.syncCommonToBackupDevices(a.Path) + } + // Sleep for 1s and wait for bluez to set the attributes before sending the attribute change signal + time.Sleep(1 * time.Second) + a.notifyPropertiesChanged() + }) + if err != nil { + logger.Warning(err) + } + + err = a.core.Adapter().Discovering().ConnectChanged(func(hasValue bool, value bool) { + if !hasValue { + return + } + if a.Discovering != value { + a.Discovering = value + logger.Debugf("%s Discovering: %v", a, value) + + if value { + a.bt.syncCommonToBackupDevices(a.Path) + a.discoveringTimer.Reset(defaultDiscoveringTimeout) + } else { + // 停止扫描了,设备属性不会再更新了,于是更新设备到备份设备 + a.bt.updateBackupDevices(a.Path) + } + a.notifyPropertiesChanged() + } + }) + if err != nil { + logger.Warning(err) + } + + err = a.core.Adapter().Discoverable().ConnectChanged(func(hasValue bool, value bool) { + if !hasValue { + return + } + a.Discoverable = value + logger.Debugf("%s Discoverable: %v", a, value) + a.notifyPropertiesChanged() + }) + if err != nil { + logger.Warning(err) + } + + err = a.core.Adapter().DiscoverableTimeout().ConnectChanged(func(hasValue bool, value uint32) { + if !hasValue { + return + } + a.DiscoverableTimeout = value + logger.Debugf("%s DiscoverableTimeout: %v", a, value) + a.notifyPropertiesChanged() + }) + if err != nil { + logger.Warning(err) + } +} + +func (a *adapter) startDiscovery() { + a.discoveringFinished = false + // 已经开始扫描 或 回连未结束 禁止开始扫描 + if a.Discovering || !a.autoConnectFinished { + return + } + + logger.Debugf("start discovery") + err := a.core.Adapter().StartDiscovery(0) + if err != nil { + logger.Warningf("failed to start discovery for %s: %v", a, err) + } else { + logger.Debug("reset timer for stop scan") + // a.waitDiscovery = false + // start discovering success, reset discovering timer + a.discoveringTimer.Reset(defaultDiscoveringTimeout) + } +} diff --git a/system/bluetooth1/agent.go b/system/bluetooth1/agent.go new file mode 100644 index 000000000..68d1dddbc --- /dev/null +++ b/system/bluetooth1/agent.go @@ -0,0 +1,488 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package bluetooth + +import ( + "errors" + "fmt" + "strings" + "sync" + + "github.com/godbus/dbus/v5" + btcommon "github.com/linuxdeepin/dde-daemon/common/bluetooth" + bluez "github.com/linuxdeepin/go-dbus-factory/system/org.bluez" + sysbtagent "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.bluetooth1.agent" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +const ( + agentDBusPath = dbusPath + "/Agent" + agentDBusInterface = "org.bluez.Agent1" +) + +type userAgentMap struct { + mu sync.Mutex + m map[string]*sessionAgentMapItem // key 是 uid + activeUid string +} + +type sessionAgentMapItem struct { + sessions map[dbus.ObjectPath]login1.Session // key 是 session 的路径 + agents map[dbus.ObjectPath]sysbtagent.Agent // key 是 agent 的路径 +} + +func (m *userAgentMap) setActiveUid(uid string) { + m.mu.Lock() + m.activeUid = uid + m.mu.Unlock() +} + +func newUserAgentMap() *userAgentMap { + return &userAgentMap{ + m: make(map[string]*sessionAgentMapItem, 1), + } +} + +func (m *userAgentMap) addAgent(uid string, agent sysbtagent.Agent) { + m.mu.Lock() + defer m.mu.Unlock() + + item, ok := m.m[uid] + if ok { + if item.agents == nil { + item.agents = make(map[dbus.ObjectPath]sysbtagent.Agent, 1) + } + if len(item.agents) > 10 { + // 限制数量 + return + } + item.agents[agent.Path_()] = agent + } else { + m.m[uid] = &sessionAgentMapItem{ + agents: map[dbus.ObjectPath]sysbtagent.Agent{ + agent.Path_(): agent, + }, + } + } +} + +func (m *userAgentMap) handleNameLost(name string) { + m.mu.Lock() + defer m.mu.Unlock() + + for _, item := range m.m { + for path, agent := range item.agents { + if agent.ServiceName_() == name { + logger.Debug("remove agent", name, path) + delete(item.agents, path) + } + } + } +} + +func (m *userAgentMap) removeAgent(uid string, agentPath dbus.ObjectPath) error { + m.mu.Lock() + defer m.mu.Unlock() + + item, ok := m.m[uid] + if !ok { + return errors.New("invalid uid") + } + + if _, ok := item.agents[agentPath]; !ok { + return errors.New("invalid agent path") + } + delete(item.agents, agentPath) + return nil +} + +func (m *userAgentMap) addUser(uid string) { + m.mu.Lock() + defer m.mu.Unlock() + + _, ok := m.m[uid] + if !ok { + m.m[uid] = &sessionAgentMapItem{ + sessions: make(map[dbus.ObjectPath]login1.Session), + agents: make(map[dbus.ObjectPath]sysbtagent.Agent), + } + } +} + +func (m *userAgentMap) removeUser(uid string) { + m.mu.Lock() + defer m.mu.Unlock() + + item, ok := m.m[uid] + if !ok { + return + } + + for sessionPath, session := range item.sessions { + session.RemoveAllHandlers() + delete(item.sessions, sessionPath) + } + delete(m.m, uid) +} + +func (m *userAgentMap) hasUser(uid string) bool { + m.mu.Lock() + defer m.mu.Unlock() + _, ok := m.m[uid] + return ok +} + +func (m *userAgentMap) addSession(uid string, session login1.Session) bool { + m.mu.Lock() + defer m.mu.Unlock() + + item, ok := m.m[uid] + if !ok { + return false + } + + _, ok = item.sessions[session.Path_()] + if ok { + return false + } + item.sessions[session.Path_()] = session + return true +} + +func (m *userAgentMap) removeSession(sessionPath dbus.ObjectPath) { + m.mu.Lock() + defer m.mu.Unlock() + + for _, item := range m.m { + for sPath, session := range item.sessions { + if sPath == sessionPath { + session.RemoveAllHandlers() + delete(item.sessions, sPath) + } + } + } +} + +func (m *userAgentMap) getActiveAgent() sysbtagent.Agent { + m.mu.Lock() + defer m.mu.Unlock() + + if m.activeUid == "" { + return nil + } + + item := m.m[m.activeUid] + if item == nil { + return nil + } + // 目前只使用标准的 + return item.agents[btcommon.SessionAgentPath] +} + +func (m *userAgentMap) GetActiveAgentName() string { + agent := m.getActiveAgent() + if agent != nil { + return agent.ServiceName_() + } + return "" +} + +func (m *userAgentMap) GetAllAgentNames() (result []string) { + m.mu.Lock() + defer m.mu.Unlock() + + for _, item := range m.m { + // 目前只使用标准的 + agent := item.agents[btcommon.SessionAgentPath] + if agent != nil { + result = append(result, agent.ServiceName_()) + } + } + return result +} + +type authorize struct { + path dbus.ObjectPath + key string + accept bool +} + +type agent struct { + service *dbusutil.Service + bluezManager bluez.Manager + + b *SysBluetooth + rspChan chan authorize + + mu sync.Mutex + requestDevice dbus.ObjectPath +} + +func (*agent) GetInterfaceName() string { + return agentDBusInterface +} + +func toErrFromAgent(err error) *dbus.Error { + if err == nil { + return nil + } + busErr, ok := err.(dbus.Error) + if !ok { + // 强制转换为 Rejected + return &dbus.Error{ + Name: btcommon.ErrNameRejected, + Body: []interface{}{err.Error()}, + } + } + + if busErr.Name == btcommon.ErrNameRejected || busErr.Name == btcommon.ErrNameCanceled { + return &busErr + } + + // 强制转换为 Rejected + return &dbus.Error{ + Name: btcommon.ErrNameRejected, + Body: []interface{}{fmt.Sprintf("[%s] %s", busErr.Name, busErr.Error())}, + } +} + +/*****************************************************************************/ + +// Release method gets called when the service daemon unregisters the agent. +// An agent can use it to do cleanup tasks. There is no need to unregister the +// agent, because when this method gets called it has already been unregistered. +func (a *agent) Release() *dbus.Error { + logger.Info("Release()") + return nil +} + +// RequestPinCode method gets called when the service daemon needs to get the passkey for an authentication. +// The return value should be a string of 1-16 characters length. The string can be alphanumeric. +// Possible errors: org.bluez.Error.Rejected +// +// org.bluez.Error.Canceled +func (a *agent) RequestPinCode(device dbus.ObjectPath) (pinCode string, busErr *dbus.Error) { + logger.Info("RequestPinCode()") + + ua := a.b.getActiveUserAgent() + if ua == nil { + logger.Warning("ua is nil") + return "", btcommon.ErrRejected + } + + d, err := a.b.getDevice(device) + if err != nil { + logger.Warning(err) + return "", btcommon.ErrRejected + } + d.agentWorkStart() + defer d.agentWorkEnd() + + pinCode, err = ua.RequestPinCode(0, device) + return pinCode, toErrFromAgent(err) +} + +// DisplayPinCode method gets called when the service daemon needs to display a pincode for an authentication. +// An empty reply should be returned. When the pincode needs no longer to be displayed, the Cancel method +// of the agent will be called. This is used during the pairing process of keyboards that don't support +// Bluetooth 2.1 Secure Simple Pairing, in contrast to DisplayPasskey which is used for those that do. +// This method will only ever be called once since older keyboards do not support typing notification. +// Note that the PIN will always be a 6-digit number, zero-padded to 6 digits. This is for harmony with +// the later specification. +// Possible errors: org.bluez.Error.Rejected +// +// org.bluez.Error.Canceled +func (a *agent) DisplayPinCode(device dbus.ObjectPath, pinCode string) (busErr *dbus.Error) { + logger.Info("DisplayPinCode()", pinCode) + ua := a.b.getActiveUserAgent() + if ua == nil { + logger.Warning("ua is nil") + return btcommon.ErrRejected + } + err := ua.DisplayPinCode(0, device, pinCode) + return toErrFromAgent(err) +} + +// RequestPasskey method gets called when the service daemon needs to get the passkey for an authentication. +// The return value should be a numeric value between 0-999999. +// Possible errors: org.bluez.Error.Rejected +// +// org.bluez.Error.Canceled +func (a *agent) RequestPasskey(device dbus.ObjectPath) (passkey uint32, busErr *dbus.Error) { + logger.Info("RequestPasskey()") + ua := a.b.getActiveUserAgent() + if ua == nil { + logger.Warning("ua is nil") + return 0, btcommon.ErrRejected + } + + d, err := a.b.getDevice(device) + if err != nil { + logger.Warning(err) + return 0, btcommon.ErrRejected + } + d.agentWorkStart() + defer d.agentWorkEnd() + + passkey, err = ua.RequestPasskey(0, device) + return passkey, toErrFromAgent(err) +} + +// DisplayPasskey method gets called when the service daemon needs to display a passkey for an authentication. +// The entered parameter indicates the number of already typed keys on the remote side. +// An empty reply should be returned. When the passkey needs no longer to be displayed, the Cancel method +// of the agent will be called. +// During the pairing process this method might be called multiple times to update the entered value. +// Note that the passkey will always be a 6-digit number, so the display should be zero-padded at the start if +// the value contains less than 6 digits. +func (a *agent) DisplayPasskey(device dbus.ObjectPath, passkey uint32, entered uint16) *dbus.Error { + logger.Info("DisplayPasskey()", passkey, entered) + ua := a.b.getActiveUserAgent() + if ua == nil { + logger.Warning("ua is nil") + return btcommon.ErrRejected + } + err := ua.DisplayPasskey(0, device, passkey, entered) + return toErrFromAgent(err) +} + +// RequestConfirmation This method gets called when the service daemon needs to confirm a passkey for an authentication. +// To confirm the value it should return an empty reply or an error in case the passkey is invalid. +// Note that the passkey will always be a 6-digit number, so the display should be zero-padded at the start if +// the value contains less than 6 digits. +// Possible errors: org.bluez.Error.Rejected +// +// org.bluez.Error.Canceled +func (a *agent) RequestConfirmation(device dbus.ObjectPath, passkey uint32) *dbus.Error { + logger.Info("RequestConfirmation", device, passkey) + ua := a.b.getActiveUserAgent() + if ua == nil { + logger.Warning("ua is nil") + return btcommon.ErrRejected + } + + d, err := a.b.getDevice(device) + if err != nil { + logger.Warning(err) + return btcommon.ErrRejected + } + d.agentWorkStart() + defer d.agentWorkEnd() + + if d.Icon == "audio-card" && strings.Contains(strings.ToLower(d.Name), "huawei") { + logger.Warning("audio-card device don't need confirm") + return nil + } + + err = ua.RequestConfirmation(0, device, passkey) + return toErrFromAgent(err) +} + +// RequestAuthorization method gets called to request the user to authorize an incoming pairing attempt which +// would in other circumstances trigger the just-works model. +// Possible errors: org.bluez.Error.Rejected +// +// org.bluez.Error.Canceled +func (a *agent) RequestAuthorization(device dbus.ObjectPath) *dbus.Error { + logger.Info("RequestAuthorization()") + ua := a.b.getActiveUserAgent() + if ua == nil { + logger.Warning("ua is nil") + return btcommon.ErrRejected + } + + d, err := a.b.getDevice(device) + if err != nil { + logger.Warning(err) + return btcommon.ErrRejected + } + d.agentWorkStart() + defer d.agentWorkEnd() + + err = ua.RequestAuthorization(0, device) + return toErrFromAgent(err) +} + +// AuthorizeService method gets called when the service daemon needs to authorize a connection/service request. +// Possible errors: org.bluez.Error.Rejected +// +// org.bluez.Error.Canceled +func (a *agent) AuthorizeService(device dbus.ObjectPath, uuid string) *dbus.Error { + logger.Infof("AuthorizeService %q %q", device, uuid) + _, err := a.b.getDevice(device) + if err != nil { + logger.Warning(err) + return btcommon.ErrRejected + } + + ua := a.b.getActiveUserAgent() + if ua == nil { + logger.Warning("ua is nil") + return btcommon.ErrRejected + } + err = ua.AuthorizeService(0, device, uuid) + return toErrFromAgent(err) +} + +// Cancel method gets called to indicate that the agent request failed before a reply was returned. +func (a *agent) Cancel() *dbus.Error { + logger.Info("Cancel()") + ua := a.b.getActiveUserAgent() + if ua == nil { + logger.Warning("ua is nil") + return nil + } + err := ua.Cancel(0) + return toErrFromAgent(err) +} + +/*****************************************************************************/ + +func newAgent(service *dbusutil.Service) (a *agent) { + a = &agent{ + service: service, + rspChan: make(chan authorize), + } + return +} + +func (a *agent) init() { + sysBus := a.service.Conn() + a.bluezManager = bluez.NewManager(sysBus) + a.registerDefaultAgent() +} + +func (a *agent) registerDefaultAgent() { + // register agent + err := a.bluezManager.AgentManager().RegisterAgent(0, agentDBusPath, "DisplayYesNo") + if err != nil { + logger.Warning("failed to register agent:", err) + return + } + + // request default agent + err = a.bluezManager.AgentManager().RequestDefaultAgent(0, agentDBusPath) + if err != nil { + logger.Warning("failed to become the default agent:", err) + err = a.bluezManager.AgentManager().UnregisterAgent(0, agentDBusPath) + if err != nil { + logger.Warning(err) + } + return + } +} + +func (a *agent) destroy() { + err := a.bluezManager.AgentManager().UnregisterAgent(0, agentDBusPath) + if err != nil { + logger.Warning(err) + } + + err = a.service.StopExport(a) + if err != nil { + logger.Warning(err) + } +} diff --git a/system/bluetooth/auto_connect_manager.go b/system/bluetooth1/auto_connect_manager.go similarity index 98% rename from system/bluetooth/auto_connect_manager.go rename to system/bluetooth1/auto_connect_manager.go index ffbea90fa..6b8b5f76d 100644 --- a/system/bluetooth/auto_connect_manager.go +++ b/system/bluetooth1/auto_connect_manager.go @@ -10,7 +10,7 @@ import ( "sync" "time" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" ) // 每个适配器最大 worker 数量,最大同时连接设备数。 @@ -27,7 +27,7 @@ type autoConnectManager struct { // 和单个适配器相关的数据 type acmAdapterData struct { - workers map[int]bool + workers map[int]bool // 需要等待的由设备主动重连接的设备集合 activeReconnectDevices map[dbus.ObjectPath]struct{} timer *time.Timer @@ -323,7 +323,7 @@ func (acm *autoConnectManager) addAdapter(adapterPath dbus.ObjectPath) { } acm.adapters[adapterPath] = &acmAdapterData{ - workers: make(map[int]bool), + workers: make(map[int]bool), } } diff --git a/system/bluetooth1/bluetooth.go b/system/bluetooth1/bluetooth.go new file mode 100644 index 000000000..2863913c4 --- /dev/null +++ b/system/bluetooth1/bluetooth.go @@ -0,0 +1,1110 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package bluetooth + +import ( + "fmt" + "os" + "strconv" + "strings" + "sync" + "time" + + "github.com/godbus/dbus/v5" + ConfigManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" + bluez "github.com/linuxdeepin/go-dbus-factory/system/org.bluez" + ofdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.dbus" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +const ( + bluezDBusServiceName = "org.bluez" + bluezAdapterDBusInterface = "org.bluez.Adapter1" + bluezDeviceDBusInterface = "org.bluez.Device1" + + dbusServiceName = "org.deepin.dde.Bluetooth1" + dbusPath = "/org/deepin/dde/Bluetooth1" + dbusInterface = dbusServiceName +) + +const ( + StateUnavailable = 0 + StateAvailable = 1 + StateConnected = 2 +) + +const ( + devIconComputer = "computer" + devIconPhone = "phone" + devIconModem = "modem" + devIconNetworkWireless = "network-wireless" + devIconAudioCard = "audio-card" + devIconCameraVideo = "camera-video" + devIconCameraPhoto = "camera-photo" + devIconPrinter = "printer" + devIconInputGaming = "input-gaming" + devIconInputKeyboard = "input-keyboard" + devIconInputTablet = "input-tablet" + devIconInputMouse = "input-mouse" +) + +const ( + dsettingsAppID = "org.deepin.dde.daemon" + dsettingsBluetoothName = "org.deepin.dde.daemon.bluetooth" + dsettingsAutoPairEnableKey = "autoPairEnable" + dsettingsAdapterPowerd = "adapterPowerd" + dsettingsAdapterDiscoverable = "adapterDiscoverable" +) + +//go:generate dbusutil-gen -type SysBluetooth bluetooth.go +//go:generate dbusutil-gen em -type SysBluetooth,agent + +type SysBluetooth struct { + service *dbusutil.Service + sigLoop *dbusutil.SignalLoop + config *config + objectManager bluez.ObjectManager + sysDBusDaemon ofdbus.DBus + loginManager login1.Manager + agent *agent + userAgents *userAgentMap + + // adapter + adaptersMu sync.Mutex + adapters map[dbus.ObjectPath]*adapter + + // device + devicesMu sync.Mutex + devices map[dbus.ObjectPath][]*device + + // backup device + backupDevicesMu sync.Mutex + backupDevices map[dbus.ObjectPath][]*backupDevice + + acm *autoConnectManager + + PropsMu sync.RWMutex + State uint32 // StateUnavailable/StateAvailable/StateConnected + CanSendFile bool + + // 当发起设备连接成功后,应该把连接的设备添加进设备列表 + connectedDevices map[dbus.ObjectPath][]*device + connectedMu sync.RWMutex + // 设备被清空后需要连接的设备路径 + prepareToConnectedDevice dbus.ObjectPath + prepareToConnectedMu sync.Mutex + // 升级后第一次进系统,此时需要根据之前有蓝牙连接时,打开蓝牙开关 + needFixBtPoweredStatus bool + canAutoPair func() bool + + // nolint + signals *struct { + // adapter/device properties changed signals + AdapterAdded, AdapterRemoved, AdapterPropertiesChanged struct { + adapterJSON string + } + + DeviceAdded, DeviceRemoved, DevicePropertiesChanged struct { + devJSON string + } + } +} + +func newSysBluetooth(service *dbusutil.Service) (b *SysBluetooth) { + sysBus := service.Conn() + b = &SysBluetooth{ + service: service, + sigLoop: dbusutil.NewSignalLoop(sysBus, 100), + userAgents: newUserAgentMap(), + needFixBtPoweredStatus: false, + } + + b.config = newConfig() + b.loginManager = login1.NewManager(sysBus) + b.sysDBusDaemon = ofdbus.NewDBus(sysBus) + b.objectManager = bluez.NewObjectManager(sysBus) + b.adapters = make(map[dbus.ObjectPath]*adapter) + b.devices = make(map[dbus.ObjectPath][]*device) + b.backupDevices = make(map[dbus.ObjectPath][]*backupDevice) + b.connectedDevices = make(map[dbus.ObjectPath][]*device) + b.acm = newAutoConnectManager() + b.acm.connectCb = func(adapterPath, devicePath dbus.ObjectPath, wId int) error { + adapter, err := b.getAdapter(adapterPath) + if err != nil { + // 可能是适配器被移除了,停止连接 + return nil + } + if !adapter.Powered { + // 适配器电源关闭了,停止连接 + return nil + } + + adapter.autoConnectFinished = false + return b.autoConnectPairedDevice(devicePath, adapterPath) + } + + b.acm.startDiscoveryCb = func(adapterPath dbus.ObjectPath) { + adapter, err := b.getAdapter(adapterPath) + if err != nil { + // 可能是适配器被移除了,不需要开始扫描 + logger.Warningf("call getAdapter failed; adapterPath:[%s] err:[%s]", adapterPath, err) + return + } + + if !adapter.Powered { + // 适配器电源关闭了,不需要开始扫描 + logger.Warningf("adapter: [%s] is power off", adapterPath) + return + } + + adapter.autoConnectFinished = true + adapter.startDiscovery() + } + + return +} + +func (b *SysBluetooth) destroy() { + b.agent.destroy() + + b.objectManager.RemoveAllHandlers() + b.sysDBusDaemon.RemoveAllHandlers() + b.loginManager.RemoveAllHandlers() + + b.devicesMu.Lock() + for _, devices := range b.devices { + for _, device := range devices { + device.destroy() + } + } + b.devicesMu.Unlock() + + b.adaptersMu.Lock() + for _, adapter := range b.adapters { + adapter.destroy() + } + b.adaptersMu.Unlock() + + err := b.service.StopExport(b) + if err != nil { + logger.Warning(err) + } + b.sigLoop.Stop() +} + +func (*SysBluetooth) GetInterfaceName() string { + return dbusInterface +} + +func (b *SysBluetooth) init() { + var err error + b.CanSendFile, err = canSendFile() + if err != nil { + logger.Warning("canSendFile err:", err) + } + + // 需要在Load加载之前判断系统级蓝牙配置文件是否存在 + b.needFixBtPoweredStatus = !b.config.core.IsConfigFileExists() + b.sigLoop.Start() + b.config.load() + b.sysDBusDaemon.InitSignalExt(b.sigLoop, true) + _, err = b.sysDBusDaemon.ConnectNameOwnerChanged(b.handleDBusNameOwnerChanged) + if err != nil { + logger.Warning(err) + } + + ds := ConfigManager.NewConfigManager(b.sigLoop.Conn()) + + dsBluetoothPath, err := ds.AcquireManager(0, dsettingsAppID, dsettingsBluetoothName, "") + if err != nil { + logger.Warning(err) + return + } + + dsBluetooth, err := ConfigManager.NewManager(b.sigLoop.Conn(), dsBluetoothPath) + if err != nil { + logger.Warning(err) + return + } + + b.canAutoPair = func() bool { + v, err := dsBluetooth.Value(0, dsettingsAutoPairEnableKey) + if err != nil { + logger.Warning(err) + return true + } + return v.Value().(bool) + } + + logger.Info("====== dsg autoPairEnable is ======", b.canAutoPair()) + + adapterDefaultPowered = func() bool { + v, err := dsBluetooth.Value(0, dsettingsAdapterPowerd) + if err != nil { + logger.Warning(err) + return false + } + return v.Value().(bool) + }() + + adapterDefaultDiscoverable = func() bool { + v, err := dsBluetooth.Value(0, dsettingsAdapterDiscoverable) + if err != nil { + logger.Warning(err) + return true + } + return v.Value().(bool) + }() + + b.loginManager.InitSignalExt(b.sigLoop, true) + _, err = b.loginManager.ConnectSessionNew(b.handleSessionNew) + + _, err = b.loginManager.ConnectSessionRemoved(func(sessionId string, sessionPath dbus.ObjectPath) { + logger.Info("session removed", sessionId, sessionPath) + b.userAgents.removeSession(sessionPath) + }) + if err != nil { + logger.Warning(err) + } + + _, err = b.loginManager.ConnectUserRemoved(func(uid uint32, userPath dbus.ObjectPath) { + uidStr := strconv.Itoa(int(uid)) + b.userAgents.removeUser(uidStr) + }) + + _, err = b.loginManager.ConnectPrepareForSleep(b.handlePrepareForSleep) + if err != nil { + logger.Warning(err) + } + + b.objectManager.InitSignalExt(b.sigLoop, true) + _, err = b.objectManager.ConnectInterfacesAdded(b.handleInterfacesAdded) + if err != nil { + logger.Warning(err) + } + + _, err = b.objectManager.ConnectInterfacesRemoved(b.handleInterfacesRemoved) + if err != nil { + logger.Warning(err) + } + + b.agent.init() + b.loadObjects() + + b.config.clearSpareConfig(b) + go b.tryConnectPairedDevices("") +} + +const btAvailableFile = "/sys/kernel/security/bluetooth/available" + +func canSendFile() (can bool, err error) { + _, err = os.Stat(btAvailableFile) + if err != nil { + if os.IsNotExist(err) { + // 表示没有加载限制性的内核模块 + return true, nil + } + return false, err + } + + can, err = readBoolFile(btAvailableFile) + return +} + +func (b *SysBluetooth) handleSessionNew(sessionId string, sessionPath dbus.ObjectPath) { + logger.Info("session added", sessionId, sessionPath) + sysBus := b.sigLoop.Conn() + session, err := login1.NewSession(sysBus, sessionPath) + if err != nil { + logger.Warning(err) + return + } + + userInfo, err := session.User().Get(0) + if err != nil { + logger.Warning(err) + return + } + + uidStr := strconv.Itoa(int(userInfo.UID)) + if !b.userAgents.hasUser(uidStr) { + // 不关心这个用户的新 session + return + } + + newlyAdded := b.userAgents.addSession(uidStr, session) + if newlyAdded { + b.watchSession(uidStr, session) + } +} + +func (b *SysBluetooth) handlePrepareForSleep(beforeSleep bool) { + if beforeSleep { + b.stopDiscovery() + logger.Debug("prepare to sleep") + return + } + logger.Debug("Wakeup from sleep, will set adapter and try connect device") + time.AfterFunc(time.Second*3, func() { + // for _, adapter := range b.adapters { + // if !adapter.Powered { + // continue + // } + // //_ = adapter.core.Adapter().Discoverable().Set(0, b.config.Discoverable) + // } + b.tryConnectPairedDevices("") + }) +} + +func (b *SysBluetooth) watchSession(uid string, session login1.Session) { + session.InitSignalExt(b.sigLoop, true) + err := session.Active().ConnectChanged(func(hasValue bool, active bool) { + if !hasValue { + return + } + if active { + b.userAgents.setActiveUid(uid) + } + }) + + if err != nil { + logger.Warning(err) + } + + active, err := session.Active().Get(0) + if err != nil { + logger.Warning(err) + } + if active { + b.userAgents.setActiveUid(uid) + } +} + +func (b *SysBluetooth) loadObjects() { + // add exists adapters and devices + objects, err := b.objectManager.GetManagedObjects(0) + if err != nil { + logger.Error(err) + return + } + + // add adapters + for path, obj := range objects { + if _, ok := obj[bluezAdapterDBusInterface]; ok { + b.addAdapter(path) + } + } + + // then add devices + for path, obj := range objects { + if _, ok := obj[bluezDeviceDBusInterface]; ok { + b.addDevice(path) + } + } +} + +func (b *SysBluetooth) removeAllObjects() { + b.devicesMu.Lock() + for _, devices := range b.devices { + for _, device := range devices { + device.notifyDeviceRemoved() + device.destroy() + } + } + b.devices = make(map[dbus.ObjectPath][]*device) + b.devicesMu.Unlock() + + b.adaptersMu.Lock() + for _, adapter := range b.adapters { + adapter.notifyAdapterRemoved() + adapter.destroy() + } + b.adapters = make(map[dbus.ObjectPath]*adapter) + b.adaptersMu.Unlock() +} + +func (b *SysBluetooth) handleInterfacesAdded(path dbus.ObjectPath, data map[string]map[string]dbus.Variant) { + if _, ok := data[bluezAdapterDBusInterface]; ok { + b.addAdapter(path) + } + if _, ok := data[bluezDeviceDBusInterface]; ok { + b.addDeviceWithCount(path, 3) + } +} + +func (b *SysBluetooth) handleInterfacesRemoved(path dbus.ObjectPath, interfaces []string) { + if isStringInArray(bluezAdapterDBusInterface, interfaces) { + b.removeAdapter(path) + } + if isStringInArray(bluezDeviceDBusInterface, interfaces) { + b.removeDevice(path) + } +} + +func (b *SysBluetooth) handleDBusNameOwnerChanged(name, oldOwner, newOwner string) { + // if a new dbus session was installed, the name and newOwner + // will be not empty, if a dbus session was uninstalled, the + // name and oldOwner will be not empty + if name == bluezDBusServiceName { + if newOwner != "" { + logger.Info("bluetooth is starting") + time.AfterFunc(1*time.Second, func() { + b.loadObjects() + b.agent.registerDefaultAgent() + b.tryConnectPairedDevices("") + }) + } else { + logger.Info("bluetooth stopped") + b.removeAllObjects() + } + } else { + if strings.HasPrefix(name, ":") && oldOwner != "" && newOwner == "" { + b.userAgents.handleNameLost(name) + } + } +} + +func (b *SysBluetooth) addDeviceWithCount(devPath dbus.ObjectPath, count int) { + logger.Debug("receive signal device added", devPath) + if b.isDeviceExists(devPath) { + return + } + + d := newDevice(b.sigLoop, devPath) + b.adaptersMu.Lock() + d.adapter = b.adapters[d.AdapterPath] + b.adaptersMu.Unlock() + + if d.adapter == nil { + logger.Warningf("failed to add device %s, not found adapter", devPath) + if count > 0 { + logger.Debugf("retry add device %s after 100ms", devPath) + time.AfterFunc(100*time.Millisecond, func() { + b.addDeviceWithCount(devPath, count-1) + }) + } + return + } + + // device detail info is needed to write into config file + b.config.addDeviceConfig(d) + + b.devicesMu.Lock() + b.devices[d.AdapterPath] = append(b.devices[d.AdapterPath], d) + b.devicesMu.Unlock() + + // 设备加入的同时进行备份 + b.backupDevicesMu.Lock() + idx := b.indexBackupDeviceNoLock(d.AdapterPath, devPath) + if idx == -1 { + b.backupDevices[d.AdapterPath] = append(b.backupDevices[d.AdapterPath], newBackupDevice(d)) + } + b.backupDevicesMu.Unlock() + + d.notifyDeviceAdded() + + // 若扫描到需要连接的设备,直接连接 + if b.prepareToConnectedDevice == d.Path { + b.prepareToConnectedDevice = "" + go func() { + err := d.Connect() + if err != nil { + logger.Warning(err) + } + }() + } +} + +func (b *SysBluetooth) addDevice(devPath dbus.ObjectPath) { + b.addDeviceWithCount(devPath, 0) +} + +func (b *SysBluetooth) removeDevice(devPath dbus.ObjectPath) { + logger.Debug("receive signal device removed", devPath) + adapterPath, idx := b.getDeviceIndex(devPath) + if idx == -1 { + logger.Warning("repeat remove device", devPath) + return + } + + var removedDev *device + b.devicesMu.Lock() + b.devices[adapterPath], removedDev = b.doRemoveDevice(b.devices[adapterPath], idx) + b.devicesMu.Unlock() + + b.acm.handleDeviceEvent(removedDev) + + idx = b.indexBackupDevice(adapterPath, devPath) + if idx == -1 { + // 未找到备份设备,需要发送设备移除信号 + removedDev.notifyDeviceRemoved() + } else { + // 找得到备份设备,但是是已经配对的设备,一般是通过 bluetoothctl remove 命令删除已经配对的设备。 + // 备份设备也删除,并发送信号。 + adapter := b.adapters[adapterPath] + if removedDev.Paired || (adapter != nil && adapter.Discovering) { + b.removeBackupDevice(devPath) + removedDev.notifyDeviceRemoved() + } + } +} + +func (b *SysBluetooth) doRemoveDevice(devices []*device, i int) ([]*device, *device) { + // NOTE: do not remove device from config + d := devices[i] + d.destroy() + copy(devices[i:], devices[i+1:]) + devices[len(devices)-1] = nil + devices = devices[:len(devices)-1] + return devices, d +} + +func (b *SysBluetooth) removeBackupDevice(devPath dbus.ObjectPath) { + b.backupDevicesMu.Lock() + defer b.backupDevicesMu.Unlock() + + adapterPath, i := b.findBackupDeviceNoLock(devPath) + if i < 0 { + logger.Debug("repeat remove device", devPath) + return + } + + b.backupDevices[adapterPath] = b.doRemoveBackupDevice(b.backupDevices[adapterPath], i) +} + +func (b *SysBluetooth) doRemoveBackupDevice(devices []*backupDevice, i int) []*backupDevice { + copy(devices[i:], devices[i+1:]) + devices[len(devices)-1] = nil + devices = devices[:len(devices)-1] + return devices +} + +func (b *SysBluetooth) syncCommonToBackupDevices(adapterPath dbus.ObjectPath) { + logger.Debug("syncCommonToBackupDevices", adapterPath) + devices := b.getDevices(adapterPath) + + // 转换为 map + deviceMap := make(map[dbus.ObjectPath]*device) + for _, d := range devices { + deviceMap[d.Path] = d + } + + // 应该只需要关注备份的设备比普通设备多的情况。 + var removedBackupDevices []*backupDevice + var newBackupDevices []*backupDevice + + b.backupDevicesMu.Lock() + for _, backupDevice := range b.backupDevices[adapterPath] { + // 从 devices 能找到,保留,不能找到,则删除 + _, ok := deviceMap[backupDevice.Path] + if !ok { + removedBackupDevices = append(removedBackupDevices, backupDevice) + } + } + + for _, d := range devices { + newBackupDevices = append(newBackupDevices, newBackupDevice(d)) + } + b.backupDevices[adapterPath] = newBackupDevices + b.backupDevicesMu.Unlock() + + for _, d := range removedBackupDevices { + d.notifyDeviceRemoved() + } +} + +func (b *SysBluetooth) isDeviceExists(devPath dbus.ObjectPath) bool { + _, i := b.getDeviceIndex(devPath) + return i >= 0 +} + +func (b *SysBluetooth) findDevice(devPath dbus.ObjectPath) (adapterPath dbus.ObjectPath, index int) { + for p, devices := range b.devices { + for i, d := range devices { + if d.Path == devPath { + return p, i + } + } + } + return "", -1 +} + +func (b *SysBluetooth) findBackupDevice(devPath dbus.ObjectPath) (adapterPath dbus.ObjectPath, index int) { + b.backupDevicesMu.Lock() + defer b.backupDevicesMu.Unlock() + return b.findBackupDeviceNoLock(devPath) +} + +func (b *SysBluetooth) findBackupDeviceNoLock(devPath dbus.ObjectPath) (adapterPath dbus.ObjectPath, index int) { + for p, devices := range b.backupDevices { + for i, d := range devices { + if d.Path == devPath { + return p, i + } + } + } + return "", -1 +} + +func (b *SysBluetooth) indexBackupDevice(adapterPath, devPath dbus.ObjectPath) (index int) { + b.backupDevicesMu.Lock() + defer b.backupDevicesMu.Unlock() + return b.indexBackupDeviceNoLock(adapterPath, devPath) +} + +func (b *SysBluetooth) indexBackupDeviceNoLock(adapterPath, devPath dbus.ObjectPath) (index int) { + devices, ok := b.backupDevices[adapterPath] + if !ok { + return -1 + } + for idx, d := range devices { + if d.Path == devPath { + return idx + } + } + return -1 +} + +func (b *SysBluetooth) getDeviceIndex(devPath dbus.ObjectPath) (adapterPath dbus.ObjectPath, index int) { + b.devicesMu.Lock() + defer b.devicesMu.Unlock() + return b.findDevice(devPath) +} + +func (b *SysBluetooth) getDevice(devPath dbus.ObjectPath) (*device, error) { + b.devicesMu.Lock() + defer b.devicesMu.Unlock() + adapterPath, index := b.findDevice(devPath) + if index < 0 { + return nil, errInvalidDevicePath + } + return b.devices[adapterPath][index], nil +} + +func (b *SysBluetooth) getBackupDevice(devPath dbus.ObjectPath) (*backupDevice, error) { + b.backupDevicesMu.Lock() + defer b.backupDevicesMu.Unlock() + adapterPath, index := b.findBackupDeviceNoLock(devPath) + if index < 0 { + return nil, errInvalidDevicePath + } + return b.backupDevices[adapterPath][index], nil +} + +// 更新 backupDevices +func (b *SysBluetooth) updateBackupDevices(adapterPath dbus.ObjectPath) { + logger.Debug("updateBackupDevices", adapterPath) + devices := b.getDevices(adapterPath) + b.backupDevicesMu.Lock() + defer b.backupDevicesMu.Unlock() + for _, device := range devices { + index := b.indexBackupDeviceNoLock(adapterPath, device.Path) + if index < 0 { + logger.Warning("[updateBackupDevices] invalid device path: ", device.Path) + } else { + b.backupDevices[adapterPath][index] = newBackupDevice(device) + } + } +} + +func (b *SysBluetooth) getAdapterDevices(adapterAddress string) []*device { + var aPath dbus.ObjectPath + b.adaptersMu.Lock() + for adapterPath, adapter := range b.adapters { + if adapter.Address == adapterAddress { + aPath = adapterPath + break + } + } + b.adaptersMu.Unlock() + + if aPath == "" { + return nil + } + + b.devicesMu.Lock() + defer b.devicesMu.Unlock() + + devices := b.devices[aPath] + if devices == nil { + return nil + } + + result := make([]*device, 0, len(devices)) + result = append(result, devices...) + return result +} + +func (b *SysBluetooth) addAdapter(adapterPath dbus.ObjectPath) { + logger.Debug("receive signal adapter added", adapterPath) + if b.isAdapterExists(adapterPath) { + return + } + + a := newAdapter(b.sigLoop, adapterPath) + a.bt = b + // initialize adapter power state + b.config.addAdapterConfig(a.Address) + cfgPowered := b.config.getAdapterConfigPowered(a.Address) + + err := a.core.Adapter().Powered().Set(0, cfgPowered) + if err != nil { + logger.Warning(err) + } + + err = a.core.Adapter().DiscoverableTimeout().Set(0, 0) + if err != nil { + logger.Warning(err) + } + + // 读取配置文件中可被发现状态值,并修改Discoverable属性值,默认为true + discoverable := b.config.getAdapterConfigDiscoverable(a.Address) + err = a.core.Adapter().Discoverable().Set(0, discoverable) + if err != nil { + logger.Warning(err) + } + + b.adaptersMu.Lock() + b.adapters[adapterPath] = a + b.adaptersMu.Unlock() + + a.notifyAdapterAdded() + b.acm.addAdapter(adapterPath) + logger.Debug("addAdapter", adapterPath) +} + +func (b *SysBluetooth) removeAdapter(adapterPath dbus.ObjectPath) { + logger.Debug("receive signal adapter removed", adapterPath) + b.adaptersMu.Lock() + + if b.adapters[adapterPath] == nil { + b.adaptersMu.Unlock() + logger.Warning("repeat remove adapter", adapterPath) + return + } + + b.doRemoveAdapter(adapterPath) + b.adaptersMu.Unlock() + + b.devicesMu.Lock() + b.devices[adapterPath] = nil + b.devicesMu.Unlock() + b.syncCommonToBackupDevices(adapterPath) +} + +func (b *SysBluetooth) doRemoveAdapter(adapterPath dbus.ObjectPath) { + // NOTE: do not remove adapter from config file + removeAdapter := b.adapters[adapterPath] + delete(b.adapters, adapterPath) + removeAdapter.notifyAdapterRemoved() + removeAdapter.destroy() + b.acm.removeAdapter(adapterPath) +} + +func (b *SysBluetooth) getAdapter(adapterPath dbus.ObjectPath) (adapter *adapter, err error) { + b.adaptersMu.Lock() + defer b.adaptersMu.Unlock() + + adapter = b.adapters[adapterPath] + if adapter == nil { + err = fmt.Errorf("adapter not exists %s", adapterPath) + logger.Error(err) + return + } + return +} + +func (b *SysBluetooth) isAdapterExists(adapterPath dbus.ObjectPath) bool { + b.adaptersMu.Lock() + defer b.adaptersMu.Unlock() + return b.adapters[adapterPath] != nil +} + +func (b *SysBluetooth) updateState() { + newState := StateUnavailable + if len(b.adapters) > 0 { + newState = StateAvailable + } + + for _, devices := range b.devices { + for _, d := range devices { + if d.adapter != nil && d.adapter.Powered && d.connected && d.Paired { + newState = StateConnected + break + } + } + } + + b.PropsMu.Lock() + b.setPropState(uint32(newState)) + b.PropsMu.Unlock() +} + +func (b *SysBluetooth) getAdapters() []*adapter { + b.adaptersMu.Lock() + defer b.adaptersMu.Unlock() + + result := make([]*adapter, 0, len(b.adapters)) + for _, adapter := range b.adapters { + result = append(result, adapter) + } + return result +} + +func (b *SysBluetooth) getDevices(adapterPath dbus.ObjectPath) []*device { + b.devicesMu.Lock() + defer b.devicesMu.Unlock() + + devices := b.devices[adapterPath] + result := make([]*device, len(devices)) + copy(result, devices) + return result +} + +func (b *SysBluetooth) tryConnectPairedDevices(adapterPath dbus.ObjectPath) { + if b.canAutoPair != nil { + if !b.canAutoPair() { + logger.Info("can't auto pair beacuse autoPairEnable key is unable") + return + } + } else { + return + } + + b.setAutoConnectFinishedStatus(adapterPath, false) + + inputOnly := true + // 自动连接时长 + defaultConnectDuration := 2 * time.Minute + if b.getActiveUserAgent() != nil { + // 表示用户已经登录 + inputOnly = false + // 可能有用户控制,为便于用户控制,缩短自动连接时长。 + defaultConnectDuration = 20 * time.Second + } + logger.Debugf("tryConnectPairedDevices adapterPath: %q, inputOnly: %v", adapterPath, inputOnly) + adapterDevicesMap := b.getPairedDevicesForAutoConnect(adapterPath) + + for adapterPath, devices := range adapterDevicesMap { + if inputOnly { + // 登录界面,只需要输入设备 + devices = filterOutDevices(devices, func(device *device) bool { + return strings.HasPrefix(device.Icon, "input") + }) + } + logger.Debug("before soft devices:", devices) + b.config.softDevices(devices) + logger.Debug("after soft devices:", devices) + var deviceInfos []autoDeviceInfo + priority := 0 + // 可能由设备主动连接的设备 + var activeReconnectDevices []*device + for _, d := range devices { + if d.maybeReconnectByDevice() { + activeReconnectDevices = append(activeReconnectDevices, d) + } + connectDuration := defaultConnectDuration + if d.shouldReconnectByHost() { + logger.Debug("try auto connect", d) + } else { + logger.Debugf("do not auto connect %v, but try connect once", d) + connectDuration = 1 * time.Second + if !d.Trusted { + err := d.core.Trusted().Set(0, true) + if err != nil { + logger.Warning(err) + } + } + err := d.cancelBlock() + if err != nil { + logger.Warning(err) + } + } + deviceInfos = append(deviceInfos, autoDeviceInfo{ + adapter: adapterPath, + device: d.Path, + alias: d.Alias, + priority: priority, + connectDurationMax: connectDuration, + }) + priority++ + } + b.setAutoConnectFinishedStatus(adapterPath, false) + b.acm.addDevices(adapterPath, deviceInfos, activeReconnectDevices) + } +} + +func (b *SysBluetooth) autoConnectPairedDevice(devPath dbus.ObjectPath, adapterPath dbus.ObjectPath) error { + device, err := b.getDevice(devPath) + if err != nil { + return err + } + + if device.connected { + logger.Debugf("%v is already connected", device) + return nil + } + + switch device.Icon { + // 只自动连接一个这些图标的设备 + case devIconAudioCard, devIconInputKeyboard, devIconInputMouse, devIconInputTablet: + connectedDevice := b.findFirstConnectedDeviceByIcon(device.Icon) + if connectedDevice != nil { + logger.Debugf("there is already a connected %v, icon: %v, do not auto connect it: %v", + connectedDevice, device.Icon, device) + return nil + } + } + + logger.Debug("auto connect paired", device) + err = device.doConnect(false) + if err != nil { + logger.Debugf("failed to auto connect %v: %v", device, err) + // 设置 connect phase 可以造成界面上一直在连接,而不中断的情况。 + device.setConnectPhase(connectPhaseConnectFailedSleep) + time.Sleep(3 * time.Second) + device.setConnectPhase(connectPhaseNone) + } + return err +} + +// 当 adapterPath 为空时,获取所有适配器的配对,但未连接的设备。 +// 当 adapterPath 不为空时,或者获取指定适配器的配对,但未连接的设备。 +func (b *SysBluetooth) getPairedDevicesForAutoConnect(adapterPath dbus.ObjectPath) map[dbus.ObjectPath][]*device { + adapters := b.getAdapters() + if adapterPath != "" { + var theAdapter *adapter + for _, adapter := range adapters { + if adapter.Path == adapterPath { + theAdapter = adapter + break + } + } + if theAdapter == nil { + return nil + } + adapters = []*adapter{theAdapter} + } + result := make(map[dbus.ObjectPath][]*device) + for _, adapter := range adapters { + // 当适配器打开电源时才自动连接 + if !adapter.Powered { + continue + } + devices := b.getDevices(adapter.Path) + var tmpDevices []*device + for _, d := range devices { + if d != nil && d.Paired && !d.connected { + tmpDevices = append(tmpDevices, d) + } + } + + result[adapter.Path] = tmpDevices + } + + return result +} + +// 判断设备是否为经典蓝牙设备 +func (d *device) isBREDRDevice() bool { + technologies, err := d.getTechnologies() + if err != nil { + logger.Warningf("failed to get %v technologies: %v", + d, err) + return false + } + for _, tech := range technologies { + if tech == "BR/EDR" { + return true + } + } + return false +} + +func (b *SysBluetooth) addConnectedDevice(connectedDev *device) { + b.connectedMu.Lock() + b.connectedDevices[connectedDev.AdapterPath] = append(b.connectedDevices[connectedDev.AdapterPath], connectedDev) + b.connectedMu.Unlock() +} + +func (b *SysBluetooth) removeConnectedDevice(disconnectedDev *device) { + b.connectedMu.Lock() + // check if dev exist in connectedDevices map, if exist, remove device + if connectedDevices, ok := _bt.connectedDevices[disconnectedDev.AdapterPath]; ok { + var tempDevices []*device + for _, dev := range connectedDevices { + // check if disconnected device exist in connected devices, if exist, abandon this + if dev.Address != disconnectedDev.Address { + tempDevices = append(tempDevices, dev) + } + } + _bt.connectedDevices[disconnectedDev.AdapterPath] = tempDevices + } + b.connectedMu.Unlock() +} + +func (b *SysBluetooth) getConnectedDeviceByAddress(address string) *device { + b.connectedMu.Lock() + defer b.connectedMu.Unlock() + + for _, devices := range b.connectedDevices { + for _, dev := range devices { + if dev.Address == address { + return dev + } + } + } + + return nil +} + +func (b *SysBluetooth) findFirstConnectedDeviceByIcon(icon string) *device { + b.connectedMu.Lock() + defer b.connectedMu.Unlock() + + for _, devices := range b.connectedDevices { + for _, dev := range devices { + if dev.Icon == icon { + return dev + } + } + } + return nil +} + +func (b *SysBluetooth) setAutoConnectFinishedStatus(adapterPath dbus.ObjectPath, status bool) { + adapter, err := b.getAdapter(adapterPath) + if err != nil { + // 可能是适配器被移除了 + logger.Warningf("call getAdapter failed; adapterPath:[%s] err:[%s]", adapterPath, err) + return + } + + if !adapter.Powered { + // 适配器电源关闭了 + logger.Warningf("adapter: [%s] is power off", adapterPath) + return + } + adapter.autoConnectFinished = status + + return +} + +func (b *SysBluetooth) stopDiscovery() { + b.adaptersMu.Lock() + defer b.adaptersMu.Unlock() + + for _, adapter := range b.adapters { + if adapter.Discovering { + err := adapter.core.Adapter().StopDiscovery(0) + if err != nil { + logger.Warning(err) + } + } + } + + return +} diff --git a/system/bluetooth/bluetooth_dbusutil.go b/system/bluetooth1/bluetooth_dbusutil.go similarity index 100% rename from system/bluetooth/bluetooth_dbusutil.go rename to system/bluetooth1/bluetooth_dbusutil.go diff --git a/system/bluetooth1/bluetooth_ifc.go b/system/bluetooth1/bluetooth_ifc.go new file mode 100644 index 000000000..eaf1d4b75 --- /dev/null +++ b/system/bluetooth1/bluetooth_ifc.go @@ -0,0 +1,429 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package bluetooth + +import ( + "fmt" + "strconv" + "time" + + "github.com/godbus/dbus/v5" + sysbtagent "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.bluetooth1.agent" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (b *SysBluetooth) ConnectDevice(devPath dbus.ObjectPath, adapterPath dbus.ObjectPath) *dbus.Error { + device, err := b.getDevice(devPath) + if err != nil { + logger.Debug("getDevice failed:", err) + adapter, err := b.getAdapter(adapterPath) + if err != nil { + logger.Debug("getAdapter failed:", err) + return dbusutil.ToError(err) + } + + // 当蓝牙在扫描中,打开蓝牙设备,扫描到蓝牙设备后,关闭蓝牙设备,此时bluez该设备已被移除,但backup中依旧存在蓝牙设备 + // 导致了控制中心第一次手动连接此蓝牙时报错,第二次连接时无响应,因此在第二次连接时直接将此蓝牙设备移除,并弹出横幅 + // Note Bug 107601 + bakDevice, err := b.getBackupDevice(devPath) + if err != nil { + logger.Warning("call getBackupDevice err:", err) + } else { + b.removeBackupDevice(devPath) + bakDevice.notifyDeviceRemoved() + notifyConnectFailedHostDown(bakDevice.Alias) + } + + // 当处于扫描状态时且无法得到device,将准备连接设备置空,防止自动连接 + if adapter.Discovering { + b.prepareToConnectedDevice = "" + return nil + } + + // 当扫描一分钟后停止,此时连接设备,会先开始扫描,然后将连接的此设备设为准备连接状态,发现此设备后,直接连接 + adapter.startDiscovery() + adapter.scanReadyToConnectDeviceTimeoutFlag = true + b.prepareToConnectedMu.Lock() + b.prepareToConnectedDevice = devPath + b.prepareToConnectedMu.Unlock() + } else { + go func() { + err := device.Connect() + if err != nil { + logger.Warning(err) + } + }() + } + return nil +} + +func (b *SysBluetooth) DisconnectDevice(devPath dbus.ObjectPath) *dbus.Error { + device, err := b.getDevice(devPath) + if err != nil { + return dbusutil.ToError(err) + } + go device.Disconnect() + return nil +} + +func (b *SysBluetooth) RemoveDevice(adapterPath, devPath dbus.ObjectPath) *dbus.Error { + adapter, err := b.getAdapter(adapterPath) + if err != nil { + return dbusutil.ToError(err) + } + // find remove device from map + removeDev, err := b.getDevice(devPath) + if err != nil { + logger.Warningf("failed to get device, err: %v", err) + return dbusutil.ToError(err) + } + + // 删除之前先取消配对,无论是否配对状态都应取消,防止配对过程中,关闭蓝牙异常 + err = removeDev.cancelPairing() + if err != nil { + logger.Warning("call cancelPairing err: ", err) + } + + // check if device connect state is connecting, if is, mark remove state as true + deviceState := removeDev.getState() + if deviceState == deviceStateConnecting { + removeDev.markNeedRemove(true) + } else { + // connection finish, allow removing device directly + b.removeBackupDevice(devPath) + err = adapter.core.Adapter().RemoveDevice(0, devPath) + if err != nil { + logger.Warningf("failed to remove device %q from adapter %q: %v", + devPath, adapterPath, err) + return dbusutil.ToError(err) + } + } + return nil +} + +func (b *SysBluetooth) SetDeviceAlias(device dbus.ObjectPath, alias string) *dbus.Error { + d, err := b.getDevice(device) + if err != nil { + return dbusutil.ToError(err) + } + err = d.core.Alias().Set(0, alias) + if err != nil { + return dbusutil.ToError(err) + } + return nil +} + +func (b *SysBluetooth) SetDeviceTrusted(device dbus.ObjectPath, trusted bool) *dbus.Error { + d, err := b.getDevice(device) + if err != nil { + return dbusutil.ToError(err) + } + err = d.core.Trusted().Set(0, trusted) + if err != nil { + return dbusutil.ToError(err) + } + return nil +} + +// GetDevices return all device objects that marshaled by json. +func (b *SysBluetooth) GetDevices(adapterPath dbus.ObjectPath) (devicesJSON string, busErr *dbus.Error) { + _, err := b.getAdapter(adapterPath) + if err != nil { + return "", dbusutil.ToError(err) + } + + var deviceMap = make(map[dbus.ObjectPath]*backupDevice) + b.backupDevicesMu.Lock() + for _, d := range b.backupDevices[adapterPath] { + deviceMap[d.Path] = d + } + b.backupDevicesMu.Unlock() + + b.devicesMu.Lock() + for _, d := range b.devices[adapterPath] { + deviceMap[d.Path] = newBackupDevice(d) + } + b.devicesMu.Unlock() + + var devices []*backupDevice + for _, d := range deviceMap { + devices = append(devices, d) + } + devicesJSON = marshalJSON(devices) + return +} + +// GetAdapters return all adapter objects that marshaled by json. +func (b *SysBluetooth) GetAdapters() (adaptersJSON string, err *dbus.Error) { + adapters := make([]*adapter, 0, len(b.adapters)) + b.adaptersMu.Lock() + for _, a := range b.adapters { + adapters = append(adapters, a) + } + b.adaptersMu.Unlock() + adaptersJSON = marshalJSON(adapters) + return +} + +func (b *SysBluetooth) RequestDiscovery(adapterPath dbus.ObjectPath) *dbus.Error { + adapter, err := b.getAdapter(adapterPath) + if err != nil { + return dbusutil.ToError(err) + } + + if !adapter.Powered { + err = fmt.Errorf("'%s' power off", adapter) + return dbusutil.ToError(err) + } + + discovering, err := adapter.core.Adapter().Discovering().Get(0) + if err != nil { + return dbusutil.ToError(err) + } + + if discovering { + // if adapter is discovering now, just return + return nil + } + + adapter.startDiscovery() + + return nil +} + +func (b *SysBluetooth) SetAdapterPowered(adapterPath dbus.ObjectPath, + powered bool) *dbus.Error { + + logger.Debug("SetAdapterPowered", adapterPath, powered) + + adapter, err := b.getAdapter(adapterPath) + if err != nil { + return dbusutil.ToError(err) + } + // 将DDE和前端的蓝牙 power 状态在设置时,立马保持同步 + // 为了避免,在下发power off给bluez后 bluez返回属性值中携带,power、discovering、class值,DDE在监听时, + // 当先收到 discovering,后收到power时 + // 在discovering改变时,此时power状态依旧为true,当时此时power是false状态,导致闪开后关闭 + // Note: BUG102434 + adapter.poweredActionTime = time.Now() + adapter.Powered = powered + adapter.discoveringFinished = false + + err = adapter.core.Adapter().Powered().Set(0, powered) + if err != nil { + logger.Warningf("failed to set %s powered: %v", adapter, err) + return dbusutil.ToError(err) + } + _bt.config.setAdapterConfigPowered(adapter.Address, powered) + + return nil +} + +func (b *SysBluetooth) SetAdapterAlias(adapterPath dbus.ObjectPath, alias string) *dbus.Error { + adapter, err := b.getAdapter(adapterPath) + if err != nil { + return dbusutil.ToError(err) + } + + err = adapter.core.Adapter().Alias().Set(0, alias) + if err != nil { + logger.Warningf("failed to set %s alias: %v", adapter, err) + return dbusutil.ToError(err) + } + + return nil +} + +func (b *SysBluetooth) SetAdapterDiscoverable(adapterPath dbus.ObjectPath, + discoverable bool) *dbus.Error { + logger.Debug("SetAdapterDiscoverable", adapterPath, discoverable) + + adapter, err := b.getAdapter(adapterPath) + if err != nil { + return dbusutil.ToError(err) + } + + if !adapter.Powered { + err = fmt.Errorf("'%s' power off", adapter) + return dbusutil.ToError(err) + } + + err = adapter.core.Adapter().Discoverable().Set(0, discoverable) + if err != nil { + logger.Warningf("failed to set %s discoverable: %v", adapter, err) + return dbusutil.ToError(err) + } + _bt.config.setAdapterConfigDiscoverable(adapter.Address, discoverable) + + return nil +} + +func (b *SysBluetooth) SetAdapterDiscovering(adapterPath dbus.ObjectPath, + discovering bool) *dbus.Error { + logger.Debug("SetAdapterDiscovering", adapterPath, discovering) + + adapter, err := b.getAdapter(adapterPath) + if err != nil { + return dbusutil.ToError(err) + } + + if !adapter.Powered { + err = fmt.Errorf("'%s' power off", adapter) + return dbusutil.ToError(err) + } + + if discovering { + adapter.startDiscovery() + } else { + err = adapter.core.Adapter().StopDiscovery(0) + if err != nil { + logger.Warningf("failed to stop discovery for %s: %v", adapter, err) + return dbusutil.ToError(err) + } + } + + return nil +} + +func (b *SysBluetooth) SetAdapterDiscoverableTimeout(adapterPath dbus.ObjectPath, + discoverableTimeout uint32) *dbus.Error { + logger.Debug("SetAdapterDiscoverableTimeout", adapterPath, discoverableTimeout) + + adapter, err := b.getAdapter(adapterPath) + if err != nil { + return dbusutil.ToError(err) + } + + err = adapter.core.Adapter().DiscoverableTimeout().Set(0, discoverableTimeout) + if err != nil { + logger.Warningf("failed to set %s discoverableTimeout: %v", adapter, err) + return dbusutil.ToError(err) + } + + return nil +} + +func (b *SysBluetooth) getActiveUserAgent() sysbtagent.Agent { + return b.userAgents.getActiveAgent() +} + +func (b *SysBluetooth) RegisterAgent(sender dbus.Sender, agentPath dbus.ObjectPath) *dbus.Error { + uid, err := b.service.GetConnUID(string(sender)) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + uidStr := strconv.Itoa(int(uid)) + b.userAgents.addUser(uidStr) + + sessionDetails, err := b.loginManager.ListSessions(0) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + sysBus := b.service.Conn() + for _, detail := range sessionDetails { + if detail.UID == uid { + session, err := login1.NewSession(sysBus, detail.Path) + if err != nil { + logger.Warning(err) + continue + } + newlyAdded := b.userAgents.addSession(uidStr, session) + if newlyAdded { + b.watchSession(uidStr, session) + } + } + } + + agent, err := sysbtagent.NewAgent(sysBus, string(sender), agentPath) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + b.userAgents.addAgent(uidStr, agent) + // 防止第一次进入系统,此时无设备连接,但是 needFixBtPoweredStatus 为true,此时打开蓝牙添加设备后paired为true + // 此时在调用addDevice接口后,会走不必要的逻辑,因此将此标志位置为false规避 + b.needFixBtPoweredStatus = false + go b.tryConnectPairedDevices("") + + logger.Debugf("agent registered, sender: %q, agentPath: %q", sender, agentPath) + return nil +} + +func (b *SysBluetooth) UnregisterAgent(sender dbus.Sender, agentPath dbus.ObjectPath) *dbus.Error { + uid, err := b.service.GetConnUID(string(sender)) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + uidStr := strconv.Itoa(int(uid)) + err = b.userAgents.removeAgent(uidStr, agentPath) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + logger.Debugf("agent unregistered, sender: %q, agentPath: %q", sender, agentPath) + return nil +} + +func (b *SysBluetooth) DebugInfo() (info string, busErr *dbus.Error) { + info = fmt.Sprintf("adapters: %s\ndevices: %s", marshalJSON(b.adapters), marshalJSON(b.devices)) + return info, nil +} + +// ClearUnpairedDevice will remove all device in unpaired list +func (b *SysBluetooth) ClearUnpairedDevice() *dbus.Error { + logger.Debug("ClearUnpairedDevice") + var removeDevices []*device + b.devicesMu.Lock() + for _, devices := range b.devices { + for _, d := range devices { + if !d.Paired { + logger.Info("remove unpaired device", d) + removeDevices = append(removeDevices, d) + } + } + } + b.devicesMu.Unlock() + + for _, d := range removeDevices { + err := b.RemoveDevice(d.AdapterPath, d.Path) + if err != nil { + logger.Warning(err) + } + } + return nil +} + +// 断开所有音频设备 +func (b *SysBluetooth) DisconnectAudioDevices() *dbus.Error { + logger.Debug("call DisconnectAudioDevices") + b.adaptersMu.Lock() + devices := make([]*device, 0, len(b.adapters)) + for aPath, _ := range b.adapters { + b.connectedMu.Lock() + for _, d := range b.connectedDevices[aPath] { + for _, uuid := range d.UUIDs { + if uuid == A2DP_SINK_UUID && d.connected { + logger.Infof("disconnect A2DP %s", d) + devices = append(devices, d) + } + } + } + b.connectedMu.Unlock() + } + b.adaptersMu.Unlock() + + for _, device := range devices { + device.Disconnect() + } + + return nil +} diff --git a/system/bluetooth/bluez_profile.go b/system/bluetooth1/bluez_profile.go similarity index 100% rename from system/bluetooth/bluez_profile.go rename to system/bluetooth1/bluez_profile.go diff --git a/system/bluetooth/bluez_uuid.go b/system/bluetooth1/bluez_uuid.go similarity index 100% rename from system/bluetooth/bluez_uuid.go rename to system/bluetooth1/bluez_uuid.go diff --git a/system/bluetooth/config.go b/system/bluetooth1/config.go similarity index 100% rename from system/bluetooth/config.go rename to system/bluetooth1/config.go diff --git a/system/bluetooth1/config_test.go b/system/bluetooth1/config_test.go new file mode 100644 index 000000000..a7d71b3e3 --- /dev/null +++ b/system/bluetooth1/config_test.go @@ -0,0 +1,119 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package bluetooth + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +const adapteraddress = "00:1A:7D:DA:71:13" +const deviceaddress = "00:1A:7D:DA:71:13/00:1A:7D:DA:71:11" +const testfile = "testfile" + +var _deviceConfig = &deviceConfig{ + Icon: "computer", + Connected: false, + LatestTime: 0, +} + +func Test_config(t *testing.T) { + configAdapters := map[string]*adapterConfig{ + "00:1A:7D:DA:71:13": { + Powered: false, + Discoverable: true, + }, + } + + configDevices := map[string]*deviceConfig{ + "00:1A:7D:DA:71:13/00:1A:7D:DA:71:11": { + Icon: "computer", + Connected: false, + LatestTime: 0, + }, + "00:1A:7D:DA:71:13/00:1A:7D:DA:71:13": { + Icon: "computer", + Connected: false, + LatestTime: 0, + }, + "00:1A:7D:DA:71:13/0B:4C:03:C8:EA:7C": { + Icon: "", + Connected: false, + LatestTime: 0, + }, + "00:1A:7D:DA:71:13/10:D0:7A:B1:D3:2F": { + Icon: "", + Connected: false, + LatestTime: 0, + }, + "00:1A:7D:DA:71:13/10:E9:53:E9:EA:3C": { + Icon: "phone", + Connected: false, + LatestTime: 0, + }, + } + + c := &config{} + c.core.SetConfigFile(testfile) + logger.Info("load bluetooth config file:", c.core.GetConfigFile()) + c.Adapters = make(map[string]*adapterConfig) + c.Devices = make(map[string]*deviceConfig) + //c.Discoverable = true + + c.addAdapterConfig(adapteraddress) + + for address, configDevice := range configDevices { + c.addConfigDevice(address, configDevice) + } + + c.load() + + assert.Equal(t, c.Adapters, configAdapters) + assert.Equal(t, c.Devices, configDevices) + //assert.True(t, c.Discoverable) + + c.setAdapterConfigPowered(adapteraddress, false) + assert.False(t, c.getAdapterConfigPowered(adapteraddress)) + + c.setAdapterConfigPowered(adapteraddress, true) + assert.True(t, c.getAdapterConfigPowered(adapteraddress)) + + c.setConfigDeviceConnected(deviceaddress, _deviceConfig, true) + assert.True(t, c.getDeviceConfigConnected(deviceaddress)) + + c.setConfigDeviceConnected(deviceaddress, _deviceConfig, false) + assert.False(t, c.getDeviceConfigConnected(deviceaddress)) + + err := os.Remove(testfile) + logger.Warning("Remove failed:", err) +} + +func (c *config) addConfigDevice(address string, addDeviceconfig *deviceConfig) { + if c.isDeviceConfigExist(address) { + return + } + + deviceInfo := newDeviceConfig() + deviceInfo.Icon = addDeviceconfig.Icon + deviceInfo.LatestTime = 0 + deviceInfo.Connected = addDeviceconfig.Connected + + c.Devices[address] = deviceInfo + c.save() +} + +func (c *config) setConfigDeviceConnected(address string, Deviceconfig *deviceConfig, connected bool) { + dc, ok := c.getDeviceConfig(address) + if !ok { + return + } + + dc.Connected = connected + dc.Icon = Deviceconfig.Icon + + c.save() +} diff --git a/system/bluetooth1/device.go b/system/bluetooth1/device.go new file mode 100644 index 000000000..6f8790a2a --- /dev/null +++ b/system/bluetooth1/device.go @@ -0,0 +1,920 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package bluetooth + +import ( + "errors" + "fmt" + "path/filepath" + "strings" + "sync" + "time" + + "github.com/godbus/dbus/v5" + bluez "github.com/linuxdeepin/go-dbus-factory/system/org.bluez" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/dbusutil/proxy" +) + +const ( + deviceStateDisconnected = 0 + // device state is connecting or disconnecting, mark them as device state doing + deviceStateConnecting = 1 + deviceStateConnected = 2 + deviceStateDisconnecting = 3 +) + +const ( + resourceUnavailable = "Resource temporarily unavailable" +) + +type deviceState uint32 + +func (s deviceState) String() string { + switch s { + case deviceStateDisconnected: + return "Disconnected" + case deviceStateConnecting: + return "Connecting" + case deviceStateConnected: + return "Connected" + case deviceStateDisconnecting: + return "Disconnecting" + default: + return fmt.Sprintf("Unknown(%d)", s) + } +} + +var ( + errInvalidDevicePath = fmt.Errorf("invalid device path") +) + +type device struct { + core bluez.Device + adapter *adapter + + Path dbus.ObjectPath + AdapterPath dbus.ObjectPath + + Alias string + Trusted bool + Paired bool + State deviceState + ServicesResolved bool + ConnectState bool + + // optional + UUIDs []string + Name string + Icon string + RSSI int16 + Address string + + connected bool + connectedTime time.Time + retryConnectCount int + agentWorking bool + needNotify bool + + connectPhase connectPhase + disconnectPhase disconnectPhase + disconnectChan chan struct{} + mu sync.Mutex + pairingFailedTime time.Time + + // mark if pc or mobile request a connection + // if is pc, then do not need to show notification window + // else show notification window + isInitiativeConnect bool + // remove device when device state is connecting or disconnecting may cause blueZ crash + // to avoid this situation, remove device only allowed when connected or disconnected finished + needRemove bool + removeLock sync.Mutex + inputReconnectMode string + blocked bool +} + +// 设备的备份,扫描结束3分钟后保存设备 +type backupDevice struct { + Path dbus.ObjectPath + AdapterPath dbus.ObjectPath + + Alias string + Trusted bool + Paired bool + State deviceState + ServicesResolved bool + ConnectState bool + + // optional + UUIDs []string + Name string + Icon string + RSSI int16 + Address string +} + +type connectPhase uint32 + +const ( + connectPhaseNone = iota + connectPhaseStart + connectPhasePairStart + connectPhasePairEnd + connectPhaseConnectProfilesStart + connectPhaseConnectProfilesEnd + connectPhaseConnectFailedSleep // 反复连接过程中,失败后的短暂延时 +) + +type disconnectPhase uint32 + +const ( + disconnectPhaseNone = iota + disconnectPhaseStart + disconnectPhaseDisconnectStart + disconnectPhaseDisconnectEnd +) + +func (d *device) setDisconnectPhase(value disconnectPhase) { + d.mu.Lock() + d.disconnectPhase = value + d.mu.Unlock() + + switch value { + case disconnectPhaseDisconnectStart: + logger.Debugf("%s disconnect start", d) + case disconnectPhaseDisconnectEnd: + logger.Debugf("%s disconnect end", d) + } + d.updateState() + d.notifyDevicePropertiesChanged() +} + +func (d *device) getDisconnectPhase() disconnectPhase { + d.mu.Lock() + value := d.disconnectPhase + d.mu.Unlock() + return value +} + +func (d *device) setConnectPhase(value connectPhase) { + d.mu.Lock() + d.connectPhase = value + d.mu.Unlock() + + switch value { + case connectPhasePairStart: + logger.Debugf("%s pair start", d) + case connectPhasePairEnd: + logger.Debugf("%s pair end", d) + + case connectPhaseConnectProfilesStart: + logger.Debugf("%s connect profiles start", d) + case connectPhaseConnectProfilesEnd: + logger.Debugf("%s connect profiles end", d) + } + + d.updateState() + d.notifyDevicePropertiesChanged() + if d.Paired && d.State == deviceStateConnected && d.ConnectState && d.needNotify { + d.needNotify = false + notifyConnected(d.Alias) + } +} + +func (d *device) getConnectPhase() connectPhase { + d.mu.Lock() + value := d.connectPhase + d.mu.Unlock() + return value +} + +func (d *device) agentWorkStart() { + logger.Debugf("%s agent work start", d) + d.mu.Lock() + d.agentWorking = true + d.mu.Unlock() + d.updateState() + d.notifyDevicePropertiesChanged() +} + +func (d *device) agentWorkEnd() { + logger.Debugf("%s agent work end", d) + d.mu.Lock() + d.agentWorking = false + d.mu.Unlock() + d.updateState() + d.notifyDevicePropertiesChanged() +} + +func (d *device) String() string { + return fmt.Sprintf("device [%s] %s", d.Address, d.Alias) +} + +func newDevice(systemSigLoop *dbusutil.SignalLoop, dpath dbus.ObjectPath) (d *device) { + d = &device{Path: dpath} + systemConn := systemSigLoop.Conn() + d.core, _ = bluez.NewDevice(systemConn, dpath) + d.AdapterPath, _ = d.core.Adapter().Get(0) + d.Name, _ = d.core.Name().Get(0) + d.Alias, _ = d.core.Alias().Get(0) + d.Address, _ = d.core.Address().Get(0) + d.Trusted, _ = d.core.Trusted().Get(0) + d.Paired, _ = d.core.Paired().Get(0) + d.connected, _ = d.core.Connected().Get(0) + d.UUIDs, _ = d.core.UUIDs().Get(0) + d.ServicesResolved, _ = d.core.ServicesResolved().Get(0) + d.Icon, _ = d.core.Icon().Get(0) + d.RSSI, _ = d.core.RSSI().Get(0) + d.blocked, _ = d.core.Blocked().Get(0) + d.needNotify = true + var err error + d.inputReconnectMode, err = d.getInputReconnectModeRaw() + if err != nil { + logger.Warning(err) + } + d.updateState() + + // 升级后第一次进入系统,登录界面时,当之前有蓝牙连接时,打开蓝牙开关(蓝牙可被发现状态 为默认状态),否则关闭 + if d.Paired && _bt.needFixBtPoweredStatus { + // 防止多个设备反复打开蓝牙 + adapter, err := _bt.getAdapter(d.AdapterPath) + if err != nil { + return + } + + if !adapter.Powered { + _bt.SetAdapterPowered(d.AdapterPath, true) + _bt.needFixBtPoweredStatus = false + } + } + + if d.Paired && d.connected { + d.ConnectState = true + //切換用户时添加设备到connectedDevices列表中 + _bt.addConnectedDevice(d) + } + d.disconnectChan = make(chan struct{}) + d.core.InitSignalExt(systemSigLoop, true) + d.connectProperties() + return +} + +func (d *device) destroy() { + d.core.RemoveHandler(proxy.RemoveAllHandlers) +} + +func (d *device) notifyDeviceAdded() { + logger.Debug("notifyDeviceAdded", d.Alias, d.Path) + err := _bt.service.Emit(_bt, "DeviceAdded", marshalJSON(d)) + if err != nil { + logger.Warning(err) + } + _bt.updateState() +} + +func (d *device) notifyDeviceRemoved() { + logger.Debug("notifyDeviceRemoved", d.Alias, d.Path) + err := _bt.service.Emit(_bt, "DeviceRemoved", marshalJSON(d)) + if err != nil { + logger.Warning(err) + } + _bt.updateState() +} + +func (d *device) notifyDevicePropertiesChanged() { + err := _bt.service.Emit(_bt, "DevicePropertiesChanged", marshalJSON(d)) + if err != nil { + logger.Warning(err) + } + _bt.updateState() +} + +func (d *device) connectProperties() { + err := d.core.Connected().ConnectChanged(func(hasValue bool, connected bool) { + if !hasValue { + return + } + logger.Debugf("%s Connected: %v", d, connected) + d.connected = connected + + //音频设备主动发起连接时也断开之前的音频连接 + if d.connected && d.Paired { + go d.audioA2DPWorkaround() + } + + // check if device need to be removed, if is, remove device + needRemove := d.getAndResetNeedRemove() + if needRemove { + // start remove device + d.adapter.bt.removeBackupDevice(d.Path) + err := d.adapter.core.Adapter().RemoveDevice(0, d.Path) + if err != nil { + logger.Warningf("failed to remove device %q from adapter %q: %v", + d.adapter.Path, d.Path, err) + return + } + return + } + + if connected { + d.ConnectState = true + d.connectedTime = time.Now() + _bt.config.setDeviceConfigConnected(d, true) + _bt.acm.handleDeviceEvent(d) + dev := _bt.getConnectedDeviceByAddress(d.Address) + if dev == nil { + _bt.addConnectedDevice(d) + logger.Debug("connectedDevices", _bt.connectedDevices) + } + } else { + //If the pairing is successful and connected, the signal will be sent when the device is disconnected + if d.Paired && d.ConnectState { + notifyDisconnected(d.Alias) + } + d.needNotify = true + d.ConnectState = false + + // if disconnect success, remove device from map + _bt.removeConnectedDevice(d) + // when disconnected quickly after connecting, automatically try to connect + sinceConnected := time.Since(d.connectedTime) + logger.Debug("sinceConnected:", sinceConnected) + logger.Debug("retryConnectCount:", d.retryConnectCount) + + if sinceConnected < 300*time.Millisecond { + if d.retryConnectCount == 0 { + go func() { + err := d.Connect() + if err != nil { + logger.Warning(err) + } + }() + } + d.retryConnectCount++ + } else if sinceConnected > 2*time.Second { + d.retryConnectCount = 0 + } + + select { + case d.disconnectChan <- struct{}{}: + logger.Debugf("%s disconnectChan send done", d) + default: + } + } + d.updateState() + d.notifyDevicePropertiesChanged() + + if d.needNotify && d.Paired && d.State == deviceStateConnected && d.ConnectState { + d.notifyConnectedChanged() + } + }) + if err != nil { + logger.Warning(err) + } + + _ = d.core.Name().ConnectChanged(func(hasValue bool, value string) { + if !hasValue { + return + } + logger.Debugf("%s Name: %v", d, value) + d.Name = value + d.notifyDevicePropertiesChanged() + }) + + _ = d.core.Alias().ConnectChanged(func(hasValue bool, value string) { + if !hasValue { + return + } + d.Alias = value + logger.Debugf("%s Alias: %v", d, value) + d.notifyDevicePropertiesChanged() + }) + + _ = d.core.Address().ConnectChanged(func(hasValue bool, value string) { + if !hasValue { + return + } + d.Address = value + logger.Debugf("%s Address: %v", d, value) + d.notifyDevicePropertiesChanged() + }) + + _ = d.core.Trusted().ConnectChanged(func(hasValue bool, value bool) { + if !hasValue { + return + } + d.Trusted = value + logger.Debugf("%s Trusted: %v", d, value) + d.notifyDevicePropertiesChanged() + }) + + _ = d.core.Paired().ConnectChanged(func(hasValue bool, value bool) { + if !hasValue { + return + } + d.Paired = value + d.updateState() // Paired属性被修改,影响到下面使用的State和ConnectState + logger.Debugf("%s Paired: %v State: %v", d, value, d.State) + + if d.Paired && d.connected && d.State == deviceStateConnected { + d.ConnectState = true + dev := _bt.getConnectedDeviceByAddress(d.Address) + if dev == nil { + _bt.addConnectedDevice(d) + } + } + + if d.needNotify && d.Paired && d.State == deviceStateConnected && d.ConnectState { + notifyConnected(d.Alias) + d.needNotify = false + } + d.notifyDevicePropertiesChanged() + }) + + _ = d.core.ServicesResolved().ConnectChanged(func(hasValue bool, value bool) { + if !hasValue { + return + } + d.ServicesResolved = value + logger.Debugf("%s ServicesResolved: %v", d, value) + d.notifyDevicePropertiesChanged() + }) + + _ = d.core.Icon().ConnectChanged(func(hasValue bool, value string) { + if !hasValue { + return + } + d.Icon = value + logger.Debugf("%s Icon: %v", d, value) + d.notifyDevicePropertiesChanged() + var err error + d.inputReconnectMode, err = d.getInputReconnectModeRaw() + if err != nil { + logger.Warning(err) + } + }) + + _ = d.core.UUIDs().ConnectChanged(func(hasValue bool, value []string) { + if !hasValue { + return + } + d.UUIDs = value + logger.Debugf("%s UUIDs: %v", d, value) + d.notifyDevicePropertiesChanged() + }) + + _ = d.core.RSSI().ConnectChanged(func(hasValue bool, value int16) { + if !hasValue { + d.RSSI = 0 + logger.Debugf("%s RSSI invalidated", d) + } else { + d.RSSI = value + logger.Debugf("%s RSSI: %v", d, value) + } + d.notifyDevicePropertiesChanged() + }) + + _ = d.core.LegacyPairing().ConnectChanged(func(hasValue bool, value bool) { + if !hasValue { + return + } + logger.Debugf("%s LegacyPairing: %v", d, value) + }) + + _ = d.core.Blocked().ConnectChanged(func(hasValue bool, value bool) { + if !hasValue { + return + } + logger.Debugf("%s Blocked: %v", d, value) + d.blocked = value + }) +} + +func (d *device) notifyConnectedChanged() { + connectPhase := d.getConnectPhase() + if connectPhase != connectPhaseNone { + // connect is in progress + logger.Debugf("%s handleNotifySend: connect is in progress", d) + return + } + + disconnectPhase := d.getDisconnectPhase() + if disconnectPhase != disconnectPhaseNone { + // disconnect is in progress + logger.Debugf("%s handleNotifySend: disconnect is in progress", d) + return + } + + if d.connected { + notifyConnected(d.Alias) + d.needNotify = false + //} else { + // if time.Since(d.pairingFailedTime) < 2*time.Second { + // return + // } + // notifyDisconnected(d.Alias) + } +} + +func (d *device) updateState() { + newState := d.getState() + if d.State != newState { + d.State = newState + logger.Debugf("%s State: %s", d, d.State) + } +} + +func (d *device) getState() deviceState { + d.mu.Lock() + defer d.mu.Unlock() + if d.agentWorking { + return deviceStateConnecting + } + + if d.connectPhase != connectPhaseNone { + return deviceStateConnecting + + } else if d.disconnectPhase != connectPhaseNone { + return deviceStateDisconnecting + + } else { + if d.connected && d.Paired { + return deviceStateConnected + } else { + return deviceStateDisconnected + } + } +} + +func (d *device) getAddress() string { + if d.adapter != nil { + return d.adapter.Address + "/" + d.Address + } + return "/" +} + +func (d *device) doConnect(hasNotify bool) error { + connectPhase := d.getConnectPhase() + disconnectPhase := d.getDisconnectPhase() + if connectPhase != connectPhaseNone { + logger.Warningf("%s connect is in progress", d) + return nil + } else if disconnectPhase != disconnectPhaseNone { + logger.Debugf("%s disconnect is in progress", d) + return nil + } + + d.setConnectPhase(connectPhaseStart) + defer d.setConnectPhase(connectPhaseNone) + + err := d.cancelBlock() + if err != nil { + // if hasNotify { + // // TODO(jouyouyun): notify device blocked + // } + return err + } + + err = d.doPair() + if err != nil { + d.ConnectState = false + if hasNotify { + notifyConnectFailedHostDown(d.Alias) + } + return err + } + + d.audioA2DPWorkaround() + + err = d.doRealConnect() + if err != nil { + if hasNotify { + if resourceUnavailable == err.Error() { + notifyConnectFailedResourceUnavailable(d.Alias, d.adapter.Alias) + } else { + notifyConnectFailedHostDown(d.Alias) + } + } + d.ConnectState = false + return err + } + + d.ConnectState = true + d.notifyDevicePropertiesChanged() + if d.needNotify && d.Paired && d.State == deviceStateConnected && d.ConnectState { + notifyConnected(d.Alias) + d.needNotify = false + } + return nil +} + +func (d *device) doRealConnect() error { + if d.adapter.Discovering { + err := d.adapter.core.Adapter().StopDiscovery(0) + if err != nil { + logger.Warning(err) + } + defer func() { + err = d.adapter.core.Adapter().StartDiscovery(0) + if err != nil { + logger.Warning(err) + } + }() + } + d.setConnectPhase(connectPhaseConnectProfilesStart) + err := d.core.Connect(0) + d.setConnectPhase(connectPhaseConnectProfilesEnd) + if err != nil { + if strings.Contains(err.Error(), "Input/output error") { + logger.Info("Input/output error -> ignore profile fail.") + } else { + // connect failed + logger.Warningf("%s connect failed: %v", d, err) + _bt.config.setDeviceConfigConnected(d, false) + return err + } + } + + // connect succeeded + logger.Infof("%s connect succeeded", d) + _bt.config.setDeviceConfigConnected(d, true) + + // auto trust device when connecting success + err = d.doTrust() + if err != nil { + logger.Warning(err) + } + + return nil +} + +func (d *device) doTrust() error { + trusted, _ := d.core.Trusted().Get(0) + if trusted { + return nil + } + err := d.core.Trusted().Set(0, true) + if err != nil { + logger.Warning(err) + } + return err +} + +func (d *device) cancelBlock() error { + blocked, err := d.core.Blocked().Get(0) + if err != nil { + logger.Warning(err) + return err + } + if !blocked { + return nil + } + err = d.core.Blocked().Set(0, false) + if err != nil { + logger.Warning(err) + } + return err +} + +func (d *device) cancelPairing() error { + err := d.core.CancelPairing(0) + + return err +} + +func (d *device) doPair() error { + paired, err := d.core.Paired().Get(0) + if err != nil { + logger.Warning(err) + return err + } + if paired { + logger.Debugf("%s already paired", d) + return nil + } + + d.setConnectPhase(connectPhasePairStart) + err = d.core.Pair(0) + d.setConnectPhase(connectPhasePairEnd) + if err != nil { + logger.Warningf("%s pair failed: %v", d, err) + d.pairingFailedTime = time.Now() + d.setConnectPhase(connectPhaseNone) + return err + } + + logger.Warningf("%s pair succeeded", d) + return nil +} + +func (d *device) markNeedRemove(need bool) { + d.removeLock.Lock() + d.needRemove = need + d.removeLock.Unlock() +} + +// get and reset needRemove +func (d *device) getAndResetNeedRemove() bool { + d.removeLock.Lock() + defer d.removeLock.Unlock() + needRemove := d.needRemove + // if needRemove is true, reset needRemove + if needRemove { + d.needRemove = false + } + return needRemove +} + +func (d *device) audioA2DPWorkaround() { + // TODO: remove work code if bluez a2dp is ok + // bluez do not support muti a2dp devices + // disconnect a2dp device before connect + for _, uuid := range d.UUIDs { + if uuid == A2DP_SINK_UUID { + _bt.disconnectA2DPDeviceExcept(d) + } + } +} + +func (d *device) Connect() error { + logger.Debug(d, "call Connect()") + err := d.doConnect(true) + return err +} + +func (d *device) Disconnect() { + logger.Debugf("%s call Disconnect()", d) + + disconnectPhase := d.getDisconnectPhase() + if disconnectPhase != disconnectPhaseNone { + logger.Debugf("%s disconnect is in progress", d) + return + } + + d.setDisconnectPhase(disconnectPhaseStart) + defer d.setDisconnectPhase(disconnectPhaseNone) + + connected, err := d.core.Connected().Get(0) + if err != nil { + logger.Warning(err) + return + } + if !connected { + logger.Debugf("%s not connected", d) + return + } + + // 如果是 LE 或由设备主动重连接的设备, 则先设置 Trusted 为 false, 防止很快地重连接。 + if d.maybeReconnectByDevice() { + err = d.core.Trusted().Set(0, false) + if err != nil { + logger.Warning("set trusted failed:", err) + } + } + + _bt.config.setDeviceConfigConnected(d, false) + + ch := d.goWaitDisconnect() + + d.setDisconnectPhase(disconnectPhaseDisconnectStart) + err = d.core.Disconnect(0) + if err != nil { + logger.Warningf("failed to disconnect %s: %v", d, err) + } + d.setDisconnectPhase(disconnectPhaseDisconnectEnd) + d.ConnectState = false + d.notifyDevicePropertiesChanged() + + <-ch + notifyDisconnected(d.Alias) + d.needNotify = true +} + +func (d *device) maybeReconnectByDevice() bool { + reconnectMode, err := d.getInputReconnectMode() + if err != nil { + logger.Warning(err) + } + if (reconnectMode == inputReconnectModeDevice || reconnectMode == inputReconnectModeAny) || + !d.isBREDRDevice() { + return true + } + return false +} + +func (d *device) shouldReconnectByHost() bool { + reconnectMode, err := d.getInputReconnectMode() + if err != nil { + logger.Warning(err) + } + if reconnectMode == inputReconnectModeDevice { + return false + } + if (reconnectMode == inputReconnectModeHost || reconnectMode == inputReconnectModeAny) || + d.isBREDRDevice() { + return true + } + return false +} + +// nolint +const ( + inputReconnectModeNone = "none" + inputReconnectModeHost = "host" + inputReconnectModeDevice = "device" + inputReconnectModeAny = "any" +) + +func (d *device) getInputReconnectMode() (string, error) { + if d.inputReconnectMode != "" { + return d.inputReconnectMode, nil + } + return d.getInputReconnectModeRaw() +} + +func (d *device) getInputReconnectModeRaw() (string, error) { + sysBus, err := dbus.SystemBus() + if err != nil { + return "", err + } + obj := sysBus.Object(d.core.ServiceName_(), d.core.Path_()) + if strings.HasPrefix(d.Icon, "input") { + propVar, err := obj.GetProperty("org.bluez.Input1.ReconnectMode") + if err != nil { + busErr, ok := err.(dbus.Error) + if ok && strings.Contains(strings.ToLower(busErr.Error()), "no such interface") { + // 这个接口不是一定存在的,所以忽略这种错误。 + return "", nil + } + return "", err + } + mode, ok := propVar.Value().(string) + if !ok { + return "", errors.New("type of the property value is not string") + } + return mode, nil + } + return "", nil +} + +func (d *device) goWaitDisconnect() chan struct{} { + ch := make(chan struct{}) + go func() { + select { + case <-d.disconnectChan: + logger.Debugf("%s disconnectChan receive ok", d) + case <-time.After(60 * time.Second): + logger.Debugf("%s disconnectChan receive timed out", d) + } + ch <- struct{}{} + }() + return ch +} + +func (d *device) getTechnologies() ([]string, error) { + if d.adapter == nil { + return nil, errors.New("d.adapter is nil") + } + var filename = filepath.Join(bluetoothPrefixDir, d.adapter.Address, d.Address, "info") + techs, err := doGetDeviceTechnologies(filename) + return techs, err +} + +// 按条件过滤出期望的设备,fn 返回 true 表示需要。 +func filterOutDevices(devices []*device, fn func(d *device) bool) (result []*device) { + for _, d := range devices { + if fn(d) { + result = append(result, d) + } + } + return +} + +func newBackupDevice(d *device) (bd *backupDevice) { + bd = &backupDevice{} + bd.AdapterPath = d.AdapterPath + bd.Path = d.Path + bd.Alias = d.Alias + bd.Paired = d.Paired + bd.Address = d.Address + bd.State = d.State + bd.Name = d.Name + bd.ConnectState = d.ConnectState + bd.Icon = d.Icon + bd.RSSI = d.RSSI + bd.ServicesResolved = d.ServicesResolved + bd.Trusted = d.Trusted + bd.UUIDs = d.UUIDs + return bd +} + +func (d *backupDevice) notifyDeviceRemoved() { + logger.Debug("backupDevice notifyDeviceRemoved", d.Alias, d.Path) + err := _bt.service.Emit(_bt, "DeviceRemoved", marshalJSON(d)) + if err != nil { + logger.Warning(err) + } +} diff --git a/system/bluetooth/doc.go b/system/bluetooth1/doc.go similarity index 100% rename from system/bluetooth/doc.go rename to system/bluetooth1/doc.go diff --git a/system/bluetooth/exported_methods_auto.go b/system/bluetooth1/exported_methods_auto.go similarity index 100% rename from system/bluetooth/exported_methods_auto.go rename to system/bluetooth1/exported_methods_auto.go diff --git a/system/bluetooth/init.go b/system/bluetooth1/init.go similarity index 100% rename from system/bluetooth/init.go rename to system/bluetooth1/init.go diff --git a/system/bluetooth/module.go b/system/bluetooth1/module.go similarity index 100% rename from system/bluetooth/module.go rename to system/bluetooth1/module.go diff --git a/system/bluetooth/utils.go b/system/bluetooth1/utils.go similarity index 100% rename from system/bluetooth/utils.go rename to system/bluetooth1/utils.go diff --git a/system/bluetooth/utils_notify.go b/system/bluetooth1/utils_notify.go similarity index 100% rename from system/bluetooth/utils_notify.go rename to system/bluetooth1/utils_notify.go diff --git a/system/bluetooth/utils_test.go b/system/bluetooth1/utils_test.go similarity index 100% rename from system/bluetooth/utils_test.go rename to system/bluetooth1/utils_test.go diff --git a/system/display/exported_methods_auto.go b/system/display/exported_methods_auto.go deleted file mode 100644 index 28e0e0091..000000000 --- a/system/display/exported_methods_auto.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by "dbusutil-gen em -type Display"; DO NOT EDIT. - -package display - -import ( - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (v *Display) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "GetConfig", - Fn: v.GetConfig, - OutArgs: []string{"cfgStr"}, - }, - { - Name: "SetBacklightBrightness", - Fn: v.SetBacklightBrightness, - InArgs: []string{"val"}, - }, - { - Name: "SetConfig", - Fn: v.SetConfig, - InArgs: []string{"cfgStr"}, - }, - { - Name: "SupportWayland", - Fn: v.SupportWayland, - OutArgs: []string{"outArg0"}, - }, - } -} diff --git a/system/display/module.go b/system/display/module.go deleted file mode 100644 index 99b36a725..000000000 --- a/system/display/module.go +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package display - -import ( - "github.com/linuxdeepin/dde-daemon/loader" - "github.com/linuxdeepin/go-lib/log" -) - -type module struct { - *loader.ModuleBase -} - -func (m *module) GetDependencies() []string { - return nil -} - -func (m *module) Start() error { - logger.Debug("module display start") - service := loader.GetService() - - d := newDisplay(service) - - so, err := service.NewServerObject(dbusPath, d) - if err != nil { - return err - } - - err = so.SetWriteCallback(d, "AutoBacklightEnabled", d.autoBacklightEnabledWriteCb) - if err != nil { - return err - } - err = so.Export() - if err != nil { - return err - } - err = service.RequestName(dbusServiceName) - if err != nil { - return err - } - - return nil -} - -func (m *module) Stop() error { - return nil -} - -func newDisplayModule(logger *log.Logger) *module { - m := new(module) - m.ModuleBase = loader.NewModuleBase("display", m, logger) - return m -} - -var logger = log.NewLogger("daemon/display") - -func init() { - loader.Register(newDisplayModule(logger)) -} diff --git a/system/display/display_test.go b/system/display1/display_test.go similarity index 98% rename from system/display/display_test.go rename to system/display1/display_test.go index 457838d7c..f45e4a6a0 100644 --- a/system/display/display_test.go +++ b/system/display1/display_test.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package display +package display1 import ( "os" diff --git a/system/display/displaycfg.go b/system/display1/displaycfg.go similarity index 98% rename from system/display/displaycfg.go rename to system/display1/displaycfg.go index 01a79b46c..eb606b111 100644 --- a/system/display/displaycfg.go +++ b/system/display1/displaycfg.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package display +package display1 import ( "bufio" @@ -17,7 +17,7 @@ import ( "strings" "sync" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-daemon/common/cpuinfo" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/log" @@ -25,9 +25,9 @@ import ( ) const ( - dbusServiceName = "com.deepin.system.Display" + dbusServiceName = "org.deepin.dde.Display1" dbusInterfaceName = dbusServiceName - dbusPath = "/com/deepin/system/Display" + dbusPath = "/org/deepin/dde/Display1" configFilePath = "/var/lib/dde-daemon/display/config.json" rendererConfigPath = "/var/lib/dde-daemon/display/rendererConfig.json" supportLabcFilePath = "/sys/firmware/devicetree/base/sensors_cfg/support_labc" diff --git a/system/display1/exported_methods_auto.go b/system/display1/exported_methods_auto.go new file mode 100644 index 000000000..97d6f4276 --- /dev/null +++ b/system/display1/exported_methods_auto.go @@ -0,0 +1,32 @@ +// Code generated by "dbusutil-gen em -type Display"; DO NOT EDIT. + +package display1 + +import ( + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (v *Display) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "GetConfig", + Fn: v.GetConfig, + OutArgs: []string{"cfgStr"}, + }, + { + Name: "SetBacklightBrightness", + Fn: v.SetBacklightBrightness, + InArgs: []string{"val"}, + }, + { + Name: "SetConfig", + Fn: v.SetConfig, + InArgs: []string{"cfgStr"}, + }, + { + Name: "SupportWayland", + Fn: v.SupportWayland, + OutArgs: []string{"outArg0"}, + }, + } +} diff --git a/system/display1/module.go b/system/display1/module.go new file mode 100644 index 000000000..b17194657 --- /dev/null +++ b/system/display1/module.go @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package display1 + +import ( + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" +) + +type module struct { + *loader.ModuleBase +} + +func (m *module) GetDependencies() []string { + return nil +} + +func (m *module) Start() error { + logger.Debug("module display start") + service := loader.GetService() + + d := newDisplay(service) + + so, err := service.NewServerObject(dbusPath, d) + if err != nil { + return err + } + + err = so.SetWriteCallback(d, "AutoBacklightEnabled", d.autoBacklightEnabledWriteCb) + if err != nil { + return err + } + err = so.Export() + if err != nil { + return err + } + err = service.RequestName(dbusServiceName) + if err != nil { + return err + } + + return nil +} + +func (m *module) Stop() error { + return nil +} + +func newDisplayModule(logger *log.Logger) *module { + m := new(module) + m.ModuleBase = loader.NewModuleBase("display", m, logger) + return m +} + +var logger = log.NewLogger("daemon/display") + +func init() { + loader.Register(newDisplayModule(logger)) +} diff --git a/system/gesture/config.go b/system/gesture/config.go deleted file mode 100644 index d4aebaac7..000000000 --- a/system/gesture/config.go +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package gesture - -import ( - "encoding/json" - "io/ioutil" - - "github.com/linuxdeepin/go-lib/utils" -) - -type Config struct { - LongPressDistance float64 `json:"longpress_distance"` - Verbose int `json:"verbose"` -} - -func loadConfig(filename string) (*Config, error) { - contents, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - var conf Config - err = json.Unmarshal(contents, &conf) - if err != nil { - return nil, err - } - return &conf, nil -} - -func getConfigPath() string { - suffix := "dde-daemon/gesture/conf.json" - filename := "/etc/" + suffix - if utils.IsFileExist(filename) { - return filename - } - return "/usr/share/" + suffix -} diff --git a/system/gesture/config_test.go b/system/gesture/config_test.go deleted file mode 100644 index 3c92bc239..000000000 --- a/system/gesture/config_test.go +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package gesture - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -var ( - configPath = "testdata/conf" -) - -func Test_loadConfig(t *testing.T) { - config, err := loadConfig(configPath) - assert.NoError(t, err) - - assert.Equal(t, config.LongPressDistance, float64(1)) - assert.Equal(t, config.Verbose, 0) -} diff --git a/system/gesture/exported_methods_auto.go b/system/gesture/exported_methods_auto.go deleted file mode 100644 index 2a1c69a71..000000000 --- a/system/gesture/exported_methods_auto.go +++ /dev/null @@ -1,27 +0,0 @@ -// Code generated by "./dbusutil-gen em -type Manager"; DO NOT EDIT. - -package gesture - -import ( - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (v *Manager) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "SetEdgeMoveStopDuration", - Fn: v.SetEdgeMoveStopDuration, - InArgs: []string{"duration"}, - }, - { - Name: "SetInputIgnore", - Fn: v.SetInputIgnore, - InArgs: []string{"node", "isIgnore"}, - }, - { - Name: "SetShortPressDuration", - Fn: v.SetShortPressDuration, - InArgs: []string{"duration"}, - }, - } -} diff --git a/system/gesture1/config.go b/system/gesture1/config.go new file mode 100644 index 000000000..36df01322 --- /dev/null +++ b/system/gesture1/config.go @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package gesture1 + +import ( + "encoding/json" + "io/ioutil" + + "github.com/linuxdeepin/go-lib/utils" +) + +type Config struct { + LongPressDistance float64 `json:"longpress_distance"` + Verbose int `json:"verbose"` +} + +func loadConfig(filename string) (*Config, error) { + contents, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + var conf Config + err = json.Unmarshal(contents, &conf) + if err != nil { + return nil, err + } + return &conf, nil +} + +func getConfigPath() string { + suffix := "dde-daemon/gesture/conf.json" + filename := "/etc/" + suffix + if utils.IsFileExist(filename) { + return filename + } + return "/usr/share/" + suffix +} diff --git a/system/gesture1/config_test.go b/system/gesture1/config_test.go new file mode 100644 index 000000000..280bb4d71 --- /dev/null +++ b/system/gesture1/config_test.go @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package gesture1 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +var ( + configPath = "testdata/conf" +) + +func Test_loadConfig(t *testing.T) { + config, err := loadConfig(configPath) + assert.NoError(t, err) + + assert.Equal(t, config.LongPressDistance, float64(1)) + assert.Equal(t, config.Verbose, 0) +} diff --git a/system/gesture/core.c b/system/gesture1/core.c similarity index 100% rename from system/gesture/core.c rename to system/gesture1/core.c diff --git a/system/gesture/core.h b/system/gesture1/core.h similarity index 100% rename from system/gesture/core.h rename to system/gesture1/core.h diff --git a/system/gesture1/exported_methods_auto.go b/system/gesture1/exported_methods_auto.go new file mode 100644 index 000000000..fd02b8e96 --- /dev/null +++ b/system/gesture1/exported_methods_auto.go @@ -0,0 +1,27 @@ +// Code generated by "./dbusutil-gen em -type Manager"; DO NOT EDIT. + +package gesture1 + +import ( + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (v *Manager) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "SetEdgeMoveStopDuration", + Fn: v.SetEdgeMoveStopDuration, + InArgs: []string{"duration"}, + }, + { + Name: "SetInputIgnore", + Fn: v.SetInputIgnore, + InArgs: []string{"node", "isIgnore"}, + }, + { + Name: "SetShortPressDuration", + Fn: v.SetShortPressDuration, + InArgs: []string{"duration"}, + }, + } +} diff --git a/system/gesture/gesture.go b/system/gesture1/gesture.go similarity index 97% rename from system/gesture/gesture.go rename to system/gesture1/gesture.go index e66402337..a6a0ab79c 100644 --- a/system/gesture/gesture.go +++ b/system/gesture1/gesture.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package gesture +package gesture1 // #cgo pkg-config: libinput glib-2.0 // #cgo CFLAGS: -W -Wall -fstack-protector-all -fPIC @@ -12,7 +12,7 @@ package gesture import "C" import ( - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-daemon/loader" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/log" @@ -21,9 +21,9 @@ import ( //go:generate dbusutil-gen em -type Manager const ( - dbusServiceName = "com.deepin.daemon.Gesture" - dbusPath = "/com/deepin/daemon/Gesture" - dbusInterface = "com.deepin.daemon.Gesture" + dbusServiceName = "org.deepin.dde.Gesture1" + dbusPath = "/org/deepin/dde/Gesture1" + dbusInterface = dbusServiceName ) type GestureType int32 @@ -231,13 +231,13 @@ func (*Manager) GetInterfaceName() string { return dbusInterface } -//duration unit ms +// duration unit ms func (*Manager) SetShortPressDuration(duration int) *dbus.Error { C.set_timer_short_duration(C.int(duration)) return nil } -//duration unit ms +// duration unit ms func (*Manager) SetEdgeMoveStopDuration(duration int) *dbus.Error { C.set_edge_move_stop_time(C.int(duration)) return nil @@ -248,7 +248,8 @@ func (*Manager) SetInputIgnore(node string, isIgnore bool) *dbus.Error { return nil } -//touchpad gesture +// touchpad gesture +// //export handleGestureEvent func handleGestureEvent(ty, direction, fingers C.int) { err := _m.service.Emit(_m, "Event", GestureType(ty).String(), @@ -284,7 +285,8 @@ func handleSwipeStop(fingers C.int) { } } -//touchscreen gesture +// touchscreen gesture +// //export handleTouchEvent func handleTouchEvent(ty, btn C.int) { err := _m.service.Emit(_m, "Event", TouchType(ty).String(), diff --git a/system/gesture/gesture_test.go b/system/gesture1/gesture_test.go similarity index 99% rename from system/gesture/gesture_test.go rename to system/gesture1/gesture_test.go index fd0b21d65..e7b0581af 100644 --- a/system/gesture/gesture_test.go +++ b/system/gesture1/gesture_test.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package gesture +package gesture1 import ( "testing" @@ -178,4 +178,4 @@ func Test_String_TouchDirection(t *testing.T) { g = TouchDirection(UNKNOWN) rtn = g.String() assert.Equal(t, m1[UNKNOWN], rtn) -} \ No newline at end of file +} diff --git a/system/gesture/testdata/conf b/system/gesture1/testdata/conf similarity index 100% rename from system/gesture/testdata/conf rename to system/gesture1/testdata/conf diff --git a/system/gesture/touchscreen_core.c b/system/gesture1/touchscreen_core.c similarity index 96% rename from system/gesture/touchscreen_core.c rename to system/gesture1/touchscreen_core.c index e4d7b6708..f4a7e20ef 100644 --- a/system/gesture/touchscreen_core.c +++ b/system/gesture1/touchscreen_core.c @@ -1,481 +1,481 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include -#include -#include -#include -#include - -#define LIBINPUT_TOUCHSCREEN_H -#define LOGGING false -#ifndef M_PI - #define M_PI 3.14159265358979323846 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "utils.h" -#include "touchscreen_core.h" -#include "_cgo_export.h" - -#if LOGGING -void logger(const char *format, ...) { - va_list argptr; - va_start(argptr, format); - vfprintf(stderr, format, argptr); - va_end(argptr); -} -#else -void logger(const char *format, ...) { -}; -#endif - -int get_edge_type() { - return (int)GT_EDGE; -} - -int get_movement_type() { - return (int)GT_MOVEMENT; -} - -//set move stop time when it's edge event -void -set_edge_move_stop_time(int duration) -{ - logger("[Duration set_edge_move_stop_time ] set: %d --> %d", edge_move_stop_time, duration); - if (duration == edge_move_stop_time) { - return ; - } - edge_move_stop_time = duration; -} - -// udpate touchscreen first touch point info -void update_first_point_relative_coordinate(double x, double y) { - start_point_scale.x = x / screen.width; - start_point_scale.y = y / screen.height; -} - -//update touchscreen last touch point info -void update_last_point_relative_coordinate(double x, double y) { - last_point.x = x; - last_point.y = y; - - last_point_scale.x = last_point.x / screen.width; - last_point_scale.y = last_point.y / screen.height; -} - -point get_last_point() { - return last_point; -} - -point get_last_point_scale() { - return last_point_scale; -} - -/////////////////////////////////list: hold touchscreen fingers info -typedef struct node { - void *value; - size_t size; - struct node *next; -} node; - -typedef struct list { - node *head; - node *tail; -} list; - - -void list_destroy(list *list) { - node *cur = list->head; - node *temp; - while (cur != NULL) { - temp = cur; - cur = cur->next; - free(temp->value); - free(temp); - } - free(list); -} - -list *list_new(const void *first_val, size_t size) { - list *l = calloc(1, sizeof *l); - l->head = calloc(1, sizeof(node)); - l->tail = l->head; - // copy arbitrary value into the location - l->head->value = malloc(size); - l->head->size = size; - memcpy(l->head->value, first_val, size); - return l; -} - -list *list_append(list *l, const void *newval, size_t size) { - l->tail->next = calloc(1, sizeof(node)); - l->tail = l->tail->next; - l->tail->value = malloc(size); - l->tail->size = size; - memcpy(l->tail->value, newval, size); - return l; -} - -size_t list_len(list *l) { - node *cur = l->head; - size_t len = 0; - while (cur != NULL) { - cur = cur->next; - len++; - } - return len; -} - - -//////////////////////////////////calculate -//distance between point a and point b -double distance_euclidian(point a, point b) { - return sqrt(pow((a.x - b.x), 2.0) + pow((a.y - b.y), 2.0)); -} - -point vec_sub(point a, point b) { - point r; - r.x = a.x - b.x; - r.y = a.y - b.y; - return r; -} - -//length from point a to origin -double line_len(point a) { - return sqrt(pow(a.x, 2.0) + pow(a.y, 2.0)); -} - -double scalar_product(point a, point b) { - return a.x * b.x + a.y * b.y; -} - -//angle between two line -//line one is pass through point a and origin -//line two is pass throught point b and origin -double lines_angle(point a, point b) { - return acos(scalar_product(a, b) / (line_len(a) * line_len(b))); -} - -//angle of fingers moving on touchscreen -double movement_angle(const movement *m) { - point diff = vec_sub(m->end, m->start); - point base = (point){1, 0}; - - if (diff.x == 0 && diff.y == 0) { - return NAN; - } - - double angle = lines_angle(diff, base); - // ref 0 0 is UPPER left corner - if (diff.y > 0) { - angle = 2 * M_PI - angle; - } - return angle; -} - -double movement_length(const movement *m) { - return distance_euclidian(m->end, m->start); -} - -// convert an angle in radians into direction enum -enum Direction angle_to_direction(double angle) { - double m_pi4 = M_PI / 4; - if (isnan(angle)) { - return DIR_NONE; - } - if ((3 * m_pi4 >= angle) && (angle > m_pi4)) { - return DIR_TOP; - } - if ((5 * m_pi4 >= angle) && (angle > 3 * m_pi4)) { - return DIR_LEFT; - } - if ((7 * m_pi4 >= angle) && (angle > 5 * m_pi4)) { - return DIR_BOT; - } - return DIR_RIGHT; -} - - -int cur_touch_finger_num(movement *m) { - int num = 0; - for (size_t i = 0; i < MOV_SLOTS; i++){ - if (m[i].down) { - num++; - } - } - return num; -} - -//valid touch distance when fingers stop on screen -int valid_move_stop_touch(double x, double y) { - double dx = x - moveStop.x; - double dy = y - moveStop.y; - return fabs(dx) < move_stop_distance && fabs(dy) < move_stop_distance; -} - -//valid stop time(ms) -int valid_move_stop_time(uint32_t duration) { - return duration > edge_move_stop_time; -} - -void init_move_stop(movement m) { - moveStop.x = m.start.x; - moveStop.y = m.start.y; - moveStop.start = m.t_start; - edge_move_stop_direction = DIR_NONE; -} - -void update_move_stop(movement m) { - if (!valid_move_stop_touch(m.end.x, m.end.y)) { - moveStop.x = m.end.x; - moveStop.y = m.end.y; - moveStop.start = m.t_end; - edge_move_stop_direction = DIR_NONE; - } -} - -void check_move_stop_time(movement m) { - if (edge_move_stop_direction != DIR_NONE) { - uint32_t duration = (m.t_end - moveStop.start) / 1000; - if (valid_move_stop_time(duration)) - handleTouchEdgeMoveStop(edge_move_stop_direction, moveStop.x / screen.width, moveStop.y / screen.height, duration); - } -} - -void check_move_stop_leave(movement m) { - if (edge_move_stop_direction != DIR_NONE) { - uint32_t duration = (m.t_end - moveStop.start) / 1000; - if (valid_move_stop_time(duration)) - handleTouchEdgeMoveStopLeave(edge_move_stop_direction, moveStop.x / screen.width, moveStop.y / screen.height, duration); - } -} - -//discern direction -enum Direction discern_direction(point start) { - if (start.x <= edge_error_limit) { - return DIR_LEFT; - } - if (start.x >= screen.width - edge_error_limit) { - return DIR_RIGHT; - } - if (start.y <= edge_error_limit) { - return DIR_TOP; - } - if (start.y >= screen.height - edge_error_limit) { - return DIR_BOT; - } - return DIR_NONE; -} - -enum Direction edge_stop_move_direction(movement *m) { - for (size_t i=0; i= min_edge_distance)) { - return discern_direction(m[i].start); - } - } - return DIR_NONE; -} - -//handle touchscreen down event -void handle_touch_event_down(struct libinput_event *event, struct movement *m) { - get_screen_info(event); - struct libinput_event_touch *tevent = libinput_event_get_touch_event(event); - int32_t slot = libinput_event_touch_get_slot(tevent); - m[slot].start.x = libinput_event_touch_get_x_transformed(tevent, screen.width); - m[slot].start.y = libinput_event_touch_get_y_transformed(tevent, screen.height); - m[slot].t_start = libinput_event_touch_get_time_usec(tevent); - m[slot].end.x = m[slot].start.x; - m[slot].end.y = m[slot].start.y; - m[slot].t_end = m[slot].t_start; - m[slot].down = true; - - update_first_point_relative_coordinate(m[slot].start.x, m[slot].start.y); - update_last_point_relative_coordinate(m[slot].end.x, m[slot].end.y); - - if (cur_touch_finger_num(m) == 1) - init_move_stop(m[slot]); //only support one finger -} - -//handle touchscreen up event -void handle_touch_event_up(struct libinput_event *event, struct movement *m) { - struct libinput_event_touch *tevent = libinput_event_get_touch_event(event); - int32_t slot = libinput_event_touch_get_slot(tevent); - m[slot].t_end = libinput_event_touch_get_time_usec(tevent); - m[slot].ready = true; - - if (cur_touch_finger_num(m) == 1) - check_move_stop_leave(m[slot]); - m[slot].down = false; -} - -//handle touchscreen cancel event -void handle_touch_event_cancel(struct libinput_event *event, struct movement *m) { - struct libinput_event_touch *tevent = libinput_event_get_touch_event(event); - int32_t slot = libinput_event_touch_get_slot(tevent); - m[slot].t_end = libinput_event_touch_get_time_usec(tevent); - m[slot].ready = false; - - if (cur_touch_finger_num(m) == 1) - check_move_stop_leave(m[slot]); - - m[slot].down = false; -} - -//handle touchscreen motion event -void handle_touch_event_motion(struct libinput_event *event, struct movement *m) { - struct libinput_event_touch *tevent = libinput_event_get_touch_event(event); - int32_t slot = libinput_event_touch_get_slot(tevent); - m[slot].end.x = libinput_event_touch_get_x_transformed(tevent, screen.width); - m[slot].end.y = libinput_event_touch_get_y_transformed(tevent, screen.height); - m[slot].t_end = libinput_event_touch_get_time_usec(tevent); - - update_last_point_relative_coordinate(m[slot].end.x, m[slot].end.y); - //check if borde move - edge_move_stop_direction = edge_stop_move_direction(m); //edge moving direction - - if (cur_touch_finger_num(m) == 1) { - update_move_stop(m[slot]); - - check_move_stop_time(m[slot]); - handleTouchMoving(m[slot].end.x / screen.width, m[slot].end.y / screen.height); - } -} - -// Get all movement slots that are currently ready -list *get_ready_movements(struct movement *m) { - list *ready = NULL; - for (size_t i = 0; i < MOV_SLOTS; i++) { - if (m[i].ready) { - if (ready == NULL) { - ready = list_new(&i, sizeof(i)); - } else { - list_append(ready, &i, sizeof(i)); - } - m[i].ready = false; - } - } - return ready; -} - -bool any_down(struct movement *m) { - for (size_t i = 0; i < MOV_SLOTS; i++){ - if (m[i].down) { - return true; - } - } - return false; -} - -////////////////////////////////////////////core -void print_gesture(gesture *g) { - printf("G(%d) T%d D%d\n", g->num, g->type, g->dir); -} - -int argmax(const size_t *arr, size_t len) { - size_t highest = 0; - int index = 0; - for (size_t i = 0; i < len; i++) { - if (arr[i] > highest) { - highest = arr[i]; - index = i; - } else if (arr[i] == highest) { - index = -1; - } - } - return index; -} - -//move direction -enum Direction movement_direction(movement *m, list *ready) { - enum Direction dir = 0; - size_t enum_votes[5] = {0}, i = 0; - // collect individually transformed directions - node *cur = ready->head; - while (cur != NULL) { - i = *((size_t *)cur->value); - enum_votes[angle_to_direction(movement_angle(m + i))]++; - cur = cur->next; - } - // check if multiple directions had the same maximum vote - if ((dir = argmax(enum_votes, 5)) < 0) { - dir = DIR_NONE; - } - return dir; -} - -//edge event move side -enum Direction edge_move_direction(movement *m, list *ready) { - movement *cm; - point start; - node *cur = ready->head; - while (cur != NULL) { - cm = (m + *((size_t *)cur->value)); - start = cm->start; - if (movement_length(cm) >= min_edge_distance) { - return discern_direction(start); - } - cur = cur->next; - } - return DIR_NONE; -} - -//get touchscreeen gesture info -gesture get_gesture(movement *m, list *ready) { - gesture g = {0}; - g.num = list_len(ready); - g.dir = movement_direction(m, ready); - enum Direction edge_dir; - if (g.dir == DIR_NONE) { - g.type = GT_TAP; - } else if (g.num > 1) { - g.type = GT_MOVEMENT; - } else if (g.num == 1) { - edge_dir = edge_move_direction(m, ready); - if (edge_dir != DIR_NONE) { - g.type = GT_EDGE; - g.dir = edge_dir; - } else { - g.type = GT_MOVEMENT; - } - } - return g; -} - -//handle touchscreen gestrue event -void handle_movements(movement *m) { - //TODO skip if some fingers are still on the screen - int distance = 0; - list *ready = get_ready_movements(m); - if (ready == NULL) { - return; - } - logger("Handle movements: begin\n"); - gesture g = get_gesture(m, ready); - logger("Handle movements: got gesture\n"); - print_gesture(&g); - - handleTouchScreenEvent((int)g.type, (int)g.dir, g.num, start_point_scale.x, start_point_scale.y, last_point_scale.x, last_point_scale.y); - - list_destroy(ready); - logger("Handle movements: end\n"); -} - -//get the physical size of a device in mm -void get_screen_info(struct libinput_event *event) { - struct libinput_device *dev = libinput_event_get_device(event); - double w, h; - libinput_device_get_size(dev, &w, &h); - screen.width = w; - screen.height = h; -} +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include +#include +#include +#include + +#define LIBINPUT_TOUCHSCREEN_H +#define LOGGING false +#ifndef M_PI + #define M_PI 3.14159265358979323846 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "touchscreen_core.h" +#include "_cgo_export.h" + +#if LOGGING +void logger(const char *format, ...) { + va_list argptr; + va_start(argptr, format); + vfprintf(stderr, format, argptr); + va_end(argptr); +} +#else +void logger(const char *format, ...) { +}; +#endif + +int get_edge_type() { + return (int)GT_EDGE; +} + +int get_movement_type() { + return (int)GT_MOVEMENT; +} + +//set move stop time when it's edge event +void +set_edge_move_stop_time(int duration) +{ + logger("[Duration set_edge_move_stop_time ] set: %d --> %d", edge_move_stop_time, duration); + if (duration == edge_move_stop_time) { + return ; + } + edge_move_stop_time = duration; +} + +// udpate touchscreen first touch point info +void update_first_point_relative_coordinate(double x, double y) { + start_point_scale.x = x / screen.width; + start_point_scale.y = y / screen.height; +} + +//update touchscreen last touch point info +void update_last_point_relative_coordinate(double x, double y) { + last_point.x = x; + last_point.y = y; + + last_point_scale.x = last_point.x / screen.width; + last_point_scale.y = last_point.y / screen.height; +} + +point get_last_point() { + return last_point; +} + +point get_last_point_scale() { + return last_point_scale; +} + +/////////////////////////////////list: hold touchscreen fingers info +typedef struct node { + void *value; + size_t size; + struct node *next; +} node; + +typedef struct list { + node *head; + node *tail; +} list; + + +void list_destroy(list *list) { + node *cur = list->head; + node *temp; + while (cur != NULL) { + temp = cur; + cur = cur->next; + free(temp->value); + free(temp); + } + free(list); +} + +list *list_new(const void *first_val, size_t size) { + list *l = calloc(1, sizeof *l); + l->head = calloc(1, sizeof(node)); + l->tail = l->head; + // copy arbitrary value into the location + l->head->value = malloc(size); + l->head->size = size; + memcpy(l->head->value, first_val, size); + return l; +} + +list *list_append(list *l, const void *newval, size_t size) { + l->tail->next = calloc(1, sizeof(node)); + l->tail = l->tail->next; + l->tail->value = malloc(size); + l->tail->size = size; + memcpy(l->tail->value, newval, size); + return l; +} + +size_t list_len(list *l) { + node *cur = l->head; + size_t len = 0; + while (cur != NULL) { + cur = cur->next; + len++; + } + return len; +} + + +//////////////////////////////////calculate +//distance between point a and point b +double distance_euclidian(point a, point b) { + return sqrt(pow((a.x - b.x), 2.0) + pow((a.y - b.y), 2.0)); +} + +point vec_sub(point a, point b) { + point r; + r.x = a.x - b.x; + r.y = a.y - b.y; + return r; +} + +//length from point a to origin +double line_len(point a) { + return sqrt(pow(a.x, 2.0) + pow(a.y, 2.0)); +} + +double scalar_product(point a, point b) { + return a.x * b.x + a.y * b.y; +} + +//angle between two line +//line one is pass through point a and origin +//line two is pass throught point b and origin +double lines_angle(point a, point b) { + return acos(scalar_product(a, b) / (line_len(a) * line_len(b))); +} + +//angle of fingers moving on touchscreen +double movement_angle(const movement *m) { + point diff = vec_sub(m->end, m->start); + point base = (point){1, 0}; + + if (diff.x == 0 && diff.y == 0) { + return NAN; + } + + double angle = lines_angle(diff, base); + // ref 0 0 is UPPER left corner + if (diff.y > 0) { + angle = 2 * M_PI - angle; + } + return angle; +} + +double movement_length(const movement *m) { + return distance_euclidian(m->end, m->start); +} + +// convert an angle in radians into direction enum +enum Direction angle_to_direction(double angle) { + double m_pi4 = M_PI / 4; + if (isnan(angle)) { + return DIR_NONE; + } + if ((3 * m_pi4 >= angle) && (angle > m_pi4)) { + return DIR_TOP; + } + if ((5 * m_pi4 >= angle) && (angle > 3 * m_pi4)) { + return DIR_LEFT; + } + if ((7 * m_pi4 >= angle) && (angle > 5 * m_pi4)) { + return DIR_BOT; + } + return DIR_RIGHT; +} + + +int cur_touch_finger_num(movement *m) { + int num = 0; + for (size_t i = 0; i < MOV_SLOTS; i++){ + if (m[i].down) { + num++; + } + } + return num; +} + +//valid touch distance when fingers stop on screen +int valid_move_stop_touch(double x, double y) { + double dx = x - moveStop.x; + double dy = y - moveStop.y; + return fabs(dx) < move_stop_distance && fabs(dy) < move_stop_distance; +} + +//valid stop time(ms) +int valid_move_stop_time(uint32_t duration) { + return duration > edge_move_stop_time; +} + +void init_move_stop(movement m) { + moveStop.x = m.start.x; + moveStop.y = m.start.y; + moveStop.start = m.t_start; + edge_move_stop_direction = DIR_NONE; +} + +void update_move_stop(movement m) { + if (!valid_move_stop_touch(m.end.x, m.end.y)) { + moveStop.x = m.end.x; + moveStop.y = m.end.y; + moveStop.start = m.t_end; + edge_move_stop_direction = DIR_NONE; + } +} + +void check_move_stop_time(movement m) { + if (edge_move_stop_direction != DIR_NONE) { + uint32_t duration = (m.t_end - moveStop.start) / 1000; + if (valid_move_stop_time(duration)) + handleTouchEdgeMoveStop(edge_move_stop_direction, moveStop.x / screen.width, moveStop.y / screen.height, duration); + } +} + +void check_move_stop_leave(movement m) { + if (edge_move_stop_direction != DIR_NONE) { + uint32_t duration = (m.t_end - moveStop.start) / 1000; + if (valid_move_stop_time(duration)) + handleTouchEdgeMoveStopLeave(edge_move_stop_direction, moveStop.x / screen.width, moveStop.y / screen.height, duration); + } +} + +//discern direction +enum Direction discern_direction(point start) { + if (start.x <= edge_error_limit) { + return DIR_LEFT; + } + if (start.x >= screen.width - edge_error_limit) { + return DIR_RIGHT; + } + if (start.y <= edge_error_limit) { + return DIR_TOP; + } + if (start.y >= screen.height - edge_error_limit) { + return DIR_BOT; + } + return DIR_NONE; +} + +enum Direction edge_stop_move_direction(movement *m) { + for (size_t i=0; i= min_edge_distance)) { + return discern_direction(m[i].start); + } + } + return DIR_NONE; +} + +//handle touchscreen down event +void handle_touch_event_down(struct libinput_event *event, struct movement *m) { + get_screen_info(event); + struct libinput_event_touch *tevent = libinput_event_get_touch_event(event); + int32_t slot = libinput_event_touch_get_slot(tevent); + m[slot].start.x = libinput_event_touch_get_x_transformed(tevent, screen.width); + m[slot].start.y = libinput_event_touch_get_y_transformed(tevent, screen.height); + m[slot].t_start = libinput_event_touch_get_time_usec(tevent); + m[slot].end.x = m[slot].start.x; + m[slot].end.y = m[slot].start.y; + m[slot].t_end = m[slot].t_start; + m[slot].down = true; + + update_first_point_relative_coordinate(m[slot].start.x, m[slot].start.y); + update_last_point_relative_coordinate(m[slot].end.x, m[slot].end.y); + + if (cur_touch_finger_num(m) == 1) + init_move_stop(m[slot]); //only support one finger +} + +//handle touchscreen up event +void handle_touch_event_up(struct libinput_event *event, struct movement *m) { + struct libinput_event_touch *tevent = libinput_event_get_touch_event(event); + int32_t slot = libinput_event_touch_get_slot(tevent); + m[slot].t_end = libinput_event_touch_get_time_usec(tevent); + m[slot].ready = true; + + if (cur_touch_finger_num(m) == 1) + check_move_stop_leave(m[slot]); + m[slot].down = false; +} + +//handle touchscreen cancel event +void handle_touch_event_cancel(struct libinput_event *event, struct movement *m) { + struct libinput_event_touch *tevent = libinput_event_get_touch_event(event); + int32_t slot = libinput_event_touch_get_slot(tevent); + m[slot].t_end = libinput_event_touch_get_time_usec(tevent); + m[slot].ready = false; + + if (cur_touch_finger_num(m) == 1) + check_move_stop_leave(m[slot]); + + m[slot].down = false; +} + +//handle touchscreen motion event +void handle_touch_event_motion(struct libinput_event *event, struct movement *m) { + struct libinput_event_touch *tevent = libinput_event_get_touch_event(event); + int32_t slot = libinput_event_touch_get_slot(tevent); + m[slot].end.x = libinput_event_touch_get_x_transformed(tevent, screen.width); + m[slot].end.y = libinput_event_touch_get_y_transformed(tevent, screen.height); + m[slot].t_end = libinput_event_touch_get_time_usec(tevent); + + update_last_point_relative_coordinate(m[slot].end.x, m[slot].end.y); + //check if borde move + edge_move_stop_direction = edge_stop_move_direction(m); //edge moving direction + + if (cur_touch_finger_num(m) == 1) { + update_move_stop(m[slot]); + + check_move_stop_time(m[slot]); + handleTouchMoving(m[slot].end.x / screen.width, m[slot].end.y / screen.height); + } +} + +// Get all movement slots that are currently ready +list *get_ready_movements(struct movement *m) { + list *ready = NULL; + for (size_t i = 0; i < MOV_SLOTS; i++) { + if (m[i].ready) { + if (ready == NULL) { + ready = list_new(&i, sizeof(i)); + } else { + list_append(ready, &i, sizeof(i)); + } + m[i].ready = false; + } + } + return ready; +} + +bool any_down(struct movement *m) { + for (size_t i = 0; i < MOV_SLOTS; i++){ + if (m[i].down) { + return true; + } + } + return false; +} + +////////////////////////////////////////////core +void print_gesture(gesture *g) { + printf("G(%d) T%d D%d\n", g->num, g->type, g->dir); +} + +int argmax(const size_t *arr, size_t len) { + size_t highest = 0; + int index = 0; + for (size_t i = 0; i < len; i++) { + if (arr[i] > highest) { + highest = arr[i]; + index = i; + } else if (arr[i] == highest) { + index = -1; + } + } + return index; +} + +//move direction +enum Direction movement_direction(movement *m, list *ready) { + enum Direction dir = 0; + size_t enum_votes[5] = {0}, i = 0; + // collect individually transformed directions + node *cur = ready->head; + while (cur != NULL) { + i = *((size_t *)cur->value); + enum_votes[angle_to_direction(movement_angle(m + i))]++; + cur = cur->next; + } + // check if multiple directions had the same maximum vote + if ((dir = argmax(enum_votes, 5)) < 0) { + dir = DIR_NONE; + } + return dir; +} + +//edge event move side +enum Direction edge_move_direction(movement *m, list *ready) { + movement *cm; + point start; + node *cur = ready->head; + while (cur != NULL) { + cm = (m + *((size_t *)cur->value)); + start = cm->start; + if (movement_length(cm) >= min_edge_distance) { + return discern_direction(start); + } + cur = cur->next; + } + return DIR_NONE; +} + +//get touchscreeen gesture info +gesture get_gesture(movement *m, list *ready) { + gesture g = {0}; + g.num = list_len(ready); + g.dir = movement_direction(m, ready); + enum Direction edge_dir; + if (g.dir == DIR_NONE) { + g.type = GT_TAP; + } else if (g.num > 1) { + g.type = GT_MOVEMENT; + } else if (g.num == 1) { + edge_dir = edge_move_direction(m, ready); + if (edge_dir != DIR_NONE) { + g.type = GT_EDGE; + g.dir = edge_dir; + } else { + g.type = GT_MOVEMENT; + } + } + return g; +} + +//handle touchscreen gestrue event +void handle_movements(movement *m) { + //TODO skip if some fingers are still on the screen + int distance = 0; + list *ready = get_ready_movements(m); + if (ready == NULL) { + return; + } + logger("Handle movements: begin\n"); + gesture g = get_gesture(m, ready); + logger("Handle movements: got gesture\n"); + print_gesture(&g); + + handleTouchScreenEvent((int)g.type, (int)g.dir, g.num, start_point_scale.x, start_point_scale.y, last_point_scale.x, last_point_scale.y); + + list_destroy(ready); + logger("Handle movements: end\n"); +} + +//get the physical size of a device in mm +void get_screen_info(struct libinput_event *event) { + struct libinput_device *dev = libinput_event_get_device(event); + double w, h; + libinput_device_get_size(dev, &w, &h); + screen.width = w; + screen.height = h; +} diff --git a/system/gesture/touchscreen_core.h b/system/gesture1/touchscreen_core.h similarity index 100% rename from system/gesture/touchscreen_core.h rename to system/gesture1/touchscreen_core.h diff --git a/system/gesture/utils.c b/system/gesture1/utils.c similarity index 100% rename from system/gesture/utils.c rename to system/gesture1/utils.c diff --git a/system/gesture/utils.h b/system/gesture1/utils.h similarity index 100% rename from system/gesture/utils.h rename to system/gesture1/utils.h diff --git a/system/hostname/hostname.go b/system/hostname/hostname.go index ba4195a15..59da69336 100644 --- a/system/hostname/hostname.go +++ b/system/hostname/hostname.go @@ -12,11 +12,11 @@ import ( "path/filepath" "strings" - hostname1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.hostname1" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" + "github.com/linuxdeepin/dde-daemon/loader" + hostname1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.hostname1" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/dde-daemon/loader" ) type Module struct { diff --git a/system/inputdevices/daemon.go b/system/inputdevices/daemon.go deleted file mode 100644 index c55d34fcc..000000000 --- a/system/inputdevices/daemon.go +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package inputdevices - -import ( - "github.com/linuxdeepin/dde-daemon/loader" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/log" -) - -var logger = log.NewLogger("daemon/system/inputdevices") - -const ( - dbusServiceName = "com.deepin.system.InputDevices" - dbusPath = "/com/deepin/system/InputDevices" - dbusInterface = "com.deepin.system.InputDevices" -) - -func init() { - loader.Register(newDaemon()) -} - -type daemon struct { - *loader.ModuleBase - inputdevices *InputDevices -} - -func newDaemon() *daemon { - d := new(daemon) - d.ModuleBase = loader.NewModuleBase("inputdevices", d, logger) - return d -} - -func (d *daemon) GetDependencies() []string { - return []string{} -} - -func (d *daemon) Start() error { - if d.inputdevices != nil { - return nil - } - - logger.Debug("start inputdevices") - d.inputdevices = newInputDevices() - - service := loader.GetService() - d.inputdevices.service = service - d.inputdevices.systemSigLoop = dbusutil.NewSignalLoop(service.Conn(), 5) - d.inputdevices.init() - - err := service.Export(dbusPath, d.inputdevices) - if err != nil { - logger.Warning(err) - return err - } - - err = service.RequestName(dbusServiceName) - if err != nil { - logger.Warning(err) - return err - } - - return nil -} - -func (d *daemon) Stop() error { - return nil -} diff --git a/system/inputdevices/exported_methods_auto.go b/system/inputdevices/exported_methods_auto.go deleted file mode 100644 index 6698af90d..000000000 --- a/system/inputdevices/exported_methods_auto.go +++ /dev/null @@ -1,26 +0,0 @@ -// Code generated by "dbusutil-gen em -type InputDevices,Touchpad"; DO NOT EDIT. - -package inputdevices - -import ( - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (v *InputDevices) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "SetWakeupDevices", - Fn: v.SetWakeupDevices, - InArgs: []string{"path", "value"}, - }, - } -} -func (v *Touchpad) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "SetTouchpadEnable", - Fn: v.SetTouchpadEnable, - InArgs: []string{"enabled"}, - }, - } -} diff --git a/system/inputdevices/touchpad.go b/system/inputdevices/touchpad.go deleted file mode 100644 index c48e8263d..000000000 --- a/system/inputdevices/touchpad.go +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package inputdevices - -import ( - "errors" - "io/ioutil" - "os" - "strings" - - "github.com/godbus/dbus" - configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" - "github.com/linuxdeepin/go-lib/dbusutil" -) - -const( - touchpadSwitchFile = "/proc/uos/touchpad_switch" - touchpadDBusPath = "/com/deepin/system/InputDevices/Touchpad" - touchpadDBusInterface = "com.deepin.system.InputDevices.Touchpad" -) - -type Touchpad struct { - service *dbusutil.Service - Enable bool - IsExist bool -} - -func newTouchpad(service *dbusutil.Service) *Touchpad { - t := &Touchpad { - service: service, - } - err := TouchpadExist(touchpadSwitchFile) - if err != nil { - logger.Warning(err) - t.setPropIsExist(false) - t.setPropEnable(false) - return t - } - t.setPropIsExist(true) - enable, err := TouchpadEnable(touchpadSwitchFile) - if err != nil { - logger.Warning(err) - } - t.setPropEnable(enable) - return t -} - -func (t *Touchpad) SetTouchpadEnable(enabled bool) *dbus.Error { - err := t.setTouchpadEnable(enabled) - return dbusutil.ToError(err) -} - -func (t *Touchpad) setTouchpadEnable(enabled bool) error { - if err := TouchpadExist(touchpadSwitchFile); err != nil { - logger.Warning(" TouchpadExist err : ", err) - return err - } - current, err := TouchpadEnable(touchpadSwitchFile) - if err != nil { - logger.Warning(" TouchpadEnable err : ", err) - return err - } - if current == enabled { - logger.Info("current touchPad state is same : ", enabled) - return nil - } - arg := "enable" - if !enabled { - arg = "disable" - } - err = ioutil.WriteFile(touchpadSwitchFile, []byte(arg), 0644) - if err != nil{ - logger.Warning(" ioutil.WriteFile err : ", err) - return err - } - t.setPropEnable(enabled) - err = setDsgConf(enabled) - if err != nil{ - logger.Warning(err) - return err - } - return nil -} - -func setDsgConf(enable bool) error { - sysBus, err := dbus.SystemBus() - if err != nil { - return err - } - ds := configManager.NewConfigManager(sysBus) - confPath, err := ds.AcquireManager(0, _dsettingsAppID, _dsettingsInputdevicesName, "") - if err != nil { - return err - } - dsManager, err := configManager.NewManager(sysBus, confPath) - if err != nil { - return err - } - err = dsManager.SetValue(0, _dsettingsTouchpadEnabledKey, dbus.MakeVariant(enable)) - if err != nil { - return err - } - return nil -} - -func TouchpadEnable(filePath string) (bool, error) { - err := TouchpadExist(filePath) - if err != nil { - return false, err - } - content, err := ioutil.ReadFile(touchpadSwitchFile) - if err != nil { - return false, err - } - return strings.Contains(string(content), "enable"), nil -} - -func TouchpadExist(filePath string) error { - if filePath != touchpadSwitchFile { - return errors.New("filePath is inValid") - } - _, err := os.Stat(touchpadSwitchFile) - if err != nil { - logger.Warning(err) - return err - } - return nil -} - -func (t *Touchpad) GetInterfaceName() string { - return touchpadDBusInterface -} - -func (t *Touchpad) export(path dbus.ObjectPath) error { - return t.service.Export(path, t) -} - -func (t *Touchpad) stopExport() error { - return t.service.StopExport(t) -} \ No newline at end of file diff --git a/system/inputdevices1/daemon.go b/system/inputdevices1/daemon.go new file mode 100644 index 000000000..364e4f47f --- /dev/null +++ b/system/inputdevices1/daemon.go @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package inputdevices1 + +import ( + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/log" +) + +var logger = log.NewLogger("daemon/system/inputdevices") + +const ( + dbusServiceName = "org.deepin.dde.InputDevices1" + dbusPath = "/org/deepin/dde/InputDevices1" + dbusInterface = dbusServiceName +) + +func init() { + loader.Register(newDaemon()) +} + +type daemon struct { + *loader.ModuleBase + inputdevices *InputDevices +} + +func newDaemon() *daemon { + d := new(daemon) + d.ModuleBase = loader.NewModuleBase("inputdevices", d, logger) + return d +} + +func (d *daemon) GetDependencies() []string { + return []string{} +} + +func (d *daemon) Start() error { + if d.inputdevices != nil { + return nil + } + + logger.Debug("start inputdevices") + d.inputdevices = newInputDevices() + + service := loader.GetService() + d.inputdevices.service = service + d.inputdevices.systemSigLoop = dbusutil.NewSignalLoop(service.Conn(), 5) + d.inputdevices.init() + + err := service.Export(dbusPath, d.inputdevices) + if err != nil { + logger.Warning(err) + return err + } + + err = service.RequestName(dbusServiceName) + if err != nil { + logger.Warning(err) + return err + } + + return nil +} + +func (d *daemon) Stop() error { + return nil +} diff --git a/system/inputdevices/dde-libinput.c b/system/inputdevices1/dde-libinput.c similarity index 100% rename from system/inputdevices/dde-libinput.c rename to system/inputdevices1/dde-libinput.c diff --git a/system/inputdevices/dde-libinput.h b/system/inputdevices1/dde-libinput.h similarity index 100% rename from system/inputdevices/dde-libinput.h rename to system/inputdevices1/dde-libinput.h diff --git a/system/inputdevices1/exported_methods_auto.go b/system/inputdevices1/exported_methods_auto.go new file mode 100644 index 000000000..92f9c92bd --- /dev/null +++ b/system/inputdevices1/exported_methods_auto.go @@ -0,0 +1,26 @@ +// Code generated by "dbusutil-gen em -type InputDevices,Touchpad"; DO NOT EDIT. + +package inputdevices1 + +import ( + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (v *InputDevices) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "SetWakeupDevices", + Fn: v.SetWakeupDevices, + InArgs: []string{"path", "value"}, + }, + } +} +func (v *Touchpad) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "SetTouchpadEnable", + Fn: v.SetTouchpadEnable, + InArgs: []string{"enabled"}, + }, + } +} diff --git a/system/inputdevices/inputdevices.go b/system/inputdevices1/inputdevices.go similarity index 95% rename from system/inputdevices/inputdevices.go rename to system/inputdevices1/inputdevices.go index de0a388a3..38bf3e439 100644 --- a/system/inputdevices/inputdevices.go +++ b/system/inputdevices1/inputdevices.go @@ -2,9 +2,10 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package inputdevices +package inputdevices1 import ( + "errors" "fmt" "io/ioutil" "os/exec" @@ -13,7 +14,7 @@ import ( "strings" "sync" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" "github.com/linuxdeepin/go-lib/dbusutil" dutils "github.com/linuxdeepin/go-lib/utils" @@ -86,6 +87,9 @@ func (m *InputDevices) init() { m.updateSupportWakeupDevices() if err := TouchpadExist(touchpadSwitchFile); err == nil { m.newTouchpad() + if m.dsgInputDevices == nil { + return + } v, err := m.dsgInputDevices.Value(0, _dsettingsTouchpadEnabledKey) if err != nil { logger.Warning(err) @@ -99,7 +103,7 @@ func (m *InputDevices) init() { }() } -//Note:由于数组默认长度为0,后面append时,需要重新申请内存和拷贝,所以效率较低 +// Note:由于数组默认长度为0,后面append时,需要重新申请内存和拷贝,所以效率较低 func getMapKeys(m map[string]string) []string { keys := []string{} for k := range m { @@ -160,6 +164,9 @@ func (m *InputDevices) tryApeendDsgData(list []string, key, value string) []stri } func (m *InputDevices) dsgSetValue(path, value string) error { + if m.dsgInputDevices == nil { + return errors.New("dsgInputDevices is nil") + } //获取旧的数据 v, err := m.dsgInputDevices.Value(0, _dsettingsDeviceWakeupStatusKey) if err != nil { @@ -234,20 +241,22 @@ func (m *InputDevices) initDSettings(sysBus *dbusutil.Service) { getDeviceWakeupStatusFunc() - //dsg配置数据改变 - m.dsgInputDevices.InitSignalExt(m.systemSigLoop, true) - _, err = m.dsgInputDevices.ConnectValueChanged(func(key string) { - if key == _dsettingsDeviceWakeupStatusKey { - getDeviceWakeupStatusFunc() - } - }) + if m.dsgInputDevices != nil { + //dsg配置数据改变 + m.dsgInputDevices.InitSignalExt(m.systemSigLoop, true) + _, err = m.dsgInputDevices.ConnectValueChanged(func(key string) { + if key == _dsettingsDeviceWakeupStatusKey { + getDeviceWakeupStatusFunc() + } + }) + } m.systemSigLoop.Start() if err != nil { logger.Warning(err) } } -//通过map不能将相同数据添加进去,append数据后计算map长度来确认重复数据 +// 通过map不能将相同数据添加进去,append数据后计算map长度来确认重复数据 func getDeleteData(truthValue, mapValue []string) (ret []string) { if len(truthValue) < len(mapValue) { tmpArr := make(map[string]int) diff --git a/system/inputdevices/inputdevices_dbusutil.go b/system/inputdevices1/inputdevices_dbusutil.go similarity index 97% rename from system/inputdevices/inputdevices_dbusutil.go rename to system/inputdevices1/inputdevices_dbusutil.go index 210898cd4..0e76f37c0 100644 --- a/system/inputdevices/inputdevices_dbusutil.go +++ b/system/inputdevices1/inputdevices_dbusutil.go @@ -1,9 +1,9 @@ // Code generated by "dbusutil-gen -type InputDevices inputdevices.go"; DO NOT EDIT. -package inputdevices +package inputdevices1 import ( - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" ) func (v *InputDevices) setPropTouchscreens(value []dbus.ObjectPath) (changed bool) { @@ -62,4 +62,4 @@ func (v *Touchpad) setPropIsExist(value bool) (changed bool) { func (v *Touchpad) emitPropChangedIsExist(value bool) error { return v.service.EmitPropertyChanged(v, "IsExist", value) -} \ No newline at end of file +} diff --git a/system/inputdevices/inputdevices_ifc.go b/system/inputdevices1/inputdevices_ifc.go similarity index 87% rename from system/inputdevices/inputdevices_ifc.go rename to system/inputdevices1/inputdevices_ifc.go index 268ff3e4e..2e13291fb 100644 --- a/system/inputdevices/inputdevices_ifc.go +++ b/system/inputdevices1/inputdevices_ifc.go @@ -2,10 +2,10 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package inputdevices +package inputdevices1 import ( - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" ) @@ -13,4 +13,3 @@ func (m *InputDevices) SetWakeupDevices(sender dbus.Sender, path string, value s err := m.setWakeupDevices(path, value) return dbusutil.ToError(err) } - diff --git a/system/inputdevices/inputdevices_test.go b/system/inputdevices1/inputdevices_test.go similarity index 95% rename from system/inputdevices/inputdevices_test.go rename to system/inputdevices1/inputdevices_test.go index b231c0237..883b404cf 100644 --- a/system/inputdevices/inputdevices_test.go +++ b/system/inputdevices1/inputdevices_test.go @@ -2,12 +2,12 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package inputdevices +package inputdevices1 import ( "testing" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/stretchr/testify/assert" ) diff --git a/system/inputdevices/libinput.go b/system/inputdevices1/libinput.go similarity index 98% rename from system/inputdevices/libinput.go rename to system/inputdevices1/libinput.go index 2a8bed1b6..ec468c9ae 100644 --- a/system/inputdevices/libinput.go +++ b/system/inputdevices1/libinput.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package inputdevices +package inputdevices1 // #cgo pkg-config: libinput libudev // #cgo CFLAGS: -W -Wall -fstack-protector-all -fPIC @@ -55,7 +55,7 @@ func handle_device_removed(event *C.struct_libinput_event, userdata unsafe.Point func notify_device_changed(event *C.struct_libinput_event, userdata unsafe.Pointer, state bool) { dev := C.libinput_event_get_device(event) - devName := C.GoString(C.libinput_device_get_name(dev)) + devName := C.GoString(C.libinput_device_get_name(dev)) udev := C.libinput_device_get_udev_device(dev) devNode := C.GoString(C.udev_device_get_devnode(udev)) devPath := C.GoString(C.udev_device_get_property_value(udev, C.CString("DEVPATH"))) diff --git a/system/inputdevices/libinput_test.go b/system/inputdevices1/libinput_test.go similarity index 95% rename from system/inputdevices/libinput_test.go rename to system/inputdevices1/libinput_test.go index e4f3d5d7d..827cc21e6 100644 --- a/system/inputdevices/libinput_test.go +++ b/system/inputdevices1/libinput_test.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package inputdevices +package inputdevices1 import ( "testing" diff --git a/system/inputdevices1/touchpad.go b/system/inputdevices1/touchpad.go new file mode 100644 index 000000000..b4e0b76b5 --- /dev/null +++ b/system/inputdevices1/touchpad.go @@ -0,0 +1,142 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package inputdevices1 + +import ( + "errors" + "io/ioutil" + "os" + "strings" + + "github.com/godbus/dbus/v5" + configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +const ( + touchpadSwitchFile = "/proc/uos/touchpad_switch" + touchpadDBusPath = "/org/deepin/dde/InputDevices1/Touchpad" + touchpadDBusInterface = "org.deepin.dde.InputDevices1.Touchpad" +) + +type Touchpad struct { + service *dbusutil.Service + Enable bool + IsExist bool +} + +func newTouchpad(service *dbusutil.Service) *Touchpad { + t := &Touchpad{ + service: service, + } + err := TouchpadExist(touchpadSwitchFile) + if err != nil { + logger.Warning(err) + t.setPropIsExist(false) + t.setPropEnable(false) + return t + } + t.setPropIsExist(true) + enable, err := TouchpadEnable(touchpadSwitchFile) + if err != nil { + logger.Warning(err) + } + t.setPropEnable(enable) + return t +} + +func (t *Touchpad) SetTouchpadEnable(enabled bool) *dbus.Error { + err := t.setTouchpadEnable(enabled) + return dbusutil.ToError(err) +} + +func (t *Touchpad) setTouchpadEnable(enabled bool) error { + if err := TouchpadExist(touchpadSwitchFile); err != nil { + logger.Warning(" TouchpadExist err : ", err) + return err + } + current, err := TouchpadEnable(touchpadSwitchFile) + if err != nil { + logger.Warning(" TouchpadEnable err : ", err) + return err + } + if current == enabled { + logger.Info("current touchPad state is same : ", enabled) + return nil + } + arg := "enable" + if !enabled { + arg = "disable" + } + err = ioutil.WriteFile(touchpadSwitchFile, []byte(arg), 0644) + if err != nil { + logger.Warning(" ioutil.WriteFile err : ", err) + return err + } + t.setPropEnable(enabled) + err = setDsgConf(enabled) + if err != nil { + logger.Warning(err) + return err + } + return nil +} + +func setDsgConf(enable bool) error { + sysBus, err := dbus.SystemBus() + if err != nil { + return err + } + ds := configManager.NewConfigManager(sysBus) + confPath, err := ds.AcquireManager(0, _dsettingsAppID, _dsettingsInputdevicesName, "") + if err != nil { + return err + } + dsManager, err := configManager.NewManager(sysBus, confPath) + if err != nil { + return err + } + err = dsManager.SetValue(0, _dsettingsTouchpadEnabledKey, dbus.MakeVariant(enable)) + if err != nil { + return err + } + return nil +} + +func TouchpadEnable(filePath string) (bool, error) { + err := TouchpadExist(filePath) + if err != nil { + return false, err + } + content, err := ioutil.ReadFile(touchpadSwitchFile) + if err != nil { + return false, err + } + return strings.Contains(string(content), "enable"), nil +} + +func TouchpadExist(filePath string) error { + if filePath != touchpadSwitchFile { + return errors.New("filePath is inValid") + } + _, err := os.Stat(touchpadSwitchFile) + if err != nil { + logger.Warning(err) + return err + } + return nil +} + +func (t *Touchpad) GetInterfaceName() string { + return touchpadDBusInterface +} + +func (t *Touchpad) export(path dbus.ObjectPath) error { + return t.service.Export(path, t) +} + +func (t *Touchpad) stopExport() error { + return t.service.StopExport(t) +} diff --git a/system/inputdevices/touchscreen.go b/system/inputdevices1/touchscreen.go similarity index 87% rename from system/inputdevices/touchscreen.go rename to system/inputdevices1/touchscreen.go index 50a585ecc..aeb2186da 100644 --- a/system/inputdevices/touchscreen.go +++ b/system/inputdevices1/touchscreen.go @@ -2,10 +2,10 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package inputdevices +package inputdevices1 import ( - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/utils" ) @@ -25,8 +25,8 @@ type Touchscreen struct { Height float64 } -const touchscreenDBusPath = "/com/deepin/system/InputDevices/Touchscreen/" -const touchscreenDBusInterface = "com.deepin.system.InputDevices.Touchscreen" +const touchscreenDBusPath = "/org/deepin/dde/InputDevices1/Touchscreen/" +const touchscreenDBusInterface = "org.deepin.dde.InputDevices1.Touchscreen" func newTouchscreen(dev *libinputDevice, service *dbusutil.Service, id uint32) *Touchscreen { t := &Touchscreen{ diff --git a/system/keyevent/daemon.go b/system/keyevent/daemon.go deleted file mode 100644 index 6416b6e23..000000000 --- a/system/keyevent/daemon.go +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package keyevent - -import ( - "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/dde-daemon/loader" -) - -const ( - dbusServiceName = "com.deepin.daemon.KeyEvent" - dbusPath = "/com/deepin/daemon/KeyEvent" - dbusInterface = dbusServiceName -) - -var logger = log.NewLogger("daemon/system/keyevent") - -func init() { - loader.Register(NewDaemon(logger)) -} - -type Daemon struct { - *loader.ModuleBase - manager *Manager -} - -func NewDaemon(logger *log.Logger) *Daemon { - daemon := new(Daemon) - daemon.ModuleBase = loader.NewModuleBase("keyevent", daemon, logger) - return daemon -} - -func (d *Daemon) GetDependencies() []string { - return []string{} -} - -func (d *Daemon) Start() (err error) { - service := loader.GetService() - d.manager = newManager(service) - - err = service.Export(dbusPath, d.manager) - if err != nil { - return - } - - err = service.RequestName(dbusServiceName) - - d.manager.start() - return -} - -func (d *Daemon) Stop() error { - if d.manager == nil { - return nil - } - d.manager.stop() - d.manager = nil - return nil -} diff --git a/system/keyevent/exported_methods_auto.go b/system/keyevent/exported_methods_auto.go deleted file mode 100644 index d9d69eb7b..000000000 --- a/system/keyevent/exported_methods_auto.go +++ /dev/null @@ -1,11 +0,0 @@ -// Code generated by "dbusutil-gen em -type Manager"; DO NOT EDIT. - -package keyevent - -import ( - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (v *Manager) GetExportedMethods() dbusutil.ExportedMethods { - return nil -} diff --git a/system/keyevent/manager.go b/system/keyevent/manager.go deleted file mode 100644 index 3ba06bb9b..000000000 --- a/system/keyevent/manager.go +++ /dev/null @@ -1,241 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package keyevent - -import ( - "errors" - "io/ioutil" - "os" - "strings" - - "github.com/godbus/dbus" - inputdevices "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.inputdevices" - "github.com/linuxdeepin/go-lib/dbusutil" -) - -//go:generate dbusutil-gen em -type Manager - -type Manager struct { - service *dbusutil.Service - quit chan bool - ch chan *KeyEvent - touchPad inputdevices.Touchpad - - leftCtrlPressed bool - leftShiftPressed bool - leftAltPressed bool - leftSuperPressed bool - - rightCtrlPressed bool - rightShiftPressed bool - rightAltPressed bool - rightSuperPressed bool - - // nolint - signals *struct { - KeyEvent struct { - keycode uint32 - pressed bool // true:按下事件,false松开事件 - ctrlPressed bool // ctrl 是否处于按下状态 - shiftPressed bool // shift 是否处于按下状态 - altPressed bool // alt 是否处于按下状态 - superPressed bool // super 是否处于按下状态 - } - } -} - -const ( - touchpadSwitchFile = "/proc/uos/touchpad_switch" -) - -// 允许发送的按键列表 -var allowList = map[uint32]bool{ - KEY_TOUCHPAD_TOGGLE: true, - KEY_POWER: true, - KEY_BLUETOOTH: true, - KEY_WLAN: true, - KEY_RFKILL: true, - KEY_TOUCHPAD_ON: true, - KEY_TOUCHPAD_OFF: true, - KEY_FN_ESC: true, - KEY_MICMUTE: true, - KEY_SWITCHVIDEOMODE: true, - KEY_SETUP: true, - KEY_CYCLEWINDOWS: true, - KEY_MODE: true, - KEY_KBDILLUMTOGGLE: true, - KEY_SCREENLOCK: true, - KEY_UNKNOWN: true, - 294: true, - KEY_CAMERA: true, -} - -func newManager(service *dbusutil.Service) *Manager { - m := &Manager{ - service: service, - quit: make(chan bool), - ch: make(chan *KeyEvent, 64), - } - - sysBus, err := dbus.SystemBus() - if err != nil { - return m - } - m.touchPad, err = inputdevices.NewTouchpad(sysBus, "/com/deepin/system/InputDevices/Touchpad") - if err != nil { - logger.Warning(err) - } - return m -} - -func (*Manager) GetInterfaceName() string { - return dbusInterface -} - -func (m *Manager) start() { - addKeyEventChannel(m.ch) - startKeyEventMonitor() - - go m.monitor() -} - -func (m *Manager) stop() { - stopKeyEventMonitor() - m.quit <- true -} - -func (m *Manager) monitor() { - for { - select { - case ev := <-m.ch: - logger.Debugf("event keycode(%d) state(%v)", ev.Keycode, ev.State) - m.handleEvent(ev) - case <-m.quit: - logger.Debug("key event monitor stop") - return - } - } -} - -func (m *Manager) handleEvent(ev *KeyEvent) { - pressed := ev.State == KEY_STATE_PRESSED - // 保存修饰键的状态 - switch ev.Keycode { - case KEY_LEFTCTRL: - m.leftCtrlPressed = pressed - case KEY_RIGHTCTRL: - m.rightCtrlPressed = pressed - case KEY_LEFTALT: - m.leftAltPressed = pressed - case KEY_RIGHTALT: - m.rightAltPressed = pressed - case KEY_LEFTSHIFT: - m.leftShiftPressed = pressed - case KEY_RIGHTSHIFT: - m.rightShiftPressed = pressed - case KEY_LEFTMETA: - m.leftSuperPressed = pressed - case KEY_RIGHTMETA: - m.leftSuperPressed = pressed - } - - // 发送DBus signal通知按键事件 - allow := allowList[ev.Keycode] - if allow { - m.emitKeyEvent(ev) - if !pressed { - return - } - - //开关触控板逻辑 - _, err := os.Stat(touchpadSwitchFile) - if err != nil { - logger.Warning(err) - return - } - switch ev.Keycode { - case KEY_TOUCHPAD_TOGGLE: - go func() { - content, err := ioutil.ReadFile(touchpadSwitchFile) - if err != nil { - logger.Warning(err) - return - } - enable := strings.Contains(string(content), "enable") - - if m.touchPad == nil { - err = errors.New("m.TouchPad is nil") - } else { - err = m.touchPad.SetTouchpadEnable(0, !enable) - } - - if err != nil { - logger.Warning("Set TouchPad state err : ", err) - - // 接口调用异常时,需要保证开关触摸板正常 - arg := string(content) - if strings.Contains(arg, "enable") { - arg = "disable" - } else { - arg = "enable" - } - err = ioutil.WriteFile(touchpadSwitchFile, []byte(arg), 0644) - if err != nil { - logger.Warning("write /proc/uos/touchpad_switch err : ", err) - } - } - }() - case KEY_TOUCHPAD_ON: - go func() { - if m.touchPad == nil { - err = errors.New("m.TouchPad is nil") - } else { - err = m.touchPad.SetTouchpadEnable(0, true) - } - - if err != nil { - logger.Warning("Set TouchPad state err : ", err) - err = ioutil.WriteFile(touchpadSwitchFile, []byte("enable"), 0644) - if err != nil { - logger.Warning("write /proc/uos/touchpad_switch err : ", err) - } - } - }() - case KEY_TOUCHPAD_OFF: - go func() { - if m.touchPad == nil { - err = errors.New("m.TouchPad is nil") - } else { - err = m.touchPad.SetTouchpadEnable(0, false) - } - - if err != nil { - logger.Warning("Set TouchPad state err : ", err) - err = ioutil.WriteFile(touchpadSwitchFile, []byte("disable"), 0644) - if err != nil { - logger.Warning("write /proc/uos/touchpad_switch err : ", err) - } - } - }() - } - } -} - -func (m *Manager) emitKeyEvent(ev *KeyEvent) { - err := m.service.Emit( - m, - "KeyEvent", - ev.Keycode, - ev.State == KEY_STATE_PRESSED, - m.leftCtrlPressed || m.rightCtrlPressed, - m.leftShiftPressed || m.rightShiftPressed, - m.leftAltPressed || m.rightAltPressed, - m.leftSuperPressed || m.rightSuperPressed, - ) - - if err != nil { - logger.Warning(err) - } -} diff --git a/system/keyevent/manager_test.go b/system/keyevent/manager_test.go deleted file mode 100644 index fdc9c9cc6..000000000 --- a/system/keyevent/manager_test.go +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package keyevent - -import "testing" - -func Test_handleEvent(t *testing.T) { - m := Manager{} - ev := &KeyEvent{ - Keycode: KEY_LEFTCTRL, - } - m.handleEvent(ev) - - ev.Keycode = KEY_RIGHTCTRL - m.handleEvent(ev) - - ev.Keycode = KEY_LEFTALT - m.handleEvent(ev) - - ev.Keycode = KEY_RIGHTALT - m.handleEvent(ev) - - ev.Keycode = KEY_LEFTSHIFT - m.handleEvent(ev) - - ev.Keycode = KEY_RIGHTSHIFT - m.handleEvent(ev) - - ev.Keycode = KEY_LEFTMETA - m.handleEvent(ev) - - ev.Keycode = KEY_RIGHTMETA - m.handleEvent(ev) -} diff --git a/system/keyevent1/daemon.go b/system/keyevent1/daemon.go new file mode 100644 index 000000000..892fa720f --- /dev/null +++ b/system/keyevent1/daemon.go @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package keyevent1 + +import ( + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" +) + +const ( + dbusServiceName = "org.deepin.dde.KeyEvent1" + dbusPath = "/org/deepin/dde/KeyEvent1" + dbusInterface = dbusServiceName +) + +var logger = log.NewLogger("daemon/system/keyevent") + +func init() { + loader.Register(NewDaemon(logger)) +} + +type Daemon struct { + *loader.ModuleBase + manager *Manager +} + +func NewDaemon(logger *log.Logger) *Daemon { + daemon := new(Daemon) + daemon.ModuleBase = loader.NewModuleBase("keyevent", daemon, logger) + return daemon +} + +func (d *Daemon) GetDependencies() []string { + return []string{} +} + +func (d *Daemon) Start() (err error) { + service := loader.GetService() + d.manager = newManager(service) + + err = service.Export(dbusPath, d.manager) + if err != nil { + return + } + + err = service.RequestName(dbusServiceName) + + d.manager.start() + return +} + +func (d *Daemon) Stop() error { + if d.manager == nil { + return nil + } + d.manager.stop() + d.manager = nil + return nil +} diff --git a/system/keyevent1/exported_methods_auto.go b/system/keyevent1/exported_methods_auto.go new file mode 100644 index 000000000..98e3528b6 --- /dev/null +++ b/system/keyevent1/exported_methods_auto.go @@ -0,0 +1,11 @@ +// Code generated by "dbusutil-gen em -type Manager"; DO NOT EDIT. + +package keyevent1 + +import ( + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (v *Manager) GetExportedMethods() dbusutil.ExportedMethods { + return nil +} diff --git a/system/keyevent/keycode.go b/system/keyevent1/keycode.go similarity index 99% rename from system/keyevent/keycode.go rename to system/keyevent1/keycode.go index 9ab6c4121..9f010120b 100644 --- a/system/keyevent/keycode.go +++ b/system/keyevent1/keycode.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package keyevent +package keyevent1 // 按键码的值在内核定义: // https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h diff --git a/system/keyevent/libinput_bridge.c b/system/keyevent1/libinput_bridge.c similarity index 100% rename from system/keyevent/libinput_bridge.c rename to system/keyevent1/libinput_bridge.c diff --git a/system/keyevent/libinput_bridge.go b/system/keyevent1/libinput_bridge.go similarity index 97% rename from system/keyevent/libinput_bridge.go rename to system/keyevent1/libinput_bridge.go index 539140b51..8bdf428a0 100644 --- a/system/keyevent/libinput_bridge.go +++ b/system/keyevent1/libinput_bridge.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package keyevent +package keyevent1 // #include "libinput_bridge.h" // #cgo pkg-config: libinput glib-2.0 @@ -10,7 +10,7 @@ package keyevent // #cgo CFLAGS: -W -Wall -fstack-protector-all -fPIC import "C" -//nolint +// nolint // 按键状态 const ( KEY_STATE_RELEASED = 0 // 松开 diff --git a/system/keyevent/libinput_bridge.h b/system/keyevent1/libinput_bridge.h similarity index 100% rename from system/keyevent/libinput_bridge.h rename to system/keyevent1/libinput_bridge.h diff --git a/system/keyevent1/manager.go b/system/keyevent1/manager.go new file mode 100644 index 000000000..0b90d47a2 --- /dev/null +++ b/system/keyevent1/manager.go @@ -0,0 +1,241 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package keyevent1 + +import ( + "errors" + "io/ioutil" + "os" + "strings" + + "github.com/godbus/dbus/v5" + inputdevices "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.inputdevices1" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +//go:generate dbusutil-gen em -type Manager + +type Manager struct { + service *dbusutil.Service + quit chan bool + ch chan *KeyEvent + touchPad inputdevices.Touchpad + + leftCtrlPressed bool + leftShiftPressed bool + leftAltPressed bool + leftSuperPressed bool + + rightCtrlPressed bool + rightShiftPressed bool + rightAltPressed bool + rightSuperPressed bool + + // nolint + signals *struct { + KeyEvent struct { + keycode uint32 + pressed bool // true:按下事件,false松开事件 + ctrlPressed bool // ctrl 是否处于按下状态 + shiftPressed bool // shift 是否处于按下状态 + altPressed bool // alt 是否处于按下状态 + superPressed bool // super 是否处于按下状态 + } + } +} + +const ( + touchpadSwitchFile = "/proc/uos/touchpad_switch" +) + +// 允许发送的按键列表 +var allowList = map[uint32]bool{ + KEY_TOUCHPAD_TOGGLE: true, + KEY_POWER: true, + KEY_BLUETOOTH: true, + KEY_WLAN: true, + KEY_RFKILL: true, + KEY_TOUCHPAD_ON: true, + KEY_TOUCHPAD_OFF: true, + KEY_FN_ESC: true, + KEY_MICMUTE: true, + KEY_SWITCHVIDEOMODE: true, + KEY_SETUP: true, + KEY_CYCLEWINDOWS: true, + KEY_MODE: true, + KEY_KBDILLUMTOGGLE: true, + KEY_SCREENLOCK: true, + KEY_UNKNOWN: true, + 294: true, + KEY_CAMERA: true, +} + +func newManager(service *dbusutil.Service) *Manager { + m := &Manager{ + service: service, + quit: make(chan bool), + ch: make(chan *KeyEvent, 64), + } + + sysBus, err := dbus.SystemBus() + if err != nil { + return m + } + m.touchPad, err = inputdevices.NewTouchpad(sysBus, "/org/deepin/dde/InputDevices1/Touchpad") + if err != nil { + logger.Warning(err) + } + return m +} + +func (*Manager) GetInterfaceName() string { + return dbusInterface +} + +func (m *Manager) start() { + addKeyEventChannel(m.ch) + startKeyEventMonitor() + + go m.monitor() +} + +func (m *Manager) stop() { + stopKeyEventMonitor() + m.quit <- true +} + +func (m *Manager) monitor() { + for { + select { + case ev := <-m.ch: + logger.Debugf("event keycode(%d) state(%v)", ev.Keycode, ev.State) + m.handleEvent(ev) + case <-m.quit: + logger.Debug("key event monitor stop") + return + } + } +} + +func (m *Manager) handleEvent(ev *KeyEvent) { + pressed := ev.State == KEY_STATE_PRESSED + // 保存修饰键的状态 + switch ev.Keycode { + case KEY_LEFTCTRL: + m.leftCtrlPressed = pressed + case KEY_RIGHTCTRL: + m.rightCtrlPressed = pressed + case KEY_LEFTALT: + m.leftAltPressed = pressed + case KEY_RIGHTALT: + m.rightAltPressed = pressed + case KEY_LEFTSHIFT: + m.leftShiftPressed = pressed + case KEY_RIGHTSHIFT: + m.rightShiftPressed = pressed + case KEY_LEFTMETA: + m.leftSuperPressed = pressed + case KEY_RIGHTMETA: + m.leftSuperPressed = pressed + } + + // 发送DBus signal通知按键事件 + allow := allowList[ev.Keycode] + if allow { + m.emitKeyEvent(ev) + if !pressed { + return + } + + //开关触控板逻辑 + _, err := os.Stat(touchpadSwitchFile) + if err != nil { + logger.Warning(err) + return + } + switch ev.Keycode { + case KEY_TOUCHPAD_TOGGLE: + go func() { + content, err := ioutil.ReadFile(touchpadSwitchFile) + if err != nil { + logger.Warning(err) + return + } + enable := strings.Contains(string(content), "enable") + + if m.touchPad == nil { + err = errors.New("m.TouchPad is nil") + } else { + err = m.touchPad.SetTouchpadEnable(0, !enable) + } + + if err != nil { + logger.Warning("Set TouchPad state err : ", err) + + // 接口调用异常时,需要保证开关触摸板正常 + arg := string(content) + if strings.Contains(arg, "enable") { + arg = "disable" + } else { + arg = "enable" + } + err = ioutil.WriteFile(touchpadSwitchFile, []byte(arg), 0644) + if err != nil { + logger.Warning("write /proc/uos/touchpad_switch err : ", err) + } + } + }() + case KEY_TOUCHPAD_ON: + go func() { + if m.touchPad == nil { + err = errors.New("m.TouchPad is nil") + } else { + err = m.touchPad.SetTouchpadEnable(0, true) + } + + if err != nil { + logger.Warning("Set TouchPad state err : ", err) + err = ioutil.WriteFile(touchpadSwitchFile, []byte("enable"), 0644) + if err != nil { + logger.Warning("write /proc/uos/touchpad_switch err : ", err) + } + } + }() + case KEY_TOUCHPAD_OFF: + go func() { + if m.touchPad == nil { + err = errors.New("m.TouchPad is nil") + } else { + err = m.touchPad.SetTouchpadEnable(0, false) + } + + if err != nil { + logger.Warning("Set TouchPad state err : ", err) + err = ioutil.WriteFile(touchpadSwitchFile, []byte("disable"), 0644) + if err != nil { + logger.Warning("write /proc/uos/touchpad_switch err : ", err) + } + } + }() + } + } +} + +func (m *Manager) emitKeyEvent(ev *KeyEvent) { + err := m.service.Emit( + m, + "KeyEvent", + ev.Keycode, + ev.State == KEY_STATE_PRESSED, + m.leftCtrlPressed || m.rightCtrlPressed, + m.leftShiftPressed || m.rightShiftPressed, + m.leftAltPressed || m.rightAltPressed, + m.leftSuperPressed || m.rightSuperPressed, + ) + + if err != nil { + logger.Warning(err) + } +} diff --git a/system/keyevent1/manager_test.go b/system/keyevent1/manager_test.go new file mode 100644 index 000000000..decd76fdc --- /dev/null +++ b/system/keyevent1/manager_test.go @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package keyevent1 + +import "testing" + +func Test_handleEvent(t *testing.T) { + m := Manager{} + ev := &KeyEvent{ + Keycode: KEY_LEFTCTRL, + } + m.handleEvent(ev) + + ev.Keycode = KEY_RIGHTCTRL + m.handleEvent(ev) + + ev.Keycode = KEY_LEFTALT + m.handleEvent(ev) + + ev.Keycode = KEY_RIGHTALT + m.handleEvent(ev) + + ev.Keycode = KEY_LEFTSHIFT + m.handleEvent(ev) + + ev.Keycode = KEY_RIGHTSHIFT + m.handleEvent(ev) + + ev.Keycode = KEY_LEFTMETA + m.handleEvent(ev) + + ev.Keycode = KEY_RIGHTMETA + m.handleEvent(ev) +} diff --git a/system/keyevent/private_keycode.go b/system/keyevent1/private_keycode.go similarity index 93% rename from system/keyevent/private_keycode.go rename to system/keyevent1/private_keycode.go index 9760324a9..89b8e6f91 100644 --- a/system/keyevent/private_keycode.go +++ b/system/keyevent1/private_keycode.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package keyevent +package keyevent1 // 厂商适配非标准按键码 // nolint diff --git a/system/lang/lang.go b/system/lang/lang.go index bed69dbb1..a50a29e25 100644 --- a/system/lang/lang.go +++ b/system/lang/lang.go @@ -5,23 +5,20 @@ package lang import ( - "os" - "path/filepath" - "sync" - "syscall" - - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-daemon/loader" - accounts "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.accounts" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" + accounts "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.accounts1" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/log" "github.com/linuxdeepin/go-lib/strv" + "os" + "path/filepath" + "sync" ) const ( - langService = "com.deepin.system.Lang" + langService = "org.deepin.dde.Lang1" userLocaleConfigFile = ".config/locale.conf" userLocaleConfigFileTmp = ".config/.locale.conf" @@ -92,7 +89,7 @@ func (l *Lang) init() { l.loadSessionList() l.listenSystemSignals() - l.updateAllUserLocale(true) + l.updateAllUserLocale() } func (l *Lang) updateLocaleBySessionPath(_ string, sessionPath dbus.ObjectPath) { @@ -128,50 +125,11 @@ func (l *Lang) updateLocaleFile(tempLocaleFilePath, localeFilePath string) { } } -func (l *Lang) updateAllUserLocale(start bool) { - if !start { - return - } - manager := login1.NewManager(l.service.Conn()) - inhibit, err := manager.Inhibit(0, "shutdown", langService, "to write language config file", "delay") - if err != nil { - logger.Warning(err) - } - // handle login1 restart - dbusObj := ofdbus.NewDBus(l.service.Conn()) - sysLoop := dbusutil.NewSignalLoop(l.service.Conn(), 10) - sysLoop.Start() - dbusObj.InitSignalExt(sysLoop, true) - _, _ = dbusObj.ConnectNameOwnerChanged(func(name string, oldOwner string, newOwner string) { - if name == "org.freedesktop.login1" && newOwner != "" && oldOwner == "" { - if inhibit != -1 { // 如果之前存在inhibit时,login1重启需要重新inhibit - err := syscall.Close(int(inhibit)) - inhibit = -1 - if err != nil { - logger.Warning("failed to close fd:", err) - return - } - inhibit, err = manager.Inhibit(0, "shutdown", langService, "to write language config file", "delay") - if err != nil { - logger.Warning(err) - } - } - } - }) - defer func() { - dbusObj.RemoveAllHandlers() - }() - // end handle login1 restart - defer func() { - err = syscall.Close(int(inhibit)) - if err != nil { - logger.Warning(err) - } - }() - +func (l *Lang) updateAllUserLocale() { l.sessionPathHomeMapMu.Lock() defer l.sessionPathHomeMapMu.Unlock() for _, homeDir := range l.sessionPathHomeMap { + logger.Debug("update local in : ", homeDir) l.updateLocaleByHomeDir(homeDir) } } @@ -184,6 +142,7 @@ func (l *Lang) deleteSessionPathHomeMap(sessionPath dbus.ObjectPath) { func (l *Lang) addSessionMap(_ string, _ dbus.ObjectPath) { l.loadSessionList() + l.updateAllUserLocale() } func (l *Lang) listenSystemSignals() { @@ -201,12 +160,6 @@ func (l *Lang) listenSystemSignals() { if err != nil { logger.Warning(err) } - - // 关机时,更新所有用户的家目录语言 - _, err = manager.ConnectPrepareForShutdown(l.updateAllUserLocale) - if err != nil { - logger.Warning(err) - } } func (l *Lang) loadSessionList() { diff --git a/system/network/config.go b/system/network/config.go deleted file mode 100644 index 429b342cb..000000000 --- a/system/network/config.go +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package network - -import ( - "encoding/json" - "io/ioutil" - "os" - "path/filepath" -) - -type Config struct { - VpnEnabled bool - Devices map[string]*DeviceConfig -} - -type DeviceConfig struct { - Enabled bool -} - -const configFile = "/var/lib/dde-daemon/network/config.json" - -func loadConfig(filename string, cfg *Config) error { - data, err := ioutil.ReadFile(filename) - if err != nil { - return err - } - err = json.Unmarshal(data, cfg) - return err -} - -func loadConfigSafe(filename string) *Config { - var cfg Config - err := loadConfig(filename, &cfg) - if err != nil && !os.IsNotExist(err) { - logger.Warning("failed to load config:", err) - } - if cfg.Devices == nil { - cfg.Devices = make(map[string]*DeviceConfig) - } - return &cfg -} - -func saveConfig(filename string, cfg *Config) error { - data, err := json.Marshal(cfg) - if err != nil { - return err - } - - dir := filepath.Dir(filename) - err = os.MkdirAll(dir, 0755) - if err != nil { - return err - } - - err = ioutil.WriteFile(filename, data, 0644) - if err != nil { - return err - } - - return nil -} diff --git a/system/network/config_test.go b/system/network/config_test.go deleted file mode 100644 index ae8058592..000000000 --- a/system/network/config_test.go +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package network - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_loadConfig(t *testing.T) { - cfg := &Config{} - err := loadConfig("./testdata/config.json", cfg) - assert.Nil(t, err) - - err = loadConfig("./testdata/config1.json", cfg) - assert.NotNil(t, err) -} - -func Test_loadConfigSafe(t *testing.T) { - cfg := loadConfigSafe("./testdata/config.json") - assert.True(t, cfg.Devices["enp2s0"].Enabled) - assert.False(t, cfg.VpnEnabled) - - loadConfigSafe("./testdata/config1.json") -} - -func Test_saveConfig(t *testing.T) { - cfg := &Config{} - err := saveConfig("./testdata/config2.json", cfg) - assert.Nil(t, err) -} diff --git a/system/network/exported_methods_auto.go b/system/network/exported_methods_auto.go deleted file mode 100644 index e923e82d9..000000000 --- a/system/network/exported_methods_auto.go +++ /dev/null @@ -1,34 +0,0 @@ -// Code generated by "dbusutil-gen em -type Network"; DO NOT EDIT. - -package network - -import ( - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (v *Network) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "EnableDevice", - Fn: v.EnableDevice, - InArgs: []string{"pathOrIface", "enabled"}, - OutArgs: []string{"cpath"}, - }, - { - Name: "IsDeviceEnabled", - Fn: v.IsDeviceEnabled, - InArgs: []string{"pathOrIface"}, - OutArgs: []string{"enabled"}, - }, - { - Name: "Ping", - Fn: v.Ping, - InArgs: []string{"host"}, - }, - { - Name: "ToggleWirelessEnabled", - Fn: v.ToggleWirelessEnabled, - OutArgs: []string{"enabled"}, - }, - } -} diff --git a/system/network/utils.go b/system/network/utils.go deleted file mode 100644 index 9c24b4395..000000000 --- a/system/network/utils.go +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package network - -// #cgo pkg-config: libudev -// #cgo CFLAGS: -W -Wall -fstack-protector-all -fPIC -// #include -// #include "utils_udev.h" -import "C" -import ( - "os/exec" - - "github.com/godbus/dbus" - networkmanager "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.networkmanager" -) - -func getSettingConnectionTimestamp(settings map[string]map[string]dbus.Variant) uint64 { - a := settings["connection"]["timestamp"].Value() - if a == nil { - return 0 - } - val, ok := a.(uint64) - if !ok { - logger.Warning("type of setting connection.timestamp is not uint64") - return 0 - } - return val -} - -func getSettingConnectionAutoconnect(settings map[string]map[string]dbus.Variant) bool { - a := settings["connection"]["autoconnect"].Value() - if a == nil { - return true - } - val, ok := a.(bool) - if !ok { - logger.Warning("type of setting connection.autoconnect is not bool") - return false - } - return val -} - -func getSettingConnectionType(settings map[string]map[string]dbus.Variant) string { - return getSettingString(settings, "connection", "type") -} - -func getSettingConnectionUuid(settings map[string]map[string]dbus.Variant) string { - return getSettingString(settings, "connection", "uuid") -} -func getSettingConnectionId(settings map[string]map[string]dbus.Variant) string { - return getSettingString(settings, "connection", "id") -} - -func getSettingString(settings map[string]map[string]dbus.Variant, key1, key2 string) string { - a := settings[key1][key2].Value() - if a == nil { - return "" - } - val, ok := a.(string) - if !ok { - logger.Warning("type of setting connection.autoconnect is not string") - return "" - } - return val -} - -func setDeviceAutoConnect(d networkmanager.Device, val bool) error { - autoConnect, err := d.Device().Autoconnect().Get(0) - if err != nil { - return err - } - - if autoConnect != val { - err = d.Device().Autoconnect().Set(0, val) - if err != nil { - return err - } - } - return nil -} - -func setDeviceManaged(d networkmanager.Device, val bool) error { - managed, err := d.Device().Managed().Get(0) - if err != nil { - return err - } - - if managed != val { - err = d.Device().Managed().Set(0, val) - if err != nil { - return err - } - } - return nil -} - -func restartIPWatchD() { - go func() { - err := exec.Command("systemctl", "restart", "ipwatchd.service").Run() - if err != nil { - logger.Warning(err) - } - }() -} diff --git a/system/network/cherry.go b/system/network1/cherry.go similarity index 95% rename from system/network/cherry.go rename to system/network1/cherry.go index f6625f096..17845e1f3 100644 --- a/system/network/cherry.go +++ b/system/network1/cherry.go @@ -2,11 +2,11 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package network +package network1 import ( - "github.com/godbus/dbus" - nmdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.networkmanager" + "github.com/godbus/dbus/v5" + nmdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.networkmanager" ) type connectionData map[string]map[string]dbus.Variant @@ -102,7 +102,6 @@ func setSettingIP6ConfigMethod(data connectionData, value string) { setSettingKey(data, "ipv6", "method", value) } - func nmGetDeviceInterface(devPath dbus.ObjectPath) (devInterface string) { d, err := nmNewDevice(devPath) if err != nil { @@ -125,4 +124,4 @@ func nmNewDevice(devPath dbus.ObjectPath) (dev nmdbus.Device, err error) { return } return -} \ No newline at end of file +} diff --git a/system/network1/config.go b/system/network1/config.go new file mode 100644 index 000000000..8c309039a --- /dev/null +++ b/system/network1/config.go @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package network1 + +import ( + "encoding/json" + "io/ioutil" + "os" + "path/filepath" +) + +type Config struct { + VpnEnabled bool + Devices map[string]*DeviceConfig +} + +type DeviceConfig struct { + Enabled bool +} + +const configFile = "/var/lib/dde-daemon/network/config.json" + +func loadConfig(filename string, cfg *Config) error { + data, err := ioutil.ReadFile(filename) + if err != nil { + return err + } + err = json.Unmarshal(data, cfg) + return err +} + +func loadConfigSafe(filename string) *Config { + var cfg Config + err := loadConfig(filename, &cfg) + if err != nil && !os.IsNotExist(err) { + logger.Warning("failed to load config:", err) + } + if cfg.Devices == nil { + cfg.Devices = make(map[string]*DeviceConfig) + } + return &cfg +} + +func saveConfig(filename string, cfg *Config) error { + data, err := json.Marshal(cfg) + if err != nil { + return err + } + + dir := filepath.Dir(filename) + err = os.MkdirAll(dir, 0755) + if err != nil { + return err + } + + err = ioutil.WriteFile(filename, data, 0644) + if err != nil { + return err + } + + return nil +} diff --git a/system/network1/config_test.go b/system/network1/config_test.go new file mode 100644 index 000000000..8cc30d27c --- /dev/null +++ b/system/network1/config_test.go @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package network1 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_loadConfig(t *testing.T) { + cfg := &Config{} + err := loadConfig("./testdata/config.json", cfg) + assert.Nil(t, err) + + err = loadConfig("./testdata/config1.json", cfg) + assert.NotNil(t, err) +} + +func Test_loadConfigSafe(t *testing.T) { + cfg := loadConfigSafe("./testdata/config.json") + assert.True(t, cfg.Devices["enp2s0"].Enabled) + assert.False(t, cfg.VpnEnabled) + + loadConfigSafe("./testdata/config1.json") +} + +func Test_saveConfig(t *testing.T) { + cfg := &Config{} + err := saveConfig("./testdata/config2.json", cfg) + assert.Nil(t, err) +} diff --git a/system/network1/exported_methods_auto.go b/system/network1/exported_methods_auto.go new file mode 100644 index 000000000..e665f03f2 --- /dev/null +++ b/system/network1/exported_methods_auto.go @@ -0,0 +1,34 @@ +// Code generated by "dbusutil-gen em -type Network"; DO NOT EDIT. + +package network1 + +import ( + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (v *Network) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "EnableDevice", + Fn: v.EnableDevice, + InArgs: []string{"pathOrIface", "enabled"}, + OutArgs: []string{"cpath"}, + }, + { + Name: "IsDeviceEnabled", + Fn: v.IsDeviceEnabled, + InArgs: []string{"pathOrIface"}, + OutArgs: []string{"enabled"}, + }, + { + Name: "Ping", + Fn: v.Ping, + InArgs: []string{"host"}, + }, + { + Name: "ToggleWirelessEnabled", + Fn: v.ToggleWirelessEnabled, + OutArgs: []string{"enabled"}, + }, + } +} diff --git a/system/network/network.go b/system/network1/network.go similarity index 97% rename from system/network/network.go rename to system/network1/network.go index 62c1c2a24..a648488a3 100644 --- a/system/network/network.go +++ b/system/network1/network.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package network +package network1 import ( "errors" @@ -10,19 +10,19 @@ import ( "sync" "time" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-daemon/loader" - "github.com/linuxdeepin/dde-daemon/network/nm" - airplanemode "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.airplanemode" - networkmanager "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.networkmanager" + "github.com/linuxdeepin/dde-daemon/network1/nm" + airplanemode "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.airplanemode1" + networkmanager "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.networkmanager" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/dbusutil/proxy" "github.com/linuxdeepin/go-lib/log" ) const ( - dbusServiceName = "com.deepin.system.Network" - dbusPath = "/com/deepin/system/Network" + dbusServiceName = "org.deepin.dde.Network1" + dbusPath = "/org/deepin/dde/Network1" dbusInterface = dbusServiceName ) diff --git a/system/network/network_dbusutil.go b/system/network1/network_dbusutil.go similarity index 95% rename from system/network/network_dbusutil.go rename to system/network1/network_dbusutil.go index 5d22d054e..8adafc95c 100644 --- a/system/network/network_dbusutil.go +++ b/system/network1/network_dbusutil.go @@ -1,6 +1,6 @@ // Code generated by "dbusutil-gen -type Network network.go"; DO NOT EDIT. -package network +package network1 func (v *Network) setPropVpnEnabled(value bool) (changed bool) { if v.VpnEnabled != value { diff --git a/system/network/network_test.go b/system/network1/network_test.go similarity index 97% rename from system/network/network_test.go rename to system/network1/network_test.go index fb210b87f..23d7fab34 100644 --- a/system/network/network_test.go +++ b/system/network1/network_test.go @@ -2,12 +2,12 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package network +package network1 import ( "testing" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/stretchr/testify/assert" ) diff --git a/system/network/ping.go b/system/network1/ping.go similarity index 99% rename from system/network/ping.go rename to system/network1/ping.go index 86b3de3fa..e8502cf98 100644 --- a/system/network/ping.go +++ b/system/network1/ping.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package network +package network1 import ( "bytes" @@ -11,7 +11,7 @@ import ( "net" "time" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" ) diff --git a/system/network/ping_test.go b/system/network1/ping_test.go similarity index 98% rename from system/network/ping_test.go rename to system/network1/ping_test.go index 6be1eb426..236cdb7fc 100644 --- a/system/network/ping_test.go +++ b/system/network1/ping_test.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -package network +package network1 import ( "testing" diff --git a/system/network/testdata/config.json b/system/network1/testdata/config.json similarity index 100% rename from system/network/testdata/config.json rename to system/network1/testdata/config.json diff --git a/system/network/testdata/config2.json b/system/network1/testdata/config2.json similarity index 100% rename from system/network/testdata/config2.json rename to system/network1/testdata/config2.json diff --git a/system/network1/utils.go b/system/network1/utils.go new file mode 100644 index 000000000..a7ae21c71 --- /dev/null +++ b/system/network1/utils.go @@ -0,0 +1,106 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package network1 + +// #cgo pkg-config: libudev +// #cgo CFLAGS: -W -Wall -fstack-protector-all -fPIC +// #include +// #include "utils_udev.h" +import "C" +import ( + "os/exec" + + "github.com/godbus/dbus/v5" + networkmanager "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.networkmanager" +) + +func getSettingConnectionTimestamp(settings map[string]map[string]dbus.Variant) uint64 { + a := settings["connection"]["timestamp"].Value() + if a == nil { + return 0 + } + val, ok := a.(uint64) + if !ok { + logger.Warning("type of setting connection.timestamp is not uint64") + return 0 + } + return val +} + +func getSettingConnectionAutoconnect(settings map[string]map[string]dbus.Variant) bool { + a := settings["connection"]["autoconnect"].Value() + if a == nil { + return true + } + val, ok := a.(bool) + if !ok { + logger.Warning("type of setting connection.autoconnect is not bool") + return false + } + return val +} + +func getSettingConnectionType(settings map[string]map[string]dbus.Variant) string { + return getSettingString(settings, "connection", "type") +} + +func getSettingConnectionUuid(settings map[string]map[string]dbus.Variant) string { + return getSettingString(settings, "connection", "uuid") +} +func getSettingConnectionId(settings map[string]map[string]dbus.Variant) string { + return getSettingString(settings, "connection", "id") +} + +func getSettingString(settings map[string]map[string]dbus.Variant, key1, key2 string) string { + a := settings[key1][key2].Value() + if a == nil { + return "" + } + val, ok := a.(string) + if !ok { + logger.Warning("type of setting connection.autoconnect is not string") + return "" + } + return val +} + +func setDeviceAutoConnect(d networkmanager.Device, val bool) error { + autoConnect, err := d.Device().Autoconnect().Get(0) + if err != nil { + return err + } + + if autoConnect != val { + err = d.Device().Autoconnect().Set(0, val) + if err != nil { + return err + } + } + return nil +} + +func setDeviceManaged(d networkmanager.Device, val bool) error { + managed, err := d.Device().Managed().Get(0) + if err != nil { + return err + } + + if managed != val { + err = d.Device().Managed().Set(0, val) + if err != nil { + return err + } + } + return nil +} + +func restartIPWatchD() { + go func() { + err := exec.Command("systemctl", "restart", "ipwatchd.service").Run() + if err != nil { + logger.Warning(err) + } + }() +} diff --git a/system/network/utils_udev.c b/system/network1/utils_udev.c similarity index 100% rename from system/network/utils_udev.c rename to system/network1/utils_udev.c diff --git a/system/network/utils_udev.h b/system/network1/utils_udev.h similarity index 100% rename from system/network/utils_udev.h rename to system/network1/utils_udev.h diff --git a/system/power/daemon.go b/system/power/daemon.go deleted file mode 100644 index d6bc3c0c5..000000000 --- a/system/power/daemon.go +++ /dev/null @@ -1,193 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package power - -import ( - "sync" - "time" - - "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/loader" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/log" -) - -var logger = log.NewLogger("daemon/system/power") - -func init() { - loader.Register(NewDaemon(logger)) -} - -type Daemon struct { - *loader.ModuleBase - manager *Manager -} - -func NewDaemon(logger *log.Logger) *Daemon { - daemon := new(Daemon) - daemon.ModuleBase = loader.NewModuleBase("power", daemon, logger) - return daemon -} - -func (d *Daemon) GetDependencies() []string { - return []string{} -} - -func (d *Daemon) Start() (err error) { - service := loader.GetService() - d.manager, err = newManager(service) - if err != nil { - return - } - - d.manager.batteriesMu.Lock() - for _, bat := range d.manager.batteries { - err := service.Export(bat.getObjPath(), bat) - if err != nil { - logger.Warning("failed to export battery:", err) - } - } - d.manager.batteriesMu.Unlock() - serverObj, err := service.NewServerObject(dbusPath, d.manager) - if err != nil { - return - } - err = serverObj.ConnectChanged(d.manager, "PowerSavingModeAuto", func(change *dbusutil.PropertyChanged) { - d.manager.updatePowerMode(false) // PowerSavingModeAuto change - err := d.manager.saveDsgConfig("PowerSavingModeAuto") - if err != nil { - logger.Warning(err) - } - }) - if err != nil { - logger.Warning(err) - } - - err = serverObj.ConnectChanged(d.manager, "PowerSavingModeEnabled", func(change *dbusutil.PropertyChanged) { - enabled := change.Value.(bool) - d.manager.PropsMu.Lock() - d.manager.updatePowerSavingState(false) - d.manager.PropsMu.Unlock() - // 历史版本只有节能和平衡之间的切换 - if enabled { - d.manager.doSetMode(ddePowerSave) - } else { - d.manager.doSetMode(ddeBalance) - } - err := d.manager.saveDsgConfig("PowerSavingModeEnabled") - if err != nil { - logger.Warning(err) - } - }) - if err != nil { - logger.Warning(err) - } - - // 属性改变后的回调函数 - err = serverObj.ConnectChanged(d.manager, "PowerSavingModeAutoWhenBatteryLow", func(change *dbusutil.PropertyChanged) { - d.manager.refreshBatteryDisplay() - d.manager.updatePowerMode(false) // PowerSavingModeAutoWhenBatteryLow change - err := d.manager.saveDsgConfig("PowerSavingModeAutoWhenBatteryLow") - if err != nil { - logger.Warning(err) - } - }) - if err != nil { - logger.Warning(err) - } - - err = serverObj.ConnectChanged(d.manager, "PowerSavingModeBrightnessDropPercent", func(change *dbusutil.PropertyChanged) { - err := d.manager.saveDsgConfig("PowerSavingModeBrightnessDropPercent") - if err != nil { - logger.Warning(err) - } - }) - if err != nil { - logger.Warning(err) - } - - if err != nil { - logger.Warning(err) - } - if d.manager.enablePerformanceInBoot() { - var once sync.Once - var handlerId dbusutil.SignalHandlerId - var highTimer *time.Timer - handlerId, err = d.manager.displayManager.ConnectSessionAdded(func(session dbus.ObjectPath) { - // 登录后两分钟内高性能,两分钟后修改回原有的mode - once.Do(func() { - highTimer = time.AfterFunc(time.Minute*2, func() { - logger.Infof(" ## time.AfterFunc 2 min manager.Mod : %s", d.manager.Mode) - d.manager.IsInBootTime = false - // ② 超时后恢复流程 - d.manager.doSetMode(d.manager.Mode) - d.manager.displayManager.RemoveHandler(handlerId) - err = serverObj.SetReadCallback(d.manager, "Mode", nil) - if err != nil { - logger.Warning(err) - } - }) - }) - - }) - if err != nil { - logger.Warning(err) - } - // ③ 查看mode时, 恢复当前设置 - err = serverObj.SetReadCallback(d.manager, "Mode", func(read *dbusutil.PropertyRead) *dbus.Error { - logger.Info("change to record mode") - if highTimer != nil { - highTimer.Stop() - } - defer func() { - err := serverObj.SetReadCallback(d.manager, "Mode", nil) - if err != nil { - logger.Warning(err) - } - }() - d.manager.IsInBootTime = false - d.manager.doSetMode(d.manager.Mode) - logger.Infof(" SetReadCallback manager.Mode : %s", d.manager.Mode) - return nil - }) - } - if err != nil { - logger.Warning(err) - } - - err = serverObj.Export() - if err != nil { - logger.Warning(err) - return - } - - err = service.RequestName(dbusServiceName) - return -} - -func (d *Daemon) Stop() error { - if d.manager == nil { - return nil - } - service := loader.GetService() - - d.manager.batteriesMu.Lock() - for _, bat := range d.manager.batteries { - err := service.StopExport(bat) - if err != nil { - logger.Warning(err) - } - } - d.manager.batteriesMu.Unlock() - - err := service.StopExport(d.manager) - if err != nil { - logger.Warning(err) - } - - d.manager.destroy() - d.manager = nil - return nil -} diff --git a/system/power/manager.go b/system/power/manager.go deleted file mode 100644 index a847d6d40..000000000 --- a/system/power/manager.go +++ /dev/null @@ -1,755 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package power - -import ( - "encoding/json" - "errors" - "io/ioutil" - "os" - "sync" - "time" - - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-api/powersupply" - "github.com/linuxdeepin/dde-api/powersupply/battery" - ConfigManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" - DisplayManager "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.DisplayManager" - gudev "github.com/linuxdeepin/go-gir/gudev-1.0" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/strv" -) - -const ( - dsettingsAppID = "org.deepin.dde.daemon" - dsettingsPowerName = "org.deepin.dde.daemon.power" - dsettingsPowerSavingModeEnabled = "powerSavingModeEnabled" - dsettingsPowerSavingModeAuto = "powerSavingModeAuto" - dsettingsPowerSavingModeAutoWhenBatteryLow = "powerSavingModeAutoWhenBatteryLow" - dsettingsPowerSavingModeBrightnessDropPercent = "powerSavingModeBrightnessDropPercent" - dsettingsPowerMappingConfig = "powerMappingConfig" - dsettingsMode = "mode" -) - -type supportMode struct { - Balance bool `json:"balance"` - Performace bool `json:"performace"` - PowerSave bool `json:"powersave"` -} - -//go:generate dbusutil-gen -type Manager,Battery -import github.com/linuxdeepin/dde-api/powersupply/battery manager.go battery.go -//go:generate dbusutil-gen em -type Manager,Battery - -// https://www.kernel.org/doc/Documentation/power/power_supply_class.txt -type Manager struct { - service *dbusutil.Service - systemSigLoop *dbusutil.SignalLoop - batteries map[string]*Battery - batteriesMu sync.Mutex - ac *AC - gudevClient *gudev.Client - dsgPower ConfigManager.Manager - // 电池是否电量低 - batteryLow bool - // 初始化是否完成 - initDone bool - - // INFO: pstate中,可选项是performance balance_performance balance_power power - - PropsMu sync.RWMutex - OnBattery bool - HasLidSwitch bool - // battery display properties: - HasBattery bool - BatteryPercentage float64 - BatteryStatus battery.Status - BatteryTimeToEmpty uint64 - BatteryTimeToFull uint64 - // 电池容量 - BatteryCapacity float64 - - // 开启和关闭节能模式 - PowerSavingModeEnabled bool `prop:"access:rw"` - - // 自动切换节能模式,依据为是否插拔电源 - PowerSavingModeAuto bool `prop:"access:rw"` - - // 低电量时自动开启 - PowerSavingModeAutoWhenBatteryLow bool `prop:"access:rw"` - - // 开启节能模式时降低亮度的百分比值 - PowerSavingModeBrightnessDropPercent uint32 `prop:"access:rw"` - - // 开启节能模式时保存的数据 - PowerSavingModeBrightnessData string `prop:"access:rw"` - - // CPU频率调节模式,支持powersave和performance - CpuGovernor string - - // CPU频率增强是否开启 - CpuBoost bool - - // 是否支持Boost - IsHighPerformanceSupported bool - - // 是否支持平衡模式 - IsBalanceSupported bool - - // 是否支持节能模式 - IsPowerSaveSupported bool - - // 是否支持切换性能模式 - SupportSwitchPowerMode bool `prop:"access:rw"` - // 当前模式 - Mode string - - // 是否在启动阶段,启动阶段不允许调节亮度; 若在启动阶段切换模式后(切节能模式降低亮度),可以调节亮度. - IsInBootTime bool - - // 上次非低电量时的模式 - lastMode string - - displayManager DisplayManager.DisplayManager - - isLowBatteryMode bool - // nolint - signals *struct { - BatteryDisplayUpdate struct { - timestamp int64 - } - - BatteryAdded struct { - path dbus.ObjectPath - } - - BatteryRemoved struct { - path dbus.ObjectPath - } - - LidClosed struct{} - LidOpened struct{} - } -} - -const ( - ddePowerSave = "powersave" - ddeBalance = "balance" - ddePerformance = "performance" - ddeLowBattery = "lowBattery" // 内部使用,在对外暴露的时候,会切换成powersave -) - -var _allPowerModeArray = []string{ - ddePowerSave, - ddeBalance, - ddePerformance, - ddeLowBattery, -} - -var _validPowerModeArray = strv.Strv{ - ddePowerSave, - ddeBalance, - ddePerformance, - ddeLowBattery, -} - -func newManager(service *dbusutil.Service) (*Manager, error) { - m := &Manager{ - service: service, - BatteryPercentage: 100, - lastMode: ddeBalance, - IsHighPerformanceSupported: true, - IsBalanceSupported: true, - IsPowerSaveSupported: true, - CpuBoost: true, - } - - err := m.init() - if err != nil { - m.destroy() - return nil, err - } - - return m, nil -} - -type AC struct { - gudevClient *gudev.Client - sysfsPath string -} - -func newAC(manager *Manager, device *gudev.Device) *AC { - sysfsPath := device.GetSysfsPath() - return &AC{ - gudevClient: manager.gudevClient, - sysfsPath: sysfsPath, - } -} - -func (ac *AC) newDevice() *gudev.Device { - return ac.gudevClient.QueryBySysfsPath(ac.sysfsPath) -} - -func (m *Manager) refreshAC(ac *gudev.Device) { // 拔插电源时候触发 - online := ac.GetPropertyAsBoolean("POWER_SUPPLY_ONLINE") - logger.Debug("ac online:", online) - onBattery := !online - - m.PropsMu.Lock() - m.setPropOnBattery(onBattery) - m.PropsMu.Unlock() - // 根据OnBattery的状态,修改节能模式 - m.updatePowerMode(false) // refreshAC -} - -func (m *Manager) initAC(devices []*gudev.Device) { - var ac *gudev.Device - for _, dev := range devices { - if powersupply.IsMains(dev) { - ac = dev - break - } - } - if ac != nil { - m.refreshAC(ac) - m.ac = newAC(m, ac) - } -} - -func (m *Manager) init() error { - m.systemSigLoop = dbusutil.NewSignalLoop(m.service.Conn(), 10) - m.systemSigLoop.Start() - err := m.initDsgConfig() - if err != nil { - logger.Warning(err) - } - - subsystems := []string{"power_supply", "input"} - m.gudevClient = gudev.NewClient(subsystems) - if m.gudevClient == nil { - return errors.New("gudevClient is nil") - } - - m.initLidSwitch() - devices := powersupply.GetDevices(m.gudevClient) - - m.initAC(devices) - m.initBatteries(devices) - for _, dev := range devices { - dev.Unref() - } - - m.gudevClient.Connect("uevent", m.handleUEvent) - m.initDone = true - - m.updatePowerMode(true) // init - - m.displayManager = DisplayManager.NewDisplayManager(m.service.Conn()) - m.displayManager.InitSignalExt(m.systemSigLoop, true) - return nil -} - -func (m *Manager) initDsgConfig() error { - logger.Info("com.deepin.system.Power module start init dconfig.") - // dsg 配置 - ds := ConfigManager.NewConfigManager(m.service.Conn()) - - dsPowerPath, err := ds.AcquireManager(0, dsettingsAppID, dsettingsPowerName, "") - if err != nil { - return err - } - dsPower, err := ConfigManager.NewManager(m.service.Conn(), dsPowerPath) - if err != nil { - return err - } - m.dsgPower = dsPower - - cfg := loadConfigSafe() - if cfg != nil { - // 将config.json中的配置完成初始化 - m.PowerSavingModeEnabled = cfg.PowerSavingModeEnabled // 开启和关闭节能模式 - m.PowerSavingModeAuto = cfg.PowerSavingModeAuto // 自动切换节能模式,依据为是否插拔电源 - m.PowerSavingModeAutoWhenBatteryLow = cfg.PowerSavingModeAutoWhenBatteryLow // 低电量时自动开启 - m.PowerSavingModeBrightnessDropPercent = cfg.PowerSavingModeBrightnessDropPercent // 开启节能模式时降低亮度的百分比值 - m.Mode = cfg.Mode - migrateErr := m.migrateFromCurrentConfigsToDsg() - if migrateErr != nil { - logger.Error("migrateFromCurrentConfigsToDsg failed, err:", migrateErr) - } - } - - getPowerSavingModeAuto := func(init bool) { - data, err := dsPower.Value(0, dsettingsPowerSavingModeAuto) - if err != nil { - logger.Warning(err) - return - } - - if init { - m.PowerSavingModeAuto = data.Value().(bool) - return - } - - m.setPropPowerSavingModeAuto(data.Value().(bool)) - } - - getPowerSavingModeEnabled := func(init bool) { - data, err := dsPower.Value(0, dsettingsPowerSavingModeEnabled) - if err != nil { - logger.Warning(err) - return - } - - if init { - m.PowerSavingModeEnabled = data.Value().(bool) - return - } - - m.setPropPowerSavingModeEnabled(data.Value().(bool)) - } - - getPowerSavingModeAutoWhenBatteryLow := func(init bool) { - data, err := dsPower.Value(0, dsettingsPowerSavingModeAutoWhenBatteryLow) - if err != nil { - logger.Warning(err) - return - } - - if init { - m.PowerSavingModeAutoWhenBatteryLow = data.Value().(bool) - return - } - - m.setPropPowerSavingModeAutoWhenBatteryLow(data.Value().(bool)) - } - - getPowerSavingModeBrightnessDropPercent := func(init bool) { - data, err := dsPower.Value(0, dsettingsPowerSavingModeBrightnessDropPercent) - if err != nil { - logger.Warning(err) - return - } - - if init { - switch vv := data.Value().(type) { - case float64: - m.PowerSavingModeBrightnessDropPercent = uint32(vv) - case int64: - m.PowerSavingModeBrightnessDropPercent = uint32(vv) - default: - logger.Warning("type is wrong! type : ", vv) - } - - return - } - - ret := false - switch vv := data.Value().(type) { - case float64: - ret = m.setPropPowerSavingModeBrightnessDropPercent(uint32(vv)) - case int64: - ret = m.setPropPowerSavingModeBrightnessDropPercent(uint32(vv)) - default: - logger.Warning("type is wrong! type : ", vv) - } - if ret { - logger.Info("Set power saving mode brightness drop percent", m.PowerSavingModeBrightnessDropPercent) - } - } - - getMode := func(init bool) string { - ret, err := dsPower.Value(0, dsettingsMode) - if err != nil { - logger.Warning(err) - return ddeBalance - } - - value := ret.Value().(string) - logger.Infof("value:%v", value) - // dsg更新配置后,校验mode有效性 - if !_validPowerModeArray.Contains(value) { - value = ddeBalance - _ = m.setDsgData(dsettingsMode, value, m.dsgPower) // 将修正后的数据回写dconfig - } - if init { - logger.Info("init ") - m.Mode = value - return value - } - m.setPropMode(value) - return value - } - - getPowerMappingConfig := func() { - data, err := dsPower.Value(0, dsettingsPowerMappingConfig) - if err != nil { - logger.Warning(err) - return - } - config := make(map[string]powerConfig) - configStr := data.Value().(string) - err = json.Unmarshal([]byte(configStr), &config) - if err != nil { - logger.Warning(err) - return - } - - for _, mode := range _allPowerModeArray { - c, ok := config[mode] - if ok { - _powerConfigMap[mode].DSPCConfig = c.DSPCConfig - } - } - } - - getPowerSavingModeAuto(true) - getPowerSavingModeEnabled(true) - getPowerSavingModeAutoWhenBatteryLow(true) - getPowerSavingModeBrightnessDropPercent(true) - getMode(true) - getPowerMappingConfig() - - dsPower.InitSignalExt(m.systemSigLoop, true) - _, _ = dsPower.ConnectValueChanged(func(key string) { - logger.Info("dconfig org.deepin.dde.daemon.power valueChanged, key : ", key) - switch key { - case dsettingsPowerSavingModeAuto: - getPowerSavingModeAuto(false) - case dsettingsPowerSavingModeEnabled: - getPowerSavingModeEnabled(false) - case dsettingsPowerSavingModeAutoWhenBatteryLow: - getPowerSavingModeAutoWhenBatteryLow(false) - case dsettingsPowerSavingModeBrightnessDropPercent: - getPowerSavingModeBrightnessDropPercent(false) - case dsettingsMode: - oldMode := m.Mode - newMode := getMode(false) - if oldMode == newMode { - return - } - // 手动(外部请求)切换到节能模式,或节能模式切换到其他模式时,关闭电池自动节能和低电量自动节能 - if ddePowerSave == oldMode || ddePowerSave == newMode { - m.PropsMu.Lock() - m.updatePowerSavingState(false) - m.PropsMu.Unlock() - } - m.doSetMode(newMode) - return - case dsettingsPowerMappingConfig: - getPowerMappingConfig() - default: - logger.Debug("Not process. valueChanged, key : ", key) - } - m.updatePowerMode(false) // dconfig change - }) - - return nil -} - -func (m *Manager) handleUEvent(client *gudev.Client, action string, device *gudev.Device) { - logger.Debug("on uevent action:", action) - defer device.Unref() - - switch action { - case "change": - if powersupply.IsMains(device) { - if m.ac == nil { - m.ac = newAC(m, device) - } else if m.ac.sysfsPath != device.GetSysfsPath() { - logger.Warning("found another AC", device.GetSysfsPath()) - return - } - - // now m.ac != nil, and sysfsPath equal - m.refreshAC(device) - time.AfterFunc(1*time.Second, m.refreshBatteries) - time.AfterFunc(3*time.Second, m.refreshBatteries) - // 电源状态变更时,需要一段时间才能稳定,因此在1分钟内,每隔5秒刷新一次,保证数据及时更新 - for i := 1; i <= 12; i++ { - time.AfterFunc(time.Duration(i*5)*time.Second, m.refreshBatteries) - } - } else if powersupply.IsSystemBattery(device) { - m.addAndExportBattery(device) - } - case "add": - if powersupply.IsSystemBattery(device) { - m.addAndExportBattery(device) - } - // ignore add mains - - case "remove": - if powersupply.IsSystemBattery(device) { - m.removeBattery(device) - } - } - -} - -func (m *Manager) initBatteries(devices []*gudev.Device) { - m.batteries = make(map[string]*Battery) - for _, dev := range devices { - m.addBattery(dev) - } - logger.Debugf("initBatteries done %#v", m.batteries) -} - -func (m *Manager) addAndExportBattery(dev *gudev.Device) { - bat, added := m.addBattery(dev) - if added { - err := m.service.Export(bat.getObjPath(), bat) - if err == nil { - m.emitBatteryAdded(bat) - } else { - logger.Warning("failed to export battery:", err) - } - } -} - -func (m *Manager) addBattery(dev *gudev.Device) (*Battery, bool) { - logger.Debug("addBattery dev:", dev) - if !powersupply.IsSystemBattery(dev) { - return nil, false - } - - sysfsPath := dev.GetSysfsPath() - logger.Debug(sysfsPath) - - m.batteriesMu.Lock() - bat, ok := m.batteries[sysfsPath] - m.batteriesMu.Unlock() - if ok { - logger.Debugf("add battery failed , sysfsPath exists %q", sysfsPath) - bat.Refresh() - return bat, false - } - - bat = newBattery(m, dev) - if bat == nil { - logger.Debugf("add batteries failed, sysfsPath %q, new battery failed", sysfsPath) - return nil, false - } - - m.batteriesMu.Lock() - m.batteries[sysfsPath] = bat - m.refreshBatteryDisplay() - m.batteriesMu.Unlock() - bat.setRefreshDoneCallback(m.refreshBatteryDisplay) - return bat, true -} - -// removeBattery remove the battery from Manager.batteries, and stop export it. -func (m *Manager) removeBattery(dev *gudev.Device) { - sysfsPath := dev.GetSysfsPath() - - m.batteriesMu.Lock() - bat, ok := m.batteries[sysfsPath] - m.batteriesMu.Unlock() - - if ok { - logger.Info("removeBattery", sysfsPath) - m.batteriesMu.Lock() - delete(m.batteries, sysfsPath) - m.refreshBatteryDisplay() - m.batteriesMu.Unlock() - - err := m.service.StopExport(bat) - if err != nil { - logger.Warning(err) - } - m.emitBatteryRemoved(bat) - - bat.destroy() - } else { - logger.Warning("removeBattery failed: invalid sysfsPath ", sysfsPath) - } -} - -func (m *Manager) emitBatteryAdded(bat *Battery) { - err := m.service.Emit(m, "BatteryAdded", bat.getObjPath()) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) emitBatteryRemoved(bat *Battery) { - err := m.service.Emit(m, "BatteryRemoved", bat.getObjPath()) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) destroy() { - logger.Debug("destroy") - m.batteriesMu.Lock() - for _, bat := range m.batteries { - bat.destroy() - } - m.batteries = nil - m.batteriesMu.Unlock() - - if m.gudevClient != nil { - m.gudevClient.Unref() - m.gudevClient = nil - } - m.systemSigLoop.Stop() -} - -const configFile = "/var/lib/dde-daemon/power/config.json" - -type Config struct { - PowerSavingModeEnabled bool - PowerSavingModeAuto bool - PowerSavingModeAutoWhenBatteryLow bool - PowerSavingModeBrightnessDropPercent uint32 - Mode string -} - -func loadConfig() (*Config, error) { - content, err := ioutil.ReadFile(configFile) - if err != nil { - return nil, err - } - var cfg Config - err = json.Unmarshal(content, &cfg) - if err != nil { - return nil, err - } - - return &cfg, nil -} - -func loadConfigSafe() *Config { - cfg, err := loadConfig() - if err != nil { - // ignore not exist error - if !os.IsNotExist(err) { - logger.Warning(err) - } - return nil - } - // 新增字段后第一次启动时,缺少两个新增字段的json,导致亮度下降百分比字段默认为0,导致与默认值不符,需要处理 - // 低电量自动待机字段的默认值为false,不会导致错误影响 - // 正常情况下该字段范围为10-40,只有在该情况下会出现0的可能 - if cfg.PowerSavingModeBrightnessDropPercent == 0 { - cfg.PowerSavingModeBrightnessDropPercent = 20 - } - - if cfg.Mode == "" { - cfg.Mode = ddeBalance - } - return cfg -} - -func (m *Manager) migrateFromCurrentConfigsToDsg() error { - err := m.saveDsgConfig("") - if err != nil { - logger.Warning("saveDsgConfig failed", err) - return err - } - - // 迁移完成后,删除本地配置文件 - err = os.Remove(configFile) - if err != nil { - logger.Warning("delete local configs file failed", err) - return err - } - - return nil -} - -func (m *Manager) saveDsgConfig(value string) (err error) { - switch value { - case "PowerSavingModeBrightnessDropPercent": - err = m.setDsgData(dsettingsPowerSavingModeBrightnessDropPercent, int64(m.PowerSavingModeBrightnessDropPercent), m.dsgPower) - if err != nil { - return err - } - case "PowerSavingModeAutoWhenBatteryLow": - err = m.setDsgData(dsettingsPowerSavingModeAutoWhenBatteryLow, m.PowerSavingModeAutoWhenBatteryLow, m.dsgPower) - if err != nil { - return err - } - case "PowerSavingModeEnabled": - err = m.setDsgData(dsettingsPowerSavingModeEnabled, m.PowerSavingModeEnabled, m.dsgPower) - if err != nil { - return err - } - case "PowerSavingModeAuto": - err = m.setDsgData(dsettingsPowerSavingModeAuto, m.PowerSavingModeAuto, m.dsgPower) - if err != nil { - return err - } - case "": - err = m.setDsgData(dsettingsPowerSavingModeBrightnessDropPercent, int64(m.PowerSavingModeBrightnessDropPercent), m.dsgPower) - if err != nil { - return err - } - err = m.setDsgData(dsettingsPowerSavingModeAutoWhenBatteryLow, m.PowerSavingModeAutoWhenBatteryLow, m.dsgPower) - if err != nil { - return err - } - err = m.setDsgData(dsettingsPowerSavingModeEnabled, m.PowerSavingModeEnabled, m.dsgPower) - if err != nil { - return err - } - err = m.setDsgData(dsettingsPowerSavingModeAuto, m.PowerSavingModeAuto, m.dsgPower) - if err != nil { - return err - } - } - - return m.setDsgData(dsettingsMode, m.Mode, m.dsgPower) -} - -func (m *Manager) doSetMode(mode string) { - logger.Info(" doSetMode, mode : ", mode) - if !_validPowerModeArray.Contains(mode) { - logger.Errorf("PowerMode %q mode is not supported", mode) - return - } - if mode == ddePowerSave && m.batteryLow { - mode = ddeLowBattery - } - fixMode := mode - if fixMode == ddeLowBattery { - fixMode = ddePowerSave - m.isLowBatteryMode = true - } else { - m.isLowBatteryMode = false - } - modeChanged := m.setPropMode(fixMode) - if modeChanged { - logger.Info("Set power mode", fixMode) - m.IsInBootTime = false - } - - // 处理ddeLowBattery情况,所以每次都要设置 - go m.setDSPCState(_powerConfigMap[mode].DSPCConfig) // doSetMode - m.setPropPowerSavingModeEnabled(_powerConfigMap[mode].PowerSavingModeEnabled) - - if m.lastMode != mode && mode != ddePowerSave && mode != ddeLowBattery { - m.lastMode = mode - } - if modeChanged { - _ = m.setDsgData(dsettingsMode, fixMode, m.dsgPower) - } -} - -// 需求: 为了提高启动速度,登录前将性能模式设置为performance -// ① 为了减小耦合性,仅写文件(doSetCpuGovernor),不修改后端相关属性 -func (m *Manager) enablePerformanceInBoot() bool { - if m.Mode == ddePerformance { - return false - } - displaySessions, err := m.displayManager.Sessions().Get(0) - if err != nil { - logger.Warning(err) - } else if len(displaySessions) > 0 { - return false - } - go m.setDSPCState(DSPCPerformance) - logger.Info("enablePerformanceInBoot performance") - m.IsInBootTime = true - return true -} diff --git a/system/power/manager_ifc.go b/system/power/manager_ifc.go deleted file mode 100644 index 1288063a4..000000000 --- a/system/power/manager_ifc.go +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package power - -import ( - "errors" - "fmt" - - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/go-lib/dbusutil" -) - -const ( - dbusServiceName = "com.deepin.system.Power" - dbusPath = "/com/deepin/system/Power" - dbusInterface = dbusServiceName -) - -func (*Manager) GetInterfaceName() string { - return dbusInterface -} - -func (m *Manager) GetBatteries() (batteries []dbus.ObjectPath, busErr *dbus.Error) { - m.batteriesMu.Lock() - - batteries = make([]dbus.ObjectPath, len(m.batteries)) - idx := 0 - for _, bat := range m.batteries { - batteries[idx] = bat.getObjPath() - idx++ - } - - m.batteriesMu.Unlock() - return batteries, nil -} - -func (m *Manager) refreshBatteries() { - logger.Debug("RefreshBatteries") - m.batteriesMu.Lock() - for _, bat := range m.batteries { - bat.Refresh() - } - m.batteriesMu.Unlock() -} - -func (m *Manager) RefreshBatteries() *dbus.Error { - m.refreshBatteries() - return nil -} - -func (m *Manager) RefreshMains() *dbus.Error { - logger.Debug("RefreshMains") - if m.ac == nil { - return nil - } - - device := m.ac.newDevice() - if device == nil { - logger.Warning("RefreshMains: ac.newDevice failed") - return nil - } - m.refreshAC(device) - return nil -} - -func (m *Manager) Refresh() *dbus.Error { - err := m.RefreshMains() - if err != nil { - return err - } - err = m.RefreshBatteries() - if err != nil { - return err - } - return nil -} - -func (m *Manager) SetCpuBoost(enabled bool) *dbus.Error { - m.setPropCpuBoost(enabled) - return nil -} - -func (m *Manager) SetCpuGovernor(governor string) *dbus.Error { - m.setPropCpuGovernor(governor) - return nil -} - -func (m *Manager) SetMode(mode string) *dbus.Error { - if m.Mode == mode { - return dbusutil.ToError(errors.New("repeat set mode")) - } - logger.Info(" SetMode mode : ", mode) - if !_validPowerModeArray.Contains(mode) { - return dbusutil.ToError(fmt.Errorf("PowerMode %q mode is not supported", mode)) - } - - // 手动(外部请求)切换到节能模式,或节能模式切换到其他模式时,关闭电池自动节能和低电量自动节能 - if ddePowerSave == m.Mode || ddePowerSave == mode { - m.PropsMu.Lock() - m.updatePowerSavingState(false) - m.PropsMu.Unlock() - } - m.doSetMode(mode) - return nil -} - -func (m *Manager) LockCpuFreq(governor string, lockTime int32) *dbus.Error { - // TODO 改用tlp - // currentGovernor, err := m.cpus.GetGovernor() - // if err != nil { - // return dbusutil.ToError(err) - // } - // - // // change cpu governor - // if governor != currentGovernor { - // err = m.cpus.SetGovernor(governor, false) - // if err != nil { - // return dbusutil.ToError(err) - // } - // - // time.AfterFunc(time.Second*time.Duration(lockTime), func() { - // err := m.cpus.SetGovernor(currentGovernor, false) - // if err != nil { - // logger.Warningf("rewrite cpu scaling_governor file failed:%v", err) - // } - // }) - // } - - return nil -} diff --git a/system/power/battery.go b/system/power1/battery.go similarity index 99% rename from system/power/battery.go rename to system/power1/battery.go index 92d2b7b11..57bc340e7 100644 --- a/system/power/battery.go +++ b/system/power1/battery.go @@ -10,7 +10,7 @@ import ( "sync" "time" - dbus "github.com/godbus/dbus" + dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-api/powersupply/battery" gudev "github.com/linuxdeepin/go-gir/gudev-1.0" "github.com/linuxdeepin/go-lib/dbusutil" diff --git a/system/power/battery_display.go b/system/power1/battery_display.go similarity index 100% rename from system/power/battery_display.go rename to system/power1/battery_display.go diff --git a/system/power/battery_display_test.go b/system/power1/battery_display_test.go similarity index 100% rename from system/power/battery_display_test.go rename to system/power1/battery_display_test.go diff --git a/system/power/battery_history.go b/system/power1/battery_history.go similarity index 100% rename from system/power/battery_history.go rename to system/power1/battery_history.go diff --git a/system/power/battery_history_test.go b/system/power1/battery_history_test.go similarity index 100% rename from system/power/battery_history_test.go rename to system/power1/battery_history_test.go diff --git a/system/power/battery_test.go b/system/power1/battery_test.go similarity index 100% rename from system/power/battery_test.go rename to system/power1/battery_test.go diff --git a/system/power1/daemon.go b/system/power1/daemon.go new file mode 100644 index 000000000..8ee4406ce --- /dev/null +++ b/system/power1/daemon.go @@ -0,0 +1,193 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package power + +import ( + "sync" + "time" + + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/log" +) + +var logger = log.NewLogger("daemon/system/power") + +func init() { + loader.Register(NewDaemon(logger)) +} + +type Daemon struct { + *loader.ModuleBase + manager *Manager +} + +func NewDaemon(logger *log.Logger) *Daemon { + daemon := new(Daemon) + daemon.ModuleBase = loader.NewModuleBase("power", daemon, logger) + return daemon +} + +func (d *Daemon) GetDependencies() []string { + return []string{} +} + +func (d *Daemon) Start() (err error) { + service := loader.GetService() + d.manager, err = newManager(service) + if err != nil { + return + } + + d.manager.batteriesMu.Lock() + for _, bat := range d.manager.batteries { + err := service.Export(bat.getObjPath(), bat) + if err != nil { + logger.Warning("failed to export battery:", err) + } + } + d.manager.batteriesMu.Unlock() + serverObj, err := service.NewServerObject(dbusPath, d.manager) + if err != nil { + return + } + err = serverObj.ConnectChanged(d.manager, "PowerSavingModeAuto", func(change *dbusutil.PropertyChanged) { + d.manager.updatePowerMode(false) // PowerSavingModeAuto change + err := d.manager.saveDsgConfig("PowerSavingModeAuto") + if err != nil { + logger.Warning(err) + } + }) + if err != nil { + logger.Warning(err) + } + + err = serverObj.ConnectChanged(d.manager, "PowerSavingModeEnabled", func(change *dbusutil.PropertyChanged) { + enabled := change.Value.(bool) + d.manager.PropsMu.Lock() + d.manager.updatePowerSavingState(false) + d.manager.PropsMu.Unlock() + // 历史版本只有节能和平衡之间的切换 + if enabled { + d.manager.doSetMode(ddePowerSave) + } else { + d.manager.doSetMode(ddeBalance) + } + err := d.manager.saveDsgConfig("PowerSavingModeEnabled") + if err != nil { + logger.Warning(err) + } + }) + if err != nil { + logger.Warning(err) + } + + // 属性改变后的回调函数 + err = serverObj.ConnectChanged(d.manager, "PowerSavingModeAutoWhenBatteryLow", func(change *dbusutil.PropertyChanged) { + d.manager.refreshBatteryDisplay() + d.manager.updatePowerMode(false) // PowerSavingModeAutoWhenBatteryLow change + err := d.manager.saveDsgConfig("PowerSavingModeAutoWhenBatteryLow") + if err != nil { + logger.Warning(err) + } + }) + if err != nil { + logger.Warning(err) + } + + err = serverObj.ConnectChanged(d.manager, "PowerSavingModeBrightnessDropPercent", func(change *dbusutil.PropertyChanged) { + err := d.manager.saveDsgConfig("PowerSavingModeBrightnessDropPercent") + if err != nil { + logger.Warning(err) + } + }) + if err != nil { + logger.Warning(err) + } + + if err != nil { + logger.Warning(err) + } + if d.manager.enablePerformanceInBoot() { + var once sync.Once + var handlerId dbusutil.SignalHandlerId + var highTimer *time.Timer + handlerId, err = d.manager.displayManager.ConnectSessionAdded(func(session dbus.ObjectPath) { + // 登录后两分钟内高性能,两分钟后修改回原有的mode + once.Do(func() { + highTimer = time.AfterFunc(time.Minute*2, func() { + logger.Infof(" ## time.AfterFunc 2 min manager.Mod : %s", d.manager.Mode) + d.manager.IsInBootTime = false + // ② 超时后恢复流程 + d.manager.doSetMode(d.manager.Mode) + d.manager.displayManager.RemoveHandler(handlerId) + err = serverObj.SetReadCallback(d.manager, "Mode", nil) + if err != nil { + logger.Warning(err) + } + }) + }) + + }) + if err != nil { + logger.Warning(err) + } + // ③ 查看mode时, 恢复当前设置 + err = serverObj.SetReadCallback(d.manager, "Mode", func(read *dbusutil.PropertyRead) *dbus.Error { + logger.Info("change to record mode") + if highTimer != nil { + highTimer.Stop() + } + defer func() { + err := serverObj.SetReadCallback(d.manager, "Mode", nil) + if err != nil { + logger.Warning(err) + } + }() + d.manager.IsInBootTime = false + d.manager.doSetMode(d.manager.Mode) + logger.Infof(" SetReadCallback manager.Mode : %s", d.manager.Mode) + return nil + }) + } + if err != nil { + logger.Warning(err) + } + + err = serverObj.Export() + if err != nil { + logger.Warning(err) + return + } + + err = service.RequestName(dbusServiceName) + return +} + +func (d *Daemon) Stop() error { + if d.manager == nil { + return nil + } + service := loader.GetService() + + d.manager.batteriesMu.Lock() + for _, bat := range d.manager.batteries { + err := service.StopExport(bat) + if err != nil { + logger.Warning(err) + } + } + d.manager.batteriesMu.Unlock() + + err := service.StopExport(d.manager) + if err != nil { + logger.Warning(err) + } + + d.manager.destroy() + d.manager = nil + return nil +} diff --git a/system/power/exported_methods_auto.go b/system/power1/exported_methods_auto.go similarity index 100% rename from system/power/exported_methods_auto.go rename to system/power1/exported_methods_auto.go diff --git a/system/power/lid_switch.go b/system/power1/lid_switch.go similarity index 100% rename from system/power/lid_switch.go rename to system/power1/lid_switch.go diff --git a/system/power/lid_switch_common.go b/system/power1/lid_switch_common.go similarity index 93% rename from system/power/lid_switch_common.go rename to system/power1/lid_switch_common.go index 1f30e207b..f0ab749ca 100644 --- a/system/power/lid_switch_common.go +++ b/system/power1/lid_switch_common.go @@ -19,8 +19,8 @@ import ( "syscall" "unsafe" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" upower "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.upower" + ofdbus "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.dbus" ) const ( @@ -47,7 +47,7 @@ func OFF(x int) int { return x % bitsPerLong } -//#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1) +// #define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1) func testBit(bit int, array []int) bool { v := (array[LONG(bit)] >> uint(OFF(bit))) & 1 return v != 0 @@ -81,7 +81,8 @@ type InputEvent struct { } // Get a useful description for an input event. Example: -// event at 1347905437.435795, code 01, type 02, val 02 +// +// event at 1347905437.435795, code 01, type 02, val 02 func (ev *InputEvent) String() string { return fmt.Sprintf("event at %d.%d, code %02d, type %02d, val %02d", ev.Time.Sec, ev.Time.Usec, ev.Code, ev.Type, ev.Value) @@ -192,7 +193,13 @@ func (m *Manager) initLidSwitchByUPower() error { if err != nil { return err } - m.HasLidSwitch = true + + hasLidSwitch, err := uPowerObj.LidIsPresent().Get(0) + if err != nil { + return err + } + + m.HasLidSwitch = hasLidSwitch return nil } diff --git a/system/power/lid_switch_common_test.go b/system/power1/lid_switch_common_test.go similarity index 100% rename from system/power/lid_switch_common_test.go rename to system/power1/lid_switch_common_test.go diff --git a/system/power/lid_switch_sw.go b/system/power1/lid_switch_sw.go similarity index 100% rename from system/power/lid_switch_sw.go rename to system/power1/lid_switch_sw.go diff --git a/system/power1/manager.go b/system/power1/manager.go new file mode 100644 index 000000000..3d60b42d1 --- /dev/null +++ b/system/power1/manager.go @@ -0,0 +1,755 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package power + +import ( + "encoding/json" + "errors" + "io/ioutil" + "os" + "sync" + "time" + + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-api/powersupply" + "github.com/linuxdeepin/dde-api/powersupply/battery" + ConfigManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" + DisplayManager "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.DisplayManager" + gudev "github.com/linuxdeepin/go-gir/gudev-1.0" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/strv" +) + +const ( + dsettingsAppID = "org.deepin.dde.daemon" + dsettingsPowerName = "org.deepin.dde.daemon.power" + dsettingsPowerSavingModeEnabled = "powerSavingModeEnabled" + dsettingsPowerSavingModeAuto = "powerSavingModeAuto" + dsettingsPowerSavingModeAutoWhenBatteryLow = "powerSavingModeAutoWhenBatteryLow" + dsettingsPowerSavingModeBrightnessDropPercent = "powerSavingModeBrightnessDropPercent" + dsettingsPowerMappingConfig = "powerMappingConfig" + dsettingsMode = "mode" +) + +type supportMode struct { + Balance bool `json:"balance"` + Performace bool `json:"performace"` + PowerSave bool `json:"powersave"` +} + +//go:generate dbusutil-gen -type Manager,Battery -import github.com/linuxdeepin/dde-api/powersupply/battery manager.go battery.go +//go:generate dbusutil-gen em -type Manager,Battery + +// https://www.kernel.org/doc/Documentation/power/power_supply_class.txt +type Manager struct { + service *dbusutil.Service + systemSigLoop *dbusutil.SignalLoop + batteries map[string]*Battery + batteriesMu sync.Mutex + ac *AC + gudevClient *gudev.Client + dsgPower ConfigManager.Manager + // 电池是否电量低 + batteryLow bool + // 初始化是否完成 + initDone bool + + // INFO: pstate中,可选项是performance balance_performance balance_power power + + PropsMu sync.RWMutex + OnBattery bool + HasLidSwitch bool + // battery display properties: + HasBattery bool + BatteryPercentage float64 + BatteryStatus battery.Status + BatteryTimeToEmpty uint64 + BatteryTimeToFull uint64 + // 电池容量 + BatteryCapacity float64 + + // 开启和关闭节能模式 + PowerSavingModeEnabled bool `prop:"access:rw"` + + // 自动切换节能模式,依据为是否插拔电源 + PowerSavingModeAuto bool `prop:"access:rw"` + + // 低电量时自动开启 + PowerSavingModeAutoWhenBatteryLow bool `prop:"access:rw"` + + // 开启节能模式时降低亮度的百分比值 + PowerSavingModeBrightnessDropPercent uint32 `prop:"access:rw"` + + // 开启节能模式时保存的数据 + PowerSavingModeBrightnessData string `prop:"access:rw"` + + // CPU频率调节模式,支持powersave和performance + CpuGovernor string + + // CPU频率增强是否开启 + CpuBoost bool + + // 是否支持Boost + IsHighPerformanceSupported bool + + // 是否支持平衡模式 + IsBalanceSupported bool + + // 是否支持节能模式 + IsPowerSaveSupported bool + + // 是否支持切换性能模式 + SupportSwitchPowerMode bool `prop:"access:rw"` + // 当前模式 + Mode string + + // 是否在启动阶段,启动阶段不允许调节亮度; 若在启动阶段切换模式后(切节能模式降低亮度),可以调节亮度. + IsInBootTime bool + + // 上次非低电量时的模式 + lastMode string + + displayManager DisplayManager.DisplayManager + + isLowBatteryMode bool + // nolint + signals *struct { + BatteryDisplayUpdate struct { + timestamp int64 + } + + BatteryAdded struct { + path dbus.ObjectPath + } + + BatteryRemoved struct { + path dbus.ObjectPath + } + + LidClosed struct{} + LidOpened struct{} + } +} + +const ( + ddePowerSave = "powersave" + ddeBalance = "balance" + ddePerformance = "performance" + ddeLowBattery = "lowBattery" // 内部使用,在对外暴露的时候,会切换成powersave +) + +var _allPowerModeArray = []string{ + ddePowerSave, + ddeBalance, + ddePerformance, + ddeLowBattery, +} + +var _validPowerModeArray = strv.Strv{ + ddePowerSave, + ddeBalance, + ddePerformance, + ddeLowBattery, +} + +func newManager(service *dbusutil.Service) (*Manager, error) { + m := &Manager{ + service: service, + BatteryPercentage: 100, + lastMode: ddeBalance, + IsHighPerformanceSupported: true, + IsBalanceSupported: true, + IsPowerSaveSupported: true, + CpuBoost: true, + } + + err := m.init() + if err != nil { + m.destroy() + return nil, err + } + + return m, nil +} + +type AC struct { + gudevClient *gudev.Client + sysfsPath string +} + +func newAC(manager *Manager, device *gudev.Device) *AC { + sysfsPath := device.GetSysfsPath() + return &AC{ + gudevClient: manager.gudevClient, + sysfsPath: sysfsPath, + } +} + +func (ac *AC) newDevice() *gudev.Device { + return ac.gudevClient.QueryBySysfsPath(ac.sysfsPath) +} + +func (m *Manager) refreshAC(ac *gudev.Device) { // 拔插电源时候触发 + online := ac.GetPropertyAsBoolean("POWER_SUPPLY_ONLINE") + logger.Debug("ac online:", online) + onBattery := !online + + m.PropsMu.Lock() + m.setPropOnBattery(onBattery) + m.PropsMu.Unlock() + // 根据OnBattery的状态,修改节能模式 + m.updatePowerMode(false) // refreshAC +} + +func (m *Manager) initAC(devices []*gudev.Device) { + var ac *gudev.Device + for _, dev := range devices { + if powersupply.IsMains(dev) { + ac = dev + break + } + } + if ac != nil { + m.refreshAC(ac) + m.ac = newAC(m, ac) + } +} + +func (m *Manager) init() error { + m.systemSigLoop = dbusutil.NewSignalLoop(m.service.Conn(), 10) + m.systemSigLoop.Start() + err := m.initDsgConfig() + if err != nil { + logger.Warning(err) + } + + subsystems := []string{"power_supply", "input"} + m.gudevClient = gudev.NewClient(subsystems) + if m.gudevClient == nil { + return errors.New("gudevClient is nil") + } + + m.initLidSwitch() + devices := powersupply.GetDevices(m.gudevClient) + + m.initAC(devices) + m.initBatteries(devices) + for _, dev := range devices { + dev.Unref() + } + + m.gudevClient.Connect("uevent", m.handleUEvent) + m.initDone = true + + m.updatePowerMode(true) // init + + m.displayManager = DisplayManager.NewDisplayManager(m.service.Conn()) + m.displayManager.InitSignalExt(m.systemSigLoop, true) + return nil +} + +func (m *Manager) initDsgConfig() error { + logger.Info("org.deepin.dde.Power1 module start init dconfig.") + // dsg 配置 + ds := ConfigManager.NewConfigManager(m.service.Conn()) + + dsPowerPath, err := ds.AcquireManager(0, dsettingsAppID, dsettingsPowerName, "") + if err != nil { + return err + } + dsPower, err := ConfigManager.NewManager(m.service.Conn(), dsPowerPath) + if err != nil { + return err + } + m.dsgPower = dsPower + + cfg := loadConfigSafe() + if cfg != nil { + // 将config.json中的配置完成初始化 + m.PowerSavingModeEnabled = cfg.PowerSavingModeEnabled // 开启和关闭节能模式 + m.PowerSavingModeAuto = cfg.PowerSavingModeAuto // 自动切换节能模式,依据为是否插拔电源 + m.PowerSavingModeAutoWhenBatteryLow = cfg.PowerSavingModeAutoWhenBatteryLow // 低电量时自动开启 + m.PowerSavingModeBrightnessDropPercent = cfg.PowerSavingModeBrightnessDropPercent // 开启节能模式时降低亮度的百分比值 + m.Mode = cfg.Mode + migrateErr := m.migrateFromCurrentConfigsToDsg() + if migrateErr != nil { + logger.Error("migrateFromCurrentConfigsToDsg failed, err:", migrateErr) + } + } + + getPowerSavingModeAuto := func(init bool) { + data, err := dsPower.Value(0, dsettingsPowerSavingModeAuto) + if err != nil { + logger.Warning(err) + return + } + + if init { + m.PowerSavingModeAuto = data.Value().(bool) + return + } + + m.setPropPowerSavingModeAuto(data.Value().(bool)) + } + + getPowerSavingModeEnabled := func(init bool) { + data, err := dsPower.Value(0, dsettingsPowerSavingModeEnabled) + if err != nil { + logger.Warning(err) + return + } + + if init { + m.PowerSavingModeEnabled = data.Value().(bool) + return + } + + m.setPropPowerSavingModeEnabled(data.Value().(bool)) + } + + getPowerSavingModeAutoWhenBatteryLow := func(init bool) { + data, err := dsPower.Value(0, dsettingsPowerSavingModeAutoWhenBatteryLow) + if err != nil { + logger.Warning(err) + return + } + + if init { + m.PowerSavingModeAutoWhenBatteryLow = data.Value().(bool) + return + } + + m.setPropPowerSavingModeAutoWhenBatteryLow(data.Value().(bool)) + } + + getPowerSavingModeBrightnessDropPercent := func(init bool) { + data, err := dsPower.Value(0, dsettingsPowerSavingModeBrightnessDropPercent) + if err != nil { + logger.Warning(err) + return + } + + if init { + switch vv := data.Value().(type) { + case float64: + m.PowerSavingModeBrightnessDropPercent = uint32(vv) + case int64: + m.PowerSavingModeBrightnessDropPercent = uint32(vv) + default: + logger.Warning("type is wrong! type : ", vv) + } + + return + } + + ret := false + switch vv := data.Value().(type) { + case float64: + ret = m.setPropPowerSavingModeBrightnessDropPercent(uint32(vv)) + case int64: + ret = m.setPropPowerSavingModeBrightnessDropPercent(uint32(vv)) + default: + logger.Warning("type is wrong! type : ", vv) + } + if ret { + logger.Info("Set power saving mode brightness drop percent", m.PowerSavingModeBrightnessDropPercent) + } + } + + getMode := func(init bool) string { + ret, err := dsPower.Value(0, dsettingsMode) + if err != nil { + logger.Warning(err) + return ddeBalance + } + + value := ret.Value().(string) + logger.Infof("value:%v", value) + // dsg更新配置后,校验mode有效性 + if !_validPowerModeArray.Contains(value) { + value = ddeBalance + _ = m.setDsgData(dsettingsMode, value, m.dsgPower) // 将修正后的数据回写dconfig + } + if init { + logger.Info("init ") + m.Mode = value + return value + } + m.setPropMode(value) + return value + } + + getPowerMappingConfig := func() { + data, err := dsPower.Value(0, dsettingsPowerMappingConfig) + if err != nil { + logger.Warning(err) + return + } + config := make(map[string]powerConfig) + configStr := data.Value().(string) + err = json.Unmarshal([]byte(configStr), &config) + if err != nil { + logger.Warning(err) + return + } + + for _, mode := range _allPowerModeArray { + c, ok := config[mode] + if ok { + _powerConfigMap[mode].DSPCConfig = c.DSPCConfig + } + } + } + + getPowerSavingModeAuto(true) + getPowerSavingModeEnabled(true) + getPowerSavingModeAutoWhenBatteryLow(true) + getPowerSavingModeBrightnessDropPercent(true) + getMode(true) + getPowerMappingConfig() + + dsPower.InitSignalExt(m.systemSigLoop, true) + _, _ = dsPower.ConnectValueChanged(func(key string) { + logger.Info("dconfig org.deepin.dde.daemon.power valueChanged, key : ", key) + switch key { + case dsettingsPowerSavingModeAuto: + getPowerSavingModeAuto(false) + case dsettingsPowerSavingModeEnabled: + getPowerSavingModeEnabled(false) + case dsettingsPowerSavingModeAutoWhenBatteryLow: + getPowerSavingModeAutoWhenBatteryLow(false) + case dsettingsPowerSavingModeBrightnessDropPercent: + getPowerSavingModeBrightnessDropPercent(false) + case dsettingsMode: + oldMode := m.Mode + newMode := getMode(false) + if oldMode == newMode { + return + } + // 手动(外部请求)切换到节能模式,或节能模式切换到其他模式时,关闭电池自动节能和低电量自动节能 + if ddePowerSave == oldMode || ddePowerSave == newMode { + m.PropsMu.Lock() + m.updatePowerSavingState(false) + m.PropsMu.Unlock() + } + m.doSetMode(newMode) + return + case dsettingsPowerMappingConfig: + getPowerMappingConfig() + default: + logger.Debug("Not process. valueChanged, key : ", key) + } + m.updatePowerMode(false) // dconfig change + }) + + return nil +} + +func (m *Manager) handleUEvent(client *gudev.Client, action string, device *gudev.Device) { + logger.Debug("on uevent action:", action) + defer device.Unref() + + switch action { + case "change": + if powersupply.IsMains(device) { + if m.ac == nil { + m.ac = newAC(m, device) + } else if m.ac.sysfsPath != device.GetSysfsPath() { + logger.Warning("found another AC", device.GetSysfsPath()) + return + } + + // now m.ac != nil, and sysfsPath equal + m.refreshAC(device) + time.AfterFunc(1*time.Second, m.refreshBatteries) + time.AfterFunc(3*time.Second, m.refreshBatteries) + // 电源状态变更时,需要一段时间才能稳定,因此在1分钟内,每隔5秒刷新一次,保证数据及时更新 + for i := 1; i <= 12; i++ { + time.AfterFunc(time.Duration(i*5)*time.Second, m.refreshBatteries) + } + } else if powersupply.IsSystemBattery(device) { + m.addAndExportBattery(device) + } + case "add": + if powersupply.IsSystemBattery(device) { + m.addAndExportBattery(device) + } + // ignore add mains + + case "remove": + if powersupply.IsSystemBattery(device) { + m.removeBattery(device) + } + } + +} + +func (m *Manager) initBatteries(devices []*gudev.Device) { + m.batteries = make(map[string]*Battery) + for _, dev := range devices { + m.addBattery(dev) + } + logger.Debugf("initBatteries done %#v", m.batteries) +} + +func (m *Manager) addAndExportBattery(dev *gudev.Device) { + bat, added := m.addBattery(dev) + if added { + err := m.service.Export(bat.getObjPath(), bat) + if err == nil { + m.emitBatteryAdded(bat) + } else { + logger.Warning("failed to export battery:", err) + } + } +} + +func (m *Manager) addBattery(dev *gudev.Device) (*Battery, bool) { + logger.Debug("addBattery dev:", dev) + if !powersupply.IsSystemBattery(dev) { + return nil, false + } + + sysfsPath := dev.GetSysfsPath() + logger.Debug(sysfsPath) + + m.batteriesMu.Lock() + bat, ok := m.batteries[sysfsPath] + m.batteriesMu.Unlock() + if ok { + logger.Debugf("add battery failed , sysfsPath exists %q", sysfsPath) + bat.Refresh() + return bat, false + } + + bat = newBattery(m, dev) + if bat == nil { + logger.Debugf("add batteries failed, sysfsPath %q, new battery failed", sysfsPath) + return nil, false + } + + m.batteriesMu.Lock() + m.batteries[sysfsPath] = bat + m.refreshBatteryDisplay() + m.batteriesMu.Unlock() + bat.setRefreshDoneCallback(m.refreshBatteryDisplay) + return bat, true +} + +// removeBattery remove the battery from Manager.batteries, and stop export it. +func (m *Manager) removeBattery(dev *gudev.Device) { + sysfsPath := dev.GetSysfsPath() + + m.batteriesMu.Lock() + bat, ok := m.batteries[sysfsPath] + m.batteriesMu.Unlock() + + if ok { + logger.Info("removeBattery", sysfsPath) + m.batteriesMu.Lock() + delete(m.batteries, sysfsPath) + m.refreshBatteryDisplay() + m.batteriesMu.Unlock() + + err := m.service.StopExport(bat) + if err != nil { + logger.Warning(err) + } + m.emitBatteryRemoved(bat) + + bat.destroy() + } else { + logger.Warning("removeBattery failed: invalid sysfsPath ", sysfsPath) + } +} + +func (m *Manager) emitBatteryAdded(bat *Battery) { + err := m.service.Emit(m, "BatteryAdded", bat.getObjPath()) + if err != nil { + logger.Warning(err) + } +} + +func (m *Manager) emitBatteryRemoved(bat *Battery) { + err := m.service.Emit(m, "BatteryRemoved", bat.getObjPath()) + if err != nil { + logger.Warning(err) + } +} + +func (m *Manager) destroy() { + logger.Debug("destroy") + m.batteriesMu.Lock() + for _, bat := range m.batteries { + bat.destroy() + } + m.batteries = nil + m.batteriesMu.Unlock() + + if m.gudevClient != nil { + m.gudevClient.Unref() + m.gudevClient = nil + } + m.systemSigLoop.Stop() +} + +const configFile = "/var/lib/dde-daemon/power/config.json" + +type Config struct { + PowerSavingModeEnabled bool + PowerSavingModeAuto bool + PowerSavingModeAutoWhenBatteryLow bool + PowerSavingModeBrightnessDropPercent uint32 + Mode string +} + +func loadConfig() (*Config, error) { + content, err := ioutil.ReadFile(configFile) + if err != nil { + return nil, err + } + var cfg Config + err = json.Unmarshal(content, &cfg) + if err != nil { + return nil, err + } + + return &cfg, nil +} + +func loadConfigSafe() *Config { + cfg, err := loadConfig() + if err != nil { + // ignore not exist error + if !os.IsNotExist(err) { + logger.Warning(err) + } + return nil + } + // 新增字段后第一次启动时,缺少两个新增字段的json,导致亮度下降百分比字段默认为0,导致与默认值不符,需要处理 + // 低电量自动待机字段的默认值为false,不会导致错误影响 + // 正常情况下该字段范围为10-40,只有在该情况下会出现0的可能 + if cfg.PowerSavingModeBrightnessDropPercent == 0 { + cfg.PowerSavingModeBrightnessDropPercent = 20 + } + + if cfg.Mode == "" { + cfg.Mode = ddeBalance + } + return cfg +} + +func (m *Manager) migrateFromCurrentConfigsToDsg() error { + err := m.saveDsgConfig("") + if err != nil { + logger.Warning("saveDsgConfig failed", err) + return err + } + + // 迁移完成后,删除本地配置文件 + err = os.Remove(configFile) + if err != nil { + logger.Warning("delete local configs file failed", err) + return err + } + + return nil +} + +func (m *Manager) saveDsgConfig(value string) (err error) { + switch value { + case "PowerSavingModeBrightnessDropPercent": + err = m.setDsgData(dsettingsPowerSavingModeBrightnessDropPercent, int64(m.PowerSavingModeBrightnessDropPercent), m.dsgPower) + if err != nil { + return err + } + case "PowerSavingModeAutoWhenBatteryLow": + err = m.setDsgData(dsettingsPowerSavingModeAutoWhenBatteryLow, m.PowerSavingModeAutoWhenBatteryLow, m.dsgPower) + if err != nil { + return err + } + case "PowerSavingModeEnabled": + err = m.setDsgData(dsettingsPowerSavingModeEnabled, m.PowerSavingModeEnabled, m.dsgPower) + if err != nil { + return err + } + case "PowerSavingModeAuto": + err = m.setDsgData(dsettingsPowerSavingModeAuto, m.PowerSavingModeAuto, m.dsgPower) + if err != nil { + return err + } + case "": + err = m.setDsgData(dsettingsPowerSavingModeBrightnessDropPercent, int64(m.PowerSavingModeBrightnessDropPercent), m.dsgPower) + if err != nil { + return err + } + err = m.setDsgData(dsettingsPowerSavingModeAutoWhenBatteryLow, m.PowerSavingModeAutoWhenBatteryLow, m.dsgPower) + if err != nil { + return err + } + err = m.setDsgData(dsettingsPowerSavingModeEnabled, m.PowerSavingModeEnabled, m.dsgPower) + if err != nil { + return err + } + err = m.setDsgData(dsettingsPowerSavingModeAuto, m.PowerSavingModeAuto, m.dsgPower) + if err != nil { + return err + } + } + + return m.setDsgData(dsettingsMode, m.Mode, m.dsgPower) +} + +func (m *Manager) doSetMode(mode string) { + logger.Info(" doSetMode, mode : ", mode) + if !_validPowerModeArray.Contains(mode) { + logger.Errorf("PowerMode %q mode is not supported", mode) + return + } + if mode == ddePowerSave && m.batteryLow { + mode = ddeLowBattery + } + fixMode := mode + if fixMode == ddeLowBattery { + fixMode = ddePowerSave + m.isLowBatteryMode = true + } else { + m.isLowBatteryMode = false + } + modeChanged := m.setPropMode(fixMode) + if modeChanged { + logger.Info("Set power mode", fixMode) + m.IsInBootTime = false + } + + // 处理ddeLowBattery情况,所以每次都要设置 + go m.setDSPCState(_powerConfigMap[mode].DSPCConfig) // doSetMode + m.setPropPowerSavingModeEnabled(_powerConfigMap[mode].PowerSavingModeEnabled) + + if m.lastMode != mode && mode != ddePowerSave && mode != ddeLowBattery { + m.lastMode = mode + } + if modeChanged { + _ = m.setDsgData(dsettingsMode, fixMode, m.dsgPower) + } +} + +// 需求: 为了提高启动速度,登录前将性能模式设置为performance +// ① 为了减小耦合性,仅写文件(doSetCpuGovernor),不修改后端相关属性 +func (m *Manager) enablePerformanceInBoot() bool { + if m.Mode == ddePerformance { + return false + } + displaySessions, err := m.displayManager.Sessions().Get(0) + if err != nil { + logger.Warning(err) + } else if len(displaySessions) > 0 { + return false + } + go m.setDSPCState(DSPCPerformance) + logger.Info("enablePerformanceInBoot performance") + m.IsInBootTime = true + return true +} diff --git a/system/power1/manager_ifc.go b/system/power1/manager_ifc.go new file mode 100644 index 000000000..73b85880e --- /dev/null +++ b/system/power1/manager_ifc.go @@ -0,0 +1,132 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package power + +import ( + "errors" + "fmt" + + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +const ( + dbusServiceName = "org.deepin.dde.Power1" + dbusPath = "/org/deepin/dde/Power1" + dbusInterface = dbusServiceName +) + +func (*Manager) GetInterfaceName() string { + return dbusInterface +} + +func (m *Manager) GetBatteries() (batteries []dbus.ObjectPath, busErr *dbus.Error) { + m.batteriesMu.Lock() + + batteries = make([]dbus.ObjectPath, len(m.batteries)) + idx := 0 + for _, bat := range m.batteries { + batteries[idx] = bat.getObjPath() + idx++ + } + + m.batteriesMu.Unlock() + return batteries, nil +} + +func (m *Manager) refreshBatteries() { + logger.Debug("RefreshBatteries") + m.batteriesMu.Lock() + for _, bat := range m.batteries { + bat.Refresh() + } + m.batteriesMu.Unlock() +} + +func (m *Manager) RefreshBatteries() *dbus.Error { + m.refreshBatteries() + return nil +} + +func (m *Manager) RefreshMains() *dbus.Error { + logger.Debug("RefreshMains") + if m.ac == nil { + return nil + } + + device := m.ac.newDevice() + if device == nil { + logger.Warning("RefreshMains: ac.newDevice failed") + return nil + } + m.refreshAC(device) + return nil +} + +func (m *Manager) Refresh() *dbus.Error { + err := m.RefreshMains() + if err != nil { + return err + } + err = m.RefreshBatteries() + if err != nil { + return err + } + return nil +} + +func (m *Manager) SetCpuBoost(enabled bool) *dbus.Error { + m.setPropCpuBoost(enabled) + return nil +} + +func (m *Manager) SetCpuGovernor(governor string) *dbus.Error { + m.setPropCpuGovernor(governor) + return nil +} + +func (m *Manager) SetMode(mode string) *dbus.Error { + if m.Mode == mode { + return dbusutil.ToError(errors.New("repeat set mode")) + } + logger.Info(" SetMode mode : ", mode) + if !_validPowerModeArray.Contains(mode) { + return dbusutil.ToError(fmt.Errorf("PowerMode %q mode is not supported", mode)) + } + + // 手动(外部请求)切换到节能模式,或节能模式切换到其他模式时,关闭电池自动节能和低电量自动节能 + if ddePowerSave == m.Mode || ddePowerSave == mode { + m.PropsMu.Lock() + m.updatePowerSavingState(false) + m.PropsMu.Unlock() + } + m.doSetMode(mode) + return nil +} + +func (m *Manager) LockCpuFreq(governor string, lockTime int32) *dbus.Error { + // TODO 改用tlp + // currentGovernor, err := m.cpus.GetGovernor() + // if err != nil { + // return dbusutil.ToError(err) + // } + // + // // change cpu governor + // if governor != currentGovernor { + // err = m.cpus.SetGovernor(governor, false) + // if err != nil { + // return dbusutil.ToError(err) + // } + // + // time.AfterFunc(time.Second*time.Duration(lockTime), func() { + // err := m.cpus.SetGovernor(currentGovernor, false) + // if err != nil { + // logger.Warningf("rewrite cpu scaling_governor file failed:%v", err) + // } + // }) + // } + + return nil +} diff --git a/system/power/manager_powersave.go b/system/power1/manager_powersave.go similarity index 100% rename from system/power/manager_powersave.go rename to system/power1/manager_powersave.go diff --git a/system/power/power_dbusutil.go b/system/power1/power_dbusutil.go similarity index 100% rename from system/power/power_dbusutil.go rename to system/power1/power_dbusutil.go diff --git a/system/power/power_key_edit.go b/system/power1/power_key_edit.go similarity index 96% rename from system/power/power_key_edit.go rename to system/power1/power_key_edit.go index af5ab6fe1..35ab3cf78 100644 --- a/system/power/power_key_edit.go +++ b/system/power1/power_key_edit.go @@ -7,7 +7,7 @@ package power import ( "errors" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" ConfigManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" "github.com/linuxdeepin/go-lib/utils" ) diff --git a/system/power/power_key_edit_test.go b/system/power1/power_key_edit_test.go similarity index 99% rename from system/power/power_key_edit_test.go rename to system/power1/power_key_edit_test.go index ed7d9231d..f81cb7d64 100644 --- a/system/power/power_key_edit_test.go +++ b/system/power1/power_key_edit_test.go @@ -30,4 +30,4 @@ func Test_interfaceToArrayString(t *testing.T) { assert.Equal(t, arr, d.result) } -} \ No newline at end of file +} diff --git a/system/power/power_test.go b/system/power1/power_test.go similarity index 94% rename from system/power/power_test.go rename to system/power1/power_test.go index c61acc830..a6a9b415b 100644 --- a/system/power/power_test.go +++ b/system/power1/power_test.go @@ -7,7 +7,7 @@ package power import ( "testing" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/stretchr/testify/assert" ) diff --git a/system/power/testdata/scaling_available_governors b/system/power1/testdata/scaling_available_governors similarity index 100% rename from system/power/testdata/scaling_available_governors rename to system/power1/testdata/scaling_available_governors diff --git a/system/power/testdata/scaling_governor b/system/power1/testdata/scaling_governor similarity index 100% rename from system/power/testdata/scaling_governor rename to system/power1/testdata/scaling_governor diff --git a/system/power/testdata/scaling_governor2 b/system/power1/testdata/scaling_governor2 similarity index 100% rename from system/power/testdata/scaling_governor2 rename to system/power1/testdata/scaling_governor2 diff --git a/system/power/testdata/setGovernor/scaling_governor b/system/power1/testdata/setGovernor/scaling_governor similarity index 100% rename from system/power/testdata/setGovernor/scaling_governor rename to system/power1/testdata/setGovernor/scaling_governor diff --git a/system/power_manager/daemon.go b/system/power_manager/daemon.go deleted file mode 100644 index f3abdbdc9..000000000 --- a/system/power_manager/daemon.go +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package power_manager - -import ( - "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/dde-daemon/loader" -) - -const ( - dbusServiceName = "com.deepin.daemon.PowerManager" - dbusPath = "/com/deepin/daemon/PowerManager" - dbusInterface = dbusServiceName -) - -var logger = log.NewLogger("daemon/system/powermanager") - -func init() { - loader.Register(NewDaemon(logger)) -} - -type Daemon struct { - *loader.ModuleBase - manager *Manager -} - -func NewDaemon(logger *log.Logger) *Daemon { - daemon := new(Daemon) - daemon.ModuleBase = loader.NewModuleBase("powermanager", daemon, logger) - return daemon -} - -func (d *Daemon) GetDependencies() []string { - return []string{} -} - -func (d *Daemon) Start() (err error) { - service := loader.GetService() - d.manager, err = newManager(service) - if err != nil { - return - } - - err = service.Export(dbusPath, d.manager) - if err != nil { - return - } - - err = service.RequestName(dbusServiceName) - return -} - -func (d *Daemon) Stop() error { - if d.manager == nil { - return nil - } - - d.manager = nil - return nil -} diff --git a/system/power_manager/manager.go b/system/power_manager/manager.go deleted file mode 100644 index 57003dd61..000000000 --- a/system/power_manager/manager.go +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package power_manager - -import ( - "os" - "os/exec" - - "github.com/godbus/dbus" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" - "github.com/linuxdeepin/go-lib/dbusutil" -) - -//go:generate dbusutil-gen em -type Manager -type Manager struct { - service *dbusutil.Service - objLogin login1.Manager - - VirtualMachineName string -} - -func newManager(service *dbusutil.Service) (*Manager, error) { - m := &Manager{ - service: service, - } - err := m.init() - if err != nil { - return nil, err - } - - name, err := detectVirtualMachine() - if err != nil { - logger.Warning(err) - } - - m.setPropVirtualMachineName(name) - - return m, nil -} - -func (*Manager) GetInterfaceName() string { - return dbusInterface -} - -func (m *Manager) init() error { - sysBus, err := dbus.SystemBus() - if err != nil { - logger.Warning(err) - return err - } - - m.objLogin = login1.NewManager(sysBus) - return nil -} - -func (m *Manager) CanShutdown() (can bool, busErr *dbus.Error) { - str, _ := m.objLogin.CanPowerOff(0) - return str == "yes", nil -} - -func (m *Manager) CanReboot() (can bool, busErr *dbus.Error) { - str, _ := m.objLogin.CanReboot(0) - return str == "yes", nil -} - -func (m *Manager) CanSuspend() (can bool, busErr *dbus.Error) { - // 虚拟机屏蔽待机 - if m.VirtualMachineName != "" { - return false, nil - } - _, err := os.Stat("/sys/power/mem_sleep") - if os.IsNotExist(err) { - return false, nil - } - - str, _ := m.objLogin.CanSuspend(0) - return str == "yes", nil -} - -func (m *Manager) CanHibernate() (can bool, busErr *dbus.Error) { - // 虚拟机屏蔽休眠 - if m.VirtualMachineName != "" { - return false, nil - } - str, _ := m.objLogin.CanHibernate(0) - return str == "yes", nil -} - -var autoConfigTargets = []string{ - "suspend.target", - "sleep.target", - "suspend-then-hibernate.target", - "hibernate.target", - "hybrid-sleep.target", -} - -func (m *Manager) maskOnVM(enable bool) { - var oper string - if enable && m.VirtualMachineName != "" { - oper = "mask" - } else { - oper = "unmask" - } - - for _, target := range autoConfigTargets { - logger.Debug("auto mask on virt") - exec.Command("systemctl", oper, target).Run() - } -} diff --git a/system/power_manager1/daemon.go b/system/power_manager1/daemon.go new file mode 100644 index 000000000..a560a58c4 --- /dev/null +++ b/system/power_manager1/daemon.go @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package power_manager + +import ( + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" +) + +const ( + dbusServiceName = "org.deepin.dde.PowerManager1" + dbusPath = "/org/deepin/dde/PowerManager1" + dbusInterface = dbusServiceName +) + +var logger = log.NewLogger("daemon/system/powermanager") + +func init() { + loader.Register(NewDaemon(logger)) +} + +type Daemon struct { + *loader.ModuleBase + manager *Manager +} + +func NewDaemon(logger *log.Logger) *Daemon { + daemon := new(Daemon) + daemon.ModuleBase = loader.NewModuleBase("powermanager", daemon, logger) + return daemon +} + +func (d *Daemon) GetDependencies() []string { + return []string{} +} + +func (d *Daemon) Start() (err error) { + service := loader.GetService() + d.manager, err = newManager(service) + if err != nil { + return + } + + err = service.Export(dbusPath, d.manager) + if err != nil { + return + } + + err = service.RequestName(dbusServiceName) + return +} + +func (d *Daemon) Stop() error { + if d.manager == nil { + return nil + } + + d.manager = nil + return nil +} diff --git a/system/power_manager/exported_methods_auto.go b/system/power_manager1/exported_methods_auto.go similarity index 100% rename from system/power_manager/exported_methods_auto.go rename to system/power_manager1/exported_methods_auto.go diff --git a/system/power_manager1/manager.go b/system/power_manager1/manager.go new file mode 100644 index 000000000..d0b85cba7 --- /dev/null +++ b/system/power_manager1/manager.go @@ -0,0 +1,111 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package power_manager + +import ( + "os" + "os/exec" + + "github.com/godbus/dbus/v5" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +//go:generate dbusutil-gen em -type Manager +type Manager struct { + service *dbusutil.Service + objLogin login1.Manager + + VirtualMachineName string +} + +func newManager(service *dbusutil.Service) (*Manager, error) { + m := &Manager{ + service: service, + } + err := m.init() + if err != nil { + return nil, err + } + + name, err := detectVirtualMachine() + if err != nil { + logger.Warning(err) + } + + m.setPropVirtualMachineName(name) + + return m, nil +} + +func (*Manager) GetInterfaceName() string { + return dbusInterface +} + +func (m *Manager) init() error { + sysBus, err := dbus.SystemBus() + if err != nil { + logger.Warning(err) + return err + } + + m.objLogin = login1.NewManager(sysBus) + return nil +} + +func (m *Manager) CanShutdown() (can bool, busErr *dbus.Error) { + str, _ := m.objLogin.CanPowerOff(0) + return str == "yes", nil +} + +func (m *Manager) CanReboot() (can bool, busErr *dbus.Error) { + str, _ := m.objLogin.CanReboot(0) + return str == "yes", nil +} + +func (m *Manager) CanSuspend() (can bool, busErr *dbus.Error) { + // 虚拟机屏蔽待机 + if m.VirtualMachineName != "" { + return false, nil + } + _, err := os.Stat("/sys/power/mem_sleep") + if os.IsNotExist(err) { + return false, nil + } + + str, _ := m.objLogin.CanSuspend(0) + return str == "yes", nil +} + +func (m *Manager) CanHibernate() (can bool, busErr *dbus.Error) { + // 虚拟机屏蔽休眠 + if m.VirtualMachineName != "" { + return false, nil + } + str, _ := m.objLogin.CanHibernate(0) + return str == "yes", nil +} + +var autoConfigTargets = []string{ + "suspend.target", + "sleep.target", + "suspend-then-hibernate.target", + "hibernate.target", + "hybrid-sleep.target", +} + +func (m *Manager) maskOnVM(enable bool) { + var oper string + if enable && m.VirtualMachineName != "" { + oper = "mask" + } else { + oper = "unmask" + } + + for _, target := range autoConfigTargets { + logger.Debug("auto mask on virt") + exec.Command("systemctl", oper, target).Run() + } +} diff --git a/system/power_manager/power_manager_dbusutil.go b/system/power_manager1/power_manager_dbusutil.go similarity index 100% rename from system/power_manager/power_manager_dbusutil.go rename to system/power_manager1/power_manager_dbusutil.go diff --git a/system/power_manager/utils.go b/system/power_manager1/utils.go similarity index 100% rename from system/power_manager/utils.go rename to system/power_manager1/utils.go diff --git a/system/swapsched/exported_methods_auto.go b/system/swapsched1/exported_methods_auto.go similarity index 100% rename from system/swapsched/exported_methods_auto.go rename to system/swapsched1/exported_methods_auto.go diff --git a/system/swapsched/swapsched.go b/system/swapsched1/swapsched.go similarity index 94% rename from system/swapsched/swapsched.go rename to system/swapsched1/swapsched.go index 6d7963102..3f97db370 100644 --- a/system/swapsched/swapsched.go +++ b/system/swapsched1/swapsched.go @@ -10,17 +10,17 @@ import ( "path/filepath" "time" - dbus "github.com/godbus/dbus" - login1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.login1" + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/loader" + login1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.login1" "github.com/linuxdeepin/go-lib/cgroup" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/dde-daemon/loader" ) const ( - dbusServiceName = "com.deepin.daemon.SwapSchedHelper" - dbusPath = "/com/deepin/daemon/SwapSchedHelper" + dbusServiceName = "org.deepin.dde.SwapSchedHelper1" + dbusPath = "/org/deepin/dde/SwapSchedHelper1" dbusInterface = dbusServiceName ) diff --git a/system/systeminfo/manager.go b/system/systeminfo/manager.go deleted file mode 100644 index 8c02dcd20..000000000 --- a/system/systeminfo/manager.go +++ /dev/null @@ -1,230 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package systeminfo - -import ( - "encoding/json" - "errors" - "fmt" - "os/exec" - "regexp" - "strconv" - "strings" - "sync" - - "github.com/jouyouyun/hardware/dmi" - "github.com/linuxdeepin/go-lib/dbusutil" -) - -//go:generate dbusutil-gen em -type Manager - -// 该结构体可能不包含所有的lshw数据类型,如果有缺失需要新增字段 -type lshwItemContent struct { - ID string `json:"id"` - Class string `json:"class"` - Claimed bool `json:"claimed"` - Handle string `json:"handle"` - Description string `json:"description"` - Product string `json:"product"` - Vendor string `json:"vendor"` - PhysID string `json:"physid"` - BusInfo string `json:"businfo"` - Version string `json:"version"` - Width int `json:"width"` - Clock int `json:"clock"` - Size uint64 `json:"size"` - Configuration struct { - Driver string `json:"driver"` - Latency string `json:"latency"` - } `json:"configuration"` - Capabilities struct { - PCIExpress string `json:"pciexpress"` - MSI string `json:"msi"` - PM string `json:"pm"` - VGAController bool `json:"vga_controller"` - BusMaster string `json:"bus_master"` - Capabilities string `json:"cap_list"` - ROM string `json:"rom"` - } `json:"capabilities"` -} - -type lshwClassContent []lshwItemContent - -// 缓存 lshw 指令获取到的数据 key/value --> class/data -var _lshwContent = make(map[string]lshwClassContent) -var _lshwContentMu sync.Mutex - -const ( - dbusServiceName = "com.deepin.system.SystemInfo" - dbusPath = "/com/deepin/system/SystemInfo" - dbusInterface = dbusServiceName - - KB = 1 << 10 - MB = 1 << 20 - GB = 1 << 30 - TB = 1 << 40 - EB = 1 << 50 -) - -type Manager struct { - service *dbusutil.Service - PropsMu sync.RWMutex - MemorySize uint64 - MemorySizeHuman string - CurrentSpeed uint64 - DMIInfo dmi.DMI - DisplayDriver string - VideoDriver string -} - -func formatFileSize(fileSize uint64) (size string) { - if fileSize < KB { - return fmt.Sprintf("%.2fB", float64(fileSize)/float64(1)) - } else if fileSize < MB { - return fmt.Sprintf("%.2fKB", float64(fileSize)/float64(KB)) - } else if fileSize < GB { - return fmt.Sprintf("%.2fMB", float64(fileSize)/float64(MB)) - } else if fileSize < TB { - return fmt.Sprintf("%.2fGB", float64(fileSize)/float64(GB)) - } else if fileSize < EB { - return fmt.Sprintf("%.2fTB", float64(fileSize)/float64(TB)) - } else { // if fileSize < (1024 * 1024 * 1024 * 1024 * 1024 * 1024) - return fmt.Sprintf("%.2fEB", float64(fileSize)/float64(EB)) - } -} - -func (m *Manager) GetInterfaceName() string { - return dbusInterface -} - -func NewManager(service *dbusutil.Service) *Manager { - var m = &Manager{ - service: service, - } - return m -} - -func isStrEmpty(str string) (out bool) { - return len(str) <= 0 || str == "" -} - -func getLshwData(class string) (lshwClassContent, error) { - if isStrEmpty(class) { - logger.Info("class is Empty") - return nil, errors.New("input is not allowed to be empty") - } - _lshwContentMu.Lock() - defer _lshwContentMu.Unlock() - _, ok := _lshwContent[class] - if !ok { - output, err := exec.Command("lshw", "-c", class, "-sanitize", "-quiet", "-json").Output() - if err != nil { - return nil, err - } - var newClassItemContent lshwClassContent - err = json.Unmarshal(output, &newClassItemContent) - if err != nil { - return nil, err - } - _lshwContent[class] = newClassItemContent - } - return _lshwContent[class], nil -} - -func (m *Manager) calculateMemoryViaLshw() error { - classContent, err := getLshwData("memory") - if err != nil { - logger.Warning(err) - return err - } - var ret uint64 - for _, item := range classContent { - if strings.ToLower(item.Description) == "system memory" { - ret = item.Size - } - } - memory := formatFileSize(ret) - m.PropsMu.Lock() - // set property value - m.setPropMemorySize(ret) - m.setPropMemorySizeHuman(memory) - m.PropsMu.Unlock() - logger.Debug("system memory : ", ret) - return nil -} - -func GetCurrentSpeed(systemBit int) (uint64, error) { - ret, err := getCurrentSpeed(systemBit) - return ret, err -} - -func getCurrentSpeed(systemBit int) (uint64, error) { - var ret uint64 = 0 - cmdOutBuf, err := runDmidecode() - if err != nil { - return ret, err - } - ret, err = parseCurrentSpeed(cmdOutBuf, systemBit) - if err != nil { - logger.Error(err) - return ret, err - } - logger.Debug("GetCurrentSpeed :", ret) - return ret, err -} - -func runDmidecode() (string, error) { - cmd := exec.Command("dmidecode", "-t", "processor") - out, err := cmd.Output() - if err != nil { - logger.Error(err) - } - return string(out), err -} - -// From string parse "Current Speed" -func parseCurrentSpeed(bytes string, systemBit int) (result uint64, err error) { - logger.Debug("parseCurrentSpeed data: ", bytes) - lines := strings.Split(bytes, "\n") - for _, line := range lines { - if !strings.Contains(line, "Current Speed:") { - continue - } - items := strings.Split(line, "Current Speed:") - ret := "" - if len(items) == 2 { - // Current Speed: 3200 MHz - ret = items[1] - value, err := strconv.ParseUint(strings.TrimSpace(filterUnNumber(ret)), 10, systemBit) - if err != nil { - logger.Error(err) - return result, err - } - result = value - } - break - } - return result, err -} - -// 仅保留字符串中的数字 -func filterUnNumber(value string) string { - reg, err := regexp.Compile("[^0-9]+") - if err != nil { - logger.Fatal(err) - } - return reg.ReplaceAllString(value, "") -} - -// 执行命令:/usr/bin/getconf LONG_BIT 获取系统位数 -func (m *Manager) systemBit() string { - output, err := exec.Command("/usr/bin/getconf", "LONG_BIT").Output() - if err != nil { - return "64" - } - - v := strings.TrimRight(string(output), "\n") - return v -} diff --git a/system/systeminfo/exported_methods_auto.go b/system/systeminfo1/exported_methods_auto.go similarity index 100% rename from system/systeminfo/exported_methods_auto.go rename to system/systeminfo1/exported_methods_auto.go diff --git a/system/systeminfo1/manager.go b/system/systeminfo1/manager.go new file mode 100644 index 000000000..324d865ad --- /dev/null +++ b/system/systeminfo1/manager.go @@ -0,0 +1,236 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package systeminfo + +import ( + "encoding/json" + "errors" + "fmt" + "os/exec" + "regexp" + "strconv" + "strings" + "sync" + + "github.com/jouyouyun/hardware/dmi" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +//go:generate dbusutil-gen em -type Manager + +// 该结构体可能不包含所有的lshw数据类型,如果有缺失需要新增字段 +type lshwItemContent struct { + ID string `json:"id"` + Class string `json:"class"` + Claimed bool `json:"claimed"` + Handle string `json:"handle"` + Description string `json:"description"` + Product string `json:"product"` + Vendor string `json:"vendor"` + PhysID string `json:"physid"` + BusInfo string `json:"businfo"` + Version string `json:"version"` + Width int `json:"width"` + Clock int `json:"clock"` + Size uint64 `json:"size"` + Configuration struct { + Driver string `json:"driver"` + Latency string `json:"latency"` + } `json:"configuration"` + Capabilities struct { + PCIExpress string `json:"pciexpress"` + MSI string `json:"msi"` + PM string `json:"pm"` + VGAController bool `json:"vga_controller"` + BusMaster string `json:"bus_master"` + Capabilities string `json:"cap_list"` + ROM string `json:"rom"` + } `json:"capabilities"` +} + +type lshwClassContent []lshwItemContent + +// 缓存 lshw 指令获取到的数据 key/value --> class/data +var _lshwContent = make(map[string]lshwClassContent) +var _lshwContentMu sync.Mutex + +const ( + dbusServiceName = "org.deepin.dde.SystemInfo1" + dbusPath = "/org/deepin/dde/SystemInfo1" + dbusInterface = dbusServiceName + + KB = 1 << 10 + MB = 1 << 20 + GB = 1 << 30 + TB = 1 << 40 + EB = 1 << 50 +) + +type Manager struct { + service *dbusutil.Service + PropsMu sync.RWMutex + MemorySize uint64 + MemorySizeHuman string + CurrentSpeed uint64 + DMIInfo dmi.DMI + DisplayDriver string + VideoDriver string +} + +func formatFileSize(fileSize uint64) (size string) { + if fileSize < KB { + return fmt.Sprintf("%.2fB", float64(fileSize)/float64(1)) + } else if fileSize < MB { + return fmt.Sprintf("%.2fKB", float64(fileSize)/float64(KB)) + } else if fileSize < GB { + return fmt.Sprintf("%.2fMB", float64(fileSize)/float64(MB)) + } else if fileSize < TB { + return fmt.Sprintf("%.2fGB", float64(fileSize)/float64(GB)) + } else if fileSize < EB { + return fmt.Sprintf("%.2fTB", float64(fileSize)/float64(TB)) + } else { // if fileSize < (1024 * 1024 * 1024 * 1024 * 1024 * 1024) + return fmt.Sprintf("%.2fEB", float64(fileSize)/float64(EB)) + } +} + +func (m *Manager) GetInterfaceName() string { + return dbusInterface +} + +func NewManager(service *dbusutil.Service) *Manager { + var m = &Manager{ + service: service, + } + v, err := dmi.GetDMI() + if err != nil { + logger.Warning(err) + } else { + m.DMIInfo = *v + } + return m +} + +func isStrEmpty(str string) (out bool) { + return len(str) <= 0 || str == "" +} + +func getLshwData(class string) (lshwClassContent, error) { + if isStrEmpty(class) { + logger.Info("class is Empty") + return nil, errors.New("input is not allowed to be empty") + } + _lshwContentMu.Lock() + defer _lshwContentMu.Unlock() + _, ok := _lshwContent[class] + if !ok { + output, err := exec.Command("lshw", "-c", class, "-sanitize", "-quiet", "-json").Output() + if err != nil { + return nil, err + } + var newClassItemContent lshwClassContent + err = json.Unmarshal(output, &newClassItemContent) + if err != nil { + return nil, err + } + _lshwContent[class] = newClassItemContent + } + return _lshwContent[class], nil +} + +func (m *Manager) calculateMemoryViaLshw() error { + classContent, err := getLshwData("memory") + if err != nil { + logger.Warning(err) + return err + } + var ret uint64 + for _, item := range classContent { + if strings.ToLower(item.Description) == "system memory" { + ret = item.Size + } + } + memory := formatFileSize(ret) + m.PropsMu.Lock() + // set property value + m.setPropMemorySize(ret) + m.setPropMemorySizeHuman(memory) + m.PropsMu.Unlock() + logger.Debug("system memory : ", ret) + return nil +} + +func GetCurrentSpeed(systemBit int) (uint64, error) { + ret, err := getCurrentSpeed(systemBit) + return ret, err +} + +func getCurrentSpeed(systemBit int) (uint64, error) { + var ret uint64 = 0 + cmdOutBuf, err := runDmidecode() + if err != nil { + return ret, err + } + ret, err = parseCurrentSpeed(cmdOutBuf, systemBit) + if err != nil { + logger.Error(err) + return ret, err + } + logger.Debug("GetCurrentSpeed :", ret) + return ret, err +} + +func runDmidecode() (string, error) { + cmd := exec.Command("dmidecode", "-t", "processor") + out, err := cmd.Output() + if err != nil { + logger.Error(err) + } + return string(out), err +} + +// From string parse "Current Speed" +func parseCurrentSpeed(bytes string, systemBit int) (result uint64, err error) { + logger.Debug("parseCurrentSpeed data: ", bytes) + lines := strings.Split(bytes, "\n") + for _, line := range lines { + if !strings.Contains(line, "Current Speed:") { + continue + } + items := strings.Split(line, "Current Speed:") + ret := "" + if len(items) == 2 { + // Current Speed: 3200 MHz + ret = items[1] + value, err := strconv.ParseUint(strings.TrimSpace(filterUnNumber(ret)), 10, systemBit) + if err != nil { + logger.Error(err) + return result, err + } + result = value + } + break + } + return result, err +} + +// 仅保留字符串中的数字 +func filterUnNumber(value string) string { + reg, err := regexp.Compile("[^0-9]+") + if err != nil { + logger.Fatal(err) + } + return reg.ReplaceAllString(value, "") +} + +// 执行命令:/usr/bin/getconf LONG_BIT 获取系统位数 +func (m *Manager) systemBit() string { + output, err := exec.Command("/usr/bin/getconf", "LONG_BIT").Output() + if err != nil { + return "64" + } + + v := strings.TrimRight(string(output), "\n") + return v +} diff --git a/system/systeminfo/systeminfo.go b/system/systeminfo1/systeminfo.go similarity index 99% rename from system/systeminfo/systeminfo.go rename to system/systeminfo1/systeminfo.go index b56498ce5..9aaf24313 100644 --- a/system/systeminfo/systeminfo.go +++ b/system/systeminfo1/systeminfo.go @@ -5,7 +5,7 @@ package systeminfo import ( - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/log" "strings" diff --git a/system/systeminfo/systeminfo_dbusutil.go b/system/systeminfo1/systeminfo_dbusutil.go similarity index 100% rename from system/systeminfo/systeminfo_dbusutil.go rename to system/systeminfo1/systeminfo_dbusutil.go diff --git a/system/systeminfo/systeminfo_test.go b/system/systeminfo1/systeminfo_test.go similarity index 100% rename from system/systeminfo/systeminfo_test.go rename to system/systeminfo1/systeminfo_test.go diff --git a/system/timedated/exported_methods_auto.go b/system/timedate1/exported_methods_auto.go similarity index 100% rename from system/timedated/exported_methods_auto.go rename to system/timedate1/exported_methods_auto.go diff --git a/system/timedate1/manager.go b/system/timedate1/manager.go new file mode 100644 index 000000000..7bfb06beb --- /dev/null +++ b/system/timedate1/manager.go @@ -0,0 +1,354 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package timedated + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "strings" + "sync" + + dbus "github.com/godbus/dbus/v5" + ConfigManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" + polkit "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.policykit1" + systemd1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.systemd1" + timedate1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.timedate1" + timesync1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.timesync1" + + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/keyfile" +) + +//go:generate dbusutil-gen -type Manager manager.go +//go:generate dbusutil-gen em -type Manager + +type Manager struct { + core timedate1.Timedate + service *dbusutil.Service + PropsMu sync.RWMutex + NTPServer string + timesyncd timesync1.Timesync1 + systemd systemd1.Manager + setNTPServerMu sync.RWMutex + signalLoop *dbusutil.SignalLoop + dsManager ConfigManager.Manager +} + +const ( + dbusServiceName = "org.deepin.dde.Timedate1" + dbusPath = "/org/deepin/dde/Timedate1" + dbusInterface = dbusServiceName + + timedate1ActionId = "org.freedesktop.timedate1.set-time" + + timeSyncCfgFile = "/etc/systemd/timesyncd.conf.d/deepin.conf" + + timesyncdService = "systemd-timesyncd.service" +) + +const ( + dsettingsAppID = "org.deepin.dde.daemon" + dsettingsTimeDatedName = "org.deepin.dde.daemon.timedated" + dsettingsKeyObsoleteNTPServer = "ObsoleteNTPServer" + dsettingsKeyNTPServer = "NTPServer" +) + +func NewManager(service *dbusutil.Service) (*Manager, error) { + core := timedate1.NewTimedate(service.Conn()) + m := &Manager{ + core: core, + service: service, + } + return m, nil +} + +func (m *Manager) initDsgConfig() { + // dsg config + ds := ConfigManager.NewConfigManager(m.signalLoop.Conn()) + + dsPath, err := ds.AcquireManager(0, dsettingsAppID, dsettingsTimeDatedName, "") + if err != nil { + logger.Warning(err) + return + } + + m.dsManager, err = ConfigManager.NewManager(m.signalLoop.Conn(), dsPath) + if err != nil { + logger.Warning(err) + return + } +} + +func (m *Manager) getDsgObsoleteNTPServer() string { + if m.dsManager == nil { + return "" + } + v, err := m.dsManager.Value(0, dsettingsKeyObsoleteNTPServer) + if err != nil { + logger.Warning(err) + return "" + } + + return v.Value().(string) +} + +func (m *Manager) getDsgNTPServer() string { + if m.dsManager == nil { + return "" + } + v, err := m.dsManager.Value(0, dsettingsKeyNTPServer) + if err != nil { + logger.Warning(err) + return "" + } + + return v.Value().(string) +} + +func (m *Manager) setDsgObsoleteNTPServer(server string) error { + if m.dsManager == nil { + return errors.New("dsManager is nil") + } + return m.dsManager.SetValue(0, dsettingsKeyObsoleteNTPServer, dbus.MakeVariant(server)) +} + +func (m *Manager) setDsgNTPServer(server string) error { + if m.dsManager == nil { + return errors.New("dsManager is nil") + } + return m.dsManager.SetValue(0, dsettingsKeyNTPServer, dbus.MakeVariant(server)) +} + +func (m *Manager) start() { + + m.signalLoop = dbusutil.NewSignalLoop(m.service.Conn(), 10) + m.signalLoop.Start() + + m.initDsgConfig() + + m.timesyncd = timesync1.NewTimesync1(m.service.Conn()) + server, err := getNTPServer() + if err != nil { + logger.Warning(err) + } + obsoleteNTPServer := m.getDsgObsoleteNTPServer() + ntpServer := m.getDsgNTPServer() + + logger.Infof("dsg obolete ntp server: %s; dsg ntp server: %s", obsoleteNTPServer, ntpServer) + m.systemd = systemd1.NewManager(m.service.Conn()) + syncFn := func() { + ntp, err := m.core.NTP().Get(0) + if err != nil { + logger.Warning(err) + } + + if ntpServer == "" { + if m.isUnitEnable(timesyncdService) && ntp { + serverName, err := m.timesyncd.ServerName().Get(0) + if err != nil { + logger.Warning(err) + } + err = m.setNTPServer(serverName) + if err != nil { + logger.Warning(err) + } + } + } else { + err = m.setNTPServer(ntpServer) + if err != nil { + logger.Warning(err) + } + if m.isUnitEnable(timesyncdService) && ntp { + go func() { + _, err := m.systemd.RestartUnit(0, timesyncdService, "replace") + if err != nil { + logger.Warning("failed to restart systemd timesyncd service:", err) + } + }() + } + } + } + // 第一次启动时,默认无NTPServer文件.如果时间同步状态是开启的(系统默认开启),将时间同步服务数据同步到timedated中 + if server == "" { + syncFn() + } else { + if server != ntpServer { + if server != obsoleteNTPServer && obsoleteNTPServer != "-" { + m.setNTPServer(server) + // 文件里已经有值,同步到 dconf 中 + m.setDsgNTPServer(server) + } else { + // 使用 dconf 配置 + syncFn() + } + } else { + m.setNTPServer(server) + } + } + + if obsoleteNTPServer != "-" { + // 将obsolete ntp server 标记为已经使用过 + m.setDsgObsoleteNTPServer("-") + } + m.timesyncd.InitSignalExt(m.signalLoop, true) + err = m.timesyncd.ServerName().ConnectChanged(func(hasValue bool, value string) { + if !hasValue { + return + } + err = m.setNTPServer(server) + if err != nil { + logger.Warning(err) + } + err = m.setDsgNTPServer(server) + if err != nil { + logger.Warning(err) + } + }) + if err != nil { + logger.Warning(err) + } + m.systemd.InitSignalExt(m.signalLoop, true) + + _, err = m.systemd.ConnectUnitNew(func(id string, unit dbus.ObjectPath) { + // 监听systemd-timesyncd.service服务的启动,代表了开启了时间同步服务,获取该服务的时间服务器数据, + // 如果开启NTP后直接读取timesync1的数据,有可能存在服务未启动的情况,该服务无法被dbus-daemon启动. + if id == timesyncdService { + if !m.isUnitEnable(timesyncdService) { + return + } + ntp, err := m.core.NTP().Get(0) + if err != nil { + logger.Warning(err) + return + } + if !ntp { + return + } + server, err = m.timesyncd.ServerName().Get(dbus.FlagNoAutoStart) + if err != nil { + logger.Warning(err) + return + } + if server != "" { + err = m.setNTPServer(server) + if err != nil { + logger.Warning(err) + } + err = m.setDsgNTPServer(server) + if err != nil { + logger.Warning(err) + } + } + } + }) + if err != nil { + logger.Warning(err) + } +} + +func (m *Manager) setNTPServer(value string) error { + m.PropsMu.RLock() + if m.NTPServer == value { + m.PropsMu.RUnlock() + return nil + } + m.PropsMu.RUnlock() + + m.setNTPServerMu.Lock() + defer m.setNTPServerMu.Unlock() + err := setNTPServer(value) + if err != nil { + return err + } + + m.PropsMu.Lock() + m.NTPServer = value + m.PropsMu.Unlock() + return m.emitPropChangedNTPServer(value) +} + +func (*Manager) GetInterfaceName() string { + return dbusInterface +} + +func (m *Manager) destroy() { + if m.core == nil { + return + } + m.core = nil +} + +func (m *Manager) checkAuthorization(method, msg string, sender dbus.Sender) error { + isAuthorized, err := doAuthorized(msg, string(sender)) + if err != nil { + logger.Warning("Has error occurred in doAuthorized:", err) + return err + } + if !isAuthorized { + logger.Warning("Failed to authorize") + return fmt.Errorf("[%s] Failed to authorize for %v", method, sender) + } + return nil +} + +func doAuthorized(msg, sysBusName string) (bool, error) { + systemBus, err := dbus.SystemBus() + if err != nil { + return false, err + } + authority := polkit.NewAuthority(systemBus) + subject := polkit.MakeSubject(polkit.SubjectKindSystemBusName) + subject.SetDetail("name", sysBusName) + detail := map[string]string{ + "polkit.message": msg, + } + ret, err := authority.CheckAuthorization(0, subject, timedate1ActionId, + detail, polkit.CheckAuthorizationFlagsAllowUserInteraction, "") + if err != nil { + return false, err + } + return ret.IsAuthorized, nil +} + +func setNTPServer(server string) error { + kf := keyfile.NewKeyFile() + err := kf.LoadFromFile(timeSyncCfgFile) + if err != nil && !os.IsNotExist(err) { + return err + } + + kf.SetString("Time", "NTP", server) + + dir := filepath.Dir(timeSyncCfgFile) + err = os.MkdirAll(dir, 0755) + if err != nil { + return err + } + + err = kf.SaveToFile(timeSyncCfgFile) + return err +} + +func getNTPServer() (string, error) { + kf := keyfile.NewKeyFile() + err := kf.LoadFromFile(timeSyncCfgFile) + if err != nil && !os.IsNotExist(err) { + return "", err + } + + server, _ := kf.GetString("Time", "NTP") + return server, nil +} + +func (m *Manager) isUnitEnable(unit string) bool { + state, err := m.systemd.GetUnitFileState(0, unit) + if err != nil { + logger.Warning(err) + return false + } + return "enabled" == strings.TrimSpace(state) +} diff --git a/system/timedate1/manager_ifc.go b/system/timedate1/manager_ifc.go new file mode 100644 index 000000000..f3d9d2c5d --- /dev/null +++ b/system/timedate1/manager_ifc.go @@ -0,0 +1,127 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package timedated + +import ( + "os" + + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/timedate1/zoneinfo" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +// SetTime set the current time and date, +// pass a value of microseconds since 1 Jan 1970 UTC +func (m *Manager) SetTime(sender dbus.Sender, usec int64, relative bool, message string) *dbus.Error { + // TODO: check usec validity + err := m.core.SetTime(0, usec, relative, false) + return dbusutil.ToError(err) +} + +// SetTimezone set the system time zone, the value from /usr/share/zoneinfo/zone.tab +func (m *Manager) SetTimezone(sender dbus.Sender, timezone, message string) *dbus.Error { + ok, err := zoneinfo.IsZoneValid(timezone) + if err != nil { + return dbusutil.ToError(err) + } + if !ok { + logger.Warning("invalid zone:", timezone) + return dbusutil.ToError(zoneinfo.ErrZoneInvalid) + } + + err = m.checkAuthorization("SetTimezone", message, sender) + if err != nil { + return dbusutil.ToError(err) + } + + currentTimezone, err := m.core.Timezone().Get(0) + if err != nil { + return dbusutil.ToError(err) + } + + if currentTimezone == timezone { + return nil + } + err = m.core.SetTimezone(0, timezone, false) + return dbusutil.ToError(err) +} + +// SetLocalRTC to control whether the RTC is the local time or UTC. +func (m *Manager) SetLocalRTC(sender dbus.Sender, enabled bool, fixSystem bool, message string) *dbus.Error { + err := m.checkAuthorization("SetLocalRTC", message, sender) + if err != nil { + return dbusutil.ToError(err) + } + + currentLocalRTCEnabled, err := m.core.LocalRTC().Get(0) + if err != nil { + return dbusutil.ToError(err) + } + + if currentLocalRTCEnabled == enabled { + return nil + } + err = m.core.SetLocalRTC(0, enabled, fixSystem, false) + return dbusutil.ToError(err) +} + +// SetNTP to control whether the system clock is synchronized with the network +func (m *Manager) SetNTP(sender dbus.Sender, enabled bool, message string) *dbus.Error { + currentNTPEnabled, err := m.core.NTP().Get(0) + if err != nil { + return dbusutil.ToError(err) + } + + if currentNTPEnabled == enabled { + return nil + } + + err = m.core.SetNTP(0, enabled, false) + if err != nil { + return dbusutil.ToError(err) + } + + // 关闭NTP时删除clock文件,使systemd以RTC时间为准 + if !enabled { + err := os.Remove("/var/lib/systemd/timesync/clock") + if err != nil { + if !os.IsNotExist(err) { + logger.Warning("delete [/var/lib/systemd/timesync/clock] err:", err) + } + } + } + + return dbusutil.ToError(err) +} + +func (m *Manager) SetNTPServer(sender dbus.Sender, server, message string) *dbus.Error { + err := m.checkAuthorization("SetNTPServer", message, sender) + if err != nil { + return dbusutil.ToError(err) + } + + err = m.setNTPServer(server) + if err != nil { + logger.Warning(err) + } + err = m.setDsgNTPServer(server) + if err != nil { + logger.Warning(err) + } + + ntp, err := m.core.NTP().Get(0) + if err != nil { + logger.Warning(err) + } else if ntp { + // ntp enabled + go func() { + _, err := m.systemd.RestartUnit(0, timesyncdService, "replace") + if err != nil { + logger.Warning("failed to restart systemd timesyncd service:", err) + } + }() + } + return nil +} diff --git a/system/timedated/timedated.go b/system/timedate1/timedated.go similarity index 100% rename from system/timedated/timedated.go rename to system/timedate1/timedated.go index 363a516cd..b63414cf6 100644 --- a/system/timedated/timedated.go +++ b/system/timedate1/timedated.go @@ -5,8 +5,8 @@ package timedated import ( - "github.com/linuxdeepin/go-lib/log" "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" ) type Daemon struct { diff --git a/system/timedated/timedated_dbusutil.go b/system/timedate1/timedated_dbusutil.go similarity index 100% rename from system/timedated/timedated_dbusutil.go rename to system/timedate1/timedated_dbusutil.go diff --git a/system/timedated/manager.go b/system/timedated/manager.go deleted file mode 100644 index 26a6bd662..000000000 --- a/system/timedated/manager.go +++ /dev/null @@ -1,341 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package timedated - -import ( - "fmt" - "os" - "path/filepath" - "strings" - "sync" - - dbus "github.com/godbus/dbus" - ConfigManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" - polkit "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.policykit1" - systemd1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.systemd1" - timedate1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.timedate1" - timesync1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.timesync1" - - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/keyfile" -) - -//go:generate dbusutil-gen -type Manager manager.go -//go:generate dbusutil-gen em -type Manager - -type Manager struct { - core timedate1.Timedate - service *dbusutil.Service - PropsMu sync.RWMutex - NTPServer string - timesyncd timesync1.Timesync1 - systemd systemd1.Manager - setNTPServerMu sync.RWMutex - signalLoop *dbusutil.SignalLoop - dsManager ConfigManager.Manager -} - -const ( - dbusServiceName = "com.deepin.daemon.Timedated" - dbusPath = "/com/deepin/daemon/Timedated" - dbusInterface = dbusServiceName - - timedate1ActionId = "org.freedesktop.timedate1.set-time" - - timeSyncCfgFile = "/etc/systemd/timesyncd.conf.d/deepin.conf" - - timesyncdService = "systemd-timesyncd.service" -) - -const ( - dsettingsAppID = "org.deepin.dde.daemon" - dsettingsTimeDatedName = "org.deepin.dde.daemon.timedated" - dsettingsKeyObsoleteNTPServer = "ObsoleteNTPServer" - dsettingsKeyNTPServer = "NTPServer" -) - -func NewManager(service *dbusutil.Service) (*Manager, error) { - core := timedate1.NewTimedate(service.Conn()) - m := &Manager{ - core: core, - service: service, - } - return m, nil -} - -func (m *Manager) initDsgConfig() { - // dsg config - ds := ConfigManager.NewConfigManager(m.signalLoop.Conn()) - - dsPath, err := ds.AcquireManager(0, dsettingsAppID, dsettingsTimeDatedName, "") - if err != nil { - logger.Warning(err) - return - } - - m.dsManager, err = ConfigManager.NewManager(m.signalLoop.Conn(), dsPath) - if err != nil { - logger.Warning(err) - return - } -} - -func (m *Manager) getDsgObsoleteNTPServer() string { - v, err := m.dsManager.Value(0, dsettingsKeyObsoleteNTPServer) - if err != nil { - logger.Warning(err) - return "" - } - - return v.Value().(string) -} - -func (m *Manager) getDsgNTPServer() string { - v, err := m.dsManager.Value(0, dsettingsKeyNTPServer) - if err != nil { - logger.Warning(err) - return "" - } - - return v.Value().(string) -} - -func (m *Manager) setDsgObsoleteNTPServer(server string) error { - return m.dsManager.SetValue(0, dsettingsKeyObsoleteNTPServer, dbus.MakeVariant(server)) -} - -func (m *Manager) setDsgNTPServer(server string) error { - return m.dsManager.SetValue(0, dsettingsKeyNTPServer, dbus.MakeVariant(server)) -} - -func (m *Manager) start() { - - m.signalLoop = dbusutil.NewSignalLoop(m.service.Conn(), 10) - m.signalLoop.Start() - - m.initDsgConfig() - - m.timesyncd = timesync1.NewTimesync1(m.service.Conn()) - server, err := getNTPServer() - if err != nil { - logger.Warning(err) - } - obsoleteNTPServer := m.getDsgObsoleteNTPServer() - ntpServer := m.getDsgNTPServer() - - logger.Infof("dsg obolete ntp server: %s; dsg ntp server: %s", obsoleteNTPServer, ntpServer) - m.systemd = systemd1.NewManager(m.service.Conn()) - syncFn := func() { - ntp, err := m.core.NTP().Get(0) - if err != nil { - logger.Warning(err) - } - - if ntpServer == "" { - if m.isUnitEnable(timesyncdService) && ntp { - serverName, err := m.timesyncd.ServerName().Get(0) - if err != nil { - logger.Warning(err) - } - err = m.setNTPServer(serverName) - if err != nil { - logger.Warning(err) - } - } - } else { - err = m.setNTPServer(ntpServer) - if err != nil { - logger.Warning(err) - } - if m.isUnitEnable(timesyncdService) && ntp { - go func() { - _, err := m.systemd.RestartUnit(0, timesyncdService, "replace") - if err != nil { - logger.Warning("failed to restart systemd timesyncd service:", err) - } - }() - } - } - } - // 第一次启动时,默认无NTPServer文件.如果时间同步状态是开启的(系统默认开启),将时间同步服务数据同步到timedated中 - if server == "" { - syncFn() - } else { - if server != ntpServer { - if server != obsoleteNTPServer && obsoleteNTPServer != "-" { - m.setNTPServer(server) - // 文件里已经有值,同步到 dconf 中 - m.setDsgNTPServer(server) - } else { - // 使用 dconf 配置 - syncFn() - } - } else { - m.setNTPServer(server) - } - } - - if obsoleteNTPServer != "-" { - // 将obsolete ntp server 标记为已经使用过 - m.setDsgObsoleteNTPServer("-") - } - m.timesyncd.InitSignalExt(m.signalLoop, true) - err = m.timesyncd.ServerName().ConnectChanged(func(hasValue bool, value string) { - if !hasValue { - return - } - err = m.setNTPServer(server) - if err != nil { - logger.Warning(err) - } - err = m.setDsgNTPServer(server) - if err != nil { - logger.Warning(err) - } - }) - if err != nil { - logger.Warning(err) - } - m.systemd.InitSignalExt(m.signalLoop, true) - - _, err = m.systemd.ConnectUnitNew(func(id string, unit dbus.ObjectPath) { - // 监听systemd-timesyncd.service服务的启动,代表了开启了时间同步服务,获取该服务的时间服务器数据, - // 如果开启NTP后直接读取timesync1的数据,有可能存在服务未启动的情况,该服务无法被dbus-daemon启动. - if id == timesyncdService { - if !m.isUnitEnable(timesyncdService) { - return - } - ntp, err := m.core.NTP().Get(0) - if err != nil { - logger.Warning(err) - return - } - if !ntp { - return - } - server, err = m.timesyncd.ServerName().Get(dbus.FlagNoAutoStart) - if err != nil { - logger.Warning(err) - return - } - if server != "" { - err = m.setNTPServer(server) - if err != nil { - logger.Warning(err) - } - err = m.setDsgNTPServer(server) - if err != nil { - logger.Warning(err) - } - } - } - }) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) setNTPServer(value string) error { - m.PropsMu.RLock() - if m.NTPServer == value { - m.PropsMu.RUnlock() - return nil - } - m.PropsMu.RUnlock() - - m.setNTPServerMu.Lock() - defer m.setNTPServerMu.Unlock() - err := setNTPServer(value) - if err != nil { - return err - } - - m.PropsMu.Lock() - m.NTPServer = value - m.PropsMu.Unlock() - return m.emitPropChangedNTPServer(value) -} - -func (*Manager) GetInterfaceName() string { - return dbusInterface -} - -func (m *Manager) destroy() { - if m.core == nil { - return - } - m.core = nil -} - -func (m *Manager) checkAuthorization(method, msg string, sender dbus.Sender) error { - isAuthorized, err := doAuthorized(msg, string(sender)) - if err != nil { - logger.Warning("Has error occurred in doAuthorized:", err) - return err - } - if !isAuthorized { - logger.Warning("Failed to authorize") - return fmt.Errorf("[%s] Failed to authorize for %v", method, sender) - } - return nil -} - -func doAuthorized(msg, sysBusName string) (bool, error) { - systemBus, err := dbus.SystemBus() - if err != nil { - return false, err - } - authority := polkit.NewAuthority(systemBus) - subject := polkit.MakeSubject(polkit.SubjectKindSystemBusName) - subject.SetDetail("name", sysBusName) - detail := map[string]string{ - "polkit.message": msg, - } - ret, err := authority.CheckAuthorization(0, subject, timedate1ActionId, - detail, polkit.CheckAuthorizationFlagsAllowUserInteraction, "") - if err != nil { - return false, err - } - return ret.IsAuthorized, nil -} - -func setNTPServer(server string) error { - kf := keyfile.NewKeyFile() - err := kf.LoadFromFile(timeSyncCfgFile) - if err != nil && !os.IsNotExist(err) { - return err - } - - kf.SetString("Time", "NTP", server) - - dir := filepath.Dir(timeSyncCfgFile) - err = os.MkdirAll(dir, 0755) - if err != nil { - return err - } - - err = kf.SaveToFile(timeSyncCfgFile) - return err -} - -func getNTPServer() (string, error) { - kf := keyfile.NewKeyFile() - err := kf.LoadFromFile(timeSyncCfgFile) - if err != nil && !os.IsNotExist(err) { - return "", err - } - - server, _ := kf.GetString("Time", "NTP") - return server, nil -} - -func (m *Manager) isUnitEnable(unit string) bool { - state, err := m.systemd.GetUnitFileState(0, unit) - if err != nil { - logger.Warning(err) - return false - } - return "enabled" == strings.TrimSpace(state) -} diff --git a/system/timedated/manager_ifc.go b/system/timedated/manager_ifc.go deleted file mode 100644 index 82c16a8d0..000000000 --- a/system/timedated/manager_ifc.go +++ /dev/null @@ -1,127 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package timedated - -import ( - "os" - - "github.com/godbus/dbus" - "github.com/linuxdeepin/dde-daemon/timedate/zoneinfo" - "github.com/linuxdeepin/go-lib/dbusutil" -) - -// SetTime set the current time and date, -// pass a value of microseconds since 1 Jan 1970 UTC -func (m *Manager) SetTime(sender dbus.Sender, usec int64, relative bool, message string) *dbus.Error { - // TODO: check usec validity - err := m.core.SetTime(0, usec, relative, false) - return dbusutil.ToError(err) -} - -// SetTimezone set the system time zone, the value from /usr/share/zoneinfo/zone.tab -func (m *Manager) SetTimezone(sender dbus.Sender, timezone, message string) *dbus.Error { - ok, err := zoneinfo.IsZoneValid(timezone) - if err != nil { - return dbusutil.ToError(err) - } - if !ok { - logger.Warning("invalid zone:", timezone) - return dbusutil.ToError(zoneinfo.ErrZoneInvalid) - } - - err = m.checkAuthorization("SetTimezone", message, sender) - if err != nil { - return dbusutil.ToError(err) - } - - currentTimezone, err := m.core.Timezone().Get(0) - if err != nil { - return dbusutil.ToError(err) - } - - if currentTimezone == timezone { - return nil - } - err = m.core.SetTimezone(0, timezone, false) - return dbusutil.ToError(err) -} - -// SetLocalRTC to control whether the RTC is the local time or UTC. -func (m *Manager) SetLocalRTC(sender dbus.Sender, enabled bool, fixSystem bool, message string) *dbus.Error { - err := m.checkAuthorization("SetLocalRTC", message, sender) - if err != nil { - return dbusutil.ToError(err) - } - - currentLocalRTCEnabled, err := m.core.LocalRTC().Get(0) - if err != nil { - return dbusutil.ToError(err) - } - - if currentLocalRTCEnabled == enabled { - return nil - } - err = m.core.SetLocalRTC(0, enabled, fixSystem, false) - return dbusutil.ToError(err) -} - -// SetNTP to control whether the system clock is synchronized with the network -func (m *Manager) SetNTP(sender dbus.Sender, enabled bool, message string) *dbus.Error { - currentNTPEnabled, err := m.core.NTP().Get(0) - if err != nil { - return dbusutil.ToError(err) - } - - if currentNTPEnabled == enabled { - return nil - } - - err = m.core.SetNTP(0, enabled, false) - if err != nil { - return dbusutil.ToError(err) - } - - // 关闭NTP时删除clock文件,使systemd以RTC时间为准 - if !enabled { - err := os.Remove("/var/lib/systemd/timesync/clock") - if err != nil { - if !os.IsNotExist(err) { - logger.Warning("delete [/var/lib/systemd/timesync/clock] err:", err) - } - } - } - - return dbusutil.ToError(err) -} - -func (m *Manager) SetNTPServer(sender dbus.Sender, server, message string) *dbus.Error { - err := m.checkAuthorization("SetNTPServer", message, sender) - if err != nil { - return dbusutil.ToError(err) - } - - err = m.setNTPServer(server) - if err != nil { - logger.Warning(err) - } - err = m.setDsgNTPServer(server) - if err != nil { - logger.Warning(err) - } - - ntp, err := m.core.NTP().Get(0) - if err != nil { - logger.Warning(err) - } else if ntp { - // ntp enabled - go func() { - _, err := m.systemd.RestartUnit(0, timesyncdService, "replace") - if err != nil { - logger.Warning("failed to restart systemd timesyncd service:", err) - } - }() - } - return nil -} diff --git a/system/uadp/daemon.go b/system/uadp/daemon.go deleted file mode 100644 index 9fb060de1..000000000 --- a/system/uadp/daemon.go +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package uadp - -import ( - "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/dde-daemon/loader" -) - -const ( - dbusServiceName = "com.deepin.daemon.Uadp" - dbusPath = "/com/deepin/daemon/Uadp" - dbusInterface = dbusServiceName -) - -var logger = log.NewLogger("daemon/system/uadp") - -func init() { - loader.Register(NewDaemon(logger)) -} - -type Daemon struct { - *loader.ModuleBase - manager *Manager -} - -func NewDaemon(logger *log.Logger) *Daemon { - daemon := new(Daemon) - daemon.ModuleBase = loader.NewModuleBase("uadp", daemon, logger) - return daemon -} - -func (d *Daemon) GetDependencies() []string { - return []string{} -} - -func (d *Daemon) Start() (err error) { - logger.Debug("start") - service := loader.GetService() - d.manager = newManager(service) - - err = service.Export(dbusPath, d.manager) - if err != nil { - return - } - - err = service.RequestName(dbusServiceName) - - d.manager.start() - return -} - -func (d *Daemon) Stop() error { - if d.manager == nil { - return nil - } - d.manager.stop() - d.manager = nil - return nil -} diff --git a/system/uadp/manager.go b/system/uadp/manager.go deleted file mode 100644 index 354830b55..000000000 --- a/system/uadp/manager.go +++ /dev/null @@ -1,171 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package uadp - -import ( - "github.com/godbus/dbus" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/procfs" -) - -//go:generate dbusutil-gen em -type Manager - -// RSA-2048 -const uadpEncryptMaxSize = 256 - 11 -const uadpDecryptMaxSize = 256 - -type Manager struct { - service *dbusutil.Service - - ctx *CryptoContext - aesCtx *AesContext - dm *DataManager -} - -func newManager(service *dbusutil.Service) *Manager { - logger.Debugf("newManager") - m := &Manager{ - service: service, - ctx: NewCryptoContext(), - aesCtx: NewAesContext(), - dm: NewDataManager(uadpDataDir), - } - - if m.ctx.handle != nil && !m.ctx.Load(uadpKeyFile) { - m.ctx.CreateKey() - m.ctx.Save(uadpKeyFile) - } - - m.dm.Load(uadpDataMap) - - return m -} - -func (*Manager) GetInterfaceName() string { - return dbusInterface -} - -func (m *Manager) start() { - -} - -func (m *Manager) stop() { - -} - -func (m *Manager) Available() (bool, *dbus.Error) { - return m.ctx.Available(), nil -} - -func (m *Manager) ListName(sender dbus.Sender) ([]string, *dbus.Error) { - exec, err := m.getExecPath(sender) - if err != nil { - logger.Warning(err) - return []string{}, dbusutil.ToError(err) - } - - return m.dm.ListName(exec), nil -} - -func (m *Manager) Set(sender dbus.Sender, name string, data []byte) *dbus.Error { - exec, err := m.getExecPath(sender) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - aesKey := m.aesCtx.GenKey() - encryptedData, err := m.aesCtx.Encrypt(data, aesKey) - if err != nil { - logger.Warning(err) - } - encryptedKey := m.ctx.Encrypt(aesKey) - if len(encryptedKey) == 0 { - encryptedKey = aesKey - } - - err = m.dm.SetData(uadpDataDir, exec, name, encryptedKey, encryptedData) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - err = m.dm.Save(uadpDataMap) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - return nil -} - -func (m *Manager) Get(sender dbus.Sender, name string) ([]byte, *dbus.Error) { - exec, err := m.getExecPath(sender) - if err != nil { - logger.Warning(err) - return []byte{}, dbusutil.ToError(err) - } - - key, data, err := m.dm.GetData(exec, name) - if err != nil { - logger.Warning(err) - } - - decryptedKey := m.ctx.Decrypt(key) - if len(decryptedKey) == 0 { - decryptedKey = key - } - decryptedData, _ := m.aesCtx.Decrypt(data, decryptedKey) - - return decryptedData, dbusutil.ToError(err) -} - -func (m *Manager) Delete(sender dbus.Sender, name string) *dbus.Error { - exec, err := m.getExecPath(sender) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - m.dm.DeleteData(exec, name) - - err = m.dm.Save(uadpDataMap) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - return nil -} - -func (m *Manager) Release(sender dbus.Sender) *dbus.Error { - exec, err := m.getExecPath(sender) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - - m.dm.DeleteProcess(exec) - - err = m.dm.Save(uadpDataMap) - if err != nil { - logger.Warning(err) - return dbusutil.ToError(err) - } - return nil -} - -func (m *Manager) getExecPath(sender dbus.Sender) (string, error) { - pid, err := m.service.GetConnPID(string(sender)) - if err != nil { - return "", err - } - - execPath, err := procfs.Process(pid).Exe() - if err != nil { - return "", err - } - - return execPath, nil -} diff --git a/system/uadp/aes.go b/system/uadp1/aes.go similarity index 100% rename from system/uadp/aes.go rename to system/uadp1/aes.go diff --git a/system/uadp/crypto.c b/system/uadp1/crypto.c similarity index 100% rename from system/uadp/crypto.c rename to system/uadp1/crypto.c diff --git a/system/uadp/crypto.go b/system/uadp1/crypto.go similarity index 100% rename from system/uadp/crypto.go rename to system/uadp1/crypto.go diff --git a/system/uadp/crypto.h b/system/uadp1/crypto.h similarity index 100% rename from system/uadp/crypto.h rename to system/uadp1/crypto.h diff --git a/system/uadp/crypto_test.go b/system/uadp1/crypto_test.go similarity index 100% rename from system/uadp/crypto_test.go rename to system/uadp1/crypto_test.go diff --git a/system/uadp1/daemon.go b/system/uadp1/daemon.go new file mode 100644 index 000000000..ef0665fdf --- /dev/null +++ b/system/uadp1/daemon.go @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package uadp + +import ( + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" +) + +const ( + dbusServiceName = "org.deepin.dde.Uadp1" + dbusPath = "/org/deepin/dde/Uadp1" + dbusInterface = dbusServiceName +) + +var logger = log.NewLogger("daemon/system/uadp") + +func init() { + loader.Register(NewDaemon(logger)) +} + +type Daemon struct { + *loader.ModuleBase + manager *Manager +} + +func NewDaemon(logger *log.Logger) *Daemon { + daemon := new(Daemon) + daemon.ModuleBase = loader.NewModuleBase("uadp", daemon, logger) + return daemon +} + +func (d *Daemon) GetDependencies() []string { + return []string{} +} + +func (d *Daemon) Start() (err error) { + logger.Debug("start") + service := loader.GetService() + d.manager = newManager(service) + + err = service.Export(dbusPath, d.manager) + if err != nil { + return + } + + err = service.RequestName(dbusServiceName) + + d.manager.start() + return +} + +func (d *Daemon) Stop() error { + if d.manager == nil { + return nil + } + d.manager.stop() + d.manager = nil + return nil +} diff --git a/system/uadp/data_manager.go b/system/uadp1/data_manager.go similarity index 100% rename from system/uadp/data_manager.go rename to system/uadp1/data_manager.go diff --git a/system/uadp/data_manager_test.go b/system/uadp1/data_manager_test.go similarity index 100% rename from system/uadp/data_manager_test.go rename to system/uadp1/data_manager_test.go diff --git a/system/uadp/dde_tc.c b/system/uadp1/dde_tc.c similarity index 100% rename from system/uadp/dde_tc.c rename to system/uadp1/dde_tc.c diff --git a/system/uadp/dde_tc.h b/system/uadp1/dde_tc.h similarity index 100% rename from system/uadp/dde_tc.h rename to system/uadp1/dde_tc.h diff --git a/system/uadp/dde_tc_copy.h b/system/uadp1/dde_tc_copy.h similarity index 100% rename from system/uadp/dde_tc_copy.h rename to system/uadp1/dde_tc_copy.h diff --git a/system/uadp/exported_methods_auto.go b/system/uadp1/exported_methods_auto.go similarity index 100% rename from system/uadp/exported_methods_auto.go rename to system/uadp1/exported_methods_auto.go diff --git a/system/uadp1/manager.go b/system/uadp1/manager.go new file mode 100644 index 000000000..d33c3ecfc --- /dev/null +++ b/system/uadp1/manager.go @@ -0,0 +1,171 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package uadp + +import ( + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/procfs" +) + +//go:generate dbusutil-gen em -type Manager + +// RSA-2048 +const uadpEncryptMaxSize = 256 - 11 +const uadpDecryptMaxSize = 256 + +type Manager struct { + service *dbusutil.Service + + ctx *CryptoContext + aesCtx *AesContext + dm *DataManager +} + +func newManager(service *dbusutil.Service) *Manager { + logger.Debugf("newManager") + m := &Manager{ + service: service, + ctx: NewCryptoContext(), + aesCtx: NewAesContext(), + dm: NewDataManager(uadpDataDir), + } + + if m.ctx.handle != nil && !m.ctx.Load(uadpKeyFile) { + m.ctx.CreateKey() + m.ctx.Save(uadpKeyFile) + } + + m.dm.Load(uadpDataMap) + + return m +} + +func (*Manager) GetInterfaceName() string { + return dbusInterface +} + +func (m *Manager) start() { + +} + +func (m *Manager) stop() { + +} + +func (m *Manager) Available() (bool, *dbus.Error) { + return m.ctx.Available(), nil +} + +func (m *Manager) ListName(sender dbus.Sender) ([]string, *dbus.Error) { + exec, err := m.getExecPath(sender) + if err != nil { + logger.Warning(err) + return []string{}, dbusutil.ToError(err) + } + + return m.dm.ListName(exec), nil +} + +func (m *Manager) Set(sender dbus.Sender, name string, data []byte) *dbus.Error { + exec, err := m.getExecPath(sender) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + aesKey := m.aesCtx.GenKey() + encryptedData, err := m.aesCtx.Encrypt(data, aesKey) + if err != nil { + logger.Warning(err) + } + encryptedKey := m.ctx.Encrypt(aesKey) + if len(encryptedKey) == 0 { + encryptedKey = aesKey + } + + err = m.dm.SetData(uadpDataDir, exec, name, encryptedKey, encryptedData) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + err = m.dm.Save(uadpDataMap) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + return nil +} + +func (m *Manager) Get(sender dbus.Sender, name string) ([]byte, *dbus.Error) { + exec, err := m.getExecPath(sender) + if err != nil { + logger.Warning(err) + return []byte{}, dbusutil.ToError(err) + } + + key, data, err := m.dm.GetData(exec, name) + if err != nil { + logger.Warning(err) + } + + decryptedKey := m.ctx.Decrypt(key) + if len(decryptedKey) == 0 { + decryptedKey = key + } + decryptedData, _ := m.aesCtx.Decrypt(data, decryptedKey) + + return decryptedData, dbusutil.ToError(err) +} + +func (m *Manager) Delete(sender dbus.Sender, name string) *dbus.Error { + exec, err := m.getExecPath(sender) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + m.dm.DeleteData(exec, name) + + err = m.dm.Save(uadpDataMap) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + return nil +} + +func (m *Manager) Release(sender dbus.Sender) *dbus.Error { + exec, err := m.getExecPath(sender) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + + m.dm.DeleteProcess(exec) + + err = m.dm.Save(uadpDataMap) + if err != nil { + logger.Warning(err) + return dbusutil.ToError(err) + } + return nil +} + +func (m *Manager) getExecPath(sender dbus.Sender) (string, error) { + pid, err := m.service.GetConnPID(string(sender)) + if err != nil { + return "", err + } + + execPath, err := procfs.Process(pid).Exe() + if err != nil { + return "", err + } + + return execPath, nil +} diff --git a/systeminfo/utils.go b/systeminfo/utils.go deleted file mode 100644 index ed17aeb89..000000000 --- a/systeminfo/utils.go +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package systeminfo - -import ( - "fmt" - "io/ioutil" - "os/exec" - "strconv" - "strings" -) - -const ( - memKeyTotal = "MemTotal" - memKeyDelim = ":" - lscpuKeyDelim = ":" -) - -func getMemoryFromFile(file string) (uint64, error) { - ret, err := parseInfoFile(file, memKeyDelim) - if err != nil { - return 0, err - } - - value, ok := ret[memKeyTotal] - if !ok { - return 0, fmt.Errorf("Can not find the key '%s'", memKeyTotal) - } - - cap, err := strconv.ParseUint(strings.Split(value, " ")[0], 10, 64) - if err != nil { - return 0, err - } - - return cap * 1024, nil -} - -//执行命令:/usr/bin/getconf LONG_BIT 获取系统位数 -func systemBit() string { - output, err := exec.Command("/usr/bin/getconf", "LONG_BIT").Output() - if err != nil { - return "64" - } - - v := strings.TrimRight(string(output), "\n") - return v -} - -func runLscpu() (map[string]string, error) { - cmd := exec.Command("lscpu") - cmd.Env = []string{"LC_ALL=C"} - out, err := cmd.Output() - if err != nil { - return nil, err - } - - lines := strings.Split(string(out), "\n") - res := make(map[string]string, len(lines)) - for _, line := range lines { - items := strings.Split(line, lscpuKeyDelim) - if len(items) != 2 { - continue - } - - res[items[0]] = strings.TrimSpace(items[1]) - } - - return res, nil -} - -func parseInfoFile(file, delim string) (map[string]string, error) { - content, err := ioutil.ReadFile(file) - if err != nil { - return nil, err - } - - var ret = make(map[string]string) - lines := strings.Split(string(content), "\n") - for _, line := range lines { - if len(line) == 0 { - continue - } - - array := strings.Split(line, delim) - if len(array) != 2 { - continue - } - - ret[strings.TrimSpace(array[0])] = strings.TrimSpace(array[1]) - } - - return ret, nil -} diff --git a/systeminfo/cache.go b/systeminfo1/cache.go similarity index 100% rename from systeminfo/cache.go rename to systeminfo1/cache.go diff --git a/systeminfo/cpu.go b/systeminfo1/cpu.go similarity index 81% rename from systeminfo/cpu.go rename to systeminfo1/cpu.go index fb65e5383..750df4426 100644 --- a/systeminfo/cpu.go +++ b/systeminfo1/cpu.go @@ -6,9 +6,9 @@ package systeminfo import ( "fmt" + "math" "strconv" "strings" - "math" ) const ( @@ -23,9 +23,36 @@ const ( lscpuKeyMaxMHz = "CPU max MHz" lscpuKeyModelName = "Model name" lscpuKeyCount = "CPU(s)" - compareAllowMin = 1e-6 + lscpuKeyCPUfamily = "CPU family" + lscpuKeyModel = "Model" + lscpuKeyStepping = "Stepping" + compareAllowMin = 1e-6 ) +func getProcessorByLscpuExt(data map[string]string, freq float64) (string, error) { + modelName, ok := data[lscpuKeyModelName] + if !ok { + return "", fmt.Errorf("can not find the key %q", lscpuKeyModelName) + } + + cpuCountStr, ok := data[lscpuKeyCount] + if !ok { + logger.Warningf("can not find the key %q", lscpuKeyCount) + return modelName, nil + } + + cpuCount, err := strconv.ParseInt(cpuCountStr, 10, 64) + if err != nil { + logger.Warning(err) + return modelName, nil + } + if strings.Contains(modelName, "Hz") { + return fmt.Sprintf("%s x %d", modelName, cpuCount), nil + } else { + return fmt.Sprintf("%s @ %.2fGHz x %d", modelName, freq, cpuCount), nil + } +} + func getProcessorByLscpu(data map[string]string) (string, error) { modelName, ok := data[lscpuKeyModelName] if !ok { @@ -56,9 +83,9 @@ func getCPUMaxMHzByLscpu(data map[string]string) (float64, error) { return strconv.ParseFloat(maxMHz, 64) } -//float数比较 +// float数比较 func isFloatEqual(f1, f2 float64) bool { - return math.Abs(f1 - f2) < compareAllowMin + return math.Abs(f1-f2) < compareAllowMin } func GetCPUInfo(file string) (string, error) { diff --git a/systeminfo/disk.go b/systeminfo1/disk.go similarity index 97% rename from systeminfo/disk.go rename to systeminfo1/disk.go index f7013bfc1..e0f15a250 100644 --- a/systeminfo/disk.go +++ b/systeminfo1/disk.go @@ -7,9 +7,10 @@ package systeminfo import ( "fmt" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" ) -//nolint + +// nolint type diskInfo struct { Drive dbus.ObjectPath // org.freedesktop.UDisks2.Block Drive MountPoints []string // org.freedesktop.UDisks2.Filesystem MountPoints diff --git a/systeminfo/distro.go b/systeminfo1/distro.go similarity index 100% rename from systeminfo/distro.go rename to systeminfo1/distro.go diff --git a/systeminfo/exported_methods_auto.go b/systeminfo1/exported_methods_auto.go similarity index 100% rename from systeminfo/exported_methods_auto.go rename to systeminfo1/exported_methods_auto.go diff --git a/systeminfo/info.go b/systeminfo1/info.go similarity index 91% rename from systeminfo/info.go rename to systeminfo1/info.go index 6c10de2ad..cad078ba5 100644 --- a/systeminfo/info.go +++ b/systeminfo1/info.go @@ -8,11 +8,11 @@ import ( "sync" "time" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-daemon/common/cpuinfo" "github.com/linuxdeepin/dde-daemon/loader" - systeminfo "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.systeminfo" ConfigManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" + systeminfo "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.systeminfo1" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/log" ) @@ -20,8 +20,8 @@ import ( //go:generate dbusutil-gen em -type SystemInfo const ( - dbusServiceName = "com.deepin.daemon.SystemInfo" - dbusPath = "/com/deepin/daemon/SystemInfo" + dbusServiceName = "org.deepin.dde.SystemInfo1" + dbusPath = "/org/deepin/dde/SystemInfo1" dbusInterface = dbusServiceName dsettingsAppID = "org.deepin.dde.daemon" dsettingsSystemInfoName = "org.deepin.dde.daemon.systeminfo" @@ -125,7 +125,7 @@ func (d *Daemon) initSysSystemInfo() { d.sigSystemLoop.Start() d.systeminfo.InitSignalExt(d.sigSystemLoop, true) - // 通过 demicode 获取 "CPU 频率", 接收 com.deepin.daemon.SystemInfo 的属性 CurrentSpeed 改变信号 + // 通过 demicode 获取 "CPU 频率", 接收 org.deepin.dde.SystemInfo1 的属性 CurrentSpeed 改变信号 err = d.systeminfo.CurrentSpeed().ConnectChanged(func(hasValue bool, value uint64) { logger.Infof("demicode hasValue : %t, CurrentSpeed : %d", hasValue, value) if !hasValue { @@ -240,6 +240,16 @@ func (info *SystemInfo) init() { } } + // 适配兆芯KX-7000 + if lscpuRes[lscpuKeyCPUfamily] == "7" && + lscpuRes[lscpuKeyModel] == "107" && + lscpuRes[lscpuKeyStepping] == "1" { + info.Processor, err = getProcessorByLscpuExt(lscpuRes, info.CPUMaxMHz/1000) + if err != nil { + logger.Warning(err) + } + } + if info.Processor == "" { info.Processor, err = getProcessorByLscpu(lscpuRes) if err != nil { diff --git a/systeminfo/info_test.go b/systeminfo1/info_test.go similarity index 100% rename from systeminfo/info_test.go rename to systeminfo1/info_test.go diff --git a/systeminfo/init.go b/systeminfo1/init.go similarity index 100% rename from systeminfo/init.go rename to systeminfo1/init.go diff --git a/systeminfo/lsblk_disk.go b/systeminfo1/lsblk_disk.go similarity index 100% rename from systeminfo/lsblk_disk.go rename to systeminfo1/lsblk_disk.go index 7588d409c..4aa50cef5 100644 --- a/systeminfo/lsblk_disk.go +++ b/systeminfo1/lsblk_disk.go @@ -5,9 +5,9 @@ package systeminfo import ( - "fmt" "crypto/sha256" "encoding/json" + "fmt" "os/exec" "strconv" "strings" diff --git a/systeminfo/testdata/arm-cpuinfo b/systeminfo1/testdata/arm-cpuinfo similarity index 100% rename from systeminfo/testdata/arm-cpuinfo rename to systeminfo1/testdata/arm-cpuinfo diff --git a/systeminfo/testdata/cpuinfo b/systeminfo1/testdata/cpuinfo similarity index 100% rename from systeminfo/testdata/cpuinfo rename to systeminfo1/testdata/cpuinfo diff --git a/systeminfo/testdata/deepin-version b/systeminfo1/testdata/deepin-version similarity index 100% rename from systeminfo/testdata/deepin-version rename to systeminfo1/testdata/deepin-version diff --git a/systeminfo/testdata/hw_kirin-cpuinfo b/systeminfo1/testdata/hw_kirin-cpuinfo similarity index 100% rename from systeminfo/testdata/hw_kirin-cpuinfo rename to systeminfo1/testdata/hw_kirin-cpuinfo diff --git a/systeminfo/testdata/loonson3-cpuinfo b/systeminfo1/testdata/loonson3-cpuinfo similarity index 100% rename from systeminfo/testdata/loonson3-cpuinfo rename to systeminfo1/testdata/loonson3-cpuinfo diff --git a/systeminfo/testdata/lsCPU b/systeminfo1/testdata/lsCPU similarity index 100% rename from systeminfo/testdata/lsCPU rename to systeminfo1/testdata/lsCPU diff --git a/systeminfo/testdata/lsb-release b/systeminfo1/testdata/lsb-release similarity index 100% rename from systeminfo/testdata/lsb-release rename to systeminfo1/testdata/lsb-release diff --git a/systeminfo/testdata/meminfo b/systeminfo1/testdata/meminfo similarity index 100% rename from systeminfo/testdata/meminfo rename to systeminfo1/testdata/meminfo diff --git a/systeminfo/testdata/sw-cpuinfo b/systeminfo1/testdata/sw-cpuinfo similarity index 100% rename from systeminfo/testdata/sw-cpuinfo rename to systeminfo1/testdata/sw-cpuinfo diff --git a/systeminfo/testdata/systeminfo.cache b/systeminfo1/testdata/systeminfo.cache similarity index 100% rename from systeminfo/testdata/systeminfo.cache rename to systeminfo1/testdata/systeminfo.cache diff --git a/systeminfo1/utils.go b/systeminfo1/utils.go new file mode 100644 index 000000000..01fa584c2 --- /dev/null +++ b/systeminfo1/utils.go @@ -0,0 +1,95 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package systeminfo + +import ( + "fmt" + "io/ioutil" + "os/exec" + "strconv" + "strings" +) + +const ( + memKeyTotal = "MemTotal" + memKeyDelim = ":" + lscpuKeyDelim = ":" +) + +func getMemoryFromFile(file string) (uint64, error) { + ret, err := parseInfoFile(file, memKeyDelim) + if err != nil { + return 0, err + } + + value, ok := ret[memKeyTotal] + if !ok { + return 0, fmt.Errorf("Can not find the key '%s'", memKeyTotal) + } + + cap, err := strconv.ParseUint(strings.Split(value, " ")[0], 10, 64) + if err != nil { + return 0, err + } + + return cap * 1024, nil +} + +// 执行命令:/usr/bin/getconf LONG_BIT 获取系统位数 +func systemBit() string { + output, err := exec.Command("/usr/bin/getconf", "LONG_BIT").Output() + if err != nil { + return "64" + } + + v := strings.TrimRight(string(output), "\n") + return v +} + +func runLscpu() (map[string]string, error) { + cmd := exec.Command("lscpu") + cmd.Env = []string{"LC_ALL=C"} + out, err := cmd.Output() + if err != nil { + return nil, err + } + + lines := strings.Split(string(out), "\n") + res := make(map[string]string, len(lines)) + for _, line := range lines { + items := strings.SplitN(line, lscpuKeyDelim, 2) + if len(items) != 2 { + continue + } + + res[items[0]] = strings.TrimSpace(items[1]) + } + + return res, nil +} + +func parseInfoFile(file, delim string) (map[string]string, error) { + content, err := ioutil.ReadFile(file) + if err != nil { + return nil, err + } + + var ret = make(map[string]string) + lines := strings.Split(string(content), "\n") + for _, line := range lines { + if len(line) == 0 { + continue + } + + array := strings.Split(line, delim) + if len(array) != 2 { + continue + } + + ret[strings.TrimSpace(array[0])] = strings.TrimSpace(array[1]) + } + + return ret, nil +} diff --git a/systeminfo/version.go b/systeminfo1/version.go similarity index 100% rename from systeminfo/version.go rename to systeminfo1/version.go diff --git a/timedate/daemon.go b/timedate/daemon.go deleted file mode 100644 index 074d0e5fe..000000000 --- a/timedate/daemon.go +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package timedate - -import ( - "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/dde-daemon/loader" -) - -var ( - logger = log.NewLogger("daemon/timedate") -) - -type Daemon struct { - *loader.ModuleBase - manager *Manager - managerFormat *ManagerFormat -} - -func NewDaemon(logger *log.Logger) *Daemon { - daemon := new(Daemon) - daemon.ModuleBase = loader.NewModuleBase("timedate", daemon, logger) - return daemon -} - -func (d *Daemon) GetDependencies() []string { - return []string{} -} - -// Start to run time date manager -func (d *Daemon) Start() error { - if d.manager != nil { - return nil - } - service := loader.GetService() - - var err error - d.manager, err = NewManager(service) - if err != nil { - return err - } - - err = service.Export(dbusPath, d.manager) - if err != nil { - return err - } - - d.managerFormat, err = newManagerFormat(service) - if err != nil { - return err - } - - err = service.Export(dbusFormatPath, d.managerFormat) - if err != nil { - return err - } - - err = d.managerFormat.initPropertyWriteCallback(service) - if err != nil { - logger.Warning("call SetWriteCallback err:", err) - } else { - logger.Info("call SetWriteCallback successful.") - } - - err = service.RequestName(dbusFormatServiceName) - if err != nil { - return err - } - - err = service.RequestName(dbusServiceName) - if err != nil { - return err - } - - go func() { - d.manager.init() - }() - - go func() { - d.managerFormat.init() - }() - - return nil -} - -// Stop the time date manager -func (d *Daemon) Stop() error { - if d.manager == nil { - return nil - } - - service := loader.GetService() - err := service.ReleaseName(dbusServiceName) - if err != nil { - return err - } - - err = service.StopExport(d.manager) - if err != nil { - return err - } - - d.manager.destroy() - d.manager = nil - - d.managerFormat.destroy() - d.managerFormat = nil - return nil -} diff --git a/timedate/manager.go b/timedate/manager.go deleted file mode 100644 index a41743d02..000000000 --- a/timedate/manager.go +++ /dev/null @@ -1,271 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package timedate - -import ( - "os" - "os/user" - "strings" - "sync" - - "github.com/godbus/dbus" - accounts "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.accounts" - timedated "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.timedated" - timedate1 "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.timedate1" - "github.com/linuxdeepin/go-gir/gio-2.0" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/dbusutil/gsprop" - "github.com/linuxdeepin/go-lib/dbusutil/proxy" - ddbus "github.com/linuxdeepin/dde-daemon/dbus" - "github.com/linuxdeepin/dde-daemon/session/common" -) - -const ( - timeDateSchema = "com.deepin.dde.datetime" - settingsKey24Hour = "is-24hour" - settingsKeyTimezoneList = "user-timezone-list" - settingsKeyDSTOffset = "dst-offset" - settingsKeyWeekdayFormat = "weekday-format" - settingsKeyShortDateFormat = "short-date-format" - settingsKeyLongDateFormat = "long-date-format" - settingsKeyShortTimeFormat = "short-time-format" - settingsKeyLongTimeFormat = "long-time-format" - settingsKeyWeekBegins = "week-begins" - - dbusServiceName = "com.deepin.daemon.Timedate" - dbusPath = "/com/deepin/daemon/Timedate" - dbusInterface = dbusServiceName -) - -//go:generate dbusutil-gen -type Manager manager.go -//go:generate dbusutil-gen em -type Manager - -// Manage time settings -type Manager struct { - service *dbusutil.Service - systemSigLoop *dbusutil.SignalLoop - PropsMu sync.RWMutex - // Whether can use NTP service - CanNTP bool - // Whether enable NTP service - NTP bool - // Whether set RTC to Local standard - LocalRTC bool - - // Current timezone - Timezone string - NTPServer string - - // dbusutil-gen: ignore-below - // Use 24 hour format to display time - Use24HourFormat gsprop.Bool `prop:"access:rw"` - // DST offset - DSTOffset gsprop.Int `prop:"access:rw"` - // User added timezone list - UserTimezones gsprop.Strv - - // weekday shows format - WeekdayFormat gsprop.Int `prop:"access:rw"` - - // short date shows format - ShortDateFormat gsprop.Int `prop:"access:rw"` - - // long date shows format - LongDateFormat gsprop.Int `prop:"access:rw"` - - // short time shows format - ShortTimeFormat gsprop.Int `prop:"access:rw"` - - // long time shows format - LongTimeFormat gsprop.Int `prop:"access:rw"` - - WeekBegins gsprop.Int `prop:"access:rw"` - - settings *gio.Settings - td timedate1.Timedate - setter timedated.Timedated - userObj accounts.User - - //nolint - signals *struct { - TimeUpdate struct { - } - } -} - -// Create Manager, if create freedesktop timedate1 failed return error -func NewManager(service *dbusutil.Service) (*Manager, error) { - sysBus, err := dbus.SystemBus() - if err != nil { - return nil, err - } - - var m = &Manager{ - service: service, - } - - m.systemSigLoop = dbusutil.NewSignalLoop(sysBus, 10) - m.td = timedate1.NewTimedate(sysBus) - m.setter = timedated.NewTimedated(sysBus) - - m.settings = gio.NewSettings(timeDateSchema) - m.Use24HourFormat.Bind(m.settings, settingsKey24Hour) - m.DSTOffset.Bind(m.settings, settingsKeyDSTOffset) - m.UserTimezones.Bind(m.settings, settingsKeyTimezoneList) - - m.WeekdayFormat.Bind(m.settings, settingsKeyWeekdayFormat) - m.ShortDateFormat.Bind(m.settings, settingsKeyShortDateFormat) - m.LongDateFormat.Bind(m.settings, settingsKeyLongDateFormat) - m.ShortTimeFormat.Bind(m.settings, settingsKeyShortTimeFormat) - m.LongTimeFormat.Bind(m.settings, settingsKeyLongTimeFormat) - m.WeekBegins.Bind(m.settings, settingsKeyWeekBegins) - - return m, nil -} - -func (m *Manager) init() { - m.PropsMu.Lock() - - canNTP, err := m.td.CanNTP().Get(0) - if err != nil { - logger.Warning(err) - } - m.setPropCanNTP(canNTP) - - ntp, err := m.td.NTP().Get(0) - if err != nil { - logger.Warning(err) - } - m.setPropNTP(ntp) - - localRTC, err := m.td.LocalRTC().Get(0) - if err != nil { - logger.Warning(err) - } - m.setPropLocalRTC(localRTC) - - timezone, err := m.td.Timezone().Get(0) - if err != nil { - logger.Warning(err) - } - - targetPath, err := os.Readlink("/etc/localtime") - if err != nil { - logger.Warning("Error reading the symlink:", err) - } - - subPath := "/usr/share/zoneinfo/" - idx := strings.Index(targetPath, subPath) - if idx >= 0 { - extractedPath := targetPath[idx:] - actualZone := strings.TrimPrefix(extractedPath, subPath) - if actualZone != "" && actualZone != timezone { - logger.Warningf("/etc/localtime : %s, org.freedesktop.timedate1.Timezone : %s", actualZone, timezone) - timezone = actualZone - } - } - m.setPropTimezone(timezone) - - m.PropsMu.Unlock() - - newList, hasNil := filterNilString(m.UserTimezones.Get()) - if hasNil { - m.UserTimezones.Set(newList) - } - err = m.AddUserTimezone(m.Timezone) - if err != nil { - logger.Warning("AddUserTimezone error:", err) - } - - err = common.ActivateSysDaemonService(m.setter.ServiceName_()) - if err != nil { - logger.Warning(err) - } else { - ntpServer, err := m.setter.NTPServer().Get(0) - if err != nil { - logger.Warning(err) - } else { - m.NTPServer = ntpServer - } - } - - sysBus := m.systemSigLoop.Conn() - m.initUserObj(sysBus) - m.handleGSettingsChanged() - m.systemSigLoop.Start() - m.listenPropChanged() -} - -func (m *Manager) destroy() { - m.settings.Unref() - m.td.RemoveHandler(proxy.RemoveAllHandlers) - m.systemSigLoop.Stop() -} - -func (*Manager) GetInterfaceName() string { - return dbusInterface -} - -func (m *Manager) initUserObj(systemConn *dbus.Conn) { - cur, err := user.Current() - if err != nil { - logger.Warning("failed to get current user:", err) - return - } - - err = common.ActivateSysDaemonService("com.deepin.daemon.Accounts") - if err != nil { - logger.Warning(err) - } - - m.userObj, err = ddbus.NewUserByUid(systemConn, cur.Uid) - if err != nil { - logger.Warning("failed to new user object:", err) - return - } - - // sync use 24 hour format - use24hourFormat := m.settings.GetBoolean(settingsKey24Hour) - err = m.userObj.SetUse24HourFormat(0, use24hourFormat) - if err != nil { - logger.Warning(err) - } - - weekdayFormat := m.settings.GetInt(settingsKeyWeekdayFormat) - err = m.userObj.SetWeekdayFormat(0, weekdayFormat) - if err != nil { - logger.Warning(err) - } - - shortDateFormat := m.settings.GetInt(settingsKeyShortDateFormat) - err = m.userObj.SetShortDateFormat(0, shortDateFormat) - if err != nil { - logger.Warning(err) - } - - longDateFormat := m.settings.GetInt(settingsKeyLongDateFormat) - err = m.userObj.SetLongDateFormat(0, longDateFormat) - if err != nil { - logger.Warning(err) - } - - shortTimeFormat := m.settings.GetInt(settingsKeyShortTimeFormat) - err = m.userObj.SetShortTimeFormat(0, shortTimeFormat) - if err != nil { - logger.Warning(err) - } - - longTimeFormat := m.settings.GetInt(settingsKeyLongTimeFormat) - err = m.userObj.SetLongDateFormat(0, longTimeFormat) - if err != nil { - logger.Warning(err) - } - - weekBegins := m.settings.GetInt(settingsKeyWeekBegins) - err = m.userObj.SetWeekBegins(0, weekBegins) - if err != nil { - logger.Warning(err) - } -} diff --git a/timedate/manager_ifc.go b/timedate/manager_ifc.go deleted file mode 100644 index 0d7c9970f..000000000 --- a/timedate/manager_ifc.go +++ /dev/null @@ -1,204 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package timedate - -import ( - "time" - - "github.com/godbus/dbus" - "github.com/linuxdeepin/go-lib/dbusutil" - . "github.com/linuxdeepin/go-lib/gettext" - "github.com/linuxdeepin/dde-daemon/timedate/zoneinfo" -) - -func (m *Manager) Reset() *dbus.Error { - return m.SetNTP(true) -} - -// SetDate Set the system clock to the specified. -// -// The time may be specified in the format '2015' '1' '1' '18' '18' '18' '8'. -func (m *Manager) SetDate(year, month, day, hour, min, sec, nsec int32) *dbus.Error { - loc, err := time.LoadLocation(m.Timezone) - if err != nil { - logger.Debugf("Load location '%s' failed: %v", m.Timezone, err) - return dbusutil.ToError(err) - } - t := time.Date(int(year), time.Month(month), int(day), - int(hour), int(min), int(sec), int(nsec), loc) - - // microseconds since 1 Jan 1970 UTC - us := (t.Unix() * 1000000) + int64(t.Nanosecond()/1000) - err1 := m.SetTime(us, false) - if err1 == nil { - err = m.service.Emit(m, "TimeUpdate") - if err != nil { - logger.Debug("emit TimeUpdate failed:", err) - } - } - return err1 -} - -// Set the system clock to the specified. -// -// usec: pass a value of microseconds since 1 Jan 1970 UTC. -// -// relative: if true, the passed usec value will be added to the current system time; if false, the current system time will be set to the passed usec value. -func (m *Manager) SetTime(usec int64, relative bool) *dbus.Error { - err := m.setter.SetTime(0, usec, relative, - Tr("Authentication is required to set the system time")) - if err != nil { - logger.Debug("SetTime failed:", err) - } - - return dbusutil.ToError(err) -} - -// To control whether the system clock is synchronized with the network. -// -// useNTP: if true, enable ntp; else disable -func (m *Manager) SetNTP(useNTP bool) *dbus.Error { - err := m.setter.SetNTP(0, useNTP, - Tr("Authentication is required to control whether network time synchronization shall be enabled")) - if err != nil { - logger.Debug("SetNTP failed:", err) - } - - return dbusutil.ToError(err) -} - -func (m *Manager) SetNTPServer(server string) *dbus.Error { - err := m.setter.SetNTPServer(0, server, - Tr("Authentication is required to change NTP server")) - if err != nil { - logger.Warning("SetNTPServer failed:", err) - } - - return dbusutil.ToError(err) -} - -func (m *Manager) GetSampleNTPServers() (servers []string, busErr *dbus.Error) { - servers = []string{ - "ntp.ntsc.ac.cn", - "cn.ntp.org.cn", - - "0.debian.pool.ntp.org", - "1.debian.pool.ntp.org", - "2.debian.pool.ntp.org", - "3.debian.pool.ntp.org", - - "0.arch.pool.ntp.org", - "1.arch.pool.ntp.org", - "2.arch.pool.ntp.org", - "3.arch.pool.ntp.org", - - "0.fedora.pool.ntp.org", - "1.fedora.pool.ntp.org", - "2.fedora.pool.ntp.org", - "3.fedora.pool.ntp.org", - } - return servers, nil -} - -// To control whether the RTC is the local time or UTC. -// Standards are divided into: localtime and UTC. -// UTC standard will automatically adjust the daylight saving time. -// -// 实时时间(RTC)是否使用 local 时间标准。时间标准分为 local 和 UTC。 -// UTC 时间标准会自动根据夏令时而调整系统时间。 -// -// localRTC: whether to use local time. -// -// fixSystem: if true, will use the RTC time to adjust the system clock; if false, the system time is written to the RTC taking the new setting into account. -func (m *Manager) SetLocalRTC(localRTC, fixSystem bool) *dbus.Error { - err := m.setter.SetLocalRTC(0, localRTC, fixSystem, - Tr("Authentication is required to control whether the RTC stores the local or UTC time")) - if err != nil { - logger.Debug("SetLocalRTC failed:", err) - } - - return dbusutil.ToError(err) -} - -// Set the system time zone to the specified value. -// timezones you may parse from /usr/share/zoneinfo/zone.tab. -// -// zone: pass a value like "Asia/Shanghai" to set the timezone. -func (m *Manager) SetTimezone(zone string) *dbus.Error { - ok, err := zoneinfo.IsZoneValid(zone) - if err != nil { - return dbusutil.ToError(err) - } - if !ok { - logger.Debug("Invalid zone:", zone) - return dbusutil.ToError(zoneinfo.ErrZoneInvalid) - } - - err = m.setter.SetTimezone(0, zone, - Tr("Authentication is required to set the system timezone")) - if err != nil { - logger.Debug("SetTimezone failed:", err) - return dbusutil.ToError(err) - } - - return m.AddUserTimezone(zone) -} - -// Add the specified time zone to user time zone list. -func (m *Manager) AddUserTimezone(zone string) *dbus.Error { - ok, err := zoneinfo.IsZoneValid(zone) - if err != nil { - return dbusutil.ToError(err) - } - if !ok { - logger.Debug("Invalid zone:", zone) - return dbusutil.ToError(zoneinfo.ErrZoneInvalid) - } - - oldList, hasNil := filterNilString(m.UserTimezones.Get()) - newList, added := addItemToList(zone, oldList) - if added || hasNil { - m.UserTimezones.Set(newList) - } - return nil -} - -// Delete the specified time zone from user time zone list. -func (m *Manager) DeleteUserTimezone(zone string) *dbus.Error { - ok, err := zoneinfo.IsZoneValid(zone) - if err != nil { - return dbusutil.ToError(err) - } - if !ok { - logger.Debug("Invalid zone:", zone) - return dbusutil.ToError(zoneinfo.ErrZoneInvalid) - } - - oldList, hasNil := filterNilString(m.UserTimezones.Get()) - newList, deleted := deleteItemFromList(zone, oldList) - if deleted || hasNil { - m.UserTimezones.Set(newList) - } - return nil -} - -// GetZoneInfo returns the information of the specified time zone. -func (m *Manager) GetZoneInfo(zone string) (zoneInfo zoneinfo.ZoneInfo, busErr *dbus.Error) { - m.PropsMu.Lock() - info, err := zoneinfo.GetZoneInfo(zone) - m.PropsMu.Unlock() - if err != nil { - logger.Debugf("Get zone info for '%s' failed: %v", zone, err) - return zoneinfo.ZoneInfo{}, dbusutil.ToError(err) - } - - return *info, nil -} - -// GetZoneList returns all the valid timezones. -func (m *Manager) GetZoneList() (zoneList []string, busErr *dbus.Error) { - zoneList, err := zoneinfo.GetAllZones() - return zoneList, dbusutil.ToError(err) -} diff --git a/timedate1/daemon.go b/timedate1/daemon.go new file mode 100644 index 000000000..e015d5596 --- /dev/null +++ b/timedate1/daemon.go @@ -0,0 +1,111 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package timedate + +import ( + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" +) + +var ( + logger = log.NewLogger("daemon/timedate") +) + +type Daemon struct { + *loader.ModuleBase + manager *Manager + managerFormat *ManagerFormat +} + +func NewDaemon(logger *log.Logger) *Daemon { + daemon := new(Daemon) + daemon.ModuleBase = loader.NewModuleBase("timedate", daemon, logger) + return daemon +} + +func (d *Daemon) GetDependencies() []string { + return []string{} +} + +// Start to run time date manager +func (d *Daemon) Start() error { + if d.manager != nil { + return nil + } + service := loader.GetService() + + var err error + d.manager, err = NewManager(service) + if err != nil { + return err + } + + err = service.Export(dbusPath, d.manager) + if err != nil { + return err + } + + d.managerFormat, err = newManagerFormat(service) + if err != nil { + return err + } + + err = service.Export(dbusFormatPath, d.managerFormat) + if err != nil { + return err + } + + err = d.managerFormat.initPropertyWriteCallback(service) + if err != nil { + logger.Warning("call SetWriteCallback err:", err) + } else { + logger.Info("call SetWriteCallback successful.") + } + + err = service.RequestName(dbusFormatServiceName) + if err != nil { + return err + } + + err = service.RequestName(dbusServiceName) + if err != nil { + return err + } + + go func() { + d.manager.init() + }() + + go func() { + d.managerFormat.init() + }() + + return nil +} + +// Stop the time date manager +func (d *Daemon) Stop() error { + if d.manager == nil { + return nil + } + + service := loader.GetService() + err := service.ReleaseName(dbusServiceName) + if err != nil { + return err + } + + err = service.StopExport(d.manager) + if err != nil { + return err + } + + d.manager.destroy() + d.manager = nil + + d.managerFormat.destroy() + d.managerFormat = nil + return nil +} diff --git a/timedate/daemon_test.go b/timedate1/daemon_test.go similarity index 100% rename from timedate/daemon_test.go rename to timedate1/daemon_test.go diff --git a/timedate/exported_methods_auto.go b/timedate1/exported_methods_auto.go similarity index 100% rename from timedate/exported_methods_auto.go rename to timedate1/exported_methods_auto.go diff --git a/timedate/handle_event.go b/timedate1/handle_event.go similarity index 100% rename from timedate/handle_event.go rename to timedate1/handle_event.go diff --git a/timedate/init.go b/timedate1/init.go similarity index 100% rename from timedate/init.go rename to timedate1/init.go diff --git a/timedate1/manager.go b/timedate1/manager.go new file mode 100644 index 000000000..1d28bb6e7 --- /dev/null +++ b/timedate1/manager.go @@ -0,0 +1,271 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package timedate + +import ( + "os" + "os/user" + "strings" + "sync" + + "github.com/godbus/dbus/v5" + ddbus "github.com/linuxdeepin/dde-daemon/dbus" + "github.com/linuxdeepin/dde-daemon/session/common" + accounts "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.accounts1" + timedated "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.timedate1" + timedate1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.timedate1" + "github.com/linuxdeepin/go-gir/gio-2.0" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/dbusutil/gsprop" + "github.com/linuxdeepin/go-lib/dbusutil/proxy" +) + +const ( + timeDateSchema = "com.deepin.dde.datetime" + settingsKey24Hour = "is-24hour" + settingsKeyTimezoneList = "user-timezone-list" + settingsKeyDSTOffset = "dst-offset" + settingsKeyWeekdayFormat = "weekday-format" + settingsKeyShortDateFormat = "short-date-format" + settingsKeyLongDateFormat = "long-date-format" + settingsKeyShortTimeFormat = "short-time-format" + settingsKeyLongTimeFormat = "long-time-format" + settingsKeyWeekBegins = "week-begins" + + dbusServiceName = "org.deepin.dde.Timedate1" + dbusPath = "/org/deepin/dde/Timedate1" + dbusInterface = dbusServiceName +) + +//go:generate dbusutil-gen -type Manager manager.go +//go:generate dbusutil-gen em -type Manager + +// Manage time settings +type Manager struct { + service *dbusutil.Service + systemSigLoop *dbusutil.SignalLoop + PropsMu sync.RWMutex + // Whether can use NTP service + CanNTP bool + // Whether enable NTP service + NTP bool + // Whether set RTC to Local standard + LocalRTC bool + + // Current timezone + Timezone string + NTPServer string + + // dbusutil-gen: ignore-below + // Use 24 hour format to display time + Use24HourFormat gsprop.Bool `prop:"access:rw"` + // DST offset + DSTOffset gsprop.Int `prop:"access:rw"` + // User added timezone list + UserTimezones gsprop.Strv + + // weekday shows format + WeekdayFormat gsprop.Int `prop:"access:rw"` + + // short date shows format + ShortDateFormat gsprop.Int `prop:"access:rw"` + + // long date shows format + LongDateFormat gsprop.Int `prop:"access:rw"` + + // short time shows format + ShortTimeFormat gsprop.Int `prop:"access:rw"` + + // long time shows format + LongTimeFormat gsprop.Int `prop:"access:rw"` + + WeekBegins gsprop.Int `prop:"access:rw"` + + settings *gio.Settings + td timedate1.Timedate + setter timedated.Timedate + userObj accounts.User + + //nolint + signals *struct { + TimeUpdate struct { + } + } +} + +// Create Manager, if create freedesktop timedate1 failed return error +func NewManager(service *dbusutil.Service) (*Manager, error) { + sysBus, err := dbus.SystemBus() + if err != nil { + return nil, err + } + + var m = &Manager{ + service: service, + } + + m.systemSigLoop = dbusutil.NewSignalLoop(sysBus, 10) + m.td = timedate1.NewTimedate(sysBus) + m.setter = timedated.NewTimedate(sysBus) + + m.settings = gio.NewSettings(timeDateSchema) + m.Use24HourFormat.Bind(m.settings, settingsKey24Hour) + m.DSTOffset.Bind(m.settings, settingsKeyDSTOffset) + m.UserTimezones.Bind(m.settings, settingsKeyTimezoneList) + + m.WeekdayFormat.Bind(m.settings, settingsKeyWeekdayFormat) + m.ShortDateFormat.Bind(m.settings, settingsKeyShortDateFormat) + m.LongDateFormat.Bind(m.settings, settingsKeyLongDateFormat) + m.ShortTimeFormat.Bind(m.settings, settingsKeyShortTimeFormat) + m.LongTimeFormat.Bind(m.settings, settingsKeyLongTimeFormat) + m.WeekBegins.Bind(m.settings, settingsKeyWeekBegins) + + return m, nil +} + +func (m *Manager) init() { + m.PropsMu.Lock() + + canNTP, err := m.td.CanNTP().Get(0) + if err != nil { + logger.Warning(err) + } + m.setPropCanNTP(canNTP) + + ntp, err := m.td.NTP().Get(0) + if err != nil { + logger.Warning(err) + } + m.setPropNTP(ntp) + + localRTC, err := m.td.LocalRTC().Get(0) + if err != nil { + logger.Warning(err) + } + m.setPropLocalRTC(localRTC) + + timezone, err := m.td.Timezone().Get(0) + if err != nil { + logger.Warning(err) + } + + targetPath, err := os.Readlink("/etc/localtime") + if err != nil { + logger.Warning("Error reading the symlink:", err) + } + + subPath := "/usr/share/zoneinfo/" + idx := strings.Index(targetPath, subPath) + if idx >= 0 { + extractedPath := targetPath[idx:] + actualZone := strings.TrimPrefix(extractedPath, subPath) + if actualZone != "" && actualZone != timezone { + logger.Warningf("/etc/localtime : %s, org.freedesktop.timedate1.Timezone : %s", actualZone, timezone) + timezone = actualZone + } + } + m.setPropTimezone(timezone) + + m.PropsMu.Unlock() + + newList, hasNil := filterNilString(m.UserTimezones.Get()) + if hasNil { + m.UserTimezones.Set(newList) + } + err = m.AddUserTimezone(m.Timezone) + if err != nil { + logger.Warning("AddUserTimezone error:", err) + } + + err = common.ActivateSysDaemonService(m.setter.ServiceName_()) + if err != nil { + logger.Warning(err) + } else { + ntpServer, err := m.setter.NTPServer().Get(0) + if err != nil { + logger.Warning(err) + } else { + m.NTPServer = ntpServer + } + } + + sysBus := m.systemSigLoop.Conn() + m.initUserObj(sysBus) + m.handleGSettingsChanged() + m.systemSigLoop.Start() + m.listenPropChanged() +} + +func (m *Manager) destroy() { + m.settings.Unref() + m.td.RemoveHandler(proxy.RemoveAllHandlers) + m.systemSigLoop.Stop() +} + +func (*Manager) GetInterfaceName() string { + return dbusInterface +} + +func (m *Manager) initUserObj(systemConn *dbus.Conn) { + cur, err := user.Current() + if err != nil { + logger.Warning("failed to get current user:", err) + return + } + + err = common.ActivateSysDaemonService("org.deepin.dde.Accounts1") + if err != nil { + logger.Warning(err) + } + + m.userObj, err = ddbus.NewUserByUid(systemConn, cur.Uid) + if err != nil { + logger.Warning("failed to new user object:", err) + return + } + + // sync use 24 hour format + use24hourFormat := m.settings.GetBoolean(settingsKey24Hour) + err = m.userObj.SetUse24HourFormat(0, use24hourFormat) + if err != nil { + logger.Warning(err) + } + + weekdayFormat := m.settings.GetInt(settingsKeyWeekdayFormat) + err = m.userObj.SetWeekdayFormat(0, weekdayFormat) + if err != nil { + logger.Warning(err) + } + + shortDateFormat := m.settings.GetInt(settingsKeyShortDateFormat) + err = m.userObj.SetShortDateFormat(0, shortDateFormat) + if err != nil { + logger.Warning(err) + } + + longDateFormat := m.settings.GetInt(settingsKeyLongDateFormat) + err = m.userObj.SetLongDateFormat(0, longDateFormat) + if err != nil { + logger.Warning(err) + } + + shortTimeFormat := m.settings.GetInt(settingsKeyShortTimeFormat) + err = m.userObj.SetShortTimeFormat(0, shortTimeFormat) + if err != nil { + logger.Warning(err) + } + + longTimeFormat := m.settings.GetInt(settingsKeyLongTimeFormat) + err = m.userObj.SetLongDateFormat(0, longTimeFormat) + if err != nil { + logger.Warning(err) + } + + weekBegins := m.settings.GetInt(settingsKeyWeekBegins) + err = m.userObj.SetWeekBegins(0, weekBegins) + if err != nil { + logger.Warning(err) + } +} diff --git a/timedate/manager_format.go b/timedate1/manager_format.go similarity index 93% rename from timedate/manager_format.go rename to timedate1/manager_format.go index 886199674..ece68bc99 100644 --- a/timedate/manager_format.go +++ b/timedate1/manager_format.go @@ -9,16 +9,16 @@ import ( "strings" "sync" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/gettext" ) const ( - dbusFormatPath = "/com/deepin/daemon/Format" - dbusFormatInterface = "com.deepin.daemon.Format" - configManagerId = "org.desktopspec.ConfigManager" - dbusFormatServiceName = dbusFormatInterface + dbusFormatPath = "/org/deepin/dde/Format" + dbusFormatInterface = "org.deepin.dde.Format" + configManagerId = "org.desktopspec.ConfigManager" + dbusFormatServiceName = dbusFormatInterface ) //go:generate dbusutil-gen -type ManagerFormat manager_format.go @@ -31,12 +31,12 @@ type ManagerFormat struct { PropsMu sync.RWMutex // dsg config - CurrencySymbol string `prop:"access:rw"` + CurrencySymbol string `prop:"access:rw"` PositiveCurrencyFormat string `prop:"access:rw"` NegativeCurrencyFormat string `prop:"access:rw"` - DecimalSymbol string `prop:"access:rw"` - DigitGroupingSymbol string `prop:"access:rw"` - DigitGrouping string `prop:"access:rw"` + DecimalSymbol string `prop:"access:rw"` + DigitGroupingSymbol string `prop:"access:rw"` + DigitGrouping string `prop:"access:rw"` configManagerPath dbus.ObjectPath } @@ -82,7 +82,7 @@ func newManagerFormat(service *dbusutil.Service) (*ManagerFormat, error) { logger.Infof(" [newManagerFormat] space : %v, decimalSymbol : %v", space, decimalSymbol) if decimalSymbol == string("Space") || decimalSymbol == space { - if m.setPropDecimalSymbol(space){ + if m.setPropDecimalSymbol(space) { m.setDsgData("decimalSymbol", space) } } @@ -251,7 +251,7 @@ func (m *ManagerFormat) getDsgData(key string) string { } systemConnObj := systemConn.Object("org.desktopspec.ConfigManager", m.configManagerPath) var value string - err = systemConnObj.Call("org.desktopspec.ConfigManager.Manager.value",0, key).Store(&value) + err = systemConnObj.Call("org.desktopspec.ConfigManager.Manager.value", 0, key).Store(&value) if err != nil { logger.Warningf("getDsgData key : %s. err : %s", key, err) return "" @@ -267,7 +267,7 @@ func (m *ManagerFormat) setDsgData(key, value string) bool { return false } systemConnObj := systemConn.Object("org.desktopspec.ConfigManager", m.configManagerPath) - err = systemConnObj.Call("org.desktopspec.ConfigManager.Manager.setValue",0, key, dbus.MakeVariant(value)).Store() + err = systemConnObj.Call("org.desktopspec.ConfigManager.Manager.setValue", 0, key, dbus.MakeVariant(value)).Store() if err != nil { logger.Warningf("setDsgData key : %s. err : %s", key, err) return false @@ -275,4 +275,4 @@ func (m *ManagerFormat) setDsgData(key, value string) bool { logger.Infof("setDsgData key : %s , value : %s", key, value) return true -} \ No newline at end of file +} diff --git a/timedate1/manager_ifc.go b/timedate1/manager_ifc.go new file mode 100644 index 000000000..03fd93407 --- /dev/null +++ b/timedate1/manager_ifc.go @@ -0,0 +1,204 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package timedate + +import ( + "time" + + "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/timedate1/zoneinfo" + "github.com/linuxdeepin/go-lib/dbusutil" + . "github.com/linuxdeepin/go-lib/gettext" +) + +func (m *Manager) Reset() *dbus.Error { + return m.SetNTP(true) +} + +// SetDate Set the system clock to the specified. +// +// The time may be specified in the format '2015' '1' '1' '18' '18' '18' '8'. +func (m *Manager) SetDate(year, month, day, hour, min, sec, nsec int32) *dbus.Error { + loc, err := time.LoadLocation(m.Timezone) + if err != nil { + logger.Debugf("Load location '%s' failed: %v", m.Timezone, err) + return dbusutil.ToError(err) + } + t := time.Date(int(year), time.Month(month), int(day), + int(hour), int(min), int(sec), int(nsec), loc) + + // microseconds since 1 Jan 1970 UTC + us := (t.Unix() * 1000000) + int64(t.Nanosecond()/1000) + err1 := m.SetTime(us, false) + if err1 == nil { + err = m.service.Emit(m, "TimeUpdate") + if err != nil { + logger.Debug("emit TimeUpdate failed:", err) + } + } + return err1 +} + +// Set the system clock to the specified. +// +// usec: pass a value of microseconds since 1 Jan 1970 UTC. +// +// relative: if true, the passed usec value will be added to the current system time; if false, the current system time will be set to the passed usec value. +func (m *Manager) SetTime(usec int64, relative bool) *dbus.Error { + err := m.setter.SetTime(0, usec, relative, + Tr("Authentication is required to set the system time")) + if err != nil { + logger.Debug("SetTime failed:", err) + } + + return dbusutil.ToError(err) +} + +// To control whether the system clock is synchronized with the network. +// +// useNTP: if true, enable ntp; else disable +func (m *Manager) SetNTP(useNTP bool) *dbus.Error { + err := m.setter.SetNTP(0, useNTP, + Tr("Authentication is required to control whether network time synchronization shall be enabled")) + if err != nil { + logger.Debug("SetNTP failed:", err) + } + + return dbusutil.ToError(err) +} + +func (m *Manager) SetNTPServer(server string) *dbus.Error { + err := m.setter.SetNTPServer(0, server, + Tr("Authentication is required to change NTP server")) + if err != nil { + logger.Warning("SetNTPServer failed:", err) + } + + return dbusutil.ToError(err) +} + +func (m *Manager) GetSampleNTPServers() (servers []string, busErr *dbus.Error) { + servers = []string{ + "ntp.ntsc.ac.cn", + "cn.ntp.org.cn", + + "0.debian.pool.ntp.org", + "1.debian.pool.ntp.org", + "2.debian.pool.ntp.org", + "3.debian.pool.ntp.org", + + "0.arch.pool.ntp.org", + "1.arch.pool.ntp.org", + "2.arch.pool.ntp.org", + "3.arch.pool.ntp.org", + + "0.fedora.pool.ntp.org", + "1.fedora.pool.ntp.org", + "2.fedora.pool.ntp.org", + "3.fedora.pool.ntp.org", + } + return servers, nil +} + +// To control whether the RTC is the local time or UTC. +// Standards are divided into: localtime and UTC. +// UTC standard will automatically adjust the daylight saving time. +// +// 实时时间(RTC)是否使用 local 时间标准。时间标准分为 local 和 UTC。 +// UTC 时间标准会自动根据夏令时而调整系统时间。 +// +// localRTC: whether to use local time. +// +// fixSystem: if true, will use the RTC time to adjust the system clock; if false, the system time is written to the RTC taking the new setting into account. +func (m *Manager) SetLocalRTC(localRTC, fixSystem bool) *dbus.Error { + err := m.setter.SetLocalRTC(0, localRTC, fixSystem, + Tr("Authentication is required to control whether the RTC stores the local or UTC time")) + if err != nil { + logger.Debug("SetLocalRTC failed:", err) + } + + return dbusutil.ToError(err) +} + +// Set the system time zone to the specified value. +// timezones you may parse from /usr/share/zoneinfo/zone.tab. +// +// zone: pass a value like "Asia/Shanghai" to set the timezone. +func (m *Manager) SetTimezone(zone string) *dbus.Error { + ok, err := zoneinfo.IsZoneValid(zone) + if err != nil { + return dbusutil.ToError(err) + } + if !ok { + logger.Debug("Invalid zone:", zone) + return dbusutil.ToError(zoneinfo.ErrZoneInvalid) + } + + err = m.setter.SetTimezone(0, zone, + Tr("Authentication is required to set the system timezone")) + if err != nil { + logger.Debug("SetTimezone failed:", err) + return dbusutil.ToError(err) + } + + return m.AddUserTimezone(zone) +} + +// Add the specified time zone to user time zone list. +func (m *Manager) AddUserTimezone(zone string) *dbus.Error { + ok, err := zoneinfo.IsZoneValid(zone) + if err != nil { + return dbusutil.ToError(err) + } + if !ok { + logger.Debug("Invalid zone:", zone) + return dbusutil.ToError(zoneinfo.ErrZoneInvalid) + } + + oldList, hasNil := filterNilString(m.UserTimezones.Get()) + newList, added := addItemToList(zone, oldList) + if added || hasNil { + m.UserTimezones.Set(newList) + } + return nil +} + +// Delete the specified time zone from user time zone list. +func (m *Manager) DeleteUserTimezone(zone string) *dbus.Error { + ok, err := zoneinfo.IsZoneValid(zone) + if err != nil { + return dbusutil.ToError(err) + } + if !ok { + logger.Debug("Invalid zone:", zone) + return dbusutil.ToError(zoneinfo.ErrZoneInvalid) + } + + oldList, hasNil := filterNilString(m.UserTimezones.Get()) + newList, deleted := deleteItemFromList(zone, oldList) + if deleted || hasNil { + m.UserTimezones.Set(newList) + } + return nil +} + +// GetZoneInfo returns the information of the specified time zone. +func (m *Manager) GetZoneInfo(zone string) (zoneInfo zoneinfo.ZoneInfo, busErr *dbus.Error) { + m.PropsMu.Lock() + info, err := zoneinfo.GetZoneInfo(zone) + m.PropsMu.Unlock() + if err != nil { + logger.Debugf("Get zone info for '%s' failed: %v", zone, err) + return zoneinfo.ZoneInfo{}, dbusutil.ToError(err) + } + + return *info, nil +} + +// GetZoneList returns all the valid timezones. +func (m *Manager) GetZoneList() (zoneList []string, busErr *dbus.Error) { + zoneList, err := zoneinfo.GetAllZones() + return zoneList, dbusutil.ToError(err) +} diff --git a/timedate/manager_test.go b/timedate1/manager_test.go similarity index 100% rename from timedate/manager_test.go rename to timedate1/manager_test.go diff --git a/timedate/timedate_dbusutil.go b/timedate1/timedate_dbusutil.go similarity index 100% rename from timedate/timedate_dbusutil.go rename to timedate1/timedate_dbusutil.go diff --git a/timedate/timedate_format_dbusutil.go b/timedate1/timedate_format_dbusutil.go similarity index 100% rename from timedate/timedate_format_dbusutil.go rename to timedate1/timedate_format_dbusutil.go diff --git a/timedate/utils.go b/timedate1/utils.go similarity index 100% rename from timedate/utils.go rename to timedate1/utils.go diff --git a/timedate/utils_test.go b/timedate1/utils_test.go similarity index 100% rename from timedate/utils_test.go rename to timedate1/utils_test.go diff --git a/timedate/zoneinfo/testdata/dst_data b/timedate1/zoneinfo/testdata/dst_data similarity index 100% rename from timedate/zoneinfo/testdata/dst_data rename to timedate1/zoneinfo/testdata/dst_data diff --git a/timedate/zoneinfo/testdata/zone1970.tab b/timedate1/zoneinfo/testdata/zone1970.tab similarity index 100% rename from timedate/zoneinfo/testdata/zone1970.tab rename to timedate1/zoneinfo/testdata/zone1970.tab diff --git a/timedate/zoneinfo/timestamp.c b/timedate1/zoneinfo/timestamp.c similarity index 100% rename from timedate/zoneinfo/timestamp.c rename to timedate1/zoneinfo/timestamp.c diff --git a/timedate/zoneinfo/timestamp.h b/timedate1/zoneinfo/timestamp.h similarity index 100% rename from timedate/zoneinfo/timestamp.h rename to timedate1/zoneinfo/timestamp.h diff --git a/timedate/zoneinfo/wrapper.go b/timedate1/zoneinfo/wrapper.go similarity index 100% rename from timedate/zoneinfo/wrapper.go rename to timedate1/zoneinfo/wrapper.go diff --git a/timedate/zoneinfo/zdump.c b/timedate1/zoneinfo/zdump.c similarity index 100% rename from timedate/zoneinfo/zdump.c rename to timedate1/zoneinfo/zdump.c diff --git a/timedate/zoneinfo/zdump.h b/timedate1/zoneinfo/zdump.h similarity index 100% rename from timedate/zoneinfo/zdump.h rename to timedate1/zoneinfo/zdump.h diff --git a/timedate/zoneinfo/zone.go b/timedate1/zoneinfo/zone.go similarity index 100% rename from timedate/zoneinfo/zone.go rename to timedate1/zoneinfo/zone.go diff --git a/timedate/zoneinfo/zone_test.go b/timedate1/zoneinfo/zone_test.go similarity index 100% rename from timedate/zoneinfo/zone_test.go rename to timedate1/zoneinfo/zone_test.go diff --git a/trayicon/daemon.go b/trayicon/daemon.go deleted file mode 100644 index 43aa13d77..000000000 --- a/trayicon/daemon.go +++ /dev/null @@ -1,103 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package trayicon - -import ( - "os" - - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/log" - x "github.com/linuxdeepin/go-x11-client" - "github.com/linuxdeepin/dde-daemon/loader" -) - -type Daemon struct { - *loader.ModuleBase - manager *TrayManager - snw *StatusNotifierWatcher - sigLoop *dbusutil.SignalLoop // session bus signal loop -} - -const moduleName = "trayicon" - -func NewDaemon(logger *log.Logger) *Daemon { - daemon := new(Daemon) - daemon.ModuleBase = loader.NewModuleBase(moduleName, daemon, logger) - return daemon -} - -func (d *Daemon) GetDependencies() []string { - return []string{} -} - -func (d *Daemon) Name() string { - return moduleName -} - -func (d *Daemon) Start() error { - var err error - // init x conn - XConn, err = x.NewConn() - if err != nil { - return err - } - - initX() - service := loader.GetService() - d.manager = NewTrayManager(service) - - sessionBus, err := dbus.SessionBus() - if err != nil { - return err - } - - d.sigLoop = dbusutil.NewSignalLoop(sessionBus, 10) - d.sigLoop.Start() - - err = service.Export(dbusPath, d.manager) - if err != nil { - return err - } - - err = d.manager.sendClientMsgMANAGER() - if err != nil { - return err - } - - err = service.RequestName(dbusServiceName) - if err != nil { - return err - } - - err = service.Emit(d.manager, "Inited") - if err != nil { - return err - } - - if os.Getenv("DDE_DISABLE_STATUS_NOTIFIER_WATCHER") != "1" { - d.snw = newStatusNotifierWatcher(service, d.sigLoop) - d.snw.listenDBusNameOwnerChanged() - err = service.Export(snwDBusPath, d.snw) - if err != nil { - return err - } - err = service.RequestName(snwDBusServiceName) - if err != nil { - logger.Warning("failed to request name:", err) - return nil - } - } else { - logger.Info("disable status notifier watcher") - } - return nil -} - -func (d *Daemon) Stop() error { - if XConn != nil { - XConn.Close() - } - return nil -} diff --git a/trayicon/exported_methods_auto.go b/trayicon/exported_methods_auto.go deleted file mode 100644 index 84ed11d8e..000000000 --- a/trayicon/exported_methods_auto.go +++ /dev/null @@ -1,47 +0,0 @@ -// Code generated by "dbusutil-gen em -type TrayManager,StatusNotifierWatcher"; DO NOT EDIT. - -package trayicon - -import ( - "github.com/linuxdeepin/go-lib/dbusutil" -) - -func (v *StatusNotifierWatcher) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "RegisterStatusNotifierHost", - Fn: v.RegisterStatusNotifierHost, - InArgs: []string{"serviceName"}, - }, - { - Name: "RegisterStatusNotifierItem", - Fn: v.RegisterStatusNotifierItem, - InArgs: []string{"serviceOrPath"}, - }, - { - Name: "GetHostServiceName", - Fn: v.GetHostServiceName, - OutArgs: []string{"hostName"}, - }, - } -} -func (v *TrayManager) GetExportedMethods() dbusutil.ExportedMethods { - return dbusutil.ExportedMethods{ - { - Name: "EnableNotification", - Fn: v.EnableNotification, - InArgs: []string{"win", "enabled"}, - }, - { - Name: "GetName", - Fn: v.GetName, - InArgs: []string{"win"}, - OutArgs: []string{"name"}, - }, - { - Name: "Manage", - Fn: v.Manage, - OutArgs: []string{"ok"}, - }, - } -} diff --git a/trayicon/init.go b/trayicon/init.go deleted file mode 100644 index 532e4f24f..000000000 --- a/trayicon/init.go +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package trayicon - -import ( - x "github.com/linuxdeepin/go-x11-client" - "github.com/linuxdeepin/go-x11-client/ext/composite" - "github.com/linuxdeepin/go-x11-client/ext/damage" - "github.com/linuxdeepin/go-x11-client/util/atom" - - "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/dde-daemon/loader" -) - -func init() { - loader.Register(NewDaemon(logger)) -} - -var ( - logger = log.NewLogger("daemon/trayicon") - - XConn *x.Conn - - XA_NET_SYSTEM_TRAY_S0 x.Atom - XA_NET_SYSTEM_TRAY_OPCODE x.Atom - XA_NET_SYSTEM_TRAY_VISUAL x.Atom - XA_NET_SYSTEM_TRAY_ORIENTAION x.Atom - XA_MANAGER x.Atom -) - -func initX() { - _, err := damage.QueryVersion(XConn, damage.MajorVersion, damage.MinorVersion).Reply(XConn) - if err != nil { - logger.Warning(err) - } - - _, err = composite.QueryVersion(XConn, composite.MajorVersion, composite.MinorVersion).Reply(XConn) - if err != nil { - logger.Warning(err) - } - - XA_NET_SYSTEM_TRAY_S0, _ = atom.GetVal(XConn, "_NET_SYSTEM_TRAY_S0") - XA_NET_SYSTEM_TRAY_OPCODE, _ = atom.GetVal(XConn, "_NET_SYSTEM_TRAY_OPCODE") - XA_NET_SYSTEM_TRAY_VISUAL, _ = atom.GetVal(XConn, "_NET_SYSTEM_TRAY_VISUAL") - XA_NET_SYSTEM_TRAY_ORIENTAION, _ = atom.GetVal(XConn, "NET_SYSTEM_TRAY_ORIENTAION") - XA_MANAGER, _ = atom.GetVal(XConn, "MANAGER") -} diff --git a/trayicon1/daemon.go b/trayicon1/daemon.go new file mode 100644 index 000000000..760d9af27 --- /dev/null +++ b/trayicon1/daemon.go @@ -0,0 +1,103 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package trayicon + +import ( + "os" + + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/log" + x "github.com/linuxdeepin/go-x11-client" +) + +type Daemon struct { + *loader.ModuleBase + manager *TrayManager + snw *StatusNotifierWatcher + sigLoop *dbusutil.SignalLoop // session bus signal loop +} + +const moduleName = "trayicon" + +func NewDaemon(logger *log.Logger) *Daemon { + daemon := new(Daemon) + daemon.ModuleBase = loader.NewModuleBase(moduleName, daemon, logger) + return daemon +} + +func (d *Daemon) GetDependencies() []string { + return []string{} +} + +func (d *Daemon) Name() string { + return moduleName +} + +func (d *Daemon) Start() error { + var err error + // init x conn + XConn, err = x.NewConn() + if err != nil { + return err + } + + initX() + service := loader.GetService() + d.manager = NewTrayManager(service) + + sessionBus, err := dbus.SessionBus() + if err != nil { + return err + } + + d.sigLoop = dbusutil.NewSignalLoop(sessionBus, 10) + d.sigLoop.Start() + + err = service.Export(dbusPath, d.manager) + if err != nil { + return err + } + + err = d.manager.sendClientMsgMANAGER() + if err != nil { + return err + } + + err = service.RequestName(dbusServiceName) + if err != nil { + return err + } + + err = service.Emit(d.manager, "Inited") + if err != nil { + return err + } + + if os.Getenv("DDE_DISABLE_STATUS_NOTIFIER_WATCHER") != "1" { + d.snw = newStatusNotifierWatcher(service, d.sigLoop) + d.snw.listenDBusNameOwnerChanged() + err = service.Export(snwDBusPath, d.snw) + if err != nil { + return err + } + err = service.RequestName(snwDBusServiceName) + if err != nil { + logger.Warning("failed to request name:", err) + return nil + } + } else { + logger.Info("disable status notifier watcher") + } + return nil +} + +func (d *Daemon) Stop() error { + if XConn != nil { + XConn.Close() + } + return nil +} diff --git a/trayicon/daemon_test.go b/trayicon1/daemon_test.go similarity index 100% rename from trayicon/daemon_test.go rename to trayicon1/daemon_test.go diff --git a/trayicon1/exported_methods_auto.go b/trayicon1/exported_methods_auto.go new file mode 100644 index 000000000..65ac7d934 --- /dev/null +++ b/trayicon1/exported_methods_auto.go @@ -0,0 +1,47 @@ +// Code generated by "dbusutil-gen em -type TrayManager,StatusNotifierWatcher"; DO NOT EDIT. + +package trayicon + +import ( + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (v *StatusNotifierWatcher) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "RegisterStatusNotifierHost", + Fn: v.RegisterStatusNotifierHost, + InArgs: []string{"serviceName"}, + }, + { + Name: "RegisterStatusNotifierItem", + Fn: v.RegisterStatusNotifierItem, + InArgs: []string{"serviceOrPath"}, + }, + { + Name: "GetHostServiceName", + Fn: v.GetHostServiceName, + OutArgs: []string{"hostName"}, + }, + } +} +func (v *TrayManager) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "EnableNotification", + Fn: v.EnableNotification, + InArgs: []string{"win", "enabled"}, + }, + { + Name: "GetName", + Fn: v.GetName, + InArgs: []string{"win"}, + OutArgs: []string{"name"}, + }, + { + Name: "Manage", + Fn: v.Manage, + OutArgs: []string{"ok"}, + }, + } +} diff --git a/trayicon/icon.go b/trayicon1/icon.go similarity index 100% rename from trayicon/icon.go rename to trayicon1/icon.go diff --git a/trayicon1/init.go b/trayicon1/init.go new file mode 100644 index 000000000..de9563b4b --- /dev/null +++ b/trayicon1/init.go @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package trayicon + +import ( + x "github.com/linuxdeepin/go-x11-client" + "github.com/linuxdeepin/go-x11-client/ext/composite" + "github.com/linuxdeepin/go-x11-client/ext/damage" + "github.com/linuxdeepin/go-x11-client/util/atom" + + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" +) + +func init() { + loader.Register(NewDaemon(logger)) +} + +var ( + logger = log.NewLogger("daemon/trayicon") + + XConn *x.Conn + + XA_NET_SYSTEM_TRAY_S0 x.Atom + XA_NET_SYSTEM_TRAY_OPCODE x.Atom + XA_NET_SYSTEM_TRAY_VISUAL x.Atom + XA_NET_SYSTEM_TRAY_ORIENTAION x.Atom + XA_MANAGER x.Atom +) + +func initX() { + _, err := damage.QueryVersion(XConn, damage.MajorVersion, damage.MinorVersion).Reply(XConn) + if err != nil { + logger.Warning(err) + } + + _, err = composite.QueryVersion(XConn, composite.MajorVersion, composite.MinorVersion).Reply(XConn) + if err != nil { + logger.Warning(err) + } + + XA_NET_SYSTEM_TRAY_S0, _ = atom.GetVal(XConn, "_NET_SYSTEM_TRAY_S0") + XA_NET_SYSTEM_TRAY_OPCODE, _ = atom.GetVal(XConn, "_NET_SYSTEM_TRAY_OPCODE") + XA_NET_SYSTEM_TRAY_VISUAL, _ = atom.GetVal(XConn, "_NET_SYSTEM_TRAY_VISUAL") + XA_NET_SYSTEM_TRAY_ORIENTAION, _ = atom.GetVal(XConn, "NET_SYSTEM_TRAY_ORIENTAION") + XA_MANAGER, _ = atom.GetVal(XConn, "MANAGER") +} diff --git a/trayicon/status-notifier-watcher.go b/trayicon1/status-notifier-watcher.go similarity index 97% rename from trayicon/status-notifier-watcher.go rename to trayicon1/status-notifier-watcher.go index 3f4f820be..1c6017699 100644 --- a/trayicon/status-notifier-watcher.go +++ b/trayicon1/status-notifier-watcher.go @@ -10,8 +10,8 @@ import ( "strings" "sync" - dbus "github.com/godbus/dbus" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" + dbus "github.com/godbus/dbus/v5" + ofdbus "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.dbus" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/strv" ) diff --git a/trayicon/status-notifier-watcher_test.go b/trayicon1/status-notifier-watcher_test.go similarity index 94% rename from trayicon/status-notifier-watcher_test.go rename to trayicon1/status-notifier-watcher_test.go index 0baedac7b..14605ae78 100644 --- a/trayicon/status-notifier-watcher_test.go +++ b/trayicon1/status-notifier-watcher_test.go @@ -8,8 +8,8 @@ import ( "fmt" "testing" - dbus "github.com/godbus/dbus" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" + dbus "github.com/godbus/dbus/v5" + ofdbus "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.dbus" "github.com/stretchr/testify/assert" ) diff --git a/trayicon/tools.go b/trayicon1/tools.go similarity index 100% rename from trayicon/tools.go rename to trayicon1/tools.go diff --git a/trayicon/trayicon_dbusutil.go b/trayicon1/trayicon_dbusutil.go similarity index 100% rename from trayicon/trayicon_dbusutil.go rename to trayicon1/trayicon_dbusutil.go diff --git a/trayicon/traymanager.go b/trayicon1/traymanager.go similarity index 99% rename from trayicon/traymanager.go rename to trayicon1/traymanager.go index db0c6932c..057229a5e 100644 --- a/trayicon/traymanager.go +++ b/trayicon1/traymanager.go @@ -289,7 +289,7 @@ func (m *TrayManager) eventHandleLoop() { logger.Debug("ClientMessageEvent: system tray request dock", win) // 虚拟键盘注册插件时,任务栏调用XGetWindowProperty函数,wayland下会导致崩溃 // 此处过滤掉虚拟键盘的注册信号 - if (NewTrayIcon(win).getName() != "onboard") { + if NewTrayIcon(win).getName() != "onboard" { m.addIcon(win) } } diff --git a/trayicon/traymanager_ifc.go b/trayicon1/traymanager_ifc.go similarity index 91% rename from trayicon/traymanager_ifc.go rename to trayicon1/traymanager_ifc.go index f0010b87d..ac973a137 100644 --- a/trayicon/traymanager_ifc.go +++ b/trayicon1/traymanager_ifc.go @@ -7,15 +7,15 @@ package trayicon import ( "errors" - "github.com/godbus/dbus" + "github.com/godbus/dbus/v5" "github.com/linuxdeepin/go-lib/dbusutil" x "github.com/linuxdeepin/go-x11-client" ) const ( - dbusServiceName = "com.deepin.dde.TrayManager" + dbusServiceName = "org.deepin.dde.TrayManager1" dbusInterface = dbusServiceName - dbusPath = "/com/deepin/dde/TrayManager" + dbusPath = "/org/deepin/dde/TrayManager1" ) func (*TrayManager) GetInterfaceName() string { diff --git a/trayicon/traymanager_ifc_test.go b/trayicon1/traymanager_ifc_test.go similarity index 100% rename from trayicon/traymanager_ifc_test.go rename to trayicon1/traymanager_ifc_test.go diff --git a/x_event_monitor/daemon.go b/x_event_monitor/daemon.go deleted file mode 100644 index a83b570aa..000000000 --- a/x_event_monitor/daemon.go +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package x_event_monitor - -import ( - "os" - "strings" - - "github.com/linuxdeepin/go-lib/log" - "github.com/linuxdeepin/dde-daemon/loader" -) - -const ( - dbusServiceName = "com.deepin.api.XEventMonitor" - dbusPath = "/com/deepin/api/XEventMonitor" - dbusInterface = dbusServiceName - moduleName = "x-event-monitor" -) - -var ( - logger = log.NewLogger(moduleName) -) - -func init() { - loader.Register(NewDaemon(logger)) -} - -type Daemon struct { - *loader.ModuleBase -} - -func NewDaemon(logger *log.Logger) *Daemon { - daemon := new(Daemon) - daemon.ModuleBase = loader.NewModuleBase(moduleName, daemon, logger) - return daemon -} - -func (d *Daemon) GetDependencies() []string { - return []string{} -} - -func (d *Daemon) Name() string { - return moduleName -} - -func (d *Daemon) Start() error { - service := loader.GetService() - - m, err := newManager(service) - if err != nil { - return err - } - m.initXExtensions() - - sessionType := os.Getenv("XDG_SESSION_TYPE") - if strings.Contains(sessionType, "wayland") { - go m.listenGlobalCursorPressed() - go m.listenGlobalCursorRelease() - go m.listenGlobalCursorMove() - go m.listenGlobalAxisChanged() - } else { - go m.handleXEvent() - } - - err = service.Export(dbusPath, m) - if err != nil { - return err - } - - err = service.RequestName(dbusServiceName) - if err != nil { - return err - } - - err = service.Emit(m, "CancelAllArea") - if err != nil { - logger.Warning("Emit error:", err) - } - - return nil -} - -func (d *Daemon) Stop() error { - return nil -} diff --git a/x_event_monitor/manager.go b/x_event_monitor/manager.go deleted file mode 100644 index cad47b47a..000000000 --- a/x_event_monitor/manager.go +++ /dev/null @@ -1,846 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package x_event_monitor - -import ( - "encoding/json" - "errors" - "fmt" - "sync" - - dbus "github.com/godbus/dbus" - "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/strv" - dutils "github.com/linuxdeepin/go-lib/utils" - x "github.com/linuxdeepin/go-x11-client" - "github.com/linuxdeepin/go-x11-client/ext/ge" - "github.com/linuxdeepin/go-x11-client/ext/input" - "github.com/linuxdeepin/go-x11-client/ext/xfixes" - "github.com/linuxdeepin/go-x11-client/util/keysyms" -) - -//go:generate dbusutil-gen em -type Manager - -const fullscreenId = "d41d8cd98f00b204e9800998ecf8427e" - -var errAreasRegistered = errors.New("the areas has been registered") -var errAreasNotRegistered = errors.New("the areas has not been registered yet") - -type coordinateInfo struct { - areas []coordinateRange - moveIntoFlag bool - motionFlag bool //是否发送鼠标在区域中移动的信号 - buttonFlag bool - keyFlag bool -} - -type coordinateRange struct { - X1 int32 - Y1 int32 - X2 int32 - Y2 int32 -} - -type Manager struct { - hideCursorWhenTouch bool - cursorShowed bool - xConn *x.Conn - keySymbols *keysyms.KeySymbols - service *dbusutil.Service - sessionSigLoop *dbusutil.SignalLoop - //nolint - signals *struct { - CancelAllArea struct{} - CursorInto, CursorOut, CursorMove struct { - x, y int32 - id string - } - ButtonPress, ButtonRelease struct { - button, x, y int32 - id string - } - KeyPress, KeyRelease struct { - key string - x, y int32 - id string - } - CursorShowAgain struct{} - } - - pidAidsMap map[uint32]strv.Strv - idAreaInfoMap map[string]*coordinateInfo - idReferCountMap map[string]int32 - fullscreenMotionCount int32 - cursorMask uint32 - - mu sync.Mutex - - CursorX int32 - CursorY int32 -} - -const ( - buttonLeft = 272 - buttonRight = 273 - leftBit = 0 - rightBit = 1 - midBit = 2 - x11BtnLeft = 1 - x11BtnRight = 3 - x11BtnMid = 2 -) - -func newManager(service *dbusutil.Service) (*Manager, error) { - xConn, err := x.NewConn() - if err != nil { - return nil, err - } - keySymbols := keysyms.NewKeySymbols(xConn) - m := &Manager{ - xConn: xConn, - hideCursorWhenTouch: true, - cursorShowed: true, - keySymbols: keySymbols, - service: service, - pidAidsMap: make(map[uint32]strv.Strv), - idAreaInfoMap: make(map[string]*coordinateInfo), - idReferCountMap: make(map[string]int32), - } - sessionBus := m.service.Conn() - m.sessionSigLoop = dbusutil.NewSignalLoop(sessionBus, 10) - m.sessionSigLoop.Start() - m.cursorMask = 0 - return m, nil -} - -func (m *Manager) queryPointer() (*x.QueryPointerReply, error) { - root := m.xConn.GetDefaultScreen().Root - reply, err := x.QueryPointer(m.xConn, root).Reply(m.xConn) - return reply, err -} - -func (m *Manager) selectXInputEvents() { - logger.Debug("select input events") - var evMask uint32 = input.XIEventMaskRawMotion | - input.XIEventMaskRawButtonPress | - input.XIEventMaskRawButtonRelease | - input.XIEventMaskRawKeyPress | - input.XIEventMaskRawKeyRelease | - input.XIEventMaskRawTouchBegin | - input.XIEventMaskRawTouchEnd - err := m.doXISelectEvents(evMask) - if err != nil { - logger.Warning(err) - } -} - -const evMaskForHideCursor uint32 = input.XIEventMaskRawMotion | input.XIEventMaskRawTouchBegin - -func (m *Manager) listenGlobalCursorPressed() error { - sessionBus := m.service.Conn() - logger.Debug("[test global key] sessionBus", sessionBus) - err := sessionBus.Object("com.deepin.daemon.KWayland", - "/com/deepin/daemon/KWayland/Output").AddMatchSignal("com.deepin.daemon.KWayland.Output", "ButtonPress").Err - if err != nil { - logger.Warning(err) - return err - } - - m.sessionSigLoop.AddHandler(&dbusutil.SignalRule{ - Name: "com.deepin.daemon.KWayland.Output.ButtonPress", - }, func(sig *dbus.Signal) { - if len(sig.Body) > 1 { - key := sig.Body[0].(uint32) - x := sig.Body[1].(uint32) - y := sig.Body[2].(uint32) - m.CursorX = int32(x) - m.CursorY = int32(y) - if key == buttonLeft || key == 0 { - m.cursorMask |= uint32(uint32(1) << leftBit) - key = x11BtnLeft - } else if key == buttonRight { - m.cursorMask |= uint32(uint32(1) << rightBit) - key = x11BtnRight - } else { - m.cursorMask |= uint32(uint32(1) << midBit) - key = x11BtnMid - } - m.handleButtonEvent(int32(key), true, int32(x), int32(y)) - } - }) - return nil -} - -func (m *Manager) listenGlobalCursorRelease() error { - sessionBus := m.service.Conn() - err := sessionBus.Object("com.deepin.daemon.KWayland", - "/com/deepin/daemon/KWayland/Output").AddMatchSignal("com.deepin.daemon.KWayland.Output", "ButtonRelease").Err - if err != nil { - logger.Warning(err) - return err - } - - m.sessionSigLoop.AddHandler(&dbusutil.SignalRule{ - Name: "com.deepin.daemon.KWayland.Output.ButtonRelease", - }, func(sig *dbus.Signal) { - if len(sig.Body) > 1 { - key := sig.Body[0].(uint32) - x := sig.Body[1].(uint32) - y := sig.Body[2].(uint32) - m.CursorX = int32(x) - m.CursorY = int32(y) - - if key == buttonLeft || key == 0 { - m.cursorMask &= ^(uint32(1) << leftBit) - key = x11BtnLeft - } else if key == buttonRight { - m.cursorMask &= ^(uint32(1) << rightBit) - key = x11BtnRight - } else { - m.cursorMask &= ^(uint32(1) << midBit) - key = x11BtnMid - } - m.handleButtonEvent(int32(key), false, int32(x), int32(y)) - } - }) - return nil -} - -func (m *Manager) listenGlobalCursorMove() error { - sessionBus := m.service.Conn() - err := sessionBus.Object("com.deepin.daemon.KWayland", - "/com/deepin/daemon/KWayland/Output").AddMatchSignal("com.deepin.daemon.KWayland.Output", "CursorMove").Err - if err != nil { - logger.Warning(err) - return err - } - - m.sessionSigLoop.AddHandler(&dbusutil.SignalRule{ - Name: "com.deepin.daemon.KWayland.Output.CursorMove", - }, func(sig *dbus.Signal) { - if len(sig.Body) > 1 { - x := sig.Body[0].(uint32) - y := sig.Body[1].(uint32) - m.CursorX = int32(x) - m.CursorY = int32(y) - - //m.cursorMask |= (1 << cursorBit) - var hasPress = false - if m.cursorMask > 0 { - hasPress = true - } - - //logger.Debug("[test global cursor] get CursorMove", x, y) - m.handleCursorEvent(int32(x), int32(y), hasPress) - } - }) - return nil -} - -func (m *Manager) deselectXInputEvents() { - var evMask uint32 - if m.hideCursorWhenTouch { - evMask = evMaskForHideCursor - } - - logger.Debug("deselect input events") - err := m.doXISelectEvents(evMask) - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) doXISelectEvents(evMask uint32) error { - root := m.xConn.GetDefaultScreen().Root - err := input.XISelectEventsChecked(m.xConn, root, []input.EventMask{ - { - DeviceId: input.DeviceAllMaster, - Mask: []uint32{evMask}, - }, - }).Check(m.xConn) - return err -} - -func (m *Manager) BeginTouch() *dbus.Error { - m.beginTouch() - return nil -} - -func (m *Manager) beginMoveMouse() { - if m.cursorShowed { - return - } - err := m.doShowCursor(true) - if err != nil { - logger.Warning(err) - } - m.cursorShowed = true - err = m.service.Emit(m, "CursorShowAgain") - if err != nil { - logger.Warning(err) - } -} - -func (m *Manager) beginTouch() { - if !m.cursorShowed { - return - } - err := m.doShowCursor(false) - if err != nil { - logger.Warning(err) - } - m.cursorShowed = false -} - -func (m *Manager) doShowCursor(show bool) error { - rootWin := m.xConn.GetDefaultScreen().Root - var cookie x.VoidCookie - if show { - logger.Debug("xfixes show cursor") - cookie = xfixes.ShowCursorChecked(m.xConn, rootWin) - } else { - logger.Debug("xfixes hide cursor") - cookie = xfixes.HideCursorChecked(m.xConn, rootWin) - } - err := cookie.Check(m.xConn) - return err -} - -func (m *Manager) initXExtensions() { - _, err := xfixes.QueryVersion(m.xConn, xfixes.MajorVersion, xfixes.MinorVersion).Reply(m.xConn) - if err != nil { - logger.Warning(err) - } - - _, err = ge.QueryVersion(m.xConn, ge.MajorVersion, ge.MinorVersion).Reply(m.xConn) - if err != nil { - logger.Warning(err) - return - } - - _, err = input.XIQueryVersion(m.xConn, input.MajorVersion, input.MinorVersion).Reply(m.xConn) - if err != nil { - logger.Warning(err) - return - } - - if m.hideCursorWhenTouch { - err = m.doXISelectEvents(evMaskForHideCursor) - if err != nil { - logger.Warning(err) - } - } -} - -func (m *Manager) handleXEvent() { - eventChan := make(chan x.GenericEvent, 10) - m.xConn.AddEventChan(eventChan) - inputExtData := m.xConn.GetExtensionData(input.Ext()) - - for ev := range eventChan { - switch ev.GetEventCode() { - case x.MappingNotifyEventCode: - logger.Debug("mapping notify event") - event, _ := x.NewMappingNotifyEvent(ev) - m.keySymbols.RefreshKeyboardMapping(event) - - case x.GeGenericEventCode: - geEvent, _ := x.NewGeGenericEvent(ev) - if geEvent.Extension == inputExtData.MajorOpcode { - switch geEvent.EventType { - case input.RawMotionEventCode: - //logger.Debug("raw motion event") - if m.hideCursorWhenTouch { - m.beginMoveMouse() - } - m.mu.Lock() - _, ok := m.idReferCountMap[fullscreenId] - m.mu.Unlock() - if len(m.idAreaInfoMap) == 0 && !ok { - break - } - qpReply, err := m.queryPointer() - if err != nil { - logger.Warning(err) - } else { - /** - mouse left press: mask = 256 - mouse right press: mask = 512 - mouse middle press: mask = 1024 - **/ - - var press bool - if qpReply.Mask >= 256 { - press = true - } - m.handleCursorEvent(int32(qpReply.RootX), int32(qpReply.RootY), press) - } - - case input.RawKeyPressEventCode: - e, _ := input.NewRawKeyPressEvent(geEvent.Data) - qpReply, err := m.queryPointer() - if err != nil { - logger.Warning(err) - } else { - m.handleKeyboardEvent(int32(e.Detail), true, int32(qpReply.RootX), - int32(qpReply.RootY)) - } - case input.RawKeyReleaseEventCode: - e, _ := input.NewRawKeyReleaseEvent(geEvent.Data) - qpReply, err := m.queryPointer() - if err != nil { - logger.Warning(err) - } else { - m.handleKeyboardEvent(int32(e.Detail), false, int32(qpReply.RootX), - int32(qpReply.RootY)) - } - - case input.RawButtonPressEventCode: - e, _ := input.NewRawButtonPressEvent(geEvent.Data) - qpReply, err := m.queryPointer() - if err != nil { - logger.Warning(err) - } else { - m.handleButtonEvent(int32(e.Detail), true, int32(qpReply.RootX), - int32(qpReply.RootY)) - } - - case input.RawButtonReleaseEventCode: - e, _ := input.NewRawButtonReleaseEvent(geEvent.Data) - qpReply, err := m.queryPointer() - if err != nil { - logger.Warning(err) - } else { - m.handleButtonEvent(int32(e.Detail), false, int32(qpReply.RootX), - int32(qpReply.RootY)) - } - - case input.RawTouchBeginEventCode: - //logger.Debug("raw touch begin event") - if m.hideCursorWhenTouch { - m.beginTouch() - } - qpReply, err := m.queryPointer() - if err != nil { - logger.Warning(err) - } else { - m.handleButtonEvent(1, true, int32(qpReply.RootX), - int32(qpReply.RootY)) - } - - case input.RawTouchEndEventCode: - qpReply, err := m.queryPointer() - if err != nil { - logger.Warning(err) - } else { - m.handleButtonEvent(1, false, int32(qpReply.RootX), - int32(qpReply.RootY)) - } - } - } - } - } -} - -func (m *Manager) handleCursorEvent(x, y int32, press bool) { - m.mu.Lock() - defer m.mu.Unlock() - - press = !press - inList, outList := m.getIdList(x, y) - for _, id := range inList { - areaInfo, ok := m.idAreaInfoMap[id] - if !ok { - continue - } - - if !areaInfo.moveIntoFlag { - if press { - err := m.service.Emit(m, "CursorInto", x, y, id) - if err != nil { - logger.Warning(err) - } - areaInfo.moveIntoFlag = true - } - } - - if areaInfo.motionFlag { - err := m.service.Emit(m, "CursorMove", x, y, id) - if err != nil { - logger.Warning(err) - } - } - } - - for _, id := range outList { - areaInfo, ok := m.idAreaInfoMap[id] - if !ok { - continue - } - - if areaInfo.moveIntoFlag { - err := m.service.Emit(m, "CursorOut", x, y, id) - if err != nil { - logger.Warning(err) - } - areaInfo.moveIntoFlag = false - } - } - - _, ok := m.idReferCountMap[fullscreenId] - if ok && m.fullscreenMotionCount > 0 { - err := m.service.Emit(m, "CursorMove", x, y, fullscreenId) - if err != nil { - logger.Warning(err) - } - } -} - -func (m *Manager) handleButtonEvent(button int32, press bool, x, y int32) { - m.mu.Lock() - defer m.mu.Unlock() - - list, _ := m.getIdList(x, y) - for _, id := range list { - array, ok := m.idAreaInfoMap[id] - if !ok || !array.buttonFlag { - continue - } - - if press { - err := m.service.Emit(m, "ButtonPress", button, x, y, id) - if err != nil { - logger.Warning("Emit error:", err) - } - } else { - err := m.service.Emit(m, "ButtonRelease", button, x, y, id) - if err != nil { - logger.Warning("Emit error:", err) - } - } - } - - _, ok := m.idReferCountMap[fullscreenId] - if !ok { - return - } - - if press { - err := m.service.Emit(m, "ButtonPress", button, x, y, fullscreenId) - if err != nil { - logger.Warning("Emit error:", err) - } - } else { - err := m.service.Emit(m, "ButtonRelease", button, x, y, fullscreenId) - if err != nil { - logger.Warning("Emit error:", err) - } - } -} - -func (m *Manager) keyCode2Str(key int32) string { - str, _ := m.keySymbols.LookupString(x.Keycode(key), 0) - return str -} - -func (m *Manager) handleKeyboardEvent(code int32, press bool, x, y int32) { - m.mu.Lock() - defer m.mu.Unlock() - - list, _ := m.getIdList(x, y) - for _, id := range list { - array, ok := m.idAreaInfoMap[id] - if !ok || !array.keyFlag { - continue - } - - if press { - err := m.service.Emit(m, "KeyPress", m.keyCode2Str(code), x, y, id) - if err != nil { - logger.Warning("Emit error:", err) - } - } else { - err := m.service.Emit(m, "KeyRelease", m.keyCode2Str(code), x, y, id) - if err != nil { - logger.Warning("Emit error:", err) - } - } - } - - _, ok := m.idReferCountMap[fullscreenId] - if ok { - if press { - err := m.service.Emit(m, "KeyPress", m.keyCode2Str(code), x, y, - fullscreenId) - if err != nil { - logger.Warning("Emit error:", err) - } - } else { - err := m.service.Emit(m, "KeyRelease", m.keyCode2Str(code), x, y, - fullscreenId) - if err != nil { - logger.Warning("Emit error:", err) - } - } - } -} - -func (m *Manager) isPidAreaRegistered(pid uint32, areasId string) bool { - areasIds := m.pidAidsMap[pid] - return areasIds.Contains(areasId) -} - -func (m *Manager) registerPidArea(pid uint32, areasId string) { - areasIds := m.pidAidsMap[pid] - areasIds, _ = areasIds.Add(areasId) - m.pidAidsMap[pid] = areasIds - - m.selectXInputEvents() -} - -func (m *Manager) unregisterPidArea(pid uint32, areasId string) { - areasIds := m.pidAidsMap[pid] - areasIds, _ = areasIds.Delete(areasId) - if len(areasIds) > 0 { - m.pidAidsMap[pid] = areasIds - } else { - delete(m.pidAidsMap, pid) - } - - if len(m.pidAidsMap) == 0 { - m.deselectXInputEvents() - } -} - -func (m *Manager) RegisterArea(sender dbus.Sender, x1, y1, x2, y2, flag int32) (id string, busErr *dbus.Error) { - return m.RegisterAreas(sender, - []coordinateRange{{x1, y1, x2, y2}}, - flag) -} - -func (m *Manager) RegisterAreas(sender dbus.Sender, areas []coordinateRange, flag int32) (id string, busErr *dbus.Error) { - md5Str, ok := m.sumAreasMd5(areas, flag) - if !ok { - busErr = dbusutil.ToError(fmt.Errorf("sumAreasMd5 failed: %v", areas)) - return - } - id = md5Str - pid, err := m.service.GetConnPID(string(sender)) - if err != nil { - busErr = dbusutil.ToError(err) - return - } - logger.Debugf("RegisterAreas id %q pid %d", id, pid) - - m.mu.Lock() - defer m.mu.Unlock() - - if m.isPidAreaRegistered(pid, id) { - logger.Warningf("RegisterAreas id %q pid %d failed: %v", id, pid, errAreasRegistered) - return "", dbusutil.ToError(errAreasRegistered) - } - m.registerPidArea(pid, id) - - _, ok = m.idReferCountMap[id] - if ok { - m.idReferCountMap[id] += 1 - return id, nil - } - - info := &coordinateInfo{} - info.areas = areas - info.motionFlag = hasMotionFlag(flag) - info.buttonFlag = hasButtonFlag(flag) - info.keyFlag = hasKeyFlag(flag) - - m.idAreaInfoMap[id] = info - m.idReferCountMap[id] = 1 - - return id, nil -} - -func (m *Manager) RegisterFullScreen(sender dbus.Sender) (id string, busErr *dbus.Error) { - pid, err := m.service.GetConnPID(string(sender)) - if err != nil { - busErr = dbusutil.ToError(err) - return - } - logger.Debugf("RegisterFullScreen pid %d", pid) - - m.mu.Lock() - defer m.mu.Unlock() - - if m.isPidAreaRegistered(pid, fullscreenId) { - logger.Warningf("RegisterFullScreen pid %d failed: %v", pid, errAreasRegistered) - return "", dbusutil.ToError(errAreasRegistered) - } - - _, ok := m.idReferCountMap[fullscreenId] - if !ok { - m.idReferCountMap[fullscreenId] = 1 - } else { - m.idReferCountMap[fullscreenId] += 1 - } - m.registerPidArea(pid, fullscreenId) - return fullscreenId, nil -} - -func (m *Manager) UnregisterArea(sender dbus.Sender, id string) (ok bool, busErr *dbus.Error) { - m.mu.Lock() - defer m.mu.Unlock() - - pid, err := m.service.GetConnPID(string(sender)) - if err != nil { - return false, dbusutil.ToError(err) - } - logger.Debugf("UnregisterArea id %q pid %d", id, pid) - if !m.isPidAreaRegistered(pid, id) { - logger.Warningf("UnregisterArea id %q pid %d failed: %v", id, pid, errAreasNotRegistered) - return false, nil - } - - m.unregisterPidArea(pid, id) - - _, ok1 := m.idReferCountMap[id] - if !ok1 { - logger.Warningf("not found key %q in idReferCountMap", id) - return false, nil - } - - m.idReferCountMap[id] -= 1 - if m.idReferCountMap[id] == 0 { - delete(m.idReferCountMap, id) - delete(m.idAreaInfoMap, id) - } - logger.Debugf("area %q unregistered by pid %d", id, pid) - return true, nil -} - -func (m *Manager) RegisterFullScreenMotionFlag(sender dbus.Sender) *dbus.Error { - err := m.changeFullscreenMotionCount(true, sender) - return dbusutil.ToError(err) -} - -func (m *Manager) UnregisterFullScreenMotionFlag(sender dbus.Sender) *dbus.Error { - err := m.changeFullscreenMotionCount(false, sender) - return dbusutil.ToError(err) -} - -func (m *Manager) changeFullscreenMotionCount(add bool, sender dbus.Sender) (err error) { - pid, err := m.service.GetConnPID(string(sender)) - if err != nil { - return - } - var ( - count int32 - funcName string - ) - if add { - count = 1 - funcName = "RegisterFullScreenMotionFlag" - } else { - count = -1 - funcName = "UnregisterFullScreenMotionFlag" - } - logger.Debugf("%s pid %d", funcName, pid) - - m.mu.Lock() - defer m.mu.Unlock() - aidList, ok := m.pidAidsMap[pid] - if !ok || !aidList.Contains(fullscreenId) { - err = fmt.Errorf("%s err: pid %d hasn't registed fullscreen motion", funcName, pid) - return - } - m.fullscreenMotionCount += count - - return nil -} - -func (m *Manager) getIdList(x, y int32) ([]string, []string) { - var inList []string - var outList []string - - for id, array := range m.idAreaInfoMap { - inFlag := false - for _, area := range array.areas { - if isInArea(x, y, area) { - inFlag = true - if !isInIdList(id, inList) { - inList = append(inList, id) - } - } - } - if !inFlag { - if !isInIdList(id, outList) { - outList = append(outList, id) - } - } - } - - return inList, outList -} - -func (m *Manager) GetInterfaceName() string { - return dbusInterface -} - -func (m *Manager) sumAreasMd5(areas []coordinateRange, flag int32) (md5Str string, ok bool) { - if len(areas) < 1 { - return - } - - content := "" - for _, area := range areas { - if len(content) > 1 { - content += "-" - } - content += fmt.Sprintf("%v-%v-%v-%v", area.X1, area.Y1, area.X2, area.Y2) - } - content += fmt.Sprintf("-%v", flag) - - logger.Debug("areas content:", content) - md5Str, ok = dutils.SumStrMd5(content) - - return -} - -func (m *Manager) DebugGetPidAreasMap() (pidAreasMapJSON string, busErr *dbus.Error) { - m.mu.Lock() - data, err := json.Marshal(m.pidAidsMap) - m.mu.Unlock() - if err != nil { - return "", dbusutil.ToError(err) - } - return string(data), nil -} - -func (m *Manager) listenGlobalAxisChanged() error { - sessionBus := m.service.Conn() - err := sessionBus.Object("com.deepin.daemon.KWayland", - "/com/deepin/daemon/KWayland/Output").AddMatchSignal("com.deepin.daemon.KWayland.Output", "AxisChanged").Err - if err != nil { - logger.Warning(err) - return err - } - - m.sessionSigLoop.AddHandler(&dbusutil.SignalRule{ - Name: "com.deepin.daemon.KWayland.Output.AxisChanged", - }, func(sig *dbus.Signal) { - if len(sig.Body) > 1 { - x := sig.Body[1].(float64) - up := 4 - down := 5 - - if x < 0 { - m.handleButtonEvent(int32(up), true, m.CursorX, m.CursorY) - m.handleButtonEvent(int32(up), false, m.CursorX, m.CursorY) - } else { - m.handleButtonEvent(int32(down), true, m.CursorX, m.CursorY) - m.handleButtonEvent(int32(down), false, m.CursorX, m.CursorY) - } - } - }) - return nil -} diff --git a/x_event_monitor/manager_test.go b/x_event_monitor/manager_test.go deleted file mode 100644 index 0952f110b..000000000 --- a/x_event_monitor/manager_test.go +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package x_event_monitor - -import ( - "fmt" - - "github.com/linuxdeepin/go-lib/strv" - "github.com/stretchr/testify/assert" - - "testing" -) - -func Test_isPidAreaRegistered(t *testing.T) { - m := Manager{} - str0 := []string{"tong", "xin"} - str1 := []string{"ruan", "jian"} - m.pidAidsMap = map[uint32]strv.Strv{ - 0: str0, - 1: str1, - } - - assert.True(t, m.isPidAreaRegistered(0, "tong")) -} - -func Test_getIdList(t *testing.T) { - m := Manager{} - var area = []coordinateRange{ - {100, 100, 200, 200}, - } - var key = "tongxin" - - var coordinateInfo_ = coordinateInfo{ - areas: area, - moveIntoFlag: false, - motionFlag: false, - buttonFlag: false, - keyFlag: false, - } - - m.idAreaInfoMap = map[string]*coordinateInfo{ - key: &coordinateInfo_, - } - - inList, _ := m.getIdList(101, 101) - - for i, in := range inList { - assert.Equal(t, 0, i) - assert.Equal(t, key, in) - } - - _, outList := m.getIdList(99, 99) - for i, out := range outList { - assert.Equal(t, 0, i) - assert.Equal(t, key, out) - } -} - -func Test_sumAreasMd5(t *testing.T) { - m := Manager{} - var areasNil []coordinateRange - var expectMd5 = "eef73b4ff31a5d5e32c54719fee950c7" - - md5Str, ok := m.sumAreasMd5(areasNil, 1) - assert.False(t, ok) - assert.Equal(t, md5Str, "") - - areas := []coordinateRange{ - {100, 200, 100, 200}, - } - - md5Str, ok = m.sumAreasMd5(areas, 1) - assert.Equal(t, expectMd5, md5Str) - assert.True(t, ok) -} - -func Test_DebugGetPidAreasMap(t *testing.T) { - m := Manager{} - str0 := []string{"tong", "xin"} - str1 := []string{"ruan", "jian"} - var expectRtn string = "{\"0\":[\"tong\",\"xin\"],\"1\":[\"ruan\",\"jian\"]}" - m.pidAidsMap = map[uint32]strv.Strv{ - 0: str0, - 1: str1, - } - - rtnStr, err := m.DebugGetPidAreasMap() - - assert.Nil(t, err) - assert.Equal(t, expectRtn, rtnStr) - fmt.Printf("rtnStr:%s\n", rtnStr) -} \ No newline at end of file diff --git a/x_event_monitor/utils.go b/x_event_monitor/utils.go deleted file mode 100644 index d71d71793..000000000 --- a/x_event_monitor/utils.go +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package x_event_monitor - -const ( - MotionFlag = int32(1) //当此标志为1, 则鼠标在册注区域中移动时,会实时发送鼠标位置信号 - ButtonFlag = int32(1 << 1) - KeyFlag = int32(1 << 2) -) - -func hasMotionFlag(flag int32) bool { - return flag&MotionFlag != 0 -} - -func hasKeyFlag(flag int32) bool { - return flag&KeyFlag != 0 -} - -func hasButtonFlag(flag int32) bool { - return flag&ButtonFlag != 0 -} - -func isInArea(x, y int32, area coordinateRange) bool { - if (x >= area.X1 && x <= area.X2) && - (y >= area.Y1 && y <= area.Y2) { - return true - } - - return false -} - -func isInIdList(md5Str string, list []string) bool { - for _, v := range list { - if md5Str == v { - return true - } - } - - return false -} diff --git a/x_event_monitor/utils_test.go b/x_event_monitor/utils_test.go deleted file mode 100644 index 03c5437ea..000000000 --- a/x_event_monitor/utils_test.go +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package x_event_monitor - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func Test_hasMotionFlag (t *testing.T) { - var flag = []int32{0, 1} - - assert.False(t, hasMotionFlag(flag[0])) - assert.True(t, hasMotionFlag(flag[1])) -} - -func Test_hasKeyFlag (t *testing.T) { - var flag = []int32{1, 4} - - assert.False(t, hasKeyFlag(flag[0])) - assert.True(t, hasKeyFlag(flag[1])) -} - -func Test_hasButtonFlag (t *testing.T) { - var flag = []int32{1, 2} - - assert.False(t, hasButtonFlag(flag[0])) - assert.True(t, hasButtonFlag(flag[1])) -} - -func Test_isInArea (t *testing.T) { - var area = coordinateRange { - X1: 100, - X2: 200, - Y1: 100, - Y2: 200, - } - - var x = []int32 {99, 101} - var y = []int32 {99, 101} - - assert.True(t, isInArea(x[1], y[1], area)) - assert.False(t, isInArea(x[0], y[0], area)) -} - -func Test_isInIdList (t *testing.T) { - var list = []string {"tongxinruanjian","tongshenruanjian"} - var md5str = []string {"tongxinruanjian","tongxin"} - - assert.True(t, isInIdList(md5str[0], list)) - assert.False(t, isInIdList(md5str[1], list)) -} \ No newline at end of file diff --git a/x_event_monitor1/daemon.go b/x_event_monitor1/daemon.go new file mode 100644 index 000000000..ce28f9771 --- /dev/null +++ b/x_event_monitor1/daemon.go @@ -0,0 +1,87 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package x_event_monitor + +import ( + "os" + "strings" + + "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" +) + +const ( + dbusServiceName = "org.deepin.dde.XEventMonitor1" + dbusPath = "/org/deepin/dde/XEventMonitor1" + dbusInterface = dbusServiceName + moduleName = "x-event-monitor" +) + +var ( + logger = log.NewLogger(moduleName) +) + +func init() { + loader.Register(NewDaemon(logger)) +} + +type Daemon struct { + *loader.ModuleBase +} + +func NewDaemon(logger *log.Logger) *Daemon { + daemon := new(Daemon) + daemon.ModuleBase = loader.NewModuleBase(moduleName, daemon, logger) + return daemon +} + +func (d *Daemon) GetDependencies() []string { + return []string{} +} + +func (d *Daemon) Name() string { + return moduleName +} + +func (d *Daemon) Start() error { + service := loader.GetService() + + m, err := newManager(service) + if err != nil { + return err + } + m.initXExtensions() + + sessionType := os.Getenv("XDG_SESSION_TYPE") + if strings.Contains(sessionType, "wayland") { + go m.listenGlobalCursorPressed() + go m.listenGlobalCursorRelease() + go m.listenGlobalCursorMove() + go m.listenGlobalAxisChanged() + } else { + go m.handleXEvent() + } + + err = service.Export(dbusPath, m) + if err != nil { + return err + } + + err = service.RequestName(dbusServiceName) + if err != nil { + return err + } + + err = service.Emit(m, "CancelAllArea") + if err != nil { + logger.Warning("Emit error:", err) + } + + return nil +} + +func (d *Daemon) Stop() error { + return nil +} diff --git a/x_event_monitor/daemon_test.go b/x_event_monitor1/daemon_test.go similarity index 100% rename from x_event_monitor/daemon_test.go rename to x_event_monitor1/daemon_test.go diff --git a/x_event_monitor/exported_methods_auto.go b/x_event_monitor1/exported_methods_auto.go similarity index 100% rename from x_event_monitor/exported_methods_auto.go rename to x_event_monitor1/exported_methods_auto.go diff --git a/x_event_monitor1/manager.go b/x_event_monitor1/manager.go new file mode 100644 index 000000000..5e1701cb3 --- /dev/null +++ b/x_event_monitor1/manager.go @@ -0,0 +1,846 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package x_event_monitor + +import ( + "encoding/json" + "errors" + "fmt" + "sync" + + dbus "github.com/godbus/dbus/v5" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/strv" + dutils "github.com/linuxdeepin/go-lib/utils" + x "github.com/linuxdeepin/go-x11-client" + "github.com/linuxdeepin/go-x11-client/ext/ge" + "github.com/linuxdeepin/go-x11-client/ext/input" + "github.com/linuxdeepin/go-x11-client/ext/xfixes" + "github.com/linuxdeepin/go-x11-client/util/keysyms" +) + +//go:generate dbusutil-gen em -type Manager + +const fullscreenId = "d41d8cd98f00b204e9800998ecf8427e" + +var errAreasRegistered = errors.New("the areas has been registered") +var errAreasNotRegistered = errors.New("the areas has not been registered yet") + +type coordinateInfo struct { + areas []coordinateRange + moveIntoFlag bool + motionFlag bool //是否发送鼠标在区域中移动的信号 + buttonFlag bool + keyFlag bool +} + +type coordinateRange struct { + X1 int32 + Y1 int32 + X2 int32 + Y2 int32 +} + +type Manager struct { + hideCursorWhenTouch bool + cursorShowed bool + xConn *x.Conn + keySymbols *keysyms.KeySymbols + service *dbusutil.Service + sessionSigLoop *dbusutil.SignalLoop + //nolint + signals *struct { + CancelAllArea struct{} + CursorInto, CursorOut, CursorMove struct { + x, y int32 + id string + } + ButtonPress, ButtonRelease struct { + button, x, y int32 + id string + } + KeyPress, KeyRelease struct { + key string + x, y int32 + id string + } + CursorShowAgain struct{} + } + + pidAidsMap map[uint32]strv.Strv + idAreaInfoMap map[string]*coordinateInfo + idReferCountMap map[string]int32 + fullscreenMotionCount int32 + cursorMask uint32 + + mu sync.Mutex + + CursorX int32 + CursorY int32 +} + +const ( + buttonLeft = 272 + buttonRight = 273 + leftBit = 0 + rightBit = 1 + midBit = 2 + x11BtnLeft = 1 + x11BtnRight = 3 + x11BtnMid = 2 +) + +func newManager(service *dbusutil.Service) (*Manager, error) { + xConn, err := x.NewConn() + if err != nil { + return nil, err + } + keySymbols := keysyms.NewKeySymbols(xConn) + m := &Manager{ + xConn: xConn, + hideCursorWhenTouch: true, + cursorShowed: true, + keySymbols: keySymbols, + service: service, + pidAidsMap: make(map[uint32]strv.Strv), + idAreaInfoMap: make(map[string]*coordinateInfo), + idReferCountMap: make(map[string]int32), + } + sessionBus := m.service.Conn() + m.sessionSigLoop = dbusutil.NewSignalLoop(sessionBus, 10) + m.sessionSigLoop.Start() + m.cursorMask = 0 + return m, nil +} + +func (m *Manager) queryPointer() (*x.QueryPointerReply, error) { + root := m.xConn.GetDefaultScreen().Root + reply, err := x.QueryPointer(m.xConn, root).Reply(m.xConn) + return reply, err +} + +func (m *Manager) selectXInputEvents() { + logger.Debug("select input events") + var evMask uint32 = input.XIEventMaskRawMotion | + input.XIEventMaskRawButtonPress | + input.XIEventMaskRawButtonRelease | + input.XIEventMaskRawKeyPress | + input.XIEventMaskRawKeyRelease | + input.XIEventMaskRawTouchBegin | + input.XIEventMaskRawTouchEnd + err := m.doXISelectEvents(evMask) + if err != nil { + logger.Warning(err) + } +} + +const evMaskForHideCursor uint32 = input.XIEventMaskRawMotion | input.XIEventMaskRawTouchBegin + +func (m *Manager) listenGlobalCursorPressed() error { + sessionBus := m.service.Conn() + logger.Debug("[test global key] sessionBus", sessionBus) + err := sessionBus.Object("org.deepin.dde.KWayland1", + "/org/deepin/dde/KWayland1/Output").AddMatchSignal("org.deepin.dde.KWayland1.Output", "ButtonPress").Err + if err != nil { + logger.Warning(err) + return err + } + + m.sessionSigLoop.AddHandler(&dbusutil.SignalRule{ + Name: "org.deepin.dde.KWayland1.Output.ButtonPress", + }, func(sig *dbus.Signal) { + if len(sig.Body) > 1 { + key := sig.Body[0].(uint32) + x := sig.Body[1].(uint32) + y := sig.Body[2].(uint32) + m.CursorX = int32(x) + m.CursorY = int32(y) + if key == buttonLeft || key == 0 { + m.cursorMask |= uint32(uint32(1) << leftBit) + key = x11BtnLeft + } else if key == buttonRight { + m.cursorMask |= uint32(uint32(1) << rightBit) + key = x11BtnRight + } else { + m.cursorMask |= uint32(uint32(1) << midBit) + key = x11BtnMid + } + m.handleButtonEvent(int32(key), true, int32(x), int32(y)) + } + }) + return nil +} + +func (m *Manager) listenGlobalCursorRelease() error { + sessionBus := m.service.Conn() + err := sessionBus.Object("org.deepin.dde.KWayland1", + "/org/deepin/dde/KWayland1/Output").AddMatchSignal("org.deepin.dde.KWayland1.Output", "ButtonRelease").Err + if err != nil { + logger.Warning(err) + return err + } + + m.sessionSigLoop.AddHandler(&dbusutil.SignalRule{ + Name: "org.deepin.dde.KWayland1.Output.ButtonRelease", + }, func(sig *dbus.Signal) { + if len(sig.Body) > 1 { + key := sig.Body[0].(uint32) + x := sig.Body[1].(uint32) + y := sig.Body[2].(uint32) + m.CursorX = int32(x) + m.CursorY = int32(y) + + if key == buttonLeft || key == 0 { + m.cursorMask &= ^(uint32(1) << leftBit) + key = x11BtnLeft + } else if key == buttonRight { + m.cursorMask &= ^(uint32(1) << rightBit) + key = x11BtnRight + } else { + m.cursorMask &= ^(uint32(1) << midBit) + key = x11BtnMid + } + m.handleButtonEvent(int32(key), false, int32(x), int32(y)) + } + }) + return nil +} + +func (m *Manager) listenGlobalCursorMove() error { + sessionBus := m.service.Conn() + err := sessionBus.Object("org.deepin.dde.KWayland1", + "/org/deepin/dde/KWayland1/Output").AddMatchSignal("org.deepin.dde.KWayland1.Output", "CursorMove").Err + if err != nil { + logger.Warning(err) + return err + } + + m.sessionSigLoop.AddHandler(&dbusutil.SignalRule{ + Name: "org.deepin.dde.KWayland1.Output.CursorMove", + }, func(sig *dbus.Signal) { + if len(sig.Body) > 1 { + x := sig.Body[0].(uint32) + y := sig.Body[1].(uint32) + m.CursorX = int32(x) + m.CursorY = int32(y) + + //m.cursorMask |= (1 << cursorBit) + var hasPress = false + if m.cursorMask > 0 { + hasPress = true + } + + //logger.Debug("[test global cursor] get CursorMove", x, y) + m.handleCursorEvent(int32(x), int32(y), hasPress) + } + }) + return nil +} + +func (m *Manager) deselectXInputEvents() { + var evMask uint32 + if m.hideCursorWhenTouch { + evMask = evMaskForHideCursor + } + + logger.Debug("deselect input events") + err := m.doXISelectEvents(evMask) + if err != nil { + logger.Warning(err) + } +} + +func (m *Manager) doXISelectEvents(evMask uint32) error { + root := m.xConn.GetDefaultScreen().Root + err := input.XISelectEventsChecked(m.xConn, root, []input.EventMask{ + { + DeviceId: input.DeviceAllMaster, + Mask: []uint32{evMask}, + }, + }).Check(m.xConn) + return err +} + +func (m *Manager) BeginTouch() *dbus.Error { + m.beginTouch() + return nil +} + +func (m *Manager) beginMoveMouse() { + if m.cursorShowed { + return + } + err := m.doShowCursor(true) + if err != nil { + logger.Warning(err) + } + m.cursorShowed = true + err = m.service.Emit(m, "CursorShowAgain") + if err != nil { + logger.Warning(err) + } +} + +func (m *Manager) beginTouch() { + if !m.cursorShowed { + return + } + err := m.doShowCursor(false) + if err != nil { + logger.Warning(err) + } + m.cursorShowed = false +} + +func (m *Manager) doShowCursor(show bool) error { + rootWin := m.xConn.GetDefaultScreen().Root + var cookie x.VoidCookie + if show { + logger.Debug("xfixes show cursor") + cookie = xfixes.ShowCursorChecked(m.xConn, rootWin) + } else { + logger.Debug("xfixes hide cursor") + cookie = xfixes.HideCursorChecked(m.xConn, rootWin) + } + err := cookie.Check(m.xConn) + return err +} + +func (m *Manager) initXExtensions() { + _, err := xfixes.QueryVersion(m.xConn, xfixes.MajorVersion, xfixes.MinorVersion).Reply(m.xConn) + if err != nil { + logger.Warning(err) + } + + _, err = ge.QueryVersion(m.xConn, ge.MajorVersion, ge.MinorVersion).Reply(m.xConn) + if err != nil { + logger.Warning(err) + return + } + + _, err = input.XIQueryVersion(m.xConn, input.MajorVersion, input.MinorVersion).Reply(m.xConn) + if err != nil { + logger.Warning(err) + return + } + + if m.hideCursorWhenTouch { + err = m.doXISelectEvents(evMaskForHideCursor) + if err != nil { + logger.Warning(err) + } + } +} + +func (m *Manager) handleXEvent() { + eventChan := make(chan x.GenericEvent, 10) + m.xConn.AddEventChan(eventChan) + inputExtData := m.xConn.GetExtensionData(input.Ext()) + + for ev := range eventChan { + switch ev.GetEventCode() { + case x.MappingNotifyEventCode: + logger.Debug("mapping notify event") + event, _ := x.NewMappingNotifyEvent(ev) + m.keySymbols.RefreshKeyboardMapping(event) + + case x.GeGenericEventCode: + geEvent, _ := x.NewGeGenericEvent(ev) + if geEvent.Extension == inputExtData.MajorOpcode { + switch geEvent.EventType { + case input.RawMotionEventCode: + //logger.Debug("raw motion event") + if m.hideCursorWhenTouch { + m.beginMoveMouse() + } + m.mu.Lock() + _, ok := m.idReferCountMap[fullscreenId] + m.mu.Unlock() + if len(m.idAreaInfoMap) == 0 && !ok { + break + } + qpReply, err := m.queryPointer() + if err != nil { + logger.Warning(err) + } else { + /** + mouse left press: mask = 256 + mouse right press: mask = 512 + mouse middle press: mask = 1024 + **/ + + var press bool + if qpReply.Mask >= 256 { + press = true + } + m.handleCursorEvent(int32(qpReply.RootX), int32(qpReply.RootY), press) + } + + case input.RawKeyPressEventCode: + e, _ := input.NewRawKeyPressEvent(geEvent.Data) + qpReply, err := m.queryPointer() + if err != nil { + logger.Warning(err) + } else { + m.handleKeyboardEvent(int32(e.Detail), true, int32(qpReply.RootX), + int32(qpReply.RootY)) + } + case input.RawKeyReleaseEventCode: + e, _ := input.NewRawKeyReleaseEvent(geEvent.Data) + qpReply, err := m.queryPointer() + if err != nil { + logger.Warning(err) + } else { + m.handleKeyboardEvent(int32(e.Detail), false, int32(qpReply.RootX), + int32(qpReply.RootY)) + } + + case input.RawButtonPressEventCode: + e, _ := input.NewRawButtonPressEvent(geEvent.Data) + qpReply, err := m.queryPointer() + if err != nil { + logger.Warning(err) + } else { + m.handleButtonEvent(int32(e.Detail), true, int32(qpReply.RootX), + int32(qpReply.RootY)) + } + + case input.RawButtonReleaseEventCode: + e, _ := input.NewRawButtonReleaseEvent(geEvent.Data) + qpReply, err := m.queryPointer() + if err != nil { + logger.Warning(err) + } else { + m.handleButtonEvent(int32(e.Detail), false, int32(qpReply.RootX), + int32(qpReply.RootY)) + } + + case input.RawTouchBeginEventCode: + //logger.Debug("raw touch begin event") + if m.hideCursorWhenTouch { + m.beginTouch() + } + qpReply, err := m.queryPointer() + if err != nil { + logger.Warning(err) + } else { + m.handleButtonEvent(1, true, int32(qpReply.RootX), + int32(qpReply.RootY)) + } + + case input.RawTouchEndEventCode: + qpReply, err := m.queryPointer() + if err != nil { + logger.Warning(err) + } else { + m.handleButtonEvent(1, false, int32(qpReply.RootX), + int32(qpReply.RootY)) + } + } + } + } + } +} + +func (m *Manager) handleCursorEvent(x, y int32, press bool) { + m.mu.Lock() + defer m.mu.Unlock() + + press = !press + inList, outList := m.getIdList(x, y) + for _, id := range inList { + areaInfo, ok := m.idAreaInfoMap[id] + if !ok { + continue + } + + if !areaInfo.moveIntoFlag { + if press { + err := m.service.Emit(m, "CursorInto", x, y, id) + if err != nil { + logger.Warning(err) + } + areaInfo.moveIntoFlag = true + } + } + + if areaInfo.motionFlag { + err := m.service.Emit(m, "CursorMove", x, y, id) + if err != nil { + logger.Warning(err) + } + } + } + + for _, id := range outList { + areaInfo, ok := m.idAreaInfoMap[id] + if !ok { + continue + } + + if areaInfo.moveIntoFlag { + err := m.service.Emit(m, "CursorOut", x, y, id) + if err != nil { + logger.Warning(err) + } + areaInfo.moveIntoFlag = false + } + } + + _, ok := m.idReferCountMap[fullscreenId] + if ok && m.fullscreenMotionCount > 0 { + err := m.service.Emit(m, "CursorMove", x, y, fullscreenId) + if err != nil { + logger.Warning(err) + } + } +} + +func (m *Manager) handleButtonEvent(button int32, press bool, x, y int32) { + m.mu.Lock() + defer m.mu.Unlock() + + list, _ := m.getIdList(x, y) + for _, id := range list { + array, ok := m.idAreaInfoMap[id] + if !ok || !array.buttonFlag { + continue + } + + if press { + err := m.service.Emit(m, "ButtonPress", button, x, y, id) + if err != nil { + logger.Warning("Emit error:", err) + } + } else { + err := m.service.Emit(m, "ButtonRelease", button, x, y, id) + if err != nil { + logger.Warning("Emit error:", err) + } + } + } + + _, ok := m.idReferCountMap[fullscreenId] + if !ok { + return + } + + if press { + err := m.service.Emit(m, "ButtonPress", button, x, y, fullscreenId) + if err != nil { + logger.Warning("Emit error:", err) + } + } else { + err := m.service.Emit(m, "ButtonRelease", button, x, y, fullscreenId) + if err != nil { + logger.Warning("Emit error:", err) + } + } +} + +func (m *Manager) keyCode2Str(key int32) string { + str, _ := m.keySymbols.LookupString(x.Keycode(key), 0) + return str +} + +func (m *Manager) handleKeyboardEvent(code int32, press bool, x, y int32) { + m.mu.Lock() + defer m.mu.Unlock() + + list, _ := m.getIdList(x, y) + for _, id := range list { + array, ok := m.idAreaInfoMap[id] + if !ok || !array.keyFlag { + continue + } + + if press { + err := m.service.Emit(m, "KeyPress", m.keyCode2Str(code), x, y, id) + if err != nil { + logger.Warning("Emit error:", err) + } + } else { + err := m.service.Emit(m, "KeyRelease", m.keyCode2Str(code), x, y, id) + if err != nil { + logger.Warning("Emit error:", err) + } + } + } + + _, ok := m.idReferCountMap[fullscreenId] + if ok { + if press { + err := m.service.Emit(m, "KeyPress", m.keyCode2Str(code), x, y, + fullscreenId) + if err != nil { + logger.Warning("Emit error:", err) + } + } else { + err := m.service.Emit(m, "KeyRelease", m.keyCode2Str(code), x, y, + fullscreenId) + if err != nil { + logger.Warning("Emit error:", err) + } + } + } +} + +func (m *Manager) isPidAreaRegistered(pid uint32, areasId string) bool { + areasIds := m.pidAidsMap[pid] + return areasIds.Contains(areasId) +} + +func (m *Manager) registerPidArea(pid uint32, areasId string) { + areasIds := m.pidAidsMap[pid] + areasIds, _ = areasIds.Add(areasId) + m.pidAidsMap[pid] = areasIds + + m.selectXInputEvents() +} + +func (m *Manager) unregisterPidArea(pid uint32, areasId string) { + areasIds := m.pidAidsMap[pid] + areasIds, _ = areasIds.Delete(areasId) + if len(areasIds) > 0 { + m.pidAidsMap[pid] = areasIds + } else { + delete(m.pidAidsMap, pid) + } + + if len(m.pidAidsMap) == 0 { + m.deselectXInputEvents() + } +} + +func (m *Manager) RegisterArea(sender dbus.Sender, x1, y1, x2, y2, flag int32) (id string, busErr *dbus.Error) { + return m.RegisterAreas(sender, + []coordinateRange{{x1, y1, x2, y2}}, + flag) +} + +func (m *Manager) RegisterAreas(sender dbus.Sender, areas []coordinateRange, flag int32) (id string, busErr *dbus.Error) { + md5Str, ok := m.sumAreasMd5(areas, flag) + if !ok { + busErr = dbusutil.ToError(fmt.Errorf("sumAreasMd5 failed: %v", areas)) + return + } + id = md5Str + pid, err := m.service.GetConnPID(string(sender)) + if err != nil { + busErr = dbusutil.ToError(err) + return + } + logger.Debugf("RegisterAreas id %q pid %d", id, pid) + + m.mu.Lock() + defer m.mu.Unlock() + + if m.isPidAreaRegistered(pid, id) { + logger.Warningf("RegisterAreas id %q pid %d failed: %v", id, pid, errAreasRegistered) + return "", dbusutil.ToError(errAreasRegistered) + } + m.registerPidArea(pid, id) + + _, ok = m.idReferCountMap[id] + if ok { + m.idReferCountMap[id] += 1 + return id, nil + } + + info := &coordinateInfo{} + info.areas = areas + info.motionFlag = hasMotionFlag(flag) + info.buttonFlag = hasButtonFlag(flag) + info.keyFlag = hasKeyFlag(flag) + + m.idAreaInfoMap[id] = info + m.idReferCountMap[id] = 1 + + return id, nil +} + +func (m *Manager) RegisterFullScreen(sender dbus.Sender) (id string, busErr *dbus.Error) { + pid, err := m.service.GetConnPID(string(sender)) + if err != nil { + busErr = dbusutil.ToError(err) + return + } + logger.Debugf("RegisterFullScreen pid %d", pid) + + m.mu.Lock() + defer m.mu.Unlock() + + if m.isPidAreaRegistered(pid, fullscreenId) { + logger.Warningf("RegisterFullScreen pid %d failed: %v", pid, errAreasRegistered) + return "", dbusutil.ToError(errAreasRegistered) + } + + _, ok := m.idReferCountMap[fullscreenId] + if !ok { + m.idReferCountMap[fullscreenId] = 1 + } else { + m.idReferCountMap[fullscreenId] += 1 + } + m.registerPidArea(pid, fullscreenId) + return fullscreenId, nil +} + +func (m *Manager) UnregisterArea(sender dbus.Sender, id string) (ok bool, busErr *dbus.Error) { + m.mu.Lock() + defer m.mu.Unlock() + + pid, err := m.service.GetConnPID(string(sender)) + if err != nil { + return false, dbusutil.ToError(err) + } + logger.Debugf("UnregisterArea id %q pid %d", id, pid) + if !m.isPidAreaRegistered(pid, id) { + logger.Warningf("UnregisterArea id %q pid %d failed: %v", id, pid, errAreasNotRegistered) + return false, nil + } + + m.unregisterPidArea(pid, id) + + _, ok1 := m.idReferCountMap[id] + if !ok1 { + logger.Warningf("not found key %q in idReferCountMap", id) + return false, nil + } + + m.idReferCountMap[id] -= 1 + if m.idReferCountMap[id] == 0 { + delete(m.idReferCountMap, id) + delete(m.idAreaInfoMap, id) + } + logger.Debugf("area %q unregistered by pid %d", id, pid) + return true, nil +} + +func (m *Manager) RegisterFullScreenMotionFlag(sender dbus.Sender) *dbus.Error { + err := m.changeFullscreenMotionCount(true, sender) + return dbusutil.ToError(err) +} + +func (m *Manager) UnregisterFullScreenMotionFlag(sender dbus.Sender) *dbus.Error { + err := m.changeFullscreenMotionCount(false, sender) + return dbusutil.ToError(err) +} + +func (m *Manager) changeFullscreenMotionCount(add bool, sender dbus.Sender) (err error) { + pid, err := m.service.GetConnPID(string(sender)) + if err != nil { + return + } + var ( + count int32 + funcName string + ) + if add { + count = 1 + funcName = "RegisterFullScreenMotionFlag" + } else { + count = -1 + funcName = "UnregisterFullScreenMotionFlag" + } + logger.Debugf("%s pid %d", funcName, pid) + + m.mu.Lock() + defer m.mu.Unlock() + aidList, ok := m.pidAidsMap[pid] + if !ok || !aidList.Contains(fullscreenId) { + err = fmt.Errorf("%s err: pid %d hasn't registed fullscreen motion", funcName, pid) + return + } + m.fullscreenMotionCount += count + + return nil +} + +func (m *Manager) getIdList(x, y int32) ([]string, []string) { + var inList []string + var outList []string + + for id, array := range m.idAreaInfoMap { + inFlag := false + for _, area := range array.areas { + if isInArea(x, y, area) { + inFlag = true + if !isInIdList(id, inList) { + inList = append(inList, id) + } + } + } + if !inFlag { + if !isInIdList(id, outList) { + outList = append(outList, id) + } + } + } + + return inList, outList +} + +func (m *Manager) GetInterfaceName() string { + return dbusInterface +} + +func (m *Manager) sumAreasMd5(areas []coordinateRange, flag int32) (md5Str string, ok bool) { + if len(areas) < 1 { + return + } + + content := "" + for _, area := range areas { + if len(content) > 1 { + content += "-" + } + content += fmt.Sprintf("%v-%v-%v-%v", area.X1, area.Y1, area.X2, area.Y2) + } + content += fmt.Sprintf("-%v", flag) + + logger.Debug("areas content:", content) + md5Str, ok = dutils.SumStrMd5(content) + + return +} + +func (m *Manager) DebugGetPidAreasMap() (pidAreasMapJSON string, busErr *dbus.Error) { + m.mu.Lock() + data, err := json.Marshal(m.pidAidsMap) + m.mu.Unlock() + if err != nil { + return "", dbusutil.ToError(err) + } + return string(data), nil +} + +func (m *Manager) listenGlobalAxisChanged() error { + sessionBus := m.service.Conn() + err := sessionBus.Object("org.deepin.dde.KWayland1", + "/org/deepin/dde/KWayland1/Output").AddMatchSignal("org.deepin.dde.KWayland1.Output", "AxisChanged").Err + if err != nil { + logger.Warning(err) + return err + } + + m.sessionSigLoop.AddHandler(&dbusutil.SignalRule{ + Name: "org.deepin.dde.KWayland1.Output.AxisChanged", + }, func(sig *dbus.Signal) { + if len(sig.Body) > 1 { + x := sig.Body[1].(float64) + up := 4 + down := 5 + + if x < 0 { + m.handleButtonEvent(int32(up), true, m.CursorX, m.CursorY) + m.handleButtonEvent(int32(up), false, m.CursorX, m.CursorY) + } else { + m.handleButtonEvent(int32(down), true, m.CursorX, m.CursorY) + m.handleButtonEvent(int32(down), false, m.CursorX, m.CursorY) + } + } + }) + return nil +} diff --git a/x_event_monitor1/manager_test.go b/x_event_monitor1/manager_test.go new file mode 100644 index 000000000..b722b417e --- /dev/null +++ b/x_event_monitor1/manager_test.go @@ -0,0 +1,94 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package x_event_monitor + +import ( + "fmt" + + "github.com/linuxdeepin/go-lib/strv" + "github.com/stretchr/testify/assert" + + "testing" +) + +func Test_isPidAreaRegistered(t *testing.T) { + m := Manager{} + str0 := []string{"tong", "xin"} + str1 := []string{"ruan", "jian"} + m.pidAidsMap = map[uint32]strv.Strv{ + 0: str0, + 1: str1, + } + + assert.True(t, m.isPidAreaRegistered(0, "tong")) +} + +func Test_getIdList(t *testing.T) { + m := Manager{} + var area = []coordinateRange{ + {100, 100, 200, 200}, + } + var key = "tongxin" + + var coordinateInfo_ = coordinateInfo{ + areas: area, + moveIntoFlag: false, + motionFlag: false, + buttonFlag: false, + keyFlag: false, + } + + m.idAreaInfoMap = map[string]*coordinateInfo{ + key: &coordinateInfo_, + } + + inList, _ := m.getIdList(101, 101) + + for i, in := range inList { + assert.Equal(t, 0, i) + assert.Equal(t, key, in) + } + + _, outList := m.getIdList(99, 99) + for i, out := range outList { + assert.Equal(t, 0, i) + assert.Equal(t, key, out) + } +} + +func Test_sumAreasMd5(t *testing.T) { + m := Manager{} + var areasNil []coordinateRange + var expectMd5 = "eef73b4ff31a5d5e32c54719fee950c7" + + md5Str, ok := m.sumAreasMd5(areasNil, 1) + assert.False(t, ok) + assert.Equal(t, md5Str, "") + + areas := []coordinateRange{ + {100, 200, 100, 200}, + } + + md5Str, ok = m.sumAreasMd5(areas, 1) + assert.Equal(t, expectMd5, md5Str) + assert.True(t, ok) +} + +func Test_DebugGetPidAreasMap(t *testing.T) { + m := Manager{} + str0 := []string{"tong", "xin"} + str1 := []string{"ruan", "jian"} + var expectRtn string = "{\"0\":[\"tong\",\"xin\"],\"1\":[\"ruan\",\"jian\"]}" + m.pidAidsMap = map[uint32]strv.Strv{ + 0: str0, + 1: str1, + } + + rtnStr, err := m.DebugGetPidAreasMap() + + assert.Nil(t, err) + assert.Equal(t, expectRtn, rtnStr) + fmt.Printf("rtnStr:%s\n", rtnStr) +} diff --git a/x_event_monitor/mousearea_test.go b/x_event_monitor1/mousearea_test.go similarity index 100% rename from x_event_monitor/mousearea_test.go rename to x_event_monitor1/mousearea_test.go diff --git a/x_event_monitor1/utils.go b/x_event_monitor1/utils.go new file mode 100644 index 000000000..4baa61931 --- /dev/null +++ b/x_event_monitor1/utils.go @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package x_event_monitor + +const ( + MotionFlag = int32(1) //当此标志为1, 则鼠标在册注区域中移动时,会实时发送鼠标位置信号 + ButtonFlag = int32(1 << 1) + KeyFlag = int32(1 << 2) +) + +func hasMotionFlag(flag int32) bool { + return flag&MotionFlag != 0 +} + +func hasKeyFlag(flag int32) bool { + return flag&KeyFlag != 0 +} + +func hasButtonFlag(flag int32) bool { + return flag&ButtonFlag != 0 +} + +func isInArea(x, y int32, area coordinateRange) bool { + if (x >= area.X1 && x <= area.X2) && + (y >= area.Y1 && y <= area.Y2) { + return true + } + + return false +} + +func isInIdList(md5Str string, list []string) bool { + for _, v := range list { + if md5Str == v { + return true + } + } + + return false +} diff --git a/x_event_monitor1/utils_test.go b/x_event_monitor1/utils_test.go new file mode 100644 index 000000000..33caa51e5 --- /dev/null +++ b/x_event_monitor1/utils_test.go @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package x_event_monitor + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func Test_hasMotionFlag(t *testing.T) { + var flag = []int32{0, 1} + + assert.False(t, hasMotionFlag(flag[0])) + assert.True(t, hasMotionFlag(flag[1])) +} + +func Test_hasKeyFlag(t *testing.T) { + var flag = []int32{1, 4} + + assert.False(t, hasKeyFlag(flag[0])) + assert.True(t, hasKeyFlag(flag[1])) +} + +func Test_hasButtonFlag(t *testing.T) { + var flag = []int32{1, 2} + + assert.False(t, hasButtonFlag(flag[0])) + assert.True(t, hasButtonFlag(flag[1])) +} + +func Test_isInArea(t *testing.T) { + var area = coordinateRange{ + X1: 100, + X2: 200, + Y1: 100, + Y2: 200, + } + + var x = []int32{99, 101} + var y = []int32{99, 101} + + assert.True(t, isInArea(x[1], y[1], area)) + assert.False(t, isInArea(x[0], y[0], area)) +} + +func Test_isInIdList(t *testing.T) { + var list = []string{"tongxinruanjian", "tongshenruanjian"} + var md5str = []string{"tongxinruanjian", "tongxin"} + + assert.True(t, isInIdList(md5str[0], list)) + assert.False(t, isInIdList(md5str[1], list)) +}